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