File: | net/pipex.c |
Warning: | line 1832, column 2 Value stored to 'length' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: pipex.c,v 1.136 2022/01/02 22:36:04 jsg Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2009 Internet Initiative Japan Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include <sys/param.h> |
30 | #include <sys/systm.h> |
31 | #include <sys/mbuf.h> |
32 | #include <sys/socket.h> |
33 | #include <sys/ioctl.h> |
34 | #include <sys/select.h> |
35 | #include <sys/sysctl.h> |
36 | #include <sys/syslog.h> |
37 | #include <sys/conf.h> |
38 | #include <sys/time.h> |
39 | #include <sys/timeout.h> |
40 | #include <sys/kernel.h> |
41 | #include <sys/pool.h> |
42 | #include <sys/percpu.h> |
43 | |
44 | #include <net/if.h> |
45 | #include <net/if_types.h> |
46 | #include <netinet/in.h> |
47 | #include <netinet/if_ether.h> |
48 | #include <net/if_dl.h> |
49 | |
50 | #include <net/radix.h> |
51 | #include <net/route.h> |
52 | #include <net/ppp_defs.h> |
53 | #include <net/ppp-comp.h> |
54 | |
55 | #include "pf.h" |
56 | #if NPF1 > 0 |
57 | #include <net/pfvar.h> |
58 | #endif |
59 | |
60 | #include "bpfilter.h" |
61 | #if NBPFILTER1 > 0 |
62 | #include <net/bpf.h> |
63 | #endif |
64 | |
65 | #include <netinet/ip.h> |
66 | #include <netinet/ip_var.h> |
67 | #ifdef INET61 |
68 | #include <netinet/ip6.h> |
69 | #include <netinet6/ip6_var.h> |
70 | #endif |
71 | #include <netinet/tcp.h> |
72 | #include <netinet/udp.h> |
73 | #include <netinet/udp_var.h> |
74 | #include <crypto/arc4.h> |
75 | |
76 | /* drop static for ddb debuggability */ |
77 | #define Static |
78 | |
79 | #include <net/pipex.h> |
80 | #include "pipex_local.h" |
81 | |
82 | struct pool pipex_session_pool; |
83 | struct pool mppe_key_pool; |
84 | |
85 | /* |
86 | * Global data |
87 | * Locks used to protect global data |
88 | * A atomic operation |
89 | * I immutable after creation |
90 | * N net lock |
91 | */ |
92 | |
93 | int pipex_enable = 0; /* [N] */ |
94 | struct pipex_hash_head |
95 | pipex_session_list, /* [N] master session list */ |
96 | pipex_close_wait_list, /* [N] expired session list */ |
97 | pipex_peer_addr_hashtable[PIPEX_HASH_SIZE(512/8)], /* [N] peer's address hash */ |
98 | pipex_id_hashtable[PIPEX_HASH_SIZE(512/8)]; /* [N] peer id hash */ |
99 | |
100 | struct radix_node_head *pipex_rd_head4 = NULL((void *)0); /* [N] */ |
101 | struct radix_node_head *pipex_rd_head6 = NULL((void *)0); /* [N] */ |
102 | struct timeout pipex_timer_ch; /* callout timer context */ |
103 | int pipex_prune = 1; /* [I] walk list every seconds */ |
104 | |
105 | /* borrow an mbuf pkthdr field */ |
106 | #define ph_ppp_protoether_vtag ether_vtag |
107 | |
108 | #ifdef PIPEX_DEBUG |
109 | int pipex_debug = 0; /* [A] systcl net.inet.ip.pipex_debug */ |
110 | #endif |
111 | |
112 | /* PPP compression == MPPE is assumed, so don't answer CCP Reset-Request. */ |
113 | #define PIPEX_NO_CCP_RESETACK1 1 |
114 | |
115 | /************************************************************************ |
116 | * Core functions |
117 | ************************************************************************/ |
118 | void |
119 | pipex_init(void) |
120 | { |
121 | int i; |
122 | static int pipex_init_done = 0; |
123 | |
124 | if (pipex_init_done++) |
125 | return; |
126 | |
127 | rn_init(sizeof(struct sockaddr_in6)); |
128 | |
129 | pool_init(&pipex_session_pool, sizeof(struct pipex_session), 0, |
130 | IPL_SOFTNET0x5, PR_WAITOK0x0001, "ppxss", NULL((void *)0)); |
131 | pool_init(&mppe_key_pool, PIPEX_MPPE_KEYLEN16 * PIPEX_MPPE_NOLDKEY64, 0, |
132 | IPL_SOFTNET0x5, PR_WAITOK0x0001, "mppekey", NULL((void *)0)); |
133 | |
134 | LIST_INIT(&pipex_session_list)do { ((&pipex_session_list)->lh_first) = ((void *)0); } while (0); |
135 | LIST_INIT(&pipex_close_wait_list)do { ((&pipex_close_wait_list)->lh_first) = ((void *)0 ); } while (0); |
136 | |
137 | for (i = 0; i < nitems(pipex_id_hashtable)(sizeof((pipex_id_hashtable)) / sizeof((pipex_id_hashtable)[0 ])); i++) |
138 | LIST_INIT(&pipex_id_hashtable[i])do { ((&pipex_id_hashtable[i])->lh_first) = ((void *)0 ); } while (0); |
139 | for (i = 0; i < nitems(pipex_peer_addr_hashtable)(sizeof((pipex_peer_addr_hashtable)) / sizeof((pipex_peer_addr_hashtable )[0])); i++) |
140 | LIST_INIT(&pipex_peer_addr_hashtable[i])do { ((&pipex_peer_addr_hashtable[i])->lh_first) = ((void *)0); } while (0); |
141 | } |
142 | |
143 | void |
144 | pipex_destroy_all_sessions(void *ownersc) |
145 | { |
146 | struct pipex_session *session, *session_tmp; |
147 | |
148 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
149 | |
150 | LIST_FOREACH_SAFE(session, &pipex_session_list, session_list,for ((session) = ((&pipex_session_list)->lh_first); (session ) && ((session_tmp) = ((session)->session_list.le_next ), 1); (session) = (session_tmp)) |
151 | session_tmp)for ((session) = ((&pipex_session_list)->lh_first); (session ) && ((session_tmp) = ((session)->session_list.le_next ), 1); (session) = (session_tmp)) { |
152 | if (session->ownersc == ownersc) { |
153 | KASSERT(session->is_pppx == 0)((session->is_pppx == 0) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 153, "session->is_pppx == 0" )); |
154 | pipex_unlink_session(session); |
155 | pipex_rele_session(session); |
156 | } |
157 | } |
158 | } |
159 | |
160 | int |
161 | pipex_ioctl(void *ownersc, u_long cmd, caddr_t data) |
162 | { |
163 | int ret = 0; |
164 | |
165 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
166 | switch (cmd) { |
167 | case PIPEXCSESSION((unsigned long)0x80000000 | ((sizeof(struct pipex_session_config_req ) & 0x1fff) << 16) | ((('p')) << 8) | ((5))): |
168 | ret = pipex_config_session( |
169 | (struct pipex_session_config_req *)data, ownersc); |
170 | break; |
171 | |
172 | case PIPEXGSTAT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pipex_session_stat_req) & 0x1fff) << 16) | ( (('p')) << 8) | ((6))): |
173 | ret = pipex_get_stat((struct pipex_session_stat_req *)data, |
174 | ownersc); |
175 | break; |
176 | |
177 | case PIPEXGCLOSED((unsigned long)0x40000000 | ((sizeof(struct pipex_session_list_req ) & 0x1fff) << 16) | ((('p')) << 8) | ((7))): |
178 | ret = pipex_get_closed((struct pipex_session_list_req *)data, |
179 | ownersc); |
180 | break; |
181 | |
182 | default: |
183 | ret = ENOTTY25; |
184 | break; |
185 | } |
186 | |
187 | return (ret); |
188 | } |
189 | |
190 | /************************************************************************ |
191 | * Session management functions |
192 | ************************************************************************/ |
193 | int |
194 | pipex_init_session(struct pipex_session **rsession, |
195 | struct pipex_session_req *req) |
196 | { |
197 | struct pipex_session *session; |
198 | #ifdef PIPEX_PPPOE1 |
199 | struct ifnet *over_ifp = NULL((void *)0); |
200 | #endif |
201 | |
202 | /* Checks requested parameters. */ |
203 | switch (req->pr_protocol) { |
204 | #ifdef PIPEX_PPPOE1 |
205 | case PIPEX_PROTO_PPPOE3: |
206 | if (req->pr_peer_address.ss_family != AF_UNSPEC0) |
207 | return (EINVAL22); |
208 | break; |
209 | #endif |
210 | #if defined(PIPEX_L2TP1) || defined(PIPEX_PPTP1) |
211 | case PIPEX_PROTO_PPTP2: |
212 | case PIPEX_PROTO_L2TP1: |
213 | switch (req->pr_peer_address.ss_family) { |
214 | case AF_INET2: |
215 | if (req->pr_peer_address.ss_len != |
216 | sizeof(struct sockaddr_in)) |
217 | return (EINVAL22); |
218 | break; |
219 | #ifdef INET61 |
220 | case AF_INET624: |
221 | if (req->pr_peer_address.ss_len != |
222 | sizeof(struct sockaddr_in6)) |
223 | return (EINVAL22); |
224 | break; |
225 | #endif |
226 | default: |
227 | return (EPROTONOSUPPORT43); |
228 | } |
229 | if (req->pr_peer_address.ss_family != |
230 | req->pr_local_address.ss_family || |
231 | req->pr_peer_address.ss_len != |
232 | req->pr_local_address.ss_len) |
233 | return (EINVAL22); |
234 | break; |
235 | #endif /* defined(PIPEX_PPTP) || defined(PIPEX_L2TP) */ |
236 | default: |
237 | return (EPROTONOSUPPORT43); |
238 | } |
239 | #ifdef PIPEX_MPPE1 |
240 | if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED0x0010) != 0) { |
241 | if (req->pr_mppe_recv.keylenbits <= 0) |
242 | return (EINVAL22); |
243 | } |
244 | if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED0x0020) != 0) { |
245 | if (req->pr_mppe_send.keylenbits <= 0) |
246 | return (EINVAL22); |
247 | } |
248 | if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_REQUIRED0x0040) != 0) { |
249 | if ((req->pr_ppp_flags & |
250 | (PIPEX_PPP_MPPE_ACCEPTED0x0010 | PIPEX_PPP_MPPE_ENABLED0x0020)) != |
251 | (PIPEX_PPP_MPPE_ACCEPTED0x0010 | PIPEX_PPP_MPPE_ENABLED0x0020)) |
252 | return (EINVAL22); |
253 | } |
254 | #endif |
255 | |
256 | #ifdef PIPEX_PPPOE1 |
257 | if (req->pr_protocol == PIPEX_PROTO_PPPOE3) { |
258 | over_ifp = if_unit(req->pr_proto.pppoe.over_ifname); |
259 | if (over_ifp == NULL((void *)0)) |
260 | return (EINVAL22); |
261 | } |
262 | #endif |
263 | |
264 | /* prepare a new session */ |
265 | session = pool_get(&pipex_session_pool, PR_WAITOK0x0001 | PR_ZERO0x0008); |
266 | mtx_init(&session->pxs_mtx, IPL_SOFTNET)do { (void)(((void *)0)); (void)(0); __mtx_init((&session ->pxs_mtx), ((((0x5)) > 0x0 && ((0x5)) < 0x9 ) ? 0x9 : ((0x5)))); } while (0); |
267 | session->state = PIPEX_STATE_INITIAL0x0000; |
268 | session->protocol = req->pr_protocol; |
269 | session->session_id = req->pr_session_id; |
270 | session->peer_session_id = req->pr_peer_session_id; |
271 | session->peer_mru = req->pr_peer_mru; |
272 | session->timeout_sec = req->pr_timeout_sec; |
273 | session->ppp_flags = req->pr_ppp_flags; |
274 | session->ppp_id = req->pr_ppp_id; |
275 | |
276 | session->ip_forward = 1; |
277 | |
278 | session->stat_counters = counters_alloc(pxc_ncounters); |
279 | |
280 | session->ip_address.sin_family = AF_INET2; |
281 | session->ip_address.sin_len = sizeof(struct sockaddr_in); |
282 | session->ip_address.sin_addr = req->pr_ip_address; |
283 | |
284 | session->ip_netmask.sin_family = AF_INET2; |
285 | session->ip_netmask.sin_len = sizeof(struct sockaddr_in); |
286 | session->ip_netmask.sin_addr = req->pr_ip_netmask; |
287 | |
288 | if (session->ip_netmask.sin_addr.s_addr == 0L) |
289 | session->ip_netmask.sin_addr.s_addr = 0xffffffffL; |
290 | session->ip_address.sin_addr.s_addr &= |
291 | session->ip_netmask.sin_addr.s_addr; |
292 | |
293 | if (req->pr_peer_address.ss_len > 0) |
294 | memcpy(&session->peer, &req->pr_peer_address,__builtin_memcpy((&session->peer), (&req->pr_peer_address ), ((((req->pr_peer_address.ss_len)<(sizeof(session-> peer)))?(req->pr_peer_address.ss_len):(sizeof(session-> peer))))) |
295 | MIN(req->pr_peer_address.ss_len, sizeof(session->peer)))__builtin_memcpy((&session->peer), (&req->pr_peer_address ), ((((req->pr_peer_address.ss_len)<(sizeof(session-> peer)))?(req->pr_peer_address.ss_len):(sizeof(session-> peer))))); |
296 | if (req->pr_local_address.ss_len > 0) |
297 | memcpy(&session->local, &req->pr_local_address,__builtin_memcpy((&session->local), (&req->pr_local_address ), ((((req->pr_local_address.ss_len)<(sizeof(session-> local)))?(req->pr_local_address.ss_len):(sizeof(session-> local))))) |
298 | MIN(req->pr_local_address.ss_len, sizeof(session->local)))__builtin_memcpy((&session->local), (&req->pr_local_address ), ((((req->pr_local_address.ss_len)<(sizeof(session-> local)))?(req->pr_local_address.ss_len):(sizeof(session-> local))))); |
299 | #ifdef PIPEX_PPPOE1 |
300 | if (req->pr_protocol == PIPEX_PROTO_PPPOE3) { |
301 | session->proto.pppoe.over_ifidx = over_ifp->if_index; |
302 | if_put(over_ifp); |
303 | } |
304 | #endif |
305 | #ifdef PIPEX_PPTP1 |
306 | if (req->pr_protocol == PIPEX_PROTO_PPTP2) { |
307 | struct pipex_pptp_session *sess_pptp = &session->proto.pptp; |
308 | |
309 | sess_pptp->snd_gap = 0; |
310 | sess_pptp->rcv_gap = 0; |
311 | sess_pptp->snd_una = req->pr_proto.pptp.snd_una; |
312 | sess_pptp->snd_nxt = req->pr_proto.pptp.snd_nxt; |
313 | sess_pptp->rcv_nxt = req->pr_proto.pptp.rcv_nxt; |
314 | sess_pptp->rcv_acked = req->pr_proto.pptp.rcv_acked; |
315 | |
316 | sess_pptp->winsz = req->pr_proto.pptp.winsz; |
317 | sess_pptp->maxwinsz = req->pr_proto.pptp.maxwinsz; |
318 | sess_pptp->peer_maxwinsz = req->pr_proto.pptp.peer_maxwinsz; |
319 | /* last ack number */ |
320 | sess_pptp->ul_snd_una = sess_pptp->snd_una - 1; |
321 | } |
322 | #endif |
323 | #ifdef PIPEX_L2TP1 |
324 | if (req->pr_protocol == PIPEX_PROTO_L2TP1) { |
325 | struct pipex_l2tp_session *sess_l2tp = &session->proto.l2tp; |
326 | |
327 | /* session keys */ |
328 | sess_l2tp->tunnel_id = req->pr_proto.l2tp.tunnel_id; |
329 | sess_l2tp->peer_tunnel_id = req->pr_proto.l2tp.peer_tunnel_id; |
330 | |
331 | /* protocol options */ |
332 | sess_l2tp->option_flags = req->pr_proto.l2tp.option_flags; |
333 | |
334 | /* initial state of dynamic context */ |
335 | sess_l2tp->ns_gap = sess_l2tp->nr_gap = 0; |
336 | sess_l2tp->ns_nxt = req->pr_proto.l2tp.ns_nxt; |
337 | sess_l2tp->nr_nxt = req->pr_proto.l2tp.nr_nxt; |
338 | sess_l2tp->ns_una = req->pr_proto.l2tp.ns_una; |
339 | sess_l2tp->nr_acked = req->pr_proto.l2tp.nr_acked; |
340 | /* last ack number */ |
341 | sess_l2tp->ul_ns_una = sess_l2tp->ns_una - 1; |
342 | sess_l2tp->ipsecflowinfo = req->pr_proto.l2tp.ipsecflowinfo; |
343 | } |
344 | #endif |
345 | #ifdef PIPEX_MPPE1 |
346 | if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED0x0010) != 0) { |
347 | pipex_session_init_mppe_recv(session, |
348 | req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits, |
349 | req->pr_mppe_recv.master_key); |
350 | } |
351 | if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED0x0020) != 0) { |
352 | pipex_session_init_mppe_send(session, |
353 | req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits, |
354 | req->pr_mppe_send.master_key); |
355 | } |
356 | #endif |
357 | |
358 | *rsession = session; |
359 | |
360 | return 0; |
361 | } |
362 | |
363 | void |
364 | pipex_rele_session(struct pipex_session *session) |
365 | { |
366 | if (session->mppe_recv.old_session_keys) |
367 | pool_put(&mppe_key_pool, session->mppe_recv.old_session_keys); |
368 | counters_free(session->stat_counters, pxc_ncounters); |
369 | pool_put(&pipex_session_pool, session); |
370 | } |
371 | |
372 | int |
373 | pipex_link_session(struct pipex_session *session, struct ifnet *ifp, |
374 | void *ownersc) |
375 | { |
376 | struct pipex_hash_head *chain; |
377 | struct radix_node *rn; |
378 | |
379 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
380 | |
381 | if (pipex_rd_head4 == NULL((void *)0)) { |
382 | if (!rn_inithead((void **)&pipex_rd_head4, |
383 | offsetof(struct sockaddr_in, sin_addr)__builtin_offsetof(struct sockaddr_in, sin_addr))) |
384 | panic("rn_inithead() failed on pipex_link_session()"); |
385 | } |
386 | if (pipex_rd_head6 == NULL((void *)0)) { |
387 | if (!rn_inithead((void **)&pipex_rd_head6, |
388 | offsetof(struct sockaddr_in6, sin6_addr)__builtin_offsetof(struct sockaddr_in6, sin6_addr))) |
389 | panic("rn_inithead() failed on pipex_link_session()"); |
390 | } |
391 | if (pipex_lookup_by_session_id(session->protocol, |
392 | session->session_id)) |
393 | return (EEXIST17); |
394 | |
395 | session->ownersc = ownersc; |
396 | session->ifindex = ifp->if_index; |
397 | if (ifp->if_flags & IFF_POINTOPOINT0x10) |
398 | session->is_pppx = 1; |
399 | |
400 | if (session->is_pppx == 0 && |
401 | !in_nullhost(session->ip_address.sin_addr)((session->ip_address.sin_addr).s_addr == ((u_int32_t) (__uint32_t )(__builtin_constant_p((u_int32_t)(0x00000000)) ? (__uint32_t )(((__uint32_t)((u_int32_t)(0x00000000)) & 0xff) << 24 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff00) << 8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff0000) >> 8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff000000) >> 24) : __swap32md((u_int32_t)(0x00000000)))))) { |
402 | if (pipex_lookup_by_ip_address(session->ip_address.sin_addr) |
403 | != NULL((void *)0)) |
404 | return (EADDRINUSE48); |
405 | rn = rn_addroute(&session->ip_address, &session->ip_netmask, |
406 | pipex_rd_head4, session->ps4_rn, RTP_STATIC8); |
407 | if (rn == NULL((void *)0)) |
408 | return (ENOMEM12); |
409 | } |
410 | |
411 | LIST_INSERT_HEAD(&pipex_session_list, session, session_list)do { if (((session)->session_list.le_next = (&pipex_session_list )->lh_first) != ((void *)0)) (&pipex_session_list)-> lh_first->session_list.le_prev = &(session)->session_list .le_next; (&pipex_session_list)->lh_first = (session); (session)->session_list.le_prev = &(&pipex_session_list )->lh_first; } while (0); |
412 | chain = PIPEX_ID_HASHTABLE(session->session_id)(&pipex_id_hashtable[(session->session_id) & ((512 /8)-1)]); |
413 | LIST_INSERT_HEAD(chain, session, id_chain)do { if (((session)->id_chain.le_next = (chain)->lh_first ) != ((void *)0)) (chain)->lh_first->id_chain.le_prev = &(session)->id_chain.le_next; (chain)->lh_first = ( session); (session)->id_chain.le_prev = &(chain)->lh_first ; } while (0); |
414 | #if defined(PIPEX_PPTP1) || defined(PIPEX_L2TP1) |
415 | switch (session->protocol) { |
416 | case PIPEX_PROTO_PPTP2: |
417 | case PIPEX_PROTO_L2TP1: |
418 | chain = PIPEX_PEER_ADDR_HASHTABLE((&pipex_peer_addr_hashtable[(pipex_sockaddr_hash_key(& session->peer.sa)) & ((512/8)-1)]) |
419 | pipex_sockaddr_hash_key(&session->peer.sa))(&pipex_peer_addr_hashtable[(pipex_sockaddr_hash_key(& session->peer.sa)) & ((512/8)-1)]); |
420 | LIST_INSERT_HEAD(chain, session, peer_addr_chain)do { if (((session)->peer_addr_chain.le_next = (chain)-> lh_first) != ((void *)0)) (chain)->lh_first->peer_addr_chain .le_prev = &(session)->peer_addr_chain.le_next; (chain )->lh_first = (session); (session)->peer_addr_chain.le_prev = &(chain)->lh_first; } while (0); |
421 | } |
422 | #endif |
423 | |
424 | /* if first session is added, start timer */ |
425 | if (LIST_NEXT(session, session_list)((session)->session_list.le_next) == NULL((void *)0)) |
426 | pipex_timer_start(); |
427 | session->state = PIPEX_STATE_OPENED0x0001; |
428 | |
429 | return (0); |
430 | } |
431 | |
432 | void |
433 | pipex_unlink_session(struct pipex_session *session) |
434 | { |
435 | struct radix_node *rn; |
436 | |
437 | session->ifindex = 0; |
438 | |
439 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
440 | if (session->state == PIPEX_STATE_CLOSED0x0004) |
441 | return; |
442 | if (session->is_pppx == 0 && |
443 | !in_nullhost(session->ip_address.sin_addr)((session->ip_address.sin_addr).s_addr == ((u_int32_t) (__uint32_t )(__builtin_constant_p((u_int32_t)(0x00000000)) ? (__uint32_t )(((__uint32_t)((u_int32_t)(0x00000000)) & 0xff) << 24 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff00) << 8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff0000) >> 8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff000000) >> 24) : __swap32md((u_int32_t)(0x00000000)))))) { |
444 | KASSERT(pipex_rd_head4 != NULL)((pipex_rd_head4 != ((void *)0)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 444, "pipex_rd_head4 != NULL")); |
445 | rn = rn_delete(&session->ip_address, &session->ip_netmask, |
446 | pipex_rd_head4, (struct radix_node *)session); |
447 | KASSERT(rn != NULL)((rn != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 447, "rn != NULL")); |
448 | } |
449 | |
450 | LIST_REMOVE(session, id_chain)do { if ((session)->id_chain.le_next != ((void *)0)) (session )->id_chain.le_next->id_chain.le_prev = (session)->id_chain .le_prev; *(session)->id_chain.le_prev = (session)->id_chain .le_next; ((session)->id_chain.le_prev) = ((void *)-1); (( session)->id_chain.le_next) = ((void *)-1); } while (0); |
451 | #if defined(PIPEX_PPTP1) || defined(PIPEX_L2TP1) |
452 | switch (session->protocol) { |
453 | case PIPEX_PROTO_PPTP2: |
454 | case PIPEX_PROTO_L2TP1: |
455 | LIST_REMOVE(session, peer_addr_chain)do { if ((session)->peer_addr_chain.le_next != ((void *)0) ) (session)->peer_addr_chain.le_next->peer_addr_chain.le_prev = (session)->peer_addr_chain.le_prev; *(session)->peer_addr_chain .le_prev = (session)->peer_addr_chain.le_next; ((session)-> peer_addr_chain.le_prev) = ((void *)-1); ((session)->peer_addr_chain .le_next) = ((void *)-1); } while (0); |
456 | break; |
457 | } |
458 | #endif |
459 | if (session->state == PIPEX_STATE_CLOSE_WAIT0x0002) |
460 | LIST_REMOVE(session, state_list)do { if ((session)->state_list.le_next != ((void *)0)) (session )->state_list.le_next->state_list.le_prev = (session)-> state_list.le_prev; *(session)->state_list.le_prev = (session )->state_list.le_next; ((session)->state_list.le_prev) = ((void *)-1); ((session)->state_list.le_next) = ((void *) -1); } while (0); |
461 | LIST_REMOVE(session, session_list)do { if ((session)->session_list.le_next != ((void *)0)) ( session)->session_list.le_next->session_list.le_prev = ( session)->session_list.le_prev; *(session)->session_list .le_prev = (session)->session_list.le_next; ((session)-> session_list.le_prev) = ((void *)-1); ((session)->session_list .le_next) = ((void *)-1); } while (0); |
462 | session->state = PIPEX_STATE_CLOSED0x0004; |
463 | |
464 | /* if final session is destroyed, stop timer */ |
465 | if (LIST_EMPTY(&pipex_session_list)(((&pipex_session_list)->lh_first) == ((void *)0))) |
466 | pipex_timer_stop(); |
467 | } |
468 | |
469 | int |
470 | pipex_notify_close_session(struct pipex_session *session) |
471 | { |
472 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
473 | session->state = PIPEX_STATE_CLOSE_WAIT0x0002; |
474 | session->idle_time = 0; |
475 | LIST_INSERT_HEAD(&pipex_close_wait_list, session, state_list)do { if (((session)->state_list.le_next = (&pipex_close_wait_list )->lh_first) != ((void *)0)) (&pipex_close_wait_list)-> lh_first->state_list.le_prev = &(session)->state_list .le_next; (&pipex_close_wait_list)->lh_first = (session ); (session)->state_list.le_prev = &(&pipex_close_wait_list )->lh_first; } while (0); |
476 | |
477 | return (0); |
478 | } |
479 | |
480 | void |
481 | pipex_export_session_stats(struct pipex_session *session, |
482 | struct pipex_statistics *stats) |
483 | { |
484 | uint64_t counters[pxc_ncounters]; |
485 | |
486 | memset(stats, 0, sizeof(*stats))__builtin_memset((stats), (0), (sizeof(*stats))); |
487 | |
488 | counters_read(session->stat_counters, counters, pxc_ncounters); |
489 | stats->ipackets = counters[pxc_ipackets]; |
490 | stats->ierrors = counters[pxc_ierrors]; |
491 | stats->ibytes = counters[pxc_ibytes]; |
492 | stats->opackets = counters[pxc_opackets]; |
493 | stats->oerrors = counters[pxc_oerrors]; |
494 | stats->obytes = counters[pxc_obytes]; |
495 | stats->idle_time = session->idle_time; |
496 | } |
497 | |
498 | Static int |
499 | pipex_config_session(struct pipex_session_config_req *req, void *ownersc) |
500 | { |
501 | struct pipex_session *session; |
502 | |
503 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
504 | session = pipex_lookup_by_session_id(req->pcr_protocolpsr_protocol, |
505 | req->pcr_session_idpsr_session_id); |
506 | if (session == NULL((void *)0)) |
507 | return (EINVAL22); |
508 | if (session->ownersc != ownersc) |
509 | return (EINVAL22); |
510 | session->ip_forward = req->pcr_ip_forward; |
511 | |
512 | return (0); |
513 | } |
514 | |
515 | Static int |
516 | pipex_get_stat(struct pipex_session_stat_req *req, void *ownersc) |
517 | { |
518 | struct pipex_session *session; |
519 | |
520 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
521 | session = pipex_lookup_by_session_id(req->psr_protocol, |
522 | req->psr_session_id); |
523 | if (session == NULL((void *)0)) |
524 | return (EINVAL22); |
525 | if (session->ownersc != ownersc) |
526 | return (EINVAL22); |
527 | pipex_export_session_stats(session, &req->psr_stat); |
528 | |
529 | return (0); |
530 | } |
531 | |
532 | Static int |
533 | pipex_get_closed(struct pipex_session_list_req *req, void *ownersc) |
534 | { |
535 | struct pipex_session *session, *session_tmp; |
536 | |
537 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
538 | bzero(req, sizeof(*req))__builtin_bzero((req), (sizeof(*req))); |
539 | LIST_FOREACH_SAFE(session, &pipex_close_wait_list, state_list,for ((session) = ((&pipex_close_wait_list)->lh_first); (session) && ((session_tmp) = ((session)->state_list .le_next), 1); (session) = (session_tmp)) |
540 | session_tmp)for ((session) = ((&pipex_close_wait_list)->lh_first); (session) && ((session_tmp) = ((session)->state_list .le_next), 1); (session) = (session_tmp)) { |
541 | if (session->ownersc != ownersc) |
542 | continue; |
543 | req->plr_ppp_id[req->plr_ppp_id_count++] = session->ppp_id; |
544 | LIST_REMOVE(session, state_list)do { if ((session)->state_list.le_next != ((void *)0)) (session )->state_list.le_next->state_list.le_prev = (session)-> state_list.le_prev; *(session)->state_list.le_prev = (session )->state_list.le_next; ((session)->state_list.le_prev) = ((void *)-1); ((session)->state_list.le_next) = ((void *) -1); } while (0); |
545 | session->state = PIPEX_STATE_CLOSE_WAIT20x0003; |
546 | if (req->plr_ppp_id_count >= PIPEX_MAX_LISTREQ128) { |
547 | if (!LIST_EMPTY(&pipex_close_wait_list)(((&pipex_close_wait_list)->lh_first) == ((void *)0))) |
548 | req->plr_flags |= PIPEX_LISTREQ_MORE0x01; |
549 | break; |
550 | } |
551 | } |
552 | |
553 | return (0); |
554 | } |
555 | |
556 | Static struct pipex_session * |
557 | pipex_lookup_by_ip_address(struct in_addr addr) |
558 | { |
559 | struct pipex_session *session; |
560 | struct sockaddr_in pipex_in4, pipex_in4mask; |
561 | |
562 | if (pipex_rd_head4 == NULL((void *)0)) |
563 | return (NULL((void *)0)); |
564 | bzero(&pipex_in4, sizeof(pipex_in4))__builtin_bzero((&pipex_in4), (sizeof(pipex_in4))); |
565 | pipex_in4.sin_addr = addr; |
566 | pipex_in4.sin_family = AF_INET2; |
567 | pipex_in4.sin_len = sizeof(pipex_in4); |
568 | |
569 | bzero(&pipex_in4mask, sizeof(pipex_in4mask))__builtin_bzero((&pipex_in4mask), (sizeof(pipex_in4mask)) ); |
570 | pipex_in4mask.sin_addr.s_addr = htonl(0xFFFFFFFFL)(__uint32_t)(__builtin_constant_p(0xFFFFFFFFL) ? (__uint32_t) (((__uint32_t)(0xFFFFFFFFL) & 0xff) << 24 | ((__uint32_t )(0xFFFFFFFFL) & 0xff00) << 8 | ((__uint32_t)(0xFFFFFFFFL ) & 0xff0000) >> 8 | ((__uint32_t)(0xFFFFFFFFL) & 0xff000000) >> 24) : __swap32md(0xFFFFFFFFL)); |
571 | pipex_in4mask.sin_family = AF_INET2; |
572 | pipex_in4mask.sin_len = sizeof(pipex_in4mask); |
573 | |
574 | session = (struct pipex_session *)rn_lookup(&pipex_in4, &pipex_in4mask, |
575 | pipex_rd_head4); |
576 | |
577 | #ifdef PIPEX_DEBUG |
578 | if (session == NULL((void *)0)) { |
579 | char buf[INET_ADDRSTRLEN16]; |
580 | |
581 | PIPEX_DBG((NULL, LOG_DEBUG, "<%s> session not found (addr=%s)", |
582 | __func__, inet_ntop(AF_INET, &addr, buf, sizeof(buf)))); |
583 | } |
584 | #endif |
585 | |
586 | return (session); |
587 | } |
588 | |
589 | Static struct pipex_session * |
590 | pipex_lookup_by_session_id(int protocol, int session_id) |
591 | { |
592 | struct pipex_hash_head *list; |
593 | struct pipex_session *session; |
594 | |
595 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
596 | list = PIPEX_ID_HASHTABLE(session_id)(&pipex_id_hashtable[(session_id) & ((512/8)-1)]); |
597 | LIST_FOREACH(session, list, id_chain)for((session) = ((list)->lh_first); (session)!= ((void *)0 ); (session) = ((session)->id_chain.le_next)) { |
598 | if (session->protocol == protocol && |
599 | session->session_id == session_id) |
600 | break; |
601 | } |
602 | |
603 | #ifdef PIPEX_DEBUG |
604 | if (session == NULL((void *)0)) |
605 | PIPEX_DBG((NULL, LOG_DEBUG, |
606 | "<%s> session not found (session_id=%d)", __func__, |
607 | session_id)); |
608 | #endif |
609 | |
610 | return (session); |
611 | } |
612 | |
613 | /*********************************************************************** |
614 | * Timer functions |
615 | ***********************************************************************/ |
616 | Static void |
617 | pipex_timer_start(void) |
618 | { |
619 | timeout_set_proc(&pipex_timer_ch, pipex_timer, NULL((void *)0)); |
620 | timeout_add_sec(&pipex_timer_ch, pipex_prune); |
621 | } |
622 | |
623 | Static void |
624 | pipex_timer_stop(void) |
625 | { |
626 | timeout_del(&pipex_timer_ch); |
627 | } |
628 | |
629 | Static void |
630 | pipex_timer(void *ignored_arg) |
631 | { |
632 | struct pipex_session *session, *session_tmp; |
633 | |
634 | timeout_add_sec(&pipex_timer_ch, pipex_prune); |
635 | |
636 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); |
637 | /* walk through */ |
638 | LIST_FOREACH_SAFE(session, &pipex_session_list, session_list,for ((session) = ((&pipex_session_list)->lh_first); (session ) && ((session_tmp) = ((session)->session_list.le_next ), 1); (session) = (session_tmp)) |
639 | session_tmp)for ((session) = ((&pipex_session_list)->lh_first); (session ) && ((session_tmp) = ((session)->session_list.le_next ), 1); (session) = (session_tmp)) { |
640 | switch (session->state) { |
641 | case PIPEX_STATE_OPENED0x0001: |
642 | if (session->timeout_sec == 0) |
643 | continue; |
644 | |
645 | session->idle_time++; |
646 | if (session->idle_time < session->timeout_sec) |
647 | continue; |
648 | |
649 | pipex_notify_close_session(session); |
650 | break; |
651 | |
652 | case PIPEX_STATE_CLOSE_WAIT0x0002: |
653 | case PIPEX_STATE_CLOSE_WAIT20x0003: |
654 | /* Waiting PIPEXDSESSION from userland */ |
655 | session->idle_time++; |
656 | if (session->idle_time < PIPEX_CLOSE_TIMEOUT30) |
657 | continue; |
658 | /* Release the sessions when timeout */ |
659 | pipex_unlink_session(session); |
660 | KASSERTMSG(session->is_pppx == 0,((session->is_pppx == 0) ? (void)0 : panic("kernel %sassertion \"%s\" failed: file \"%s\", line %d" " " "FIXME session must not be released when pppx", "diagnostic " , "session->is_pppx == 0", "/usr/src/sys/net/pipex.c", 661 )) |
661 | "FIXME session must not be released when pppx")((session->is_pppx == 0) ? (void)0 : panic("kernel %sassertion \"%s\" failed: file \"%s\", line %d" " " "FIXME session must not be released when pppx", "diagnostic " , "session->is_pppx == 0", "/usr/src/sys/net/pipex.c", 661 )); |
662 | pipex_rele_session(session); |
663 | break; |
664 | |
665 | default: |
666 | break; |
667 | } |
668 | } |
669 | |
670 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); |
671 | } |
672 | |
673 | /*********************************************************************** |
674 | * Common network I/O functions. (tunnel protocol independent) |
675 | ***********************************************************************/ |
676 | Static void |
677 | pipex_ip_output(struct mbuf *m0, struct pipex_session *session) |
678 | { |
679 | int is_idle; |
680 | |
681 | if (session->is_multicast == 0) { |
682 | /* |
683 | * Multicast packet is a idle packet and it's not TCP. |
684 | */ |
685 | if (session->ip_forward == 0 && session->ip6_forward == 0) |
686 | goto drop; |
687 | /* reset idle timer */ |
688 | if (session->timeout_sec != 0) { |
689 | is_idle = 0; |
690 | m0 = ip_is_idle_packet(m0, &is_idle); |
691 | if (m0 == NULL((void *)0)) |
692 | goto dropped; |
693 | if (is_idle == 0) |
694 | /* update expire time */ |
695 | session->idle_time = 0; |
696 | } |
697 | |
698 | /* adjust tcpmss */ |
699 | if ((session->ppp_flags & PIPEX_PPP_ADJUST_TCPMSS0x0100) != 0) { |
700 | m0 = adjust_tcp_mss(m0, session->peer_mru); |
701 | if (m0 == NULL((void *)0)) |
702 | goto dropped; |
703 | } |
704 | |
705 | pipex_ppp_output(m0, session, PPP_IP0x21); |
706 | } else { |
707 | struct pipex_session *session_tmp; |
708 | struct mbuf *m; |
709 | |
710 | m0->m_flagsm_hdr.mh_flags &= ~(M_BCAST0x0100|M_MCAST0x0200); |
711 | |
712 | LIST_FOREACH(session_tmp, &pipex_session_list, session_list)for((session_tmp) = ((&pipex_session_list)->lh_first); (session_tmp)!= ((void *)0); (session_tmp) = ((session_tmp)-> session_list.le_next)) { |
713 | if (session_tmp->ownersc != session->ownersc) |
714 | continue; |
715 | if (session_tmp->ip_forward == 0 && |
716 | session_tmp->ip6_forward == 0) |
717 | continue; |
718 | m = m_copym(m0, 0, M_COPYALL1000000000, M_NOWAIT0x0002); |
719 | if (m == NULL((void *)0)) { |
720 | counters_inc(session->stat_counters, |
721 | pxc_oerrors); |
722 | continue; |
723 | } |
724 | pipex_ppp_output(m, session_tmp, PPP_IP0x21); |
725 | } |
726 | m_freem(m0); |
727 | } |
728 | |
729 | return; |
730 | drop: |
731 | m_freem(m0); |
732 | dropped: |
733 | counters_inc(session->stat_counters, pxc_oerrors); |
734 | } |
735 | |
736 | Static void |
737 | pipex_ppp_output(struct mbuf *m0, struct pipex_session *session, int proto) |
738 | { |
739 | u_char *cp, hdr[16]; |
740 | |
741 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
742 | |
743 | #ifdef PIPEX_MPPE1 |
744 | if (pipex_session_is_mppe_enabled(session)(((session)->ppp_flags & 0x0020)? 1 : 0)) { |
745 | if (proto == PPP_IP0x21) { |
746 | pipex_mppe_output(m0, session, PPP_IP0x21); |
747 | return; |
748 | } |
749 | } |
750 | #endif /* PIPEX_MPPE */ |
751 | cp = hdr; |
752 | if (session->protocol != PIPEX_PROTO_PPPOE3) { |
753 | /* PPPoE has not address and control field */ |
754 | PUTCHAR(PPP_ALLSTATIONS, cp)do { *(cp)++ = (u_char)(0xff); } while (0); |
755 | PUTCHAR(PPP_UI, cp)do { *(cp)++ = (u_char)(0x03); } while (0); |
756 | } |
757 | PUTSHORT(proto, cp)do { *(cp)++ = (u_char) ((proto) >> 8); *(cp)++ = (u_char ) (proto); } while (0); |
758 | |
759 | M_PREPEND(m0, cp - hdr, M_NOWAIT)(m0) = m_prepend((m0), (cp - hdr), (0x0002)); |
760 | if (m0 == NULL((void *)0)) |
761 | goto drop; |
762 | memcpy(mtod(m0, u_char *), hdr, cp - hdr)__builtin_memcpy((((u_char *)((m0)->m_hdr.mh_data))), (hdr ), (cp - hdr)); |
763 | |
764 | switch (session->protocol) { |
765 | #ifdef PIPEX_PPPOE1 |
766 | case PIPEX_PROTO_PPPOE3: |
767 | pipex_pppoe_output(m0, session); |
768 | break; |
769 | #endif |
770 | #ifdef PIPEX_PPTP1 |
771 | case PIPEX_PROTO_PPTP2: |
772 | pipex_pptp_output(m0, session, 1, 1); |
773 | break; |
774 | #endif |
775 | #ifdef PIPEX_L2TP1 |
776 | case PIPEX_PROTO_L2TP1: |
777 | pipex_l2tp_output(m0, session); |
778 | break; |
779 | #endif |
780 | default: |
781 | goto drop; |
782 | } |
783 | |
784 | return; |
785 | drop: |
786 | m_freem(m0); |
787 | counters_inc(session->stat_counters, pxc_oerrors); |
788 | } |
789 | |
790 | Static void |
791 | pipex_ppp_input(struct mbuf *m0, struct pipex_session *session, int decrypted) |
792 | { |
793 | int proto, hlen = 0; |
794 | struct mbuf *n; |
795 | |
796 | KASSERT(m0->m_pkthdr.len >= PIPEX_PPPMINLEN)((m0->M_dat.MH.MH_pkthdr.len >= 5) ? (void)0 : __assert ("diagnostic ", "/usr/src/sys/net/pipex.c", 796, "m0->m_pkthdr.len >= PIPEX_PPPMINLEN" )); |
797 | proto = pipex_ppp_proto(m0, session, 0, &hlen); |
798 | #ifdef PIPEX_MPPE1 |
799 | if (proto == PPP_COMP0xfd) { |
800 | if (decrypted) |
801 | goto drop; |
802 | |
803 | /* checked this on ppp_common_input() already. */ |
804 | KASSERT(pipex_session_is_mppe_accepted(session))(((((session)->ppp_flags & 0x0010)? 1 : 0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c", 804, "pipex_session_is_mppe_accepted(session)" )); |
805 | |
806 | m_adj(m0, hlen); |
807 | pipex_mppe_input(m0, session); |
808 | return; |
809 | } |
810 | if (proto == PPP_CCP0x80fd) { |
811 | if (decrypted) |
812 | goto drop; |
813 | |
814 | #if NBPFILTER1 > 0 |
815 | { |
816 | struct ifnet *ifp; |
817 | |
818 | if ((ifp = if_get(session->ifindex)) != NULL((void *)0)) { |
819 | if (ifp->if_bpf && ifp->if_typeif_data.ifi_type == IFT_PPP0x17) |
820 | bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_IN(1 << 0)); |
821 | } |
822 | if_put(ifp); |
823 | } |
824 | #endif |
825 | m_adj(m0, hlen); |
826 | pipex_ccp_input(m0, session); |
827 | return; |
828 | } |
829 | #endif |
830 | m_adj(m0, hlen); |
831 | if (!ALIGNED_POINTER(mtod(m0, caddr_t), uint32_t)1) { |
832 | n = m_dup_pkt(m0, 0, M_NOWAIT0x0002); |
833 | if (n == NULL((void *)0)) |
834 | goto drop; |
835 | m_freem(m0); |
836 | m0 = n; |
837 | } |
838 | |
839 | switch (proto) { |
840 | case PPP_IP0x21: |
841 | if (session->ip_forward == 0) |
842 | goto drop; |
843 | if (!decrypted && pipex_session_is_mppe_required(session)(((session)->ppp_flags & 0x0040)? 1 : 0)) |
844 | /* |
845 | * if ip packet received when mppe |
846 | * is required, discard it. |
847 | */ |
848 | goto drop; |
849 | pipex_ip_input(m0, session); |
850 | return; |
851 | #ifdef INET61 |
852 | case PPP_IPV60x57: |
853 | if (session->ip6_forward == 0) |
854 | goto drop; |
855 | if (!decrypted && pipex_session_is_mppe_required(session)(((session)->ppp_flags & 0x0040)? 1 : 0)) |
856 | /* |
857 | * if ip packet received when mppe |
858 | * is required, discard it. |
859 | */ |
860 | goto drop; |
861 | pipex_ip6_input(m0, session); |
862 | return; |
863 | #endif |
864 | default: |
865 | if (decrypted) |
866 | goto drop; |
867 | /* protocol must be checked on pipex_common_input() already */ |
868 | KASSERT(0)((0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 868, "0")); |
869 | goto drop; |
870 | } |
871 | |
872 | return; |
873 | drop: |
874 | m_freem(m0); |
875 | counters_inc(session->stat_counters, pxc_ierrors); |
876 | } |
877 | |
878 | Static void |
879 | pipex_ip_input(struct mbuf *m0, struct pipex_session *session) |
880 | { |
881 | struct ifnet *ifp; |
882 | struct ip *ip; |
883 | int len; |
884 | int is_idle; |
885 | |
886 | /* change recvif */ |
887 | m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = session->ifindex; |
888 | |
889 | if (ISSET(session->ppp_flags, PIPEX_PPP_INGRESS_FILTER)((session->ppp_flags) & (0x0200))) { |
890 | PIPEX_PULLUP(m0, sizeof(struct ip))if ((m0)->m_hdr.mh_len < (sizeof(struct ip))) { if ((m0 )->M_dat.MH.MH_pkthdr.len < (sizeof(struct ip))) { ; m_freem (m0); (m0) = ((void *)0); } else { (m0) = m_pullup((m0), (sizeof (struct ip))); (((m0) != ((void *)0)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 890, "(m0) != NULL")); } }; |
891 | if (m0 == NULL((void *)0)) |
892 | goto drop; |
893 | /* ingress filter */ |
894 | ip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
895 | if ((ip->ip_src.s_addr & session->ip_netmask.sin_addr.s_addr) != |
896 | session->ip_address.sin_addr.s_addr) { |
897 | char src[INET_ADDRSTRLEN16]; |
898 | |
899 | pipex_session_log(session, LOG_DEBUG7, |
900 | "ip packet discarded by ingress filter (src %s)", |
901 | inet_ntop(AF_INET2, &ip->ip_src, src, sizeof(src))); |
902 | goto drop; |
903 | } |
904 | } |
905 | |
906 | /* idle timer */ |
907 | if (session->timeout_sec != 0) { |
908 | is_idle = 0; |
909 | m0 = ip_is_idle_packet(m0, &is_idle); |
910 | if (m0 == NULL((void *)0)) |
911 | goto drop; |
912 | if (is_idle == 0) |
913 | /* update expire time */ |
914 | session->idle_time = 0; |
915 | } |
916 | |
917 | /* adjust tcpmss */ |
918 | if (session->ppp_flags & PIPEX_PPP_ADJUST_TCPMSS0x0100) { |
919 | m0 = adjust_tcp_mss(m0, session->peer_mru); |
920 | if (m0 == NULL((void *)0)) |
921 | goto drop; |
922 | } |
923 | |
924 | #if NPF1 > 0 |
925 | pf_pkt_addr_changed(m0); |
926 | #endif |
927 | |
928 | len = m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
929 | |
930 | if ((ifp = if_get(session->ifindex)) == NULL((void *)0)) |
931 | goto drop; |
932 | |
933 | #if NBPFILTER1 > 0 |
934 | if (ifp->if_bpf) |
935 | bpf_mtap_af(ifp->if_bpf, AF_INET2, m0, BPF_DIRECTION_IN(1 << 0)); |
936 | #endif |
937 | |
938 | counters_pkt(ifp->if_counters, ifc_ipackets, ifc_ibytes, len); |
939 | counters_pkt(session->stat_counters, pxc_ipackets, pxc_ibytes, len); |
940 | ipv4_input(ifp, m0); |
941 | |
942 | if_put(ifp); |
943 | |
944 | return; |
945 | drop: |
946 | m_freem(m0); |
947 | counters_inc(session->stat_counters, pxc_ierrors); |
948 | } |
949 | |
950 | #ifdef INET61 |
951 | Static void |
952 | pipex_ip6_input(struct mbuf *m0, struct pipex_session *session) |
953 | { |
954 | struct ifnet *ifp; |
955 | int len; |
956 | |
957 | /* change recvif */ |
958 | m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = session->ifindex; |
959 | |
960 | /* |
961 | * XXX: what is reasonable ingress filter ??? |
962 | * only one address is enough ?? |
963 | */ |
964 | |
965 | /* XXX: we must define idle packet for IPv6(ICMPv6). */ |
966 | |
967 | /* |
968 | * XXX: tcpmss adjustment for IPv6 is required??? |
969 | * We may use PMTUD in IPv6.... |
970 | */ |
971 | |
972 | #if NPF1 > 0 |
973 | pf_pkt_addr_changed(m0); |
974 | #endif |
975 | |
976 | len = m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
977 | |
978 | if ((ifp = if_get(session->ifindex)) == NULL((void *)0)) |
979 | goto drop; |
980 | |
981 | #if NBPFILTER1 > 0 |
982 | if (ifp->if_bpf) |
983 | bpf_mtap_af(ifp->if_bpf, AF_INET624, m0, BPF_DIRECTION_IN(1 << 0)); |
984 | #endif |
985 | |
986 | counters_pkt(ifp->if_counters, ifc_ipackets, ifc_ibytes, len); |
987 | counters_pkt(session->stat_counters, pxc_ipackets, pxc_ibytes, len); |
988 | ipv6_input(ifp, m0); |
989 | |
990 | if_put(ifp); |
991 | |
992 | return; |
993 | drop: |
994 | m_freem(m0); |
995 | counters_inc(session->stat_counters, pxc_ierrors); |
996 | } |
997 | #endif |
998 | |
999 | Static struct mbuf * |
1000 | pipex_common_input(struct pipex_session *session, struct mbuf *m0, int hlen, |
1001 | int plen) |
1002 | { |
1003 | int proto, ppphlen; |
1004 | u_char code; |
1005 | |
1006 | if ((m0->m_pkthdrM_dat.MH.MH_pkthdr.len < hlen + PIPEX_PPPMINLEN5) || |
1007 | (plen < PIPEX_PPPMINLEN5)) |
1008 | goto drop; |
1009 | |
1010 | proto = pipex_ppp_proto(m0, session, hlen, &ppphlen); |
1011 | switch (proto) { |
1012 | #ifdef PIPEX_MPPE1 |
1013 | case PPP_CCP0x80fd: |
1014 | code = 0; |
1015 | KASSERT(m0->m_pkthdr.len >= hlen + ppphlen + 1)((m0->M_dat.MH.MH_pkthdr.len >= hlen + ppphlen + 1) ? ( void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c", 1015 , "m0->m_pkthdr.len >= hlen + ppphlen + 1")); |
1016 | m_copydata(m0, hlen + ppphlen, 1, &code); |
1017 | if (code != CCP_RESETREQ14 && code != CCP_RESETACK15) |
1018 | goto not_ours; |
1019 | break; |
1020 | |
1021 | case PPP_COMP0xfd: |
1022 | if (pipex_session_is_mppe_accepted(session)(((session)->ppp_flags & 0x0010)? 1 : 0)) |
1023 | break; |
1024 | goto not_ours; |
1025 | #endif |
1026 | case PPP_IP0x21: |
1027 | #ifdef INET61 |
1028 | case PPP_IPV60x57: |
1029 | #endif |
1030 | break; |
1031 | default: |
1032 | goto not_ours; |
1033 | } |
1034 | |
1035 | /* ok, The packet is for PIPEX */ |
1036 | m_adj(m0, hlen);/* cut off the tunnel protocol header */ |
1037 | |
1038 | /* ensure the mbuf length equals the PPP frame length */ |
1039 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < plen) |
1040 | goto drop; |
1041 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len > plen) { |
1042 | if (m0->m_lenm_hdr.mh_len == m0->m_pkthdrM_dat.MH.MH_pkthdr.len) { |
1043 | m0->m_lenm_hdr.mh_len = plen; |
1044 | m0->m_pkthdrM_dat.MH.MH_pkthdr.len = plen; |
1045 | } else |
1046 | m_adj(m0, plen - m0->m_pkthdrM_dat.MH.MH_pkthdr.len); |
1047 | } |
1048 | |
1049 | pipex_ppp_input(m0, session, 0); |
1050 | |
1051 | return (NULL((void *)0)); |
1052 | |
1053 | drop: |
1054 | m_freem(m0); |
1055 | counters_inc(session->stat_counters, pxc_ierrors); |
1056 | return (NULL((void *)0)); |
1057 | |
1058 | not_ours: |
1059 | return (m0); /* Not to be handled by PIPEX */ |
1060 | } |
1061 | |
1062 | /* |
1063 | * pipex_ppp_proto |
1064 | */ |
1065 | Static int |
1066 | pipex_ppp_proto(struct mbuf *m0, struct pipex_session *session, int off, |
1067 | int *hlenp) |
1068 | { |
1069 | int proto; |
1070 | u_char *cp, pktbuf[4]; |
1071 | |
1072 | KASSERT(m0->m_pkthdr.len > sizeof(pktbuf))((m0->M_dat.MH.MH_pkthdr.len > sizeof(pktbuf)) ? (void) 0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c", 1072, "m0->m_pkthdr.len > sizeof(pktbuf)")); |
1073 | m_copydata(m0, off, sizeof(pktbuf), pktbuf); |
1074 | cp = pktbuf; |
1075 | |
1076 | if (pipex_session_has_acf(session)(((session)->ppp_flags & 0x0080)? 1 : 0)) { |
1077 | if (cp[0] == PPP_ALLSTATIONS0xff && cp[1] == PPP_UI0x03) |
1078 | cp += 2; |
1079 | #ifdef PIPEX_DEBUG |
1080 | else if (!pipex_session_is_acfc_accepted(session)(((session)->ppp_flags & 0x0001)? 1 : 0)) |
1081 | PIPEX_DBG((session, LOG_DEBUG, |
1082 | "no acf but acfc is not accepted by the peer.")); |
1083 | #endif |
1084 | } |
1085 | if ((*cp & 0x01) != 0) { |
1086 | if (!pipex_session_is_pfc_accepted(session)(((session)->ppp_flags & 0x0002)? 1 : 0)) { |
1087 | PIPEX_DBG((session, LOG_DEBUG, "Received a broken ppp " |
1088 | "frame. No protocol field. %02x-%02x", |
1089 | cp[0], cp[1])); |
1090 | return (-1); |
1091 | } |
1092 | GETCHAR(proto, cp)do { (proto) = *(cp)++; } while (0); |
1093 | } else |
1094 | GETSHORT(proto, cp)do { (proto) = *(cp)++ << 8; (proto) |= *(cp)++; } while (0); |
1095 | |
1096 | if (hlenp != NULL((void *)0)) |
1097 | *hlenp = cp - pktbuf; |
1098 | |
1099 | return (proto); |
1100 | } |
1101 | |
1102 | #ifdef PIPEX_PPPOE1 |
1103 | /*********************************************************************** |
1104 | * PPPoE |
1105 | ***********************************************************************/ |
1106 | Static u_char pipex_pppoe_padding[ETHERMIN(64 - ((6 * 2) + 2) - 4)]; |
1107 | /* |
1108 | * pipex_pppoe_lookup_session |
1109 | */ |
1110 | struct pipex_session * |
1111 | pipex_pppoe_lookup_session(struct mbuf *m0) |
1112 | { |
1113 | struct pipex_session *session; |
1114 | struct pipex_pppoe_header pppoe; |
1115 | |
1116 | /* short packet */ |
1117 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < (sizeof(struct ether_header) + sizeof(pppoe))) |
1118 | return (NULL((void *)0)); |
1119 | |
1120 | m_copydata(m0, sizeof(struct ether_header), |
1121 | sizeof(struct pipex_pppoe_header), &pppoe); |
1122 | pppoe.session_id = ntohs(pppoe.session_id)(__uint16_t)(__builtin_constant_p(pppoe.session_id) ? (__uint16_t )(((__uint16_t)(pppoe.session_id) & 0xffU) << 8 | ( (__uint16_t)(pppoe.session_id) & 0xff00U) >> 8) : __swap16md (pppoe.session_id)); |
1123 | session = pipex_lookup_by_session_id(PIPEX_PROTO_PPPOE3, |
1124 | pppoe.session_id); |
1125 | #ifdef PIPEX_DEBUG |
1126 | if (session == NULL((void *)0)) |
1127 | PIPEX_DBG((NULL, LOG_DEBUG, "<%s> session not found (id=%d)", |
1128 | __func__, pppoe.session_id)); |
1129 | #endif |
1130 | if (session && session->proto.pppoe.over_ifidx != m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx) |
1131 | session = NULL((void *)0); |
1132 | |
1133 | return (session); |
1134 | } |
1135 | |
1136 | struct mbuf * |
1137 | pipex_pppoe_input(struct mbuf *m0, struct pipex_session *session) |
1138 | { |
1139 | int hlen; |
1140 | struct pipex_pppoe_header pppoe; |
1141 | |
1142 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
1143 | /* already checked at pipex_pppoe_lookup_session */ |
1144 | KASSERT(m0->m_pkthdr.len >= (sizeof(struct ether_header) +((m0->M_dat.MH.MH_pkthdr.len >= (sizeof(struct ether_header ) + sizeof(pppoe))) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 1145, "m0->m_pkthdr.len >= (sizeof(struct ether_header) + sizeof(pppoe))" )) |
1145 | sizeof(pppoe)))((m0->M_dat.MH.MH_pkthdr.len >= (sizeof(struct ether_header ) + sizeof(pppoe))) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 1145, "m0->m_pkthdr.len >= (sizeof(struct ether_header) + sizeof(pppoe))" )); |
1146 | |
1147 | m_copydata(m0, sizeof(struct ether_header), |
1148 | sizeof(struct pipex_pppoe_header), &pppoe); |
1149 | |
1150 | hlen = sizeof(struct ether_header) + sizeof(struct pipex_pppoe_header); |
1151 | if ((m0 = pipex_common_input(session, m0, hlen, ntohs(pppoe.length)(__uint16_t)(__builtin_constant_p(pppoe.length) ? (__uint16_t )(((__uint16_t)(pppoe.length) & 0xffU) << 8 | ((__uint16_t )(pppoe.length) & 0xff00U) >> 8) : __swap16md(pppoe .length)))) |
1152 | == NULL((void *)0)) |
1153 | return (NULL((void *)0)); |
1154 | m_freem(m0); |
1155 | counters_inc(session->stat_counters, pxc_ierrors); |
1156 | return (NULL((void *)0)); |
1157 | } |
1158 | |
1159 | /* |
1160 | * pipex_ppope_output |
1161 | */ |
1162 | Static void |
1163 | pipex_pppoe_output(struct mbuf *m0, struct pipex_session *session) |
1164 | { |
1165 | struct pipex_pppoe_header *pppoe; |
1166 | struct ifnet *ifp; |
1167 | int len, padlen; |
1168 | |
1169 | /* save length for pppoe header */ |
1170 | len = m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
1171 | |
1172 | /* prepend protocol header */ |
1173 | M_PREPEND(m0, sizeof(struct pipex_pppoe_header), M_NOWAIT)(m0) = m_prepend((m0), (sizeof(struct pipex_pppoe_header)), ( 0x0002)); |
1174 | if (m0 == NULL((void *)0)) { |
1175 | PIPEX_DBG((NULL, LOG_ERR, |
1176 | "<%s> cannot prepend header.", __func__)); |
1177 | counters_inc(session->stat_counters, pxc_oerrors); |
1178 | return; |
1179 | } |
1180 | padlen = ETHERMIN(64 - ((6 * 2) + 2) - 4) - m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
1181 | if (padlen > 0) |
1182 | m_copyback(m0, m0->m_pkthdrM_dat.MH.MH_pkthdr.len, padlen, pipex_pppoe_padding, |
1183 | M_NOWAIT0x0002); |
1184 | |
1185 | /* setup pppoe header information */ |
1186 | pppoe = mtod(m0, struct pipex_pppoe_header *)((struct pipex_pppoe_header *)((m0)->m_hdr.mh_data)); |
1187 | pppoe->vertype = PIPEX_PPPOE_VERTYPE0x11; |
1188 | pppoe->code = PIPEX_PPPOE_CODE_SESSION0x00; |
1189 | pppoe->session_id = htons(session->session_id)(__uint16_t)(__builtin_constant_p(session->session_id) ? ( __uint16_t)(((__uint16_t)(session->session_id) & 0xffU ) << 8 | ((__uint16_t)(session->session_id) & 0xff00U ) >> 8) : __swap16md(session->session_id)); |
1190 | pppoe->length = htons(len)(__uint16_t)(__builtin_constant_p(len) ? (__uint16_t)(((__uint16_t )(len) & 0xffU) << 8 | ((__uint16_t)(len) & 0xff00U ) >> 8) : __swap16md(len)); |
1191 | |
1192 | m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = session->proto.pppoe.over_ifidx; |
1193 | m0->m_flagsm_hdr.mh_flags &= ~(M_BCAST0x0100|M_MCAST0x0200); |
1194 | |
1195 | ifp = if_get(session->proto.pppoe.over_ifidx); |
1196 | if (ifp != NULL((void *)0)) { |
1197 | ifp->if_output(ifp, m0, &session->peer.sa, NULL((void *)0)); |
1198 | counters_pkt(session->stat_counters, pxc_opackets, |
1199 | pxc_obytes, len); |
1200 | } else { |
1201 | m_freem(m0); |
1202 | counters_inc(session->stat_counters, pxc_oerrors); |
1203 | } |
1204 | if_put(ifp); |
1205 | } |
1206 | #endif /* PIPEX_PPPOE */ |
1207 | |
1208 | #ifdef PIPEX_PPTP1 |
1209 | /*********************************************************************** |
1210 | * PPTP |
1211 | ***********************************************************************/ |
1212 | Static void |
1213 | pipex_pptp_output(struct mbuf *m0, struct pipex_session *session, |
1214 | int has_seq, int has_ack) |
1215 | { |
1216 | int len, reqlen; |
1217 | struct pipex_gre_header *gre = NULL((void *)0); |
1218 | struct ip *ip; |
1219 | u_char *cp; |
1220 | |
1221 | reqlen = PIPEX_IPGRE_HDRLEN(sizeof(struct ip) + sizeof(struct pipex_gre_header)) + (has_seq + has_ack) * 4; |
1222 | |
1223 | len = 0; |
1224 | if (m0 != NULL((void *)0)) { |
1225 | /* save length for gre header */ |
1226 | len = m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
1227 | /* prepend protocol header */ |
1228 | M_PREPEND(m0, reqlen, M_NOWAIT)(m0) = m_prepend((m0), (reqlen), (0x0002)); |
1229 | if (m0 == NULL((void *)0)) |
1230 | goto drop; |
1231 | } else { |
1232 | MGETHDR(m0, M_DONTWAIT, MT_DATA)m0 = m_gethdr((0x0002), (1)); |
1233 | if (m0 && reqlen > MHLEN((256 - sizeof(struct m_hdr)) - sizeof(struct pkthdr))) { |
1234 | MCLGET(m0, M_DONTWAIT)(void) m_clget((m0), (0x0002), (1 << 11)); |
1235 | if ((m0->m_flagsm_hdr.mh_flags & M_EXT0x0001) == 0) { |
1236 | m_freem(m0); |
1237 | m0 = NULL((void *)0); |
1238 | } |
1239 | } |
1240 | if (m0 == NULL((void *)0)) |
1241 | goto drop; |
1242 | m0->m_pkthdrM_dat.MH.MH_pkthdr.len = m0->m_lenm_hdr.mh_len = reqlen; |
1243 | } |
1244 | |
1245 | /* setup ip header information */ |
1246 | ip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
1247 | |
1248 | ip->ip_len = htons(m0->m_pkthdr.len)(__uint16_t)(__builtin_constant_p(m0->M_dat.MH.MH_pkthdr.len ) ? (__uint16_t)(((__uint16_t)(m0->M_dat.MH.MH_pkthdr.len) & 0xffU) << 8 | ((__uint16_t)(m0->M_dat.MH.MH_pkthdr .len) & 0xff00U) >> 8) : __swap16md(m0->M_dat.MH .MH_pkthdr.len)); |
1249 | ip->ip_off = 0; |
1250 | ip->ip_ttl = MAXTTL255; |
1251 | ip->ip_p = IPPROTO_GRE47; |
1252 | ip->ip_tos = 0; |
1253 | |
1254 | ip->ip_src = session->local.sin4.sin_addr; |
1255 | ip->ip_dst = session->peer.sin4.sin_addr; |
1256 | #if NPF1 > 0 |
1257 | pf_pkt_addr_changed(m0); |
1258 | #endif |
1259 | |
1260 | /* setup gre(ver1) header information */ |
1261 | gre = PIPEX_SEEK_NEXTHDR(ip, sizeof(struct ip),((struct pipex_gre_header *) (((char *)ip) + sizeof(struct ip ))) |
1262 | struct pipex_gre_header *)((struct pipex_gre_header *) (((char *)ip) + sizeof(struct ip ))); |
1263 | gre->type = htons(PIPEX_GRE_PROTO_PPP)(__uint16_t)(__builtin_constant_p(0x880b) ? (__uint16_t)(((__uint16_t )(0x880b) & 0xffU) << 8 | ((__uint16_t)(0x880b) & 0xff00U) >> 8) : __swap16md(0x880b)); |
1264 | gre->call_id = htons(session->peer_session_id)(__uint16_t)(__builtin_constant_p(session->peer_session_id ) ? (__uint16_t)(((__uint16_t)(session->peer_session_id) & 0xffU) << 8 | ((__uint16_t)(session->peer_session_id ) & 0xff00U) >> 8) : __swap16md(session->peer_session_id )); |
1265 | gre->flags = PIPEX_GRE_KFLAG0x2000 | PIPEX_GRE_VER0x0001; /* do htons later */ |
1266 | gre->len = htons(len)(__uint16_t)(__builtin_constant_p(len) ? (__uint16_t)(((__uint16_t )(len) & 0xffU) << 8 | ((__uint16_t)(len) & 0xff00U ) >> 8) : __swap16md(len)); |
1267 | |
1268 | cp = PIPEX_SEEK_NEXTHDR(gre, sizeof(struct pipex_gre_header),u_char *)((u_char *) (((char *)gre) + sizeof(struct pipex_gre_header)) ); |
1269 | if (has_seq) { |
1270 | gre->flags |= PIPEX_GRE_SFLAG0x1000; |
1271 | PUTLONG(session->proto.pptp.snd_nxt, cp)do { *(cp)++ = (u_char) ((session->proto.pptp.snd_nxt) >> 24); *(cp)++ = (u_char) ((session->proto.pptp.snd_nxt) >> 16); *(cp)++ = (u_char) ((session->proto.pptp.snd_nxt) >> 8); *(cp)++ = (u_char) (session->proto.pptp.snd_nxt); } while (0); |
1272 | session->proto.pptp.snd_nxt++; |
1273 | session->proto.pptp.snd_gap++; |
1274 | } |
1275 | if (has_ack) { |
1276 | gre->flags |= PIPEX_GRE_AFLAG0x0080; |
1277 | session->proto.pptp.rcv_acked = session->proto.pptp.rcv_nxt - 1; |
1278 | PUTLONG(session->proto.pptp.rcv_acked, cp)do { *(cp)++ = (u_char) ((session->proto.pptp.rcv_acked) >> 24); *(cp)++ = (u_char) ((session->proto.pptp.rcv_acked) >> 16); *(cp)++ = (u_char) ((session->proto.pptp.rcv_acked) >> 8); *(cp)++ = (u_char) (session->proto.pptp.rcv_acked); } while (0); |
1279 | } |
1280 | gre->flags = htons(gre->flags)(__uint16_t)(__builtin_constant_p(gre->flags) ? (__uint16_t )(((__uint16_t)(gre->flags) & 0xffU) << 8 | ((__uint16_t )(gre->flags) & 0xff00U) >> 8) : __swap16md(gre-> flags)); |
1281 | |
1282 | m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = session->ifindex; |
1283 | ip_send(m0); |
1284 | if (len > 0) { /* network layer only */ |
1285 | /* countup statistics */ |
1286 | counters_pkt(session->stat_counters, pxc_opackets, |
1287 | pxc_obytes, len); |
1288 | } |
1289 | |
1290 | return; |
1291 | drop: |
1292 | counters_inc(session->stat_counters, pxc_oerrors); |
1293 | } |
1294 | |
1295 | struct pipex_session * |
1296 | pipex_pptp_lookup_session(struct mbuf *m0) |
1297 | { |
1298 | struct pipex_session *session; |
1299 | struct pipex_gre_header gre; |
1300 | struct ip ip; |
1301 | uint16_t flags; |
1302 | uint16_t id; |
1303 | int hlen; |
1304 | |
1305 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < PIPEX_IPGRE_HDRLEN(sizeof(struct ip) + sizeof(struct pipex_gre_header))) { |
1306 | PIPEX_DBG((NULL, LOG_DEBUG, |
1307 | "<%s> packet length is too short", __func__)); |
1308 | goto not_ours; |
1309 | } |
1310 | |
1311 | /* get ip header info */ |
1312 | m_copydata(m0, 0, sizeof(struct ip), &ip); |
1313 | hlen = ip.ip_hl << 2; |
1314 | |
1315 | /* |
1316 | * m0 has already passed ip_input(), so there is |
1317 | * no necessity for ip packet inspection. |
1318 | */ |
1319 | |
1320 | /* get gre flags */ |
1321 | m_copydata(m0, hlen, sizeof(gre), &gre); |
1322 | flags = ntohs(gre.flags)(__uint16_t)(__builtin_constant_p(gre.flags) ? (__uint16_t)(( (__uint16_t)(gre.flags) & 0xffU) << 8 | ((__uint16_t )(gre.flags) & 0xff00U) >> 8) : __swap16md(gre.flags )); |
1323 | |
1324 | /* gre version must be '1' */ |
1325 | if ((flags & PIPEX_GRE_VERMASK0x0007) != PIPEX_GRE_VER0x0001) { |
1326 | PIPEX_DBG((NULL, LOG_DEBUG, |
1327 | "<%s> gre header wrong version.", __func__)); |
1328 | goto not_ours; |
1329 | } |
1330 | |
1331 | /* gre keys must be present */ |
1332 | if ((flags & PIPEX_GRE_KFLAG0x2000) == 0) { |
1333 | PIPEX_DBG((NULL, LOG_DEBUG, |
1334 | "<%s> gre header has no keys.", __func__)); |
1335 | goto not_ours; |
1336 | } |
1337 | |
1338 | /* flag check */ |
1339 | if ((flags & PIPEX_GRE_UNUSEDFLAGS0xcf78) != 0) { |
1340 | PIPEX_DBG((NULL, LOG_DEBUG, |
1341 | "<%s> gre header has unused flags at pptp.", __func__)); |
1342 | goto not_ours; |
1343 | } |
1344 | |
1345 | /* lookup pipex session table */ |
1346 | id = ntohs(gre.call_id)(__uint16_t)(__builtin_constant_p(gre.call_id) ? (__uint16_t) (((__uint16_t)(gre.call_id) & 0xffU) << 8 | ((__uint16_t )(gre.call_id) & 0xff00U) >> 8) : __swap16md(gre.call_id )); |
1347 | session = pipex_lookup_by_session_id(PIPEX_PROTO_PPTP2, id); |
1348 | #ifdef PIPEX_DEBUG |
1349 | if (session == NULL((void *)0)) { |
1350 | PIPEX_DBG((NULL, LOG_DEBUG, |
1351 | "<%s> session not found (id=%d)", __func__, id)); |
1352 | goto not_ours; |
1353 | } |
1354 | #endif |
1355 | |
1356 | return (session); |
1357 | |
1358 | not_ours: |
1359 | return (NULL((void *)0)); |
1360 | } |
1361 | |
1362 | struct mbuf * |
1363 | pipex_pptp_input(struct mbuf *m0, struct pipex_session *session) |
1364 | { |
1365 | int hlen, has_seq, has_ack, nseq; |
1366 | const char *reason = ""; |
1367 | u_char *cp, *seqp = NULL((void *)0), *ackp = NULL((void *)0); |
1368 | uint32_t flags, seq = 0, ack = 0; |
1369 | struct ip *ip; |
1370 | struct pipex_gre_header *gre; |
1371 | struct pipex_pptp_session *pptp_session; |
1372 | int rewind = 0; |
1373 | |
1374 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
1375 | KASSERT(m0->m_pkthdr.len >= PIPEX_IPGRE_HDRLEN)((m0->M_dat.MH.MH_pkthdr.len >= (sizeof(struct ip) + sizeof (struct pipex_gre_header))) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 1375, "m0->m_pkthdr.len >= PIPEX_IPGRE_HDRLEN" )); |
1376 | pptp_session = &session->proto.pptp; |
1377 | |
1378 | /* get ip header */ |
1379 | ip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
1380 | hlen = ip->ip_hl << 2; |
1381 | |
1382 | /* seek gre header */ |
1383 | gre = PIPEX_SEEK_NEXTHDR(ip, hlen, struct pipex_gre_header *)((struct pipex_gre_header *) (((char *)ip) + hlen)); |
1384 | flags = ntohs(gre->flags)(__uint16_t)(__builtin_constant_p(gre->flags) ? (__uint16_t )(((__uint16_t)(gre->flags) & 0xffU) << 8 | ((__uint16_t )(gre->flags) & 0xff00U) >> 8) : __swap16md(gre-> flags)); |
1385 | |
1386 | /* pullup for seek sequences in header */ |
1387 | has_seq = (flags & PIPEX_GRE_SFLAG0x1000) ? 1 : 0; |
1388 | has_ack = (flags & PIPEX_GRE_AFLAG0x0080) ? 1 : 0; |
1389 | hlen = PIPEX_IPGRE_HDRLEN(sizeof(struct ip) + sizeof(struct pipex_gre_header)) + 4 * (has_seq + has_ack); |
1390 | if (m0->m_lenm_hdr.mh_len < hlen) { |
1391 | m0 = m_pullup(m0, hlen); |
1392 | if (m0 == NULL((void *)0)) { |
1393 | PIPEX_DBG((session, LOG_DEBUG, "pullup failed.")); |
1394 | goto drop; |
1395 | } |
1396 | } |
1397 | |
1398 | /* check sequence */ |
1399 | cp = PIPEX_SEEK_NEXTHDR(gre, sizeof(struct pipex_gre_header),u_char *)((u_char *) (((char *)gre) + sizeof(struct pipex_gre_header)) ); |
1400 | if (has_seq) { |
1401 | seqp = cp; |
1402 | GETLONG(seq, cp)do { (seq) = *(cp)++ << 8; (seq) |= *(cp)++; (seq) <<= 8; (seq) |= *(cp)++; (seq) <<= 8; (seq) |= *(cp)++; } while (0); |
1403 | } |
1404 | if (has_ack) { |
1405 | ackp = cp; |
1406 | GETLONG(ack, cp)do { (ack) = *(cp)++ << 8; (ack) |= *(cp)++; (ack) <<= 8; (ack) |= *(cp)++; (ack) <<= 8; (ack) |= *(cp)++; } while (0); |
1407 | if (ack + 1 == pptp_session->snd_una) { |
1408 | /* ack has not changed before */ |
1409 | } else if (SEQ32_LT(ack, pptp_session->snd_una)((int32_t)((ack) - (pptp_session->snd_una)) < 0)) { |
1410 | /* OoO ack packets should not be dropped. */ |
1411 | rewind = 1; |
1412 | } else if (SEQ32_GT(ack, pptp_session->snd_nxt)((int32_t)((ack) - (pptp_session->snd_nxt)) > 0)) { |
1413 | reason = "ack for unknown sequence"; |
1414 | goto out_seq; |
1415 | } else |
1416 | pptp_session->snd_una = ack + 1; |
1417 | } |
1418 | if (!has_seq) { |
1419 | /* ack only packet */ |
1420 | goto not_ours; |
1421 | } |
1422 | if (SEQ32_LT(seq, pptp_session->rcv_nxt)((int32_t)((seq) - (pptp_session->rcv_nxt)) < 0)) { |
1423 | rewind = 1; |
1424 | if (SEQ32_LT(seq,((int32_t)((seq) - (pptp_session->rcv_nxt - 64)) < 0) |
1425 | pptp_session->rcv_nxt - PIPEX_REWIND_LIMIT)((int32_t)((seq) - (pptp_session->rcv_nxt - 64)) < 0)) { |
1426 | reason = "out of sequence"; |
1427 | goto out_seq; |
1428 | } |
1429 | } else if (SEQ32_GE(seq, pptp_session->rcv_nxt +((int32_t)((seq) - (pptp_session->rcv_nxt + pptp_session-> maxwinsz)) >= 0) |
1430 | pptp_session->maxwinsz)((int32_t)((seq) - (pptp_session->rcv_nxt + pptp_session-> maxwinsz)) >= 0)) { |
1431 | pipex_session_log(session, LOG_DEBUG7, |
1432 | "received packet caused window overflow. seq=%u(%u-%u)" |
1433 | "may lost %d packets.", seq, pptp_session->rcv_nxt, |
1434 | pptp_session->rcv_nxt + pptp_session->maxwinsz, |
1435 | (int)SEQ32_SUB(seq, pptp_session->rcv_nxt)((int32_t)((seq) - (pptp_session->rcv_nxt)))); |
1436 | } |
1437 | |
1438 | seq++; |
1439 | nseq = SEQ32_SUB(seq, pptp_session->rcv_nxt)((int32_t)((seq) - (pptp_session->rcv_nxt))); |
1440 | if (!rewind) { |
1441 | pptp_session->rcv_nxt = seq; |
1442 | if (SEQ32_SUB(seq, pptp_session->rcv_acked)((int32_t)((seq) - (pptp_session->rcv_acked))) > |
1443 | roundup(pptp_session->winsz, 2)((((pptp_session->winsz)+((2)-1))/(2))*(2)) / 2) /* Send ack only packet. */ |
1444 | pipex_pptp_output(NULL((void *)0), session, 0, 1); |
1445 | } |
1446 | |
1447 | if ((m0 = pipex_common_input(session, m0, hlen, ntohs(gre->len)(__uint16_t)(__builtin_constant_p(gre->len) ? (__uint16_t) (((__uint16_t)(gre->len) & 0xffU) << 8 | ((__uint16_t )(gre->len) & 0xff00U) >> 8) : __swap16md(gre-> len)))) |
1448 | == NULL((void *)0)) { |
1449 | /* ok, The packet is for PIPEX */ |
1450 | if (!rewind) |
1451 | session->proto.pptp.rcv_gap += nseq; |
1452 | return (NULL((void *)0)); |
1453 | } |
1454 | |
1455 | if (rewind) |
1456 | goto out_seq; |
1457 | |
1458 | not_ours: |
1459 | seq--; /* revert original seq value */ |
1460 | |
1461 | /* |
1462 | * overwrite sequence numbers to adjust a gap between pipex and |
1463 | * userland. |
1464 | */ |
1465 | if (seqp != NULL((void *)0)) { |
1466 | seq -= pptp_session->rcv_gap; |
1467 | PUTLONG(seq, seqp)do { *(seqp)++ = (u_char) ((seq) >> 24); *(seqp)++ = (u_char ) ((seq) >> 16); *(seqp)++ = (u_char) ((seq) >> 8 ); *(seqp)++ = (u_char) (seq); } while (0); |
1468 | } |
1469 | if (ackp != NULL((void *)0)) { |
1470 | if (pptp_session->snd_nxt == pptp_session->snd_una) { |
1471 | ack -= session->proto.pptp.snd_gap; |
1472 | pptp_session->ul_snd_una = ack; |
1473 | } else { |
1474 | /* |
1475 | * There are sending packets they are not acked. |
1476 | * In this situation, (ack - snd_gap) may points |
1477 | * before sending window of userland. So we don't |
1478 | * update the ack number. |
1479 | */ |
1480 | ack = pptp_session->ul_snd_una; |
1481 | } |
1482 | PUTLONG(ack, ackp)do { *(ackp)++ = (u_char) ((ack) >> 24); *(ackp)++ = (u_char ) ((ack) >> 16); *(ackp)++ = (u_char) ((ack) >> 8 ); *(ackp)++ = (u_char) (ack); } while (0); |
1483 | } |
1484 | |
1485 | return (m0); |
1486 | out_seq: |
1487 | pipex_session_log(session, LOG_DEBUG7, |
1488 | "Received bad data packet: %s: seq=%u(%u-%u) ack=%u(%u-%u)", |
1489 | reason, seq, pptp_session->rcv_nxt, |
1490 | pptp_session->rcv_nxt + pptp_session->maxwinsz, |
1491 | ack, pptp_session->snd_una, |
1492 | pptp_session->snd_nxt); |
1493 | |
1494 | /* FALLTHROUGH */ |
1495 | drop: |
1496 | m_freem(m0); |
1497 | counters_inc(session->stat_counters, pxc_ierrors); |
1498 | |
1499 | return (NULL((void *)0)); |
1500 | } |
1501 | |
1502 | struct pipex_session * |
1503 | pipex_pptp_userland_lookup_session_ipv4(struct mbuf *m0, struct in_addr dst) |
1504 | { |
1505 | struct sockaddr_in sin; |
1506 | |
1507 | memset(&sin, 0, sizeof(sin))__builtin_memset((&sin), (0), (sizeof(sin))); |
1508 | sin.sin_len = sizeof(sin); |
1509 | sin.sin_family = AF_INET2; |
1510 | sin.sin_addr = dst; |
1511 | |
1512 | return pipex_pptp_userland_lookup_session(m0, sintosa(&sin)); |
1513 | } |
1514 | |
1515 | #ifdef INET61 |
1516 | struct pipex_session * |
1517 | pipex_pptp_userland_lookup_session_ipv6(struct mbuf *m0, struct in6_addr dst) |
1518 | { |
1519 | struct sockaddr_in6 sin6; |
1520 | |
1521 | memset(&sin6, 0, sizeof(sin6))__builtin_memset((&sin6), (0), (sizeof(sin6))); |
1522 | sin6.sin6_len = sizeof(sin6); |
1523 | sin6.sin6_family = AF_INET624; |
1524 | in6_recoverscope(&sin6, &dst); |
1525 | |
1526 | return pipex_pptp_userland_lookup_session(m0, sin6tosa(&sin6)); |
1527 | } |
1528 | #endif |
1529 | |
1530 | Static struct pipex_session * |
1531 | pipex_pptp_userland_lookup_session(struct mbuf *m0, struct sockaddr *sa) |
1532 | { |
1533 | struct pipex_gre_header gre; |
1534 | struct pipex_hash_head *list; |
1535 | struct pipex_session *session; |
1536 | uint16_t id, flags; |
1537 | |
1538 | /* pullup */ |
1539 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < sizeof(gre)) { |
1540 | PIPEX_DBG((NULL, LOG_DEBUG, |
1541 | "<%s> packet length is too short", __func__)); |
1542 | return (NULL((void *)0)); |
1543 | } |
1544 | |
1545 | /* get flags */ |
1546 | m_copydata(m0, 0, sizeof(struct pipex_gre_header), &gre); |
1547 | flags = ntohs(gre.flags)(__uint16_t)(__builtin_constant_p(gre.flags) ? (__uint16_t)(( (__uint16_t)(gre.flags) & 0xffU) << 8 | ((__uint16_t )(gre.flags) & 0xff00U) >> 8) : __swap16md(gre.flags )); |
1548 | |
1549 | /* gre version must be '1' */ |
1550 | if ((flags & PIPEX_GRE_VERMASK0x0007) != PIPEX_GRE_VER0x0001) { |
1551 | PIPEX_DBG((NULL, LOG_DEBUG, |
1552 | "<%s> gre header wrong version.", __func__)); |
1553 | return (NULL((void *)0)); |
1554 | } |
1555 | |
1556 | /* gre keys must be present */ |
1557 | if ((flags & PIPEX_GRE_KFLAG0x2000) == 0) { |
1558 | PIPEX_DBG((NULL, LOG_DEBUG, |
1559 | "<%s> gre header has no keys.", __func__)); |
1560 | return (NULL((void *)0)); |
1561 | } |
1562 | |
1563 | /* lookup pipex session table */ |
1564 | id = ntohs(gre.call_id)(__uint16_t)(__builtin_constant_p(gre.call_id) ? (__uint16_t) (((__uint16_t)(gre.call_id) & 0xffU) << 8 | ((__uint16_t )(gre.call_id) & 0xff00U) >> 8) : __swap16md(gre.call_id )); |
1565 | |
1566 | list = PIPEX_PEER_ADDR_HASHTABLE(pipex_sockaddr_hash_key(sa))(&pipex_peer_addr_hashtable[(pipex_sockaddr_hash_key(sa)) & ((512/8)-1)]); |
1567 | LIST_FOREACH(session, list, peer_addr_chain)for((session) = ((list)->lh_first); (session)!= ((void *)0 ); (session) = ((session)->peer_addr_chain.le_next)) { |
1568 | if (pipex_sockaddr_compar_addr(&session->peer.sa, sa) != 0) |
1569 | continue; |
1570 | if (session->peer_session_id == id) |
1571 | break; |
1572 | } |
1573 | #ifdef PIPEX_DEBUG |
1574 | if (session == NULL((void *)0)) { |
1575 | PIPEX_DBG((NULL, LOG_DEBUG, |
1576 | "<%s> session not found (,call_id=%d)", |
1577 | __func__, (int)gre.call_id)); |
1578 | } |
1579 | #endif |
1580 | return (session); |
1581 | } |
1582 | |
1583 | /* |
1584 | * pipex_pptp_userland_output |
1585 | */ |
1586 | struct mbuf * |
1587 | pipex_pptp_userland_output(struct mbuf *m0, struct pipex_session *session) |
1588 | { |
1589 | int len; |
1590 | struct pipex_gre_header *gre, gre0; |
1591 | uint16_t flags; |
1592 | u_char *cp, *cp0; |
1593 | uint32_t val32; |
1594 | |
1595 | len = sizeof(struct pipex_gre_header); |
1596 | m_copydata(m0, 0, len, &gre0); |
1597 | gre = &gre0; |
1598 | flags = ntohs(gre->flags)(__uint16_t)(__builtin_constant_p(gre->flags) ? (__uint16_t )(((__uint16_t)(gre->flags) & 0xffU) << 8 | ((__uint16_t )(gre->flags) & 0xff00U) >> 8) : __swap16md(gre-> flags)); |
1599 | if ((flags & PIPEX_GRE_SFLAG0x1000) != 0) |
1600 | len += 4; |
1601 | if ((flags & PIPEX_GRE_AFLAG0x0080) != 0) |
1602 | len += 4; |
1603 | |
1604 | /* check length */ |
1605 | PIPEX_PULLUP(m0, len)if ((m0)->m_hdr.mh_len < (len)) { if ((m0)->M_dat.MH .MH_pkthdr.len < (len)) { ; m_freem(m0); (m0) = ((void *)0 ); } else { (m0) = m_pullup((m0), (len)); (((m0) != ((void *) 0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 1605, "(m0) != NULL")); } }; |
1606 | if (m0 == NULL((void *)0)) { |
1607 | PIPEX_DBG((session, LOG_DEBUG, "gre header is too short.")); |
1608 | return (NULL((void *)0)); |
1609 | } |
1610 | |
1611 | gre = mtod(m0, struct pipex_gre_header *)((struct pipex_gre_header *)((m0)->m_hdr.mh_data)); |
1612 | cp = PIPEX_SEEK_NEXTHDR(gre, sizeof(struct pipex_gre_header), u_char *)((u_char *) (((char *)gre) + sizeof(struct pipex_gre_header)) ); |
1613 | |
1614 | /* |
1615 | * overwrite sequence numbers to adjust a gap between pipex and |
1616 | * userland. |
1617 | */ |
1618 | if ((flags & PIPEX_GRE_SFLAG0x1000) != 0) { |
1619 | cp0 = cp; |
1620 | GETLONG(val32, cp)do { (val32) = *(cp)++ << 8; (val32) |= *(cp)++; (val32 ) <<= 8; (val32) |= *(cp)++; (val32) <<= 8; (val32 ) |= *(cp)++; } while (0); |
1621 | val32 += session->proto.pptp.snd_gap; |
1622 | PUTLONG(val32, cp0)do { *(cp0)++ = (u_char) ((val32) >> 24); *(cp0)++ = (u_char ) ((val32) >> 16); *(cp0)++ = (u_char) ((val32) >> 8); *(cp0)++ = (u_char) (val32); } while (0); |
1623 | session->proto.pptp.snd_nxt++; |
1624 | } |
1625 | if ((flags & PIPEX_GRE_AFLAG0x0080) != 0) { |
1626 | cp0 = cp; |
1627 | GETLONG(val32, cp)do { (val32) = *(cp)++ << 8; (val32) |= *(cp)++; (val32 ) <<= 8; (val32) |= *(cp)++; (val32) <<= 8; (val32 ) |= *(cp)++; } while (0); |
1628 | val32 += session->proto.pptp.rcv_gap; |
1629 | PUTLONG(val32, cp0)do { *(cp0)++ = (u_char) ((val32) >> 24); *(cp0)++ = (u_char ) ((val32) >> 16); *(cp0)++ = (u_char) ((val32) >> 8); *(cp0)++ = (u_char) (val32); } while (0); |
1630 | if (SEQ32_GT(val32, session->proto.pptp.rcv_acked)((int32_t)((val32) - (session->proto.pptp.rcv_acked)) > 0)) |
1631 | session->proto.pptp.rcv_acked = val32; |
1632 | } |
1633 | |
1634 | return (m0); |
1635 | } |
1636 | #endif /* PIPEX_PPTP */ |
1637 | |
1638 | #ifdef PIPEX_L2TP1 |
1639 | /*********************************************************************** |
1640 | * L2TP support |
1641 | ***********************************************************************/ |
1642 | Static void |
1643 | pipex_l2tp_output(struct mbuf *m0, struct pipex_session *session) |
1644 | { |
1645 | int hlen, plen, datalen; |
1646 | struct pipex_l2tp_header *l2tp = NULL((void *)0); |
1647 | struct pipex_l2tp_seq_header *seq = NULL((void *)0); |
1648 | struct udphdr *udp; |
1649 | struct ip *ip; |
1650 | #ifdef INET61 |
1651 | struct ip6_hdr *ip6; |
1652 | #endif |
1653 | struct m_tag *mtag; |
1654 | |
1655 | hlen = sizeof(struct pipex_l2tp_header) + |
1656 | ((pipex_session_is_l2tp_data_sequencing_on(session)(((session)->proto.l2tp.option_flags & 0x00000001) ? 1 : 0)) |
1657 | ? sizeof(struct pipex_l2tp_seq_header) : 0) + |
1658 | sizeof(struct udphdr) + |
1659 | #ifdef INET61 |
1660 | ((session->peer.sin6.sin6_family == AF_INET624) |
1661 | ? sizeof(struct ip6_hdr) : sizeof(struct ip)); |
1662 | #else |
1663 | sizeof(struct ip); |
1664 | #endif |
1665 | |
1666 | datalen = 0; |
1667 | if (m0 != NULL((void *)0)) { |
1668 | datalen = m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
1669 | M_PREPEND(m0, hlen, M_NOWAIT)(m0) = m_prepend((m0), (hlen), (0x0002)); |
1670 | if (m0 == NULL((void *)0)) |
1671 | goto drop; |
1672 | } else { |
1673 | MGETHDR(m0, M_DONTWAIT, MT_DATA)m0 = m_gethdr((0x0002), (1)); |
1674 | if (m0 == NULL((void *)0)) |
1675 | goto drop; |
1676 | KASSERT(hlen <= MHLEN)((hlen <= ((256 - sizeof(struct m_hdr)) - sizeof(struct pkthdr ))) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 1676, "hlen <= MHLEN")); |
1677 | m0->m_pkthdrM_dat.MH.MH_pkthdr.len = m0->m_lenm_hdr.mh_len = hlen; |
1678 | } |
1679 | |
1680 | #ifdef INET61 |
1681 | hlen = (session->peer.sin6.sin6_family == AF_INET624) |
1682 | ? sizeof(struct ip6_hdr) : sizeof(struct ip); |
1683 | #else |
1684 | hlen = sizeof(struct ip); |
1685 | #endif |
1686 | plen = datalen + sizeof(struct pipex_l2tp_header) + |
1687 | ((pipex_session_is_l2tp_data_sequencing_on(session)(((session)->proto.l2tp.option_flags & 0x00000001) ? 1 : 0)) |
1688 | ? sizeof(struct pipex_l2tp_seq_header) : 0); |
1689 | |
1690 | l2tp = (struct pipex_l2tp_header *) |
1691 | (mtod(m0, caddr_t)((caddr_t)((m0)->m_hdr.mh_data)) + hlen + sizeof(struct udphdr)); |
1692 | l2tp->flagsver = PIPEX_L2TP_VER2 | PIPEX_L2TP_FLAG_LENGTH0x4000; |
1693 | l2tp->length = htons(plen)(__uint16_t)(__builtin_constant_p(plen) ? (__uint16_t)(((__uint16_t )(plen) & 0xffU) << 8 | ((__uint16_t)(plen) & 0xff00U ) >> 8) : __swap16md(plen)); |
1694 | l2tp->tunnel_id = htons(session->proto.l2tp.peer_tunnel_id)(__uint16_t)(__builtin_constant_p(session->proto.l2tp.peer_tunnel_id ) ? (__uint16_t)(((__uint16_t)(session->proto.l2tp.peer_tunnel_id ) & 0xffU) << 8 | ((__uint16_t)(session->proto.l2tp .peer_tunnel_id) & 0xff00U) >> 8) : __swap16md(session ->proto.l2tp.peer_tunnel_id)); |
1695 | l2tp->session_id = htons(session->peer_session_id)(__uint16_t)(__builtin_constant_p(session->peer_session_id ) ? (__uint16_t)(((__uint16_t)(session->peer_session_id) & 0xffU) << 8 | ((__uint16_t)(session->peer_session_id ) & 0xff00U) >> 8) : __swap16md(session->peer_session_id )); |
1696 | if (pipex_session_is_l2tp_data_sequencing_on(session)(((session)->proto.l2tp.option_flags & 0x00000001) ? 1 : 0)) { |
1697 | seq = (struct pipex_l2tp_seq_header *)(l2tp + 1); |
1698 | l2tp->flagsver |= PIPEX_L2TP_FLAG_SEQUENCE0x0800; |
1699 | seq->ns = htons(session->proto.l2tp.ns_nxt)(__uint16_t)(__builtin_constant_p(session->proto.l2tp.ns_nxt ) ? (__uint16_t)(((__uint16_t)(session->proto.l2tp.ns_nxt) & 0xffU) << 8 | ((__uint16_t)(session->proto.l2tp .ns_nxt) & 0xff00U) >> 8) : __swap16md(session-> proto.l2tp.ns_nxt)); |
1700 | session->proto.l2tp.ns_nxt++; |
1701 | session->proto.l2tp.ns_gap++; |
1702 | session->proto.l2tp.nr_acked = session->proto.l2tp.nr_nxt - 1; |
1703 | seq->nr = htons(session->proto.l2tp.nr_acked)(__uint16_t)(__builtin_constant_p(session->proto.l2tp.nr_acked ) ? (__uint16_t)(((__uint16_t)(session->proto.l2tp.nr_acked ) & 0xffU) << 8 | ((__uint16_t)(session->proto.l2tp .nr_acked) & 0xff00U) >> 8) : __swap16md(session-> proto.l2tp.nr_acked)); |
1704 | } |
1705 | l2tp->flagsver = htons(l2tp->flagsver)(__uint16_t)(__builtin_constant_p(l2tp->flagsver) ? (__uint16_t )(((__uint16_t)(l2tp->flagsver) & 0xffU) << 8 | ( (__uint16_t)(l2tp->flagsver) & 0xff00U) >> 8) : __swap16md (l2tp->flagsver)); |
1706 | |
1707 | plen += sizeof(struct udphdr); |
1708 | udp = (struct udphdr *)(mtod(m0, caddr_t)((caddr_t)((m0)->m_hdr.mh_data)) + hlen); |
1709 | udp->uh_sport = session->local.sin6.sin6_port; |
1710 | udp->uh_dport = session->peer.sin6.sin6_port; |
1711 | udp->uh_ulen = htons(plen)(__uint16_t)(__builtin_constant_p(plen) ? (__uint16_t)(((__uint16_t )(plen) & 0xffU) << 8 | ((__uint16_t)(plen) & 0xff00U ) >> 8) : __swap16md(plen)); |
1712 | udp->uh_sum = 0; |
1713 | |
1714 | m0->m_pkthdrM_dat.MH.MH_pkthdr.csum_flags |= M_UDP_CSUM_OUT0x0004; |
1715 | m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = session->ifindex; |
1716 | #if NPF1 > 0 |
1717 | pf_pkt_addr_changed(m0); |
1718 | #endif |
1719 | switch (session->peer.sin6.sin6_family) { |
1720 | case AF_INET2: |
1721 | ip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
1722 | ip->ip_p = IPPROTO_UDP17; |
1723 | ip->ip_src = session->local.sin4.sin_addr; |
1724 | ip->ip_dst = session->peer.sin4.sin_addr; |
1725 | ip->ip_len = htons(hlen + plen)(__uint16_t)(__builtin_constant_p(hlen + plen) ? (__uint16_t) (((__uint16_t)(hlen + plen) & 0xffU) << 8 | ((__uint16_t )(hlen + plen) & 0xff00U) >> 8) : __swap16md(hlen + plen)); |
1726 | ip->ip_ttl = MAXTTL255; |
1727 | ip->ip_tos = 0; |
1728 | ip->ip_off = 0; |
1729 | |
1730 | if (session->proto.l2tp.ipsecflowinfo > 0) { |
1731 | if ((mtag = m_tag_get(PACKET_TAG_IPSEC_FLOWINFO0x0004, |
1732 | sizeof(u_int32_t), M_NOWAIT0x0002)) == NULL((void *)0)) |
1733 | goto drop; |
1734 | *(u_int32_t *)(mtag + 1) = |
1735 | session->proto.l2tp.ipsecflowinfo; |
1736 | m_tag_prepend(m0, mtag); |
1737 | } |
1738 | |
1739 | ip_send(m0); |
1740 | break; |
1741 | #ifdef INET61 |
1742 | case AF_INET624: |
1743 | ip6 = mtod(m0, struct ip6_hdr *)((struct ip6_hdr *)((m0)->m_hdr.mh_data)); |
1744 | |
1745 | ip6->ip6_flowip6_ctlun.ip6_un1.ip6_un1_flow = 0; |
1746 | ip6->ip6_vfcip6_ctlun.ip6_un2_vfc &= ~IPV6_VERSION_MASK0xf0; |
1747 | ip6->ip6_vfcip6_ctlun.ip6_un2_vfc |= IPV6_VERSION0x60; |
1748 | ip6->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP17; |
1749 | ip6->ip6_src = session->local.sin6.sin6_addr; |
1750 | (void)in6_embedscope(&ip6->ip6_dst, |
1751 | &session->peer.sin6, NULL((void *)0)); |
1752 | /* ip6->ip6_plen will be filled in ip6_output. */ |
1753 | |
1754 | ip6_send(m0); |
1755 | break; |
1756 | #endif |
1757 | } |
1758 | udpstat_inc(udps_opackets); |
1759 | |
1760 | if (datalen > 0) { /* network layer only */ |
1761 | /* countup statistics */ |
1762 | counters_pkt(session->stat_counters, pxc_opackets, |
1763 | pxc_obytes, datalen); |
1764 | } |
1765 | |
1766 | return; |
1767 | drop: |
1768 | m_freem(m0); |
1769 | counters_inc(session->stat_counters, pxc_oerrors); |
1770 | } |
1771 | |
1772 | struct pipex_session * |
1773 | pipex_l2tp_lookup_session(struct mbuf *m0, int off) |
1774 | { |
1775 | struct pipex_session *session; |
1776 | uint16_t flags, session_id, ver; |
1777 | u_char *cp, buf[PIPEX_L2TP_MINLEN8]; |
1778 | |
1779 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < off + PIPEX_L2TP_MINLEN8) { |
1780 | PIPEX_DBG((NULL, LOG_DEBUG, |
1781 | "<%s> packet length is too short", __func__)); |
1782 | goto not_ours; |
1783 | } |
1784 | |
1785 | /* get first 16bits of L2TP */ |
1786 | m_copydata(m0, off, sizeof(buf), buf); |
1787 | cp = buf; |
1788 | GETSHORT(flags, cp)do { (flags) = *(cp)++ << 8; (flags) |= *(cp)++; } while (0); |
1789 | ver = flags & PIPEX_L2TP_VER_MASK0x000f; |
1790 | |
1791 | /* l2tp version must be '2' */ |
1792 | if (ver != PIPEX_L2TP_VER2) { |
1793 | PIPEX_DBG((NULL, LOG_DEBUG, |
1794 | "<%s> l2tp header wrong version %u.", __func__, ver)); |
1795 | goto not_ours; |
1796 | } |
1797 | if ((flags & PIPEX_L2TP_FLAG_TYPE0x8000) != 0) |
1798 | goto not_ours; |
1799 | |
1800 | if (flags & PIPEX_L2TP_FLAG_LENGTH0x4000) |
1801 | cp += 2; /* skip length field */ |
1802 | cp += 2; /* skip tunnel-id field */ |
1803 | GETSHORT(session_id, cp)do { (session_id) = *(cp)++ << 8; (session_id) |= *(cp) ++; } while (0); /* get session-id field */ |
1804 | |
1805 | /* lookup pipex session table */ |
1806 | session = pipex_lookup_by_session_id(PIPEX_PROTO_L2TP1, session_id); |
1807 | #ifdef PIPEX_DEBUG |
1808 | if (session == NULL((void *)0)) { |
1809 | PIPEX_DBG((NULL, LOG_DEBUG, |
1810 | "<%s> session not found (id=%d)", __func__, session_id)); |
1811 | goto not_ours; |
1812 | } |
1813 | #endif |
1814 | |
1815 | return (session); |
1816 | |
1817 | not_ours: |
1818 | return (NULL((void *)0)); |
1819 | } |
1820 | |
1821 | struct mbuf * |
1822 | pipex_l2tp_input(struct mbuf *m0, int off0, struct pipex_session *session, |
1823 | uint32_t ipsecflowinfo) |
1824 | { |
1825 | struct pipex_l2tp_session *l2tp_session; |
1826 | int length, offset, hlen, nseq; |
1827 | u_char *cp, *nsp, *nrp; |
1828 | uint16_t flags, ns = 0, nr = 0; |
1829 | int rewind = 0; |
1830 | |
1831 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
1832 | length = offset = ns = nr = 0; |
Value stored to 'length' is never read | |
1833 | l2tp_session = &session->proto.l2tp; |
1834 | l2tp_session->ipsecflowinfo = ipsecflowinfo; |
1835 | nsp = nrp = NULL((void *)0); |
1836 | |
1837 | m_copydata(m0, off0, sizeof(flags), &flags); |
1838 | |
1839 | flags = ntohs(flags)(__uint16_t)(__builtin_constant_p(flags) ? (__uint16_t)(((__uint16_t )(flags) & 0xffU) << 8 | ((__uint16_t)(flags) & 0xff00U) >> 8) : __swap16md(flags)) & PIPEX_L2TP_FLAG_MASK0xfff0; |
1840 | KASSERT((flags & PIPEX_L2TP_FLAG_TYPE) == 0)(((flags & 0x8000) == 0) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 1840, "(flags & PIPEX_L2TP_FLAG_TYPE) == 0" )); |
1841 | |
1842 | hlen = 2; /* flags and version fields */ |
1843 | if (flags & PIPEX_L2TP_FLAG_LENGTH0x4000) /* length */ |
1844 | hlen += 2; |
1845 | hlen += 4; /* tunnel-id and session-id */ |
1846 | if (flags & PIPEX_L2TP_FLAG_SEQUENCE0x0800) /* ns and nr */ |
1847 | hlen += 4; |
1848 | if (flags & PIPEX_L2TP_FLAG_OFFSET0x0200) /* offset */ |
1849 | hlen += 2; |
1850 | |
1851 | PIPEX_PULLUP(m0, off0 + hlen)if ((m0)->m_hdr.mh_len < (off0 + hlen)) { if ((m0)-> M_dat.MH.MH_pkthdr.len < (off0 + hlen)) { ; m_freem(m0); ( m0) = ((void *)0); } else { (m0) = m_pullup((m0), (off0 + hlen )); (((m0) != ((void *)0)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 1851, "(m0) != NULL")); } }; |
1852 | if (m0 == NULL((void *)0)) |
1853 | goto drop; |
1854 | |
1855 | cp = mtod(m0, u_char *)((u_char *)((m0)->m_hdr.mh_data)) + off0; |
1856 | cp += 2; /* flags and version */ |
1857 | if (flags & PIPEX_L2TP_FLAG_LENGTH0x4000) |
1858 | GETSHORT(length, cp)do { (length) = *(cp)++ << 8; (length) |= *(cp)++; } while (0); |
1859 | else |
1860 | length = m0->m_pkthdrM_dat.MH.MH_pkthdr.len - off0; |
1861 | cp += 4; /* skip tunnel-id and session-id field */ |
1862 | |
1863 | /* pullup for seek sequences in header */ |
1864 | nseq = 0; |
1865 | if (flags & PIPEX_L2TP_FLAG_SEQUENCE0x0800) { |
1866 | nsp = cp; |
1867 | GETSHORT(ns, cp)do { (ns) = *(cp)++ << 8; (ns) |= *(cp)++; } while (0); |
1868 | nrp = cp; |
1869 | GETSHORT(nr, cp)do { (nr) = *(cp)++ << 8; (nr) |= *(cp)++; } while (0); |
1870 | |
1871 | nr++; |
1872 | if (SEQ16_GT(nr, l2tp_session->ns_una)((int16_t)((nr) - (l2tp_session->ns_una)) > 0) && |
1873 | SEQ16_LE(nr, l2tp_session->ns_nxt)((int16_t)((nr) - (l2tp_session->ns_nxt)) <= 0)) |
1874 | /* update 'ns_una' only if the ns is in valid range */ |
1875 | l2tp_session->ns_una = nr; |
1876 | if (SEQ16_LT(ns, l2tp_session->nr_nxt)((int16_t)((ns) - (l2tp_session->nr_nxt)) < 0)) { |
1877 | rewind = 1; |
1878 | if (SEQ16_LT(ns,((int16_t)((ns) - (l2tp_session->nr_nxt - 64)) < 0) |
1879 | l2tp_session->nr_nxt - PIPEX_REWIND_LIMIT)((int16_t)((ns) - (l2tp_session->nr_nxt - 64)) < 0)) |
1880 | goto out_seq; |
1881 | } |
1882 | |
1883 | ns++; |
1884 | nseq = SEQ16_SUB(ns, l2tp_session->nr_nxt)((int16_t)((ns) - (l2tp_session->nr_nxt))); |
1885 | if (!rewind) |
1886 | l2tp_session->nr_nxt = ns; |
1887 | } |
1888 | if (flags & PIPEX_L2TP_FLAG_OFFSET0x0200) |
1889 | GETSHORT(offset, cp)do { (offset) = *(cp)++ << 8; (offset) |= *(cp)++; } while (0); |
1890 | |
1891 | length -= hlen + offset; |
1892 | hlen += off0 + offset; |
1893 | if ((m0 = pipex_common_input(session, m0, hlen, length)) == NULL((void *)0)) { |
1894 | /* ok, The packet is for PIPEX */ |
1895 | if (!rewind) |
1896 | session->proto.l2tp.nr_gap += nseq; |
1897 | return (NULL((void *)0)); |
1898 | } |
1899 | |
1900 | if (rewind) |
1901 | goto out_seq; |
1902 | |
1903 | /* |
1904 | * overwrite sequence numbers to adjust a gap between pipex and |
1905 | * userland. |
1906 | */ |
1907 | if (flags & PIPEX_L2TP_FLAG_SEQUENCE0x0800) { |
1908 | --ns; --nr; /* revert original values */ |
1909 | ns -= l2tp_session->nr_gap; |
1910 | PUTSHORT(ns, nsp)do { *(nsp)++ = (u_char) ((ns) >> 8); *(nsp)++ = (u_char ) (ns); } while (0); |
1911 | |
1912 | if (l2tp_session->ns_nxt == l2tp_session->ns_una) { |
1913 | nr -= l2tp_session->ns_gap; |
1914 | l2tp_session->ul_ns_una = nr; |
1915 | } else { |
1916 | /* |
1917 | * There are sending packets they are not acked. |
1918 | * In this situation, (ack - snd_gap) may points |
1919 | * before sending window of userland. So we don't |
1920 | * update the ack number. |
1921 | */ |
1922 | nr = l2tp_session->ul_ns_una; |
1923 | } |
1924 | PUTSHORT(nr, nrp)do { *(nrp)++ = (u_char) ((nr) >> 8); *(nrp)++ = (u_char ) (nr); } while (0); |
1925 | } |
1926 | |
1927 | return (m0); |
1928 | out_seq: |
1929 | pipex_session_log(session, LOG_DEBUG7, |
1930 | "Received bad data packet: out of sequence: seq=%u(%u-) " |
1931 | "ack=%u(%u-%u)", ns, l2tp_session->nr_nxt, nr, l2tp_session->ns_una, |
1932 | l2tp_session->ns_nxt); |
1933 | |
1934 | /* FALLTHROUGH */ |
1935 | drop: |
1936 | m_freem(m0); |
1937 | counters_inc(session->stat_counters, pxc_ierrors); |
1938 | |
1939 | return (NULL((void *)0)); |
1940 | } |
1941 | |
1942 | struct pipex_session * |
1943 | pipex_l2tp_userland_lookup_session_ipv4(struct mbuf *m0, struct in_addr dst) |
1944 | { |
1945 | struct sockaddr_in sin; |
1946 | |
1947 | memset(&sin, 0, sizeof(sin))__builtin_memset((&sin), (0), (sizeof(sin))); |
1948 | sin.sin_len = sizeof(sin); |
1949 | sin.sin_family = AF_INET2; |
1950 | sin.sin_addr = dst; |
1951 | |
1952 | return pipex_l2tp_userland_lookup_session(m0, sintosa(&sin)); |
1953 | } |
1954 | |
1955 | #ifdef INET61 |
1956 | struct pipex_session * |
1957 | pipex_l2tp_userland_lookup_session_ipv6(struct mbuf *m0, struct in6_addr dst) |
1958 | { |
1959 | struct sockaddr_in6 sin6; |
1960 | |
1961 | memset(&sin6, 0, sizeof(sin6))__builtin_memset((&sin6), (0), (sizeof(sin6))); |
1962 | sin6.sin6_len = sizeof(sin6); |
1963 | sin6.sin6_family = AF_INET624; |
1964 | in6_recoverscope(&sin6, &dst); |
1965 | |
1966 | return pipex_l2tp_userland_lookup_session(m0, sin6tosa(&sin6)); |
1967 | } |
1968 | #endif |
1969 | |
1970 | struct pipex_session * |
1971 | pipex_l2tp_userland_lookup_session(struct mbuf *m0, struct sockaddr *sa) |
1972 | { |
1973 | struct pipex_l2tp_header l2tp; |
1974 | struct pipex_hash_head *list; |
1975 | struct pipex_session *session; |
1976 | uint16_t session_id, tunnel_id, flags; |
1977 | |
1978 | if (sa->sa_family != AF_INET2 && sa->sa_family != AF_INET624) |
1979 | return (NULL((void *)0)); |
1980 | |
1981 | /* pullup */ |
1982 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < sizeof(l2tp)) { |
1983 | PIPEX_DBG((NULL, LOG_DEBUG, |
1984 | "<%s> packet length is too short", __func__)); |
1985 | return (NULL((void *)0)); |
1986 | } |
1987 | |
1988 | /* get flags */ |
1989 | m_copydata(m0, 0, sizeof(l2tp), &l2tp); |
1990 | flags = ntohs(l2tp.flagsver)(__uint16_t)(__builtin_constant_p(l2tp.flagsver) ? (__uint16_t )(((__uint16_t)(l2tp.flagsver) & 0xffU) << 8 | ((__uint16_t )(l2tp.flagsver) & 0xff00U) >> 8) : __swap16md(l2tp .flagsver)); |
1991 | |
1992 | /* l2tp version must be '2' */ |
1993 | if ((flags & PIPEX_L2TP_VER_MASK0x000f) != PIPEX_L2TP_VER2) { |
1994 | PIPEX_DBG((NULL, LOG_DEBUG, |
1995 | "<%s> l2tp header wrong version.", __func__)); |
1996 | return (NULL((void *)0)); |
1997 | } |
1998 | /* We need L2TP data messages only */ |
1999 | if ((flags & PIPEX_L2TP_FLAG_TYPE0x8000) != 0) |
2000 | return (NULL((void *)0)); |
2001 | /* No need to hook packets that don't have the sequence field */ |
2002 | if ((flags & PIPEX_L2TP_FLAG_SEQUENCE0x0800) == 0) |
2003 | return (NULL((void *)0)); |
2004 | |
2005 | session_id = ntohs(l2tp.session_id)(__uint16_t)(__builtin_constant_p(l2tp.session_id) ? (__uint16_t )(((__uint16_t)(l2tp.session_id) & 0xffU) << 8 | (( __uint16_t)(l2tp.session_id) & 0xff00U) >> 8) : __swap16md (l2tp.session_id)); |
2006 | tunnel_id = ntohs(l2tp.tunnel_id)(__uint16_t)(__builtin_constant_p(l2tp.tunnel_id) ? (__uint16_t )(((__uint16_t)(l2tp.tunnel_id) & 0xffU) << 8 | ((__uint16_t )(l2tp.tunnel_id) & 0xff00U) >> 8) : __swap16md(l2tp .tunnel_id)); |
2007 | |
2008 | list = PIPEX_PEER_ADDR_HASHTABLE(pipex_sockaddr_hash_key(sa))(&pipex_peer_addr_hashtable[(pipex_sockaddr_hash_key(sa)) & ((512/8)-1)]); |
2009 | LIST_FOREACH(session, list, peer_addr_chain)for((session) = ((list)->lh_first); (session)!= ((void *)0 ); (session) = ((session)->peer_addr_chain.le_next)) { |
2010 | if (pipex_sockaddr_compar_addr(&session->peer.sa, sa) != 0) |
2011 | continue; |
2012 | if (session->proto.l2tp.peer_tunnel_id != tunnel_id) |
2013 | continue; |
2014 | if (session->peer_session_id == session_id) |
2015 | break; |
2016 | } |
2017 | #ifdef PIPEX_DEBUG |
2018 | if (session == NULL((void *)0)) { |
2019 | PIPEX_DBG((NULL, LOG_DEBUG, "<%s> session not found " |
2020 | "(tunnel_id=%d, session_id=%d)", __func__, |
2021 | tunnel_id, session_id)); |
2022 | } |
2023 | #endif |
2024 | |
2025 | return (session); |
2026 | } |
2027 | |
2028 | struct mbuf * |
2029 | pipex_l2tp_userland_output(struct mbuf *m0, struct pipex_session *session) |
2030 | { |
2031 | struct pipex_l2tp_header *l2tp; |
2032 | struct pipex_l2tp_seq_header *seq; |
2033 | uint16_t ns, nr; |
2034 | |
2035 | /* check length */ |
2036 | PIPEX_PULLUP(m0, sizeof(struct pipex_l2tp_header) +if ((m0)->m_hdr.mh_len < (sizeof(struct pipex_l2tp_header ) + sizeof(struct pipex_l2tp_seq_header))) { if ((m0)->M_dat .MH.MH_pkthdr.len < (sizeof(struct pipex_l2tp_header) + sizeof (struct pipex_l2tp_seq_header))) { ; m_freem(m0); (m0) = ((void *)0); } else { (m0) = m_pullup((m0), (sizeof(struct pipex_l2tp_header ) + sizeof(struct pipex_l2tp_seq_header))); (((m0) != ((void * )0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2037, "(m0) != NULL")); } } |
2037 | sizeof(struct pipex_l2tp_seq_header))if ((m0)->m_hdr.mh_len < (sizeof(struct pipex_l2tp_header ) + sizeof(struct pipex_l2tp_seq_header))) { if ((m0)->M_dat .MH.MH_pkthdr.len < (sizeof(struct pipex_l2tp_header) + sizeof (struct pipex_l2tp_seq_header))) { ; m_freem(m0); (m0) = ((void *)0); } else { (m0) = m_pullup((m0), (sizeof(struct pipex_l2tp_header ) + sizeof(struct pipex_l2tp_seq_header))); (((m0) != ((void * )0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2037, "(m0) != NULL")); } }; |
2038 | if (m0 == NULL((void *)0)) |
2039 | return (NULL((void *)0)); |
2040 | |
2041 | l2tp = mtod(m0, struct pipex_l2tp_header *)((struct pipex_l2tp_header *)((m0)->m_hdr.mh_data)); |
2042 | KASSERT(ntohs(l2tp->flagsver) & PIPEX_L2TP_FLAG_SEQUENCE)(((__uint16_t)(__builtin_constant_p(l2tp->flagsver) ? (__uint16_t )(((__uint16_t)(l2tp->flagsver) & 0xffU) << 8 | ( (__uint16_t)(l2tp->flagsver) & 0xff00U) >> 8) : __swap16md (l2tp->flagsver)) & 0x0800) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 2042, "ntohs(l2tp->flagsver) & PIPEX_L2TP_FLAG_SEQUENCE" )); |
2043 | |
2044 | /* |
2045 | * overwrite sequence numbers to adjust a gap between pipex and |
2046 | * userland. |
2047 | */ |
2048 | seq = (struct pipex_l2tp_seq_header *)(l2tp + 1); |
2049 | ns = ntohs(seq->ns)(__uint16_t)(__builtin_constant_p(seq->ns) ? (__uint16_t)( ((__uint16_t)(seq->ns) & 0xffU) << 8 | ((__uint16_t )(seq->ns) & 0xff00U) >> 8) : __swap16md(seq-> ns)); |
2050 | nr = ntohs(seq->nr)(__uint16_t)(__builtin_constant_p(seq->nr) ? (__uint16_t)( ((__uint16_t)(seq->nr) & 0xffU) << 8 | ((__uint16_t )(seq->nr) & 0xff00U) >> 8) : __swap16md(seq-> nr)); |
2051 | |
2052 | ns += session->proto.l2tp.ns_gap; |
2053 | seq->ns = htons(ns)(__uint16_t)(__builtin_constant_p(ns) ? (__uint16_t)(((__uint16_t )(ns) & 0xffU) << 8 | ((__uint16_t)(ns) & 0xff00U ) >> 8) : __swap16md(ns)); |
2054 | session->proto.l2tp.ns_nxt++; |
2055 | |
2056 | nr += session->proto.l2tp.nr_gap; |
2057 | seq->nr = htons(nr)(__uint16_t)(__builtin_constant_p(nr) ? (__uint16_t)(((__uint16_t )(nr) & 0xffU) << 8 | ((__uint16_t)(nr) & 0xff00U ) >> 8) : __swap16md(nr)); |
2058 | if (SEQ16_GT(nr, session->proto.l2tp.nr_acked)((int16_t)((nr) - (session->proto.l2tp.nr_acked)) > 0)) |
2059 | session->proto.l2tp.nr_acked = nr; |
2060 | |
2061 | return (m0); |
2062 | } |
2063 | #endif /* PIPEX_L2TP */ |
2064 | |
2065 | #ifdef PIPEX_MPPE1 |
2066 | /********************************************************************** |
2067 | * MPPE |
2068 | ***********************************************************************/ |
2069 | #define PIPEX_COHERENCY_CNT_MASK0x0fff 0x0fff |
2070 | |
2071 | static inline int |
2072 | pipex_mppe_setkey(struct pipex_mppe *mppe) |
2073 | { |
2074 | rc4_keysetup(&mppe->rc4ctx, mppe->session_key, mppe->keylen); |
2075 | |
2076 | return (0); |
2077 | } |
2078 | |
2079 | static inline int |
2080 | pipex_mppe_setoldkey(struct pipex_mppe *mppe, uint16_t coher_cnt) |
2081 | { |
2082 | KASSERT(mppe->old_session_keys != NULL)((mppe->old_session_keys != ((void *)0)) ? (void)0 : __assert ("diagnostic ", "/usr/src/sys/net/pipex.c", 2082, "mppe->old_session_keys != NULL" )); |
2083 | |
2084 | rc4_keysetup(&mppe->rc4ctx, |
2085 | mppe->old_session_keys[coher_cnt & PIPEX_MPPE_OLDKEYMASK(64 - 1)], |
2086 | mppe->keylen); |
2087 | |
2088 | return (0); |
2089 | } |
2090 | |
2091 | static inline void |
2092 | pipex_mppe_crypt(struct pipex_mppe *mppe, int len, u_char *indata, |
2093 | u_char *outdata) |
2094 | { |
2095 | rc4_crypt(&mppe->rc4ctx, indata, outdata, len); |
2096 | } |
2097 | |
2098 | Static void |
2099 | pipex_mppe_init(struct pipex_mppe *mppe, int stateless, int keylenbits, |
2100 | u_char *master_key, int has_oldkey) |
2101 | { |
2102 | memset(mppe, 0, sizeof(struct pipex_mppe))__builtin_memset((mppe), (0), (sizeof(struct pipex_mppe))); |
2103 | mtx_init(&mppe->pxm_mtx, IPL_SOFTNET)do { (void)(((void *)0)); (void)(0); __mtx_init((&mppe-> pxm_mtx), ((((0x5)) > 0x0 && ((0x5)) < 0x9) ? 0x9 : ((0x5)))); } while (0); |
2104 | if (stateless) |
2105 | mppe->stateless = 1; |
2106 | if (has_oldkey) |
2107 | mppe->old_session_keys = |
2108 | pool_get(&mppe_key_pool, PR_WAITOK0x0001); |
2109 | else |
2110 | mppe->old_session_keys = NULL((void *)0); |
2111 | memcpy(mppe->master_key, master_key, sizeof(mppe->master_key))__builtin_memcpy((mppe->master_key), (master_key), (sizeof (mppe->master_key))); |
2112 | |
2113 | mppe->keylenbits = keylenbits; |
2114 | switch (keylenbits) { |
2115 | case 40: |
2116 | case 56: |
2117 | mppe->keylen = 8; |
2118 | break; |
2119 | case 128: |
2120 | mppe->keylen = 16; |
2121 | break; |
2122 | } |
2123 | |
2124 | GetNewKeyFromSHA(mppe->master_key, mppe->master_key, mppe->keylen, |
2125 | mppe->session_key); |
2126 | pipex_mppe_reduce_key(mppe); |
2127 | pipex_mppe_setkey(mppe); |
2128 | } |
2129 | |
2130 | void |
2131 | pipex_session_init_mppe_recv(struct pipex_session *session, int stateless, |
2132 | int keylenbits, u_char *master_key) |
2133 | { |
2134 | pipex_mppe_init(&session->mppe_recv, stateless, keylenbits, |
2135 | master_key, stateless); |
2136 | session->ppp_flags |= PIPEX_PPP_MPPE_ACCEPTED0x0010; |
2137 | } |
2138 | |
2139 | void |
2140 | pipex_session_init_mppe_send(struct pipex_session *session, int stateless, |
2141 | int keylenbits, u_char *master_key) |
2142 | { |
2143 | pipex_mppe_init(&session->mppe_send, stateless, keylenbits, |
2144 | master_key, 0); |
2145 | session->ppp_flags |= PIPEX_PPP_MPPE_ENABLED0x0020; |
2146 | } |
2147 | |
2148 | #include <crypto/sha1.h> |
2149 | |
2150 | static u_char SHAPad1[] = { |
2151 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
2152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
2153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
2154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
2155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
2156 | }, SHAPad2[] = { |
2157 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
2158 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
2159 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
2160 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
2161 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
2162 | }; |
2163 | |
2164 | Static void |
2165 | GetNewKeyFromSHA(u_char *StartKey, u_char *SessionKey, int SessionKeyLength, |
2166 | u_char *InterimKey) |
2167 | { |
2168 | u_char Digest[20]; |
2169 | SHA1_CTX Context; |
2170 | |
2171 | SHA1Init(&Context); |
2172 | SHA1Update(&Context, StartKey, SessionKeyLength); |
2173 | SHA1Update(&Context, SHAPad1, 40); |
2174 | SHA1Update(&Context, SessionKey, SessionKeyLength); |
2175 | SHA1Update(&Context, SHAPad2, 40); |
2176 | SHA1Final(Digest, &Context); |
2177 | |
2178 | memcpy(InterimKey, Digest, SessionKeyLength)__builtin_memcpy((InterimKey), (Digest), (SessionKeyLength)); |
2179 | } |
2180 | |
2181 | Static void |
2182 | pipex_mppe_reduce_key(struct pipex_mppe *mppe) |
2183 | { |
2184 | switch (mppe->keylenbits) { |
2185 | case 40: |
2186 | mppe->session_key[0] = 0xd1; |
2187 | mppe->session_key[1] = 0x26; |
2188 | mppe->session_key[2] = 0x9e; |
2189 | break; |
2190 | case 56: |
2191 | mppe->session_key[0] = 0xd1; |
2192 | break; |
2193 | } |
2194 | } |
2195 | |
2196 | Static void |
2197 | mppe_key_change(struct pipex_mppe *mppe) |
2198 | { |
2199 | u_char interim[16]; |
2200 | struct rc4_ctx keychg; |
2201 | |
2202 | memset(&keychg, 0, sizeof(keychg))__builtin_memset((&keychg), (0), (sizeof(keychg))); |
2203 | |
2204 | GetNewKeyFromSHA(mppe->master_key, mppe->session_key, mppe->keylen, |
2205 | interim); |
2206 | |
2207 | rc4_keysetup(&keychg, interim, mppe->keylen); |
2208 | rc4_crypt(&keychg, interim, mppe->session_key, mppe->keylen); |
2209 | |
2210 | pipex_mppe_reduce_key(mppe); |
2211 | |
2212 | if (mppe->old_session_keys) { |
2213 | int idx = mppe->coher_cnt & PIPEX_MPPE_OLDKEYMASK(64 - 1); |
2214 | memcpy(mppe->old_session_keys[idx],__builtin_memcpy((mppe->old_session_keys[idx]), (mppe-> session_key), (16)) |
2215 | mppe->session_key, PIPEX_MPPE_KEYLEN)__builtin_memcpy((mppe->old_session_keys[idx]), (mppe-> session_key), (16)); |
2216 | } |
2217 | } |
2218 | |
2219 | Static void |
2220 | pipex_mppe_input(struct mbuf *m0, struct pipex_session *session) |
2221 | { |
2222 | int pktloss, encrypt, flushed, m, n, len; |
2223 | struct pipex_mppe *mppe; |
2224 | uint16_t coher_cnt; |
2225 | struct mbuf *m1; |
2226 | u_char *cp; |
2227 | int rewind = 0; |
2228 | |
2229 | /* pullup */ |
2230 | PIPEX_PULLUP(m0, sizeof(coher_cnt))if ((m0)->m_hdr.mh_len < (sizeof(coher_cnt))) { if ((m0 )->M_dat.MH.MH_pkthdr.len < (sizeof(coher_cnt))) { ; m_freem (m0); (m0) = ((void *)0); } else { (m0) = m_pullup((m0), (sizeof (coher_cnt))); (((m0) != ((void *)0)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 2230, "(m0) != NULL")); } }; |
2231 | if (m0 == NULL((void *)0)) |
2232 | goto drop; |
2233 | |
2234 | mppe = &session->mppe_recv; |
2235 | /* get header information */ |
2236 | cp = mtod(m0, u_char *)((u_char *)((m0)->m_hdr.mh_data)); |
2237 | GETSHORT(coher_cnt, cp)do { (coher_cnt) = *(cp)++ << 8; (coher_cnt) |= *(cp)++ ; } while (0); |
2238 | flushed = ((coher_cnt & 0x8000) != 0) ? 1 : 0; |
2239 | encrypt = ((coher_cnt & 0x1000) != 0) ? 1 : 0; |
2240 | coher_cnt &= PIPEX_COHERENCY_CNT_MASK0x0fff; |
2241 | pktloss = 0; |
2242 | |
2243 | mtx_enter(&mppe->pxm_mtx); |
2244 | |
2245 | PIPEX_MPPE_DBG((session, LOG_DEBUG, "in coher_cnt=%03x %s%s", |
2246 | mppe->coher_cnt, (flushed) ? "[flushed]" : "", |
2247 | (encrypt) ? "[encrypt]" : "")); |
2248 | |
2249 | if (encrypt == 0) { |
2250 | mtx_leave(&mppe->pxm_mtx); |
2251 | pipex_session_log(session, LOG_DEBUG7, |
2252 | "Received unexpected MPPE packet.(no ecrypt)"); |
2253 | goto drop; |
2254 | } |
2255 | |
2256 | /* adjust mbuf */ |
2257 | m_adj(m0, sizeof(coher_cnt)); |
2258 | |
2259 | /* |
2260 | * L2TP data session may be used without sequencing, PPP frames may |
2261 | * arrive in disorder. The 'coherency counter' of MPPE detects such |
2262 | * situations, but we cannot distinguish between 'disorder' and |
2263 | * 'packet loss' exactly. |
2264 | * |
2265 | * When 'coherency counter' detects lost packets greater than |
2266 | * (4096 - 256), we treat as 'disorder' otherwise treat as |
2267 | * 'packet loss'. |
2268 | */ |
2269 | { |
2270 | int coher_cnt0; |
2271 | |
2272 | coher_cnt0 = coher_cnt; |
2273 | if (coher_cnt < mppe->coher_cnt) |
2274 | coher_cnt0 += 0x1000; |
2275 | if (coher_cnt0 - mppe->coher_cnt > 0x0f00) { |
2276 | if (!mppe->stateless || |
2277 | coher_cnt0 - mppe->coher_cnt |
2278 | <= 0x1000 - PIPEX_MPPE_NOLDKEY64) { |
2279 | pipex_session_log(session, LOG_DEBUG7, |
2280 | "Workaround the out-of-sequence PPP framing problem: " |
2281 | "%d => %d", mppe->coher_cnt, coher_cnt); |
2282 | mtx_leave(&mppe->pxm_mtx); |
2283 | goto drop; |
2284 | } |
2285 | rewind = 1; |
2286 | } |
2287 | } |
2288 | |
2289 | if (mppe->stateless != 0) { |
2290 | if (!rewind) { |
2291 | mppe_key_change(mppe); |
2292 | while (mppe->coher_cnt != coher_cnt) { |
2293 | mppe->coher_cnt++; |
2294 | mppe->coher_cnt &= PIPEX_COHERENCY_CNT_MASK0x0fff; |
2295 | mppe_key_change(mppe); |
2296 | pktloss++; |
2297 | } |
2298 | } |
2299 | pipex_mppe_setoldkey(mppe, coher_cnt); |
2300 | } else { |
2301 | if (flushed) { |
2302 | if (coher_cnt < mppe->coher_cnt) { |
2303 | coher_cnt += 0x1000; |
2304 | } |
2305 | pktloss += coher_cnt - mppe->coher_cnt; |
2306 | m = mppe->coher_cnt / 256; |
2307 | n = coher_cnt / 256; |
2308 | while (m++ < n) |
2309 | mppe_key_change(mppe); |
2310 | |
2311 | coher_cnt &= PIPEX_COHERENCY_CNT_MASK0x0fff; |
2312 | mppe->coher_cnt = coher_cnt; |
2313 | } else if (mppe->coher_cnt != coher_cnt) { |
2314 | int ccp_id; |
2315 | |
2316 | mtx_leave(&mppe->pxm_mtx); |
2317 | |
2318 | /* Send CCP ResetReq */ |
2319 | PIPEX_DBG((session, LOG_DEBUG, "CCP SendResetReq")); |
2320 | |
2321 | mtx_enter(&session->pxs_mtx); |
2322 | ccp_id = session->ccp_id; |
2323 | session->ccp_id++; |
2324 | mtx_leave(&session->pxs_mtx); |
2325 | |
2326 | pipex_ccp_output(session, CCP_RESETREQ14, ccp_id); |
2327 | goto drop; |
2328 | } |
2329 | if ((coher_cnt & 0xff) == 0xff) { |
2330 | mppe_key_change(mppe); |
2331 | flushed = 1; |
2332 | } |
2333 | if (flushed) |
2334 | pipex_mppe_setkey(mppe); |
2335 | } |
2336 | |
2337 | if (pktloss > 1000) { |
2338 | pipex_session_log(session, LOG_DEBUG7, |
2339 | "%d packets loss.", pktloss); |
2340 | } |
2341 | |
2342 | /* decrypt ppp payload */ |
2343 | for (m1 = m0; m1; m1 = m1->m_nextm_hdr.mh_next) { |
2344 | cp = mtod(m1, u_char *)((u_char *)((m1)->m_hdr.mh_data)); |
2345 | len = m1->m_lenm_hdr.mh_len; |
2346 | pipex_mppe_crypt(mppe, len, cp, cp); |
2347 | } |
2348 | |
2349 | if (!rewind) { |
2350 | /* update coher_cnt */ |
2351 | mppe->coher_cnt++; |
2352 | mppe->coher_cnt &= PIPEX_COHERENCY_CNT_MASK0x0fff; |
2353 | } |
2354 | |
2355 | mtx_leave(&mppe->pxm_mtx); |
2356 | |
2357 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < PIPEX_PPPMINLEN5) |
2358 | goto drop; |
2359 | |
2360 | pipex_ppp_input(m0, session, 1); |
2361 | |
2362 | return; |
2363 | drop: |
2364 | m_freem(m0); |
2365 | counters_inc(session->stat_counters, pxc_ierrors); |
2366 | } |
2367 | |
2368 | Static void |
2369 | pipex_mppe_output(struct mbuf *m0, struct pipex_session *session, |
2370 | uint16_t protocol) |
2371 | { |
2372 | int encrypt, flushed, len; |
2373 | struct mppe_header { |
2374 | uint16_t coher_cnt; |
2375 | uint16_t protocol; |
2376 | } __packed__attribute__((__packed__)) *hdr; |
2377 | u_char *cp; |
2378 | struct pipex_mppe *mppe; |
2379 | struct mbuf *m; |
2380 | |
2381 | mppe = &session->mppe_send; |
2382 | |
2383 | /* |
2384 | * create a deep-copy if the mbuf has a shared mbuf cluster. |
2385 | * this is required to handle cases of tcp retransmission. |
2386 | */ |
2387 | for (m = m0; m != NULL((void *)0); m = m->m_nextm_hdr.mh_next) { |
2388 | if (M_READONLY(m)(((m)->m_hdr.mh_flags & 0x0001) != 0 && (((m)-> m_hdr.mh_flags & 0x0008) == 0 || ((m)->M_dat.MH.MH_dat .MH_ext.ext_nextref != (m))))) { |
2389 | m = m_dup_pkt(m0, max_linkhdr, M_NOWAIT0x0002); |
2390 | m_freem(m0); |
2391 | if (m == NULL((void *)0)) |
2392 | goto drop; |
2393 | m0 = m; |
2394 | break; |
2395 | } |
2396 | } |
2397 | /* prepend mppe header */ |
2398 | M_PREPEND(m0, sizeof(struct mppe_header), M_NOWAIT)(m0) = m_prepend((m0), (sizeof(struct mppe_header)), (0x0002) ); |
2399 | if (m0 == NULL((void *)0)) |
2400 | goto drop; |
2401 | hdr = mtod(m0, struct mppe_header *)((struct mppe_header *)((m0)->m_hdr.mh_data)); |
2402 | hdr->protocol = protocol; |
2403 | |
2404 | /* check coherency counter */ |
2405 | flushed = 0; |
2406 | encrypt = 1; |
2407 | |
2408 | mtx_enter(&mppe->pxm_mtx); |
2409 | |
2410 | if (mppe->stateless != 0) { |
2411 | flushed = 1; |
2412 | mppe_key_change(mppe); |
2413 | } else { |
2414 | if ((mppe->coher_cnt % 0x100) == 0xff) { |
2415 | flushed = 1; |
2416 | mppe_key_change(mppe); |
2417 | } else if (mppe->resetreq != 0) { |
2418 | flushed = 1; |
2419 | mppe->resetreq = 0; |
2420 | } |
2421 | } |
2422 | |
2423 | if (flushed) |
2424 | pipex_mppe_setkey(mppe); |
2425 | |
2426 | PIPEX_MPPE_DBG((session, LOG_DEBUG, "out coher_cnt=%03x %s%s", |
2427 | mppe->coher_cnt, (flushed) ? "[flushed]" : "", |
2428 | (encrypt) ? "[encrypt]" : "")); |
2429 | |
2430 | /* setup header information */ |
2431 | hdr->coher_cnt = (mppe->coher_cnt++) & PIPEX_COHERENCY_CNT_MASK0x0fff; |
2432 | hdr->coher_cnt &= PIPEX_COHERENCY_CNT_MASK0x0fff; |
2433 | if (flushed) |
2434 | hdr->coher_cnt |= 0x8000; |
2435 | if (encrypt) |
2436 | hdr->coher_cnt |= 0x1000; |
2437 | |
2438 | hdr->protocol = htons(hdr->protocol)(__uint16_t)(__builtin_constant_p(hdr->protocol) ? (__uint16_t )(((__uint16_t)(hdr->protocol) & 0xffU) << 8 | ( (__uint16_t)(hdr->protocol) & 0xff00U) >> 8) : __swap16md (hdr->protocol)); |
2439 | hdr->coher_cnt = htons(hdr->coher_cnt)(__uint16_t)(__builtin_constant_p(hdr->coher_cnt) ? (__uint16_t )(((__uint16_t)(hdr->coher_cnt) & 0xffU) << 8 | ( (__uint16_t)(hdr->coher_cnt) & 0xff00U) >> 8) : __swap16md (hdr->coher_cnt)); |
2440 | |
2441 | /* encrypt chain */ |
2442 | for (m = m0; m; m = m->m_nextm_hdr.mh_next) { |
2443 | cp = mtod(m, u_char *)((u_char *)((m)->m_hdr.mh_data)); |
2444 | len = m->m_lenm_hdr.mh_len; |
2445 | if (m == m0 && len > offsetof(struct mppe_header, protocol)__builtin_offsetof(struct mppe_header, protocol)) { |
2446 | len -= offsetof(struct mppe_header, protocol)__builtin_offsetof(struct mppe_header, protocol); |
2447 | cp += offsetof(struct mppe_header, protocol)__builtin_offsetof(struct mppe_header, protocol); |
2448 | } |
2449 | pipex_mppe_crypt(mppe, len, cp, cp); |
2450 | } |
2451 | |
2452 | mtx_leave(&mppe->pxm_mtx); |
2453 | |
2454 | pipex_ppp_output(m0, session, PPP_COMP0xfd); |
2455 | |
2456 | return; |
2457 | drop: |
2458 | counters_inc(session->stat_counters, pxc_oerrors); |
2459 | } |
2460 | |
2461 | Static void |
2462 | pipex_ccp_input(struct mbuf *m0, struct pipex_session *session) |
2463 | { |
2464 | u_char *cp; |
2465 | int code, id, len; |
2466 | |
2467 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < PPP_HDRLEN4) |
2468 | goto drop; |
2469 | if ((m0 = m_pullup(m0, PPP_HDRLEN4)) == NULL((void *)0)) |
2470 | goto drop; |
2471 | |
2472 | cp = mtod(m0, u_char *)((u_char *)((m0)->m_hdr.mh_data)); |
2473 | GETCHAR(code, cp)do { (code) = *(cp)++; } while (0); |
2474 | GETCHAR(id, cp)do { (id) = *(cp)++; } while (0); |
2475 | GETSHORT(len, cp)do { (len) = *(cp)++ << 8; (len) |= *(cp)++; } while (0 ); |
2476 | |
2477 | switch (code) { |
2478 | case CCP_RESETREQ14: |
2479 | PIPEX_DBG((session, LOG_DEBUG, "CCP RecvResetReq")); |
2480 | mtx_enter(&session->mppe_send.pxm_mtx); |
2481 | session->mppe_send.resetreq = 1; |
2482 | mtx_leave(&session->mppe_send.pxm_mtx); |
2483 | #ifndef PIPEX_NO_CCP_RESETACK1 |
2484 | PIPEX_DBG((session, LOG_DEBUG, "CCP SendResetAck")); |
2485 | pipex_ccp_output(session, CCP_RESETACK15, id); |
2486 | #endif |
2487 | /* ignore error */ |
2488 | break; |
2489 | case CCP_RESETACK15: |
2490 | PIPEX_DBG((session, LOG_DEBUG, "CCP RecvResetAck")); |
2491 | break; |
2492 | default: |
2493 | PIPEX_DBG((session, LOG_DEBUG, "CCP Recv code=%d", code)); |
2494 | goto drop; |
2495 | } |
2496 | m_freem(m0); |
2497 | |
2498 | return; |
2499 | drop: |
2500 | m_freem(m0); |
2501 | counters_inc(session->stat_counters, pxc_ierrors); |
2502 | } |
2503 | |
2504 | Static int |
2505 | pipex_ccp_output(struct pipex_session *session, int code, int id) |
2506 | { |
2507 | u_char *cp; |
2508 | struct mbuf *m; |
2509 | |
2510 | MGETHDR(m, M_DONTWAIT, MT_DATA)m = m_gethdr((0x0002), (1)); |
2511 | if (m == NULL((void *)0)) { |
2512 | counters_inc(session->stat_counters, pxc_oerrors); |
2513 | return (1); |
2514 | } |
2515 | m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = 4; |
2516 | cp = mtod(m, u_char *)((u_char *)((m)->m_hdr.mh_data)); |
2517 | PUTCHAR(code, cp)do { *(cp)++ = (u_char)(code); } while (0); |
2518 | PUTCHAR(id, cp)do { *(cp)++ = (u_char)(id); } while (0); |
2519 | PUTSHORT(4, cp)do { *(cp)++ = (u_char) ((4) >> 8); *(cp)++ = (u_char) ( 4); } while (0); |
2520 | |
2521 | pipex_ppp_output(m, session, PPP_CCP0x80fd); |
2522 | |
2523 | return (0); |
2524 | } |
2525 | #endif |
2526 | /*********************************************************************** |
2527 | * Miscellaneous functions |
2528 | ***********************************************************************/ |
2529 | /* adapted from FreeBSD:src/usr.sbin/ppp/tcpmss.c */ |
2530 | /* |
2531 | * Copyright (c) 2000 Ruslan Ermilov and Brian Somers <brian@Awfulhak.org> |
2532 | * All rights reserved. |
2533 | * |
2534 | * Redistribution and use in source and binary forms, with or without |
2535 | * modification, are permitted provided that the following conditions |
2536 | * are met: |
2537 | * 1. Redistributions of source code must retain the above copyright |
2538 | * notice, this list of conditions and the following disclaimer. |
2539 | * 2. Redistributions in binary form must reproduce the above copyright |
2540 | * notice, this list of conditions and the following disclaimer in the |
2541 | * documentation and/or other materials provided with the distribution. |
2542 | * |
2543 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
2544 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
2545 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
2546 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
2547 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
2548 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
2549 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
2550 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
2551 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
2552 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
2553 | * SUCH DAMAGE. |
2554 | * |
2555 | * $FreeBSD: src/usr.sbin/ppp/tcpmss.c,v 1.1.4.3 2001/07/19 11:39:54 brian Exp $ |
2556 | */ |
2557 | #define TCP_OPTLEN_IN_SEGMENT12 12 /* timestamp option and padding */ |
2558 | #define MAXMSS(mtu)(mtu - sizeof(struct ip) - sizeof(struct tcphdr) - 12) (mtu - sizeof(struct ip) - sizeof(struct tcphdr) - \ |
2559 | TCP_OPTLEN_IN_SEGMENT12) |
2560 | /* |
2561 | * The following macro is used to update an internet checksum. "acc" is a |
2562 | * 32-bit accumulation of all the changes to the checksum (adding in old |
2563 | * 16-bit words and subtracting out new words), and "cksum" is the checksum |
2564 | * value to be updated. |
2565 | */ |
2566 | #define ADJUST_CHECKSUM(acc, cksum){ acc += cksum; if (acc < 0) { acc = -acc; acc = (acc >> 16) + (acc & 0xffff); acc += acc >> 16; cksum = (u_short ) ~acc; } else { acc = (acc >> 16) + (acc & 0xffff) ; acc += acc >> 16; cksum = (u_short) acc; } } { \ |
2567 | acc += cksum; \ |
2568 | if (acc < 0) { \ |
2569 | acc = -acc; \ |
2570 | acc = (acc >> 16) + (acc & 0xffff); \ |
2571 | acc += acc >> 16; \ |
2572 | cksum = (u_short) ~acc; \ |
2573 | } else { \ |
2574 | acc = (acc >> 16) + (acc & 0xffff); \ |
2575 | acc += acc >> 16; \ |
2576 | cksum = (u_short) acc; \ |
2577 | } \ |
2578 | } |
2579 | |
2580 | /* |
2581 | * Rewrite max-segment-size TCP option to avoid PMTU blackhole issues. |
2582 | * The mtu parameter should be the MTU bottleneck (as far as we know) |
2583 | * on the link between the source and the destination. |
2584 | */ |
2585 | Static struct mbuf * |
2586 | adjust_tcp_mss(struct mbuf *m0, int mtu) |
2587 | { |
2588 | int opt, optlen, acc, mss, maxmss, lpktp; |
2589 | struct ip *pip; |
2590 | struct tcphdr *th; |
2591 | u_char *pktp, *mssp; |
2592 | u_int16_t ip_off; |
2593 | |
2594 | lpktp = sizeof(struct ip) + sizeof(struct tcphdr) + PIPEX_TCP_OPTLEN40; |
2595 | lpktp = MIN(lpktp, m0->m_pkthdr.len)(((lpktp)<(m0->M_dat.MH.MH_pkthdr.len))?(lpktp):(m0-> M_dat.MH.MH_pkthdr.len)); |
2596 | |
2597 | PIPEX_PULLUP(m0, lpktp)if ((m0)->m_hdr.mh_len < (lpktp)) { if ((m0)->M_dat. MH.MH_pkthdr.len < (lpktp)) { ; m_freem(m0); (m0) = ((void *)0); } else { (m0) = m_pullup((m0), (lpktp)); (((m0) != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2597, "(m0) != NULL")); } }; |
2598 | if (m0 == NULL((void *)0)) |
2599 | goto drop; |
2600 | |
2601 | pktp = mtod(m0, char *)((char *)((m0)->m_hdr.mh_data)); |
2602 | pip = (struct ip *)pktp; |
2603 | ip_off = ntohs(pip->ip_off)(__uint16_t)(__builtin_constant_p(pip->ip_off) ? (__uint16_t )(((__uint16_t)(pip->ip_off) & 0xffU) << 8 | ((__uint16_t )(pip->ip_off) & 0xff00U) >> 8) : __swap16md(pip ->ip_off)); |
2604 | |
2605 | /* Non TCP or fragmented packet must not have a MSS option */ |
2606 | if (pip->ip_p != IPPROTO_TCP6 || |
2607 | (ip_off & IP_MF0x2000) != 0 || (ip_off & IP_OFFMASK0x1fff) != 0) |
2608 | goto handled; |
2609 | |
2610 | pktp += pip->ip_hl << 2; |
2611 | lpktp -= pip->ip_hl << 2; |
2612 | |
2613 | /* packet is broken */ |
2614 | if (sizeof(struct tcphdr) > lpktp) |
2615 | goto drop; |
2616 | th = (struct tcphdr *)pktp; |
2617 | |
2618 | /* |
2619 | * As RFC 973, a MSS field must only be sent in the initial |
2620 | * connection request(it must be with SYN). |
2621 | */ |
2622 | if ((th->th_flags & TH_SYN0x02) == 0) |
2623 | goto handled; |
2624 | |
2625 | lpktp = MIN(th->th_off << 4, lpktp)(((th->th_off << 4)<(lpktp))?(th->th_off << 4):(lpktp)); |
2626 | |
2627 | pktp += sizeof(struct tcphdr); |
2628 | lpktp -= sizeof(struct tcphdr); |
2629 | while (lpktp >= TCPOLEN_MAXSEG4) { |
2630 | GETCHAR(opt, pktp)do { (opt) = *(pktp)++; } while (0); |
2631 | switch (opt) { |
2632 | case TCPOPT_MAXSEG2: |
2633 | GETCHAR(optlen, pktp)do { (optlen) = *(pktp)++; } while (0); |
2634 | mssp = pktp; /* mss place holder */ |
2635 | GETSHORT(mss, pktp)do { (mss) = *(pktp)++ << 8; (mss) |= *(pktp)++; } while (0); |
2636 | maxmss = MAXMSS(mtu)(mtu - sizeof(struct ip) - sizeof(struct tcphdr) - 12); |
2637 | if (mss > maxmss) { |
2638 | PIPEX_DBG((NULL, LOG_DEBUG, |
2639 | "change tcp-mss %d => %d", mss, maxmss)); |
2640 | PUTSHORT(maxmss, mssp)do { *(mssp)++ = (u_char) ((maxmss) >> 8); *(mssp)++ = ( u_char) (maxmss); } while (0); |
2641 | acc = htons(mss)(__uint16_t)(__builtin_constant_p(mss) ? (__uint16_t)(((__uint16_t )(mss) & 0xffU) << 8 | ((__uint16_t)(mss) & 0xff00U ) >> 8) : __swap16md(mss)); |
2642 | acc -= htons(maxmss)(__uint16_t)(__builtin_constant_p(maxmss) ? (__uint16_t)(((__uint16_t )(maxmss) & 0xffU) << 8 | ((__uint16_t)(maxmss) & 0xff00U) >> 8) : __swap16md(maxmss)); |
2643 | ADJUST_CHECKSUM(acc, th->th_sum){ acc += th->th_sum; if (acc < 0) { acc = -acc; acc = ( acc >> 16) + (acc & 0xffff); acc += acc >> 16 ; th->th_sum = (u_short) ~acc; } else { acc = (acc >> 16) + (acc & 0xffff); acc += acc >> 16; th->th_sum = (u_short) acc; } }; |
2644 | } |
2645 | goto handled; |
2646 | /* NOTREACHED */ |
2647 | case TCPOPT_EOL0: |
2648 | goto handled; |
2649 | /* NOTREACHED */ |
2650 | case TCPOPT_NOP1: |
2651 | lpktp--; |
2652 | break; |
2653 | default: |
2654 | GETCHAR(optlen, pktp)do { (optlen) = *(pktp)++; } while (0); |
2655 | if (optlen < 2) /* packet is broken */ |
2656 | goto drop; |
2657 | pktp += optlen - 2; |
2658 | lpktp -= optlen; |
2659 | break; |
2660 | } |
2661 | } |
2662 | |
2663 | handled: |
2664 | return (m0); |
2665 | |
2666 | drop: |
2667 | m_freem(m0); |
2668 | return (NULL((void *)0)); |
2669 | } |
2670 | |
2671 | /* |
2672 | * Check whether a packet should reset idle timer |
2673 | * Returns 1 to don't reset timer (i.e. the packet is "idle" packet) |
2674 | */ |
2675 | Static struct mbuf * |
2676 | ip_is_idle_packet(struct mbuf *m0, int *ris_idle) |
2677 | { |
2678 | u_int16_t ip_off; |
2679 | const struct udphdr *uh; |
2680 | struct ip *pip; |
2681 | int len; |
2682 | |
2683 | /* pullup ip header */ |
2684 | len = sizeof(struct ip); |
2685 | PIPEX_PULLUP(m0, len)if ((m0)->m_hdr.mh_len < (len)) { if ((m0)->M_dat.MH .MH_pkthdr.len < (len)) { ; m_freem(m0); (m0) = ((void *)0 ); } else { (m0) = m_pullup((m0), (len)); (((m0) != ((void *) 0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2685, "(m0) != NULL")); } }; |
2686 | if (m0 == NULL((void *)0)) |
2687 | goto error; |
2688 | pip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
2689 | |
2690 | /* |
2691 | * the packet which fragmentations was not the idle packet. |
2692 | */ |
2693 | ip_off = ntohs(pip->ip_off)(__uint16_t)(__builtin_constant_p(pip->ip_off) ? (__uint16_t )(((__uint16_t)(pip->ip_off) & 0xffU) << 8 | ((__uint16_t )(pip->ip_off) & 0xff00U) >> 8) : __swap16md(pip ->ip_off)); |
2694 | if ((ip_off & IP_MF0x2000) || ((ip_off & IP_OFFMASK0x1fff) != 0)) |
2695 | goto is_active; |
2696 | |
2697 | switch (pip->ip_p) { |
2698 | case IPPROTO_IGMP2: |
2699 | goto is_active; |
2700 | case IPPROTO_ICMP1: |
2701 | len = pip->ip_hl * 4 + 8; |
2702 | PIPEX_PULLUP(m0, len)if ((m0)->m_hdr.mh_len < (len)) { if ((m0)->M_dat.MH .MH_pkthdr.len < (len)) { ; m_freem(m0); (m0) = ((void *)0 ); } else { (m0) = m_pullup((m0), (len)); (((m0) != ((void *) 0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2702, "(m0) != NULL")); } }; |
2703 | if (m0 == NULL((void *)0)) |
2704 | goto error; |
2705 | pip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
2706 | |
2707 | switch (((unsigned char *) pip)[pip->ip_hl * 4]) { |
2708 | case 0: /* Echo Reply */ |
2709 | case 8: /* Echo Request */ |
2710 | goto is_active; |
2711 | default: |
2712 | goto is_idle; |
2713 | } |
2714 | |
2715 | case IPPROTO_UDP17: |
2716 | case IPPROTO_TCP6: |
2717 | len = pip->ip_hl * 4 + sizeof(struct udphdr); |
2718 | PIPEX_PULLUP(m0, len)if ((m0)->m_hdr.mh_len < (len)) { if ((m0)->M_dat.MH .MH_pkthdr.len < (len)) { ; m_freem(m0); (m0) = ((void *)0 ); } else { (m0) = m_pullup((m0), (len)); (((m0) != ((void *) 0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2718, "(m0) != NULL")); } }; |
2719 | if (m0 == NULL((void *)0)) |
2720 | goto error; |
2721 | pip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
2722 | uh = (struct udphdr *)(mtod(m0, caddr_t)((caddr_t)((m0)->m_hdr.mh_data)) + pip->ip_hl * 4); |
2723 | |
2724 | switch (ntohs(uh->uh_sport)(__uint16_t)(__builtin_constant_p(uh->uh_sport) ? (__uint16_t )(((__uint16_t)(uh->uh_sport) & 0xffU) << 8 | (( __uint16_t)(uh->uh_sport) & 0xff00U) >> 8) : __swap16md (uh->uh_sport))) { |
2725 | case 53: /* DOMAIN */ |
2726 | case 67: /* BOOTPS */ |
2727 | case 68: /* BOOTPC */ |
2728 | case 123: /* NTP */ |
2729 | case 137: /* NETBIOS-NS */ |
2730 | case 520: /* RIP */ |
2731 | goto is_idle; |
2732 | } |
2733 | switch (ntohs(uh->uh_dport)(__uint16_t)(__builtin_constant_p(uh->uh_dport) ? (__uint16_t )(((__uint16_t)(uh->uh_dport) & 0xffU) << 8 | (( __uint16_t)(uh->uh_dport) & 0xff00U) >> 8) : __swap16md (uh->uh_dport))) { |
2734 | case 53: /* DOMAIN */ |
2735 | case 67: /* BOOTPS */ |
2736 | case 68: /* BOOTPC */ |
2737 | case 123: /* NTP */ |
2738 | case 137: /* NETBIOS-NS */ |
2739 | case 520: /* RIP */ |
2740 | goto is_idle; |
2741 | } |
2742 | goto is_active; |
2743 | default: |
2744 | goto is_active; |
2745 | } |
2746 | |
2747 | is_active: |
2748 | *ris_idle = 0; |
2749 | return (m0); |
2750 | |
2751 | is_idle: |
2752 | *ris_idle = 1; |
2753 | return (m0); |
2754 | |
2755 | error: |
2756 | return (NULL((void *)0)); |
2757 | } |
2758 | |
2759 | Static void |
2760 | pipex_session_log(struct pipex_session *session, int prio, const char *fmt, ...) |
2761 | { |
2762 | char logbuf[1024]; |
2763 | va_list ap; |
2764 | |
2765 | logpri(prio); |
2766 | if (session != NULL((void *)0)) { |
2767 | struct ifnet *ifp; |
2768 | |
2769 | ifp = if_get(session->ifindex); |
2770 | addlog("pipex: ppp=%d iface=%s protocol=%s id=%d ", |
2771 | session->ppp_id, |
2772 | ifp? ifp->if_xname : "Unknown", |
2773 | (session->protocol == PIPEX_PROTO_PPPOE3)? "PPPoE" : |
2774 | (session->protocol == PIPEX_PROTO_PPTP2)? "PPTP" : |
2775 | (session->protocol == PIPEX_PROTO_L2TP1) ? "L2TP" : |
2776 | "Unknown", session->session_id); |
2777 | if_put(ifp); |
2778 | } else |
2779 | addlog("pipex: "); |
2780 | |
2781 | va_start(ap, fmt)__builtin_va_start((ap), fmt); |
2782 | vsnprintf(logbuf, sizeof(logbuf), fmt, ap); |
2783 | va_end(ap)__builtin_va_end((ap)); |
2784 | addlog("%s\n", logbuf); |
2785 | } |
2786 | |
2787 | Static uint32_t |
2788 | pipex_sockaddr_hash_key(struct sockaddr *sa) |
2789 | { |
2790 | switch (sa->sa_family) { |
2791 | case AF_INET2: |
2792 | return ntohl(satosin(sa)->sin_addr.s_addr)(__uint32_t)(__builtin_constant_p(satosin(sa)->sin_addr.s_addr ) ? (__uint32_t)(((__uint32_t)(satosin(sa)->sin_addr.s_addr ) & 0xff) << 24 | ((__uint32_t)(satosin(sa)->sin_addr .s_addr) & 0xff00) << 8 | ((__uint32_t)(satosin(sa) ->sin_addr.s_addr) & 0xff0000) >> 8 | ((__uint32_t )(satosin(sa)->sin_addr.s_addr) & 0xff000000) >> 24) : __swap32md(satosin(sa)->sin_addr.s_addr)); |
2793 | case AF_INET624: |
2794 | return ntohl(satosin6(sa)->sin6_addr.s6_addr32[3])(__uint32_t)(__builtin_constant_p(satosin6(sa)->sin6_addr. __u6_addr.__u6_addr32[3]) ? (__uint32_t)(((__uint32_t)(satosin6 (sa)->sin6_addr.__u6_addr.__u6_addr32[3]) & 0xff) << 24 | ((__uint32_t)(satosin6(sa)->sin6_addr.__u6_addr.__u6_addr32 [3]) & 0xff00) << 8 | ((__uint32_t)(satosin6(sa)-> sin6_addr.__u6_addr.__u6_addr32[3]) & 0xff0000) >> 8 | ((__uint32_t)(satosin6(sa)->sin6_addr.__u6_addr.__u6_addr32 [3]) & 0xff000000) >> 24) : __swap32md(satosin6(sa) ->sin6_addr.__u6_addr.__u6_addr32[3])); |
2795 | } |
2796 | panic("pipex_sockaddr_hash_key: unknown address family"); |
2797 | return (0); |
2798 | } |
2799 | |
2800 | /* |
2801 | * Compare struct sockaddr_in{,6} with the address only. |
2802 | * The port number is not covered. |
2803 | */ |
2804 | Static int |
2805 | pipex_sockaddr_compar_addr(struct sockaddr *a, struct sockaddr *b) |
2806 | { |
2807 | int cmp; |
2808 | |
2809 | cmp = b->sa_family - a->sa_family; |
2810 | if (cmp != 0) |
2811 | return cmp; |
2812 | switch (a->sa_family) { |
2813 | case AF_INET2: |
2814 | return (satosin(b)->sin_addr.s_addr - |
2815 | satosin(a)->sin_addr.s_addr); |
2816 | case AF_INET624: |
2817 | cmp = (satosin6(b)->sin6_scope_id - satosin6(a)->sin6_scope_id); |
2818 | if (cmp != 0) |
2819 | return cmp; |
2820 | return (memcmp(&satosin6(a)->sin6_addr,__builtin_memcmp((&satosin6(a)->sin6_addr), (&satosin6 (b)->sin6_addr), (sizeof(struct in6_addr))) |
2821 | &satosin6(b)->sin6_addr,__builtin_memcmp((&satosin6(a)->sin6_addr), (&satosin6 (b)->sin6_addr), (sizeof(struct in6_addr))) |
2822 | sizeof(struct in6_addr))__builtin_memcmp((&satosin6(a)->sin6_addr), (&satosin6 (b)->sin6_addr), (sizeof(struct in6_addr)))); |
2823 | } |
2824 | panic("pipex_sockaddr_compar_addr: unknown address family"); |
2825 | |
2826 | return (-1); |
2827 | } |
2828 | |
2829 | int |
2830 | pipex_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, |
2831 | size_t newlen) |
2832 | { |
2833 | switch (name[0]) { |
2834 | case PIPEXCTL_ENABLE1: |
2835 | if (namelen != 1) |
2836 | return (ENOTDIR20); |
2837 | return (sysctl_int_bounded(oldp, oldlenp, newp, newlen, |
2838 | &pipex_enable, 0, 1)); |
2839 | default: |
2840 | return (ENOPROTOOPT42); |
2841 | } |
2842 | /* NOTREACHED */ |
2843 | } |