Bug Summary

File:net/pipex.c
Warning:line 1832, column 2
Value stored to 'length' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name pipex.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/net/pipex.c
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
82struct pool pipex_session_pool;
83struct 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
93int pipex_enable = 0; /* [N] */
94struct 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
100struct radix_node_head *pipex_rd_head4 = NULL((void *)0); /* [N] */
101struct radix_node_head *pipex_rd_head6 = NULL((void *)0); /* [N] */
102struct timeout pipex_timer_ch; /* callout timer context */
103int 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
109int 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 ************************************************************************/
118void
119pipex_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
143void
144pipex_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
160int
161pipex_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 ************************************************************************/
193int
194pipex_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
363void
364pipex_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
372int
373pipex_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
432void
433pipex_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
469int
470pipex_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
480void
481pipex_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
498Static int
499pipex_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
515Static int
516pipex_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
532Static int
533pipex_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
556Static struct pipex_session *
557pipex_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
589Static struct pipex_session *
590pipex_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 ***********************************************************************/
616Static void
617pipex_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
623Static void
624pipex_timer_stop(void)
625{
626 timeout_del(&pipex_timer_ch);
627}
628
629Static void
630pipex_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 ***********************************************************************/
676Static void
677pipex_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;
730drop:
731 m_freem(m0);
732dropped:
733 counters_inc(session->stat_counters, pxc_oerrors);
734}
735
736Static void
737pipex_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;
785drop:
786 m_freem(m0);
787 counters_inc(session->stat_counters, pxc_oerrors);
788}
789
790Static void
791pipex_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;
873drop:
874 m_freem(m0);
875 counters_inc(session->stat_counters, pxc_ierrors);
876}
877
878Static void
879pipex_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;
945drop:
946 m_freem(m0);
947 counters_inc(session->stat_counters, pxc_ierrors);
948}
949
950#ifdef INET61
951Static void
952pipex_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;
993drop:
994 m_freem(m0);
995 counters_inc(session->stat_counters, pxc_ierrors);
996}
997#endif
998
999Static struct mbuf *
1000pipex_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
1053drop:
1054 m_freem(m0);
1055 counters_inc(session->stat_counters, pxc_ierrors);
1056 return (NULL((void *)0));
1057
1058not_ours:
1059 return (m0); /* Not to be handled by PIPEX */
1060}
1061
1062/*
1063 * pipex_ppp_proto
1064 */
1065Static int
1066pipex_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 ***********************************************************************/
1106Static u_char pipex_pppoe_padding[ETHERMIN(64 - ((6 * 2) + 2) - 4)];
1107/*
1108 * pipex_pppoe_lookup_session
1109 */
1110struct pipex_session *
1111pipex_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
1136struct mbuf *
1137pipex_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 */
1162Static void
1163pipex_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 ***********************************************************************/
1212Static void
1213pipex_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;
1291drop:
1292 counters_inc(session->stat_counters, pxc_oerrors);
1293}
1294
1295struct pipex_session *
1296pipex_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
1358not_ours:
1359 return (NULL((void *)0));
1360}
1361
1362struct mbuf *
1363pipex_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
1458not_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);
1486out_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 */
1495drop:
1496 m_freem(m0);
1497 counters_inc(session->stat_counters, pxc_ierrors);
1498
1499 return (NULL((void *)0));
1500}
1501
1502struct pipex_session *
1503pipex_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
1516struct pipex_session *
1517pipex_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
1530Static struct pipex_session *
1531pipex_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 */
1586struct mbuf *
1587pipex_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 ***********************************************************************/
1642Static void
1643pipex_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;
1767drop:
1768 m_freem(m0);
1769 counters_inc(session->stat_counters, pxc_oerrors);
1770}
1771
1772struct pipex_session *
1773pipex_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
1817not_ours:
1818 return (NULL((void *)0));
1819}
1820
1821struct mbuf *
1822pipex_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);
1928out_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 */
1935drop:
1936 m_freem(m0);
1937 counters_inc(session->stat_counters, pxc_ierrors);
1938
1939 return (NULL((void *)0));
1940}
1941
1942struct pipex_session *
1943pipex_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
1956struct pipex_session *
1957pipex_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
1970struct pipex_session *
1971pipex_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
2028struct mbuf *
2029pipex_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
2071static inline int
2072pipex_mppe_setkey(struct pipex_mppe *mppe)
2073{
2074 rc4_keysetup(&mppe->rc4ctx, mppe->session_key, mppe->keylen);
2075
2076 return (0);
2077}
2078
2079static inline int
2080pipex_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
2091static inline void
2092pipex_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
2098Static void
2099pipex_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
2130void
2131pipex_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
2139void
2140pipex_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
2150static 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
2164Static void
2165GetNewKeyFromSHA(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
2181Static void
2182pipex_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
2196Static void
2197mppe_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
2219Static void
2220pipex_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;
2363drop:
2364 m_freem(m0);
2365 counters_inc(session->stat_counters, pxc_ierrors);
2366}
2367
2368Static void
2369pipex_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;
2457drop:
2458 counters_inc(session->stat_counters, pxc_oerrors);
2459}
2460
2461Static void
2462pipex_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;
2499drop:
2500 m_freem(m0);
2501 counters_inc(session->stat_counters, pxc_ierrors);
2502}
2503
2504Static int
2505pipex_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 */
2585Static struct mbuf *
2586adjust_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
2663handled:
2664 return (m0);
2665
2666drop:
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 */
2675Static struct mbuf *
2676ip_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
2747is_active:
2748 *ris_idle = 0;
2749 return (m0);
2750
2751is_idle:
2752 *ris_idle = 1;
2753 return (m0);
2754
2755error:
2756 return (NULL((void *)0));
2757}
2758
2759Static void
2760pipex_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
2787Static uint32_t
2788pipex_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 */
2804Static int
2805pipex_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
2829int
2830pipex_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}