1 /* $KAME: ip_encap.c,v 1.73 2001/10/02 08:30:58 itojun Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
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 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31 /*
32 * My grandfather said that there's a devil inside tunnelling technology...
33 *
34 * We have surprisingly many protocols that want packets with IP protocol
35 * #4 or #41. Here's a list of protocols that want protocol #41:
36 * RFC1933 configured tunnel
37 * RFC1933 automatic tunnel
38 * RFC2401 IPsec tunnel
39 * RFC2473 IPv6 generic packet tunnelling
40 * RFC2529 6over4 tunnel
41 * RFC3056 6to4 tunnel
42 * isatap tunnel
43 * mobile-ip6 (uses RFC2473)
44 * Here's a list of protocol that want protocol #4:
45 * RFC1853 IPv4-in-IPv4 tunnelling
46 * RFC2003 IPv4 encapsulation within IPv4
47 * RFC2344 reverse tunnelling for mobile-ip4
48 * RFC2401 IPsec tunnel
49 * Well, what can I say. They impose different en/decapsulation mechanism
50 * from each other, so they need separate protocol handler. The only one
51 * we can easily determine by protocol # is IPsec, which always has
52 * AH/ESP/IPComp header right after outer IP header.
53 *
54 * So, clearly good old protosw does not work for protocol #4 and #41.
55 * The code will let you match protocol via src/dst address pair.
56 */
57 /* XXX is M_NETADDR correct? */
58
59 /*
60 * With USE_RADIX the code will use radix table for tunnel lookup, for
61 * tunnels registered with encap_attach() with a addr/mask pair.
62 * Faster on machines with thousands of tunnel registerations (= interfaces).
63 *
64 * The code assumes that radix table code can handle non-continuous netmask,
65 * as it will pass radix table memory region with (src + dst) sockaddr pair.
66 *
67 * FreeBSD is excluded here as they make max_keylen a static variable, and
68 * thus forbid definition of radix table other than proper domains.
69 */
70 #define USE_RADIX
71
72 #include <sys/cdefs.h>
73 __KERNEL_RCSID(0, "$NetBSD: ip_encap.c,v 1.17 2004/03/04 15:15:06 wiz Exp $");
74
75 #include "opt_mrouting.h"
76 #include "opt_inet.h"
77
78 #include <sys/param.h>
79 #include <sys/systm.h>
80 #include <sys/socket.h>
81 #include <sys/sockio.h>
82 #include <sys/mbuf.h>
83 #include <sys/errno.h>
84 #include <sys/protosw.h>
85 #include <sys/queue.h>
86
87 #include <net/if.h>
88 #include <net/route.h>
89
90 #include <netinet/in.h>
91 #include <netinet/in_systm.h>
92 #include <netinet/ip.h>
93 #include <netinet/ip_var.h>
94 #include <netinet/ip_encap.h>
95 #ifdef MROUTING
96 #include <netinet/ip_mroute.h>
97 #endif /* MROUTING */
98
99 #ifdef INET6
100 #include <netinet/ip6.h>
101 #include <netinet6/ip6_var.h>
102 #include <netinet6/ip6protosw.h>
103 #include <netinet6/in6_var.h>
104 #include <netinet6/in6_pcb.h>
105 #include <netinet/icmp6.h>
106 #endif
107
108 #include <machine/stdarg.h>
109
110 #include <net/net_osdep.h>
111
112 /* to lookup a pair of address using radix tree */
113 struct sockaddr_pack {
114 u_int8_t sp_len;
115 u_int8_t sp_family; /* not really used */
116 /* followed by variable-length data */
117 };
118
119 struct pack4 {
120 struct sockaddr_pack p;
121 struct sockaddr_in mine;
122 struct sockaddr_in yours;
123 };
124 struct pack6 {
125 struct sockaddr_pack p;
126 struct sockaddr_in6 mine;
127 struct sockaddr_in6 yours;
128 };
129
130 enum direction { INBOUND, OUTBOUND };
131
132 #ifdef INET
133 static struct encaptab *encap4_lookup __P((struct mbuf *, int, int,
134 enum direction));
135 #endif
136 #ifdef INET6
137 static struct encaptab *encap6_lookup __P((struct mbuf *, int, int,
138 enum direction));
139 #endif
140 static int encap_add __P((struct encaptab *));
141 static int encap_remove __P((struct encaptab *));
142 static int encap_afcheck __P((int, const struct sockaddr *, const struct sockaddr *));
143 #ifdef USE_RADIX
144 static struct radix_node_head *encap_rnh __P((int));
145 static int mask_matchlen __P((const struct sockaddr *));
146 #endif
147 #ifndef USE_RADIX
148 static int mask_match __P((const struct encaptab *, const struct sockaddr *,
149 const struct sockaddr *));
150 #endif
151 static void encap_fillarg __P((struct mbuf *, const struct encaptab *));
152
153 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
154
155 #ifdef USE_RADIX
156 extern int max_keylen; /* radix.c */
157 struct radix_node_head *encap_head[2]; /* 0 for AF_INET, 1 for AF_INET6 */
158 #endif
159
160 void
161 encap_init()
162 {
163 static int initialized = 0;
164
165 if (initialized)
166 return;
167 initialized++;
168 #if 0
169 /*
170 * we cannot use LIST_INIT() here, since drivers may want to call
171 * encap_attach(), on driver attach. encap_init() will be called
172 * on AF_INET{,6} initialization, which happens after driver
173 * initialization - using LIST_INIT() here can nuke encap_attach()
174 * from drivers.
175 */
176 LIST_INIT(&encaptab);
177 #endif
178
179 #ifdef USE_RADIX
180 /*
181 * initialize radix lookup table.
182 * max_keylen initialization should happen before the call to rn_init().
183 */
184 rn_inithead((void *)&encap_head[0], sizeof(struct sockaddr_pack) << 3);
185 if (sizeof(struct pack4) > max_keylen)
186 max_keylen = sizeof(struct pack4);
187 #ifdef INET6
188 rn_inithead((void *)&encap_head[1], sizeof(struct sockaddr_pack) << 3);
189 if (sizeof(struct pack6) > max_keylen)
190 max_keylen = sizeof(struct pack6);
191 #endif
192 #endif
193 }
194
195 #ifdef INET
196 static struct encaptab *
197 encap4_lookup(m, off, proto, dir)
198 struct mbuf *m;
199 int off;
200 int proto;
201 enum direction dir;
202 {
203 struct ip *ip;
204 struct pack4 pack;
205 struct encaptab *ep, *match;
206 int prio, matchprio;
207 #ifdef USE_RADIX
208 struct radix_node_head *rnh = encap_rnh(AF_INET);
209 struct radix_node *rn;
210 #endif
211
212 #ifdef DIAGNOSTIC
213 if (m->m_len < sizeof(*ip))
214 panic("encap4_lookup");
215 #endif
216 ip = mtod(m, struct ip *);
217
218 bzero(&pack, sizeof(pack));
219 pack.p.sp_len = sizeof(pack);
220 pack.mine.sin_family = pack.yours.sin_family = AF_INET;
221 pack.mine.sin_len = pack.yours.sin_len = sizeof(struct sockaddr_in);
222 if (dir == INBOUND) {
223 pack.mine.sin_addr = ip->ip_dst;
224 pack.yours.sin_addr = ip->ip_src;
225 } else {
226 pack.mine.sin_addr = ip->ip_src;
227 pack.yours.sin_addr = ip->ip_dst;
228 }
229
230 match = NULL;
231 matchprio = 0;
232
233 #ifdef USE_RADIX
234 rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh);
235 if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
236 match = (struct encaptab *)rn;
237 matchprio = mask_matchlen(match->srcmask) +
238 mask_matchlen(match->dstmask);
239 }
240 #endif
241
242 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
243 if (ep->af != AF_INET)
244 continue;
245 if (ep->proto >= 0 && ep->proto != proto)
246 continue;
247 if (ep->func)
248 prio = (*ep->func)(m, off, proto, ep->arg);
249 else {
250 #ifdef USE_RADIX
251 continue;
252 #else
253 prio = mask_match(ep, (struct sockaddr *)&pack.mine,
254 (struct sockaddr *)&pack.yours);
255 #endif
256 }
257
258 /*
259 * We prioritize the matches by using bit length of the
260 * matches. mask_match() and user-supplied matching function
261 * should return the bit length of the matches (for example,
262 * if both src/dst are matched for IPv4, 64 should be returned).
263 * 0 or negative return value means "it did not match".
264 *
265 * The question is, since we have two "mask" portion, we
266 * cannot really define total order between entries.
267 * For example, which of these should be preferred?
268 * mask_match() returns 48 (32 + 16) for both of them.
269 * src=3ffe::/16, dst=3ffe:501::/32
270 * src=3ffe:501::/32, dst=3ffe::/16
271 *
272 * We need to loop through all the possible candidates
273 * to get the best match - the search takes O(n) for
274 * n attachments (i.e. interfaces).
275 *
276 * For radix-based lookup, I guess source takes precedence.
277 * See rn_{refines,lexobetter} for the correct answer.
278 */
279 if (prio <= 0)
280 continue;
281 if (prio > matchprio) {
282 matchprio = prio;
283 match = ep;
284 }
285 }
286
287 return match;
288 #undef s
289 #undef d
290 }
291
292 void
293 #if __STDC__
294 encap4_input(struct mbuf *m, ...)
295 #else
296 encap4_input(m, va_alist)
297 struct mbuf *m;
298 va_dcl
299 #endif
300 {
301 int off, proto;
302 va_list ap;
303 const struct protosw *psw;
304 struct encaptab *match;
305
306 va_start(ap, m);
307 off = va_arg(ap, int);
308 proto = va_arg(ap, int);
309 va_end(ap);
310
311 match = encap4_lookup(m, off, proto, INBOUND);
312
313 if (match) {
314 /* found a match, "match" has the best one */
315 psw = match->psw;
316 if (psw && psw->pr_input) {
317 encap_fillarg(m, match);
318 (*psw->pr_input)(m, off, proto);
319 } else
320 m_freem(m);
321 return;
322 }
323
324 /* last resort: inject to raw socket */
325 rip_input(m, off, proto);
326 }
327 #endif
328
329 #ifdef INET6
330 static struct encaptab *
331 encap6_lookup(m, off, proto, dir)
332 struct mbuf *m;
333 int off;
334 int proto;
335 enum direction dir;
336 {
337 struct ip6_hdr *ip6;
338 struct pack6 pack;
339 int prio, matchprio;
340 struct encaptab *ep, *match;
341 #ifdef USE_RADIX
342 struct radix_node_head *rnh = encap_rnh(AF_INET6);
343 struct radix_node *rn;
344 #endif
345
346 #ifdef DIAGNOSTIC
347 if (m->m_len < sizeof(*ip6))
348 panic("encap6_lookup");
349 #endif
350 ip6 = mtod(m, struct ip6_hdr *);
351
352 bzero(&pack, sizeof(pack));
353 pack.p.sp_len = sizeof(pack);
354 pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6;
355 pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6);
356 if (dir == INBOUND) {
357 pack.mine.sin6_addr = ip6->ip6_dst;
358 pack.yours.sin6_addr = ip6->ip6_src;
359 } else {
360 pack.mine.sin6_addr = ip6->ip6_src;
361 pack.yours.sin6_addr = ip6->ip6_dst;
362 }
363
364 match = NULL;
365 matchprio = 0;
366
367 #ifdef USE_RADIX
368 rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh);
369 if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
370 match = (struct encaptab *)rn;
371 matchprio = mask_matchlen(match->srcmask) +
372 mask_matchlen(match->dstmask);
373 }
374 #endif
375
376 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
377 if (ep->af != AF_INET6)
378 continue;
379 if (ep->proto >= 0 && ep->proto != proto)
380 continue;
381 if (ep->func)
382 prio = (*ep->func)(m, off, proto, ep->arg);
383 else {
384 #ifdef USE_RADIX
385 continue;
386 #else
387 prio = mask_match(ep, (struct sockaddr *)&pack.mine,
388 (struct sockaddr *)&pack.yours);
389 #endif
390 }
391
392 /* see encap4_lookup() for issues here */
393 if (prio <= 0)
394 continue;
395 if (prio > matchprio) {
396 matchprio = prio;
397 match = ep;
398 }
399 }
400
401 return match;
402 #undef s
403 #undef d
404 }
405
406 int
407 encap6_input(mp, offp, proto)
408 struct mbuf **mp;
409 int *offp;
410 int proto;
411 {
412 struct mbuf *m = *mp;
413 const struct ip6protosw *psw;
414 struct encaptab *match;
415
416 match = encap6_lookup(m, *offp, proto, INBOUND);
417
418 if (match) {
419 /* found a match */
420 psw = (const struct ip6protosw *)match->psw;
421 if (psw && psw->pr_input) {
422 encap_fillarg(m, match);
423 return (*psw->pr_input)(mp, offp, proto);
424 } else {
425 m_freem(m);
426 return IPPROTO_DONE;
427 }
428 }
429
430 /* last resort: inject to raw socket */
431 return rip6_input(mp, offp, proto);
432 }
433 #endif
434
435 static int
436 encap_add(ep)
437 struct encaptab *ep;
438 {
439 #ifdef USE_RADIX
440 struct radix_node_head *rnh = encap_rnh(ep->af);
441 #endif
442 int error = 0;
443
444 LIST_INSERT_HEAD(&encaptab, ep, chain);
445 #ifdef USE_RADIX
446 if (!ep->func && rnh) {
447 if (!rnh->rnh_addaddr((caddr_t)ep->addrpack,
448 (caddr_t)ep->maskpack, rnh, ep->nodes)) {
449 error = EEXIST;
450 goto fail;
451 }
452 }
453 #endif
454 return error;
455
456 fail:
457 LIST_REMOVE(ep, chain);
458 return error;
459 }
460
461 static int
462 encap_remove(ep)
463 struct encaptab *ep;
464 {
465 #ifdef USE_RADIX
466 struct radix_node_head *rnh = encap_rnh(ep->af);
467 #endif
468 int error = 0;
469
470 LIST_REMOVE(ep, chain);
471 #ifdef USE_RADIX
472 if (!ep->func && rnh) {
473 if (!rnh->rnh_deladdr((caddr_t)ep->addrpack,
474 (caddr_t)ep->maskpack, rnh))
475 error = ESRCH;
476 }
477 #endif
478 return error;
479 }
480
481 static int
482 encap_afcheck(af, sp, dp)
483 int af;
484 const struct sockaddr *sp;
485 const struct sockaddr *dp;
486 {
487 if (sp && dp) {
488 if (sp->sa_len != dp->sa_len)
489 return EINVAL;
490 if (af != sp->sa_family || af != dp->sa_family)
491 return EINVAL;
492 } else if (!sp && !dp)
493 ;
494 else
495 return EINVAL;
496
497 switch (af) {
498 case AF_INET:
499 if (sp && sp->sa_len != sizeof(struct sockaddr_in))
500 return EINVAL;
501 if (dp && dp->sa_len != sizeof(struct sockaddr_in))
502 return EINVAL;
503 break;
504 #ifdef INET6
505 case AF_INET6:
506 if (sp && sp->sa_len != sizeof(struct sockaddr_in6))
507 return EINVAL;
508 if (dp && dp->sa_len != sizeof(struct sockaddr_in6))
509 return EINVAL;
510 break;
511 #endif
512 default:
513 return EAFNOSUPPORT;
514 }
515
516 return 0;
517 }
518
519 /*
520 * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
521 * length of mask (sm and dm) is assumed to be same as sp/dp.
522 * Return value will be necessary as input (cookie) for encap_detach().
523 */
524 const struct encaptab *
525 encap_attach(af, proto, sp, sm, dp, dm, psw, arg)
526 int af;
527 int proto;
528 const struct sockaddr *sp, *sm;
529 const struct sockaddr *dp, *dm;
530 const struct protosw *psw;
531 void *arg;
532 {
533 struct encaptab *ep;
534 int error;
535 int s;
536 size_t l;
537 struct pack4 *pack4;
538 #ifdef INET6
539 struct pack6 *pack6;
540 #endif
541
542 s = splsoftnet();
543 /* sanity check on args */
544 error = encap_afcheck(af, sp, dp);
545 if (error)
546 goto fail;
547
548 /* check if anyone have already attached with exactly same config */
549 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
550 if (ep->af != af)
551 continue;
552 if (ep->proto != proto)
553 continue;
554 if (ep->func)
555 continue;
556 #ifdef DIAGNOSTIC
557 if (!ep->src || !ep->dst || !ep->srcmask || !ep->dstmask)
558 panic("null pointers in encaptab");
559 #endif
560 if (ep->src->sa_len != sp->sa_len ||
561 bcmp(ep->src, sp, sp->sa_len) != 0 ||
562 bcmp(ep->srcmask, sm, sp->sa_len) != 0)
563 continue;
564 if (ep->dst->sa_len != dp->sa_len ||
565 bcmp(ep->dst, dp, dp->sa_len) != 0 ||
566 bcmp(ep->dstmask, dm, dp->sa_len) != 0)
567 continue;
568
569 error = EEXIST;
570 goto fail;
571 }
572
573 switch (af) {
574 case AF_INET:
575 l = sizeof(*pack4);
576 break;
577 #ifdef INET6
578 case AF_INET6:
579 l = sizeof(*pack6);
580 break;
581 #endif
582 default:
583 goto fail;
584 }
585
586 #ifdef DIAGNOSTIC
587 /* if l exceeds the value sa_len can possibly express, it's wrong. */
588 if (l > (1 << (8 * sizeof(ep->addrpack->sa_len)))) {
589 error = EINVAL;
590 goto fail;
591 }
592 #endif
593
594 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /* M_NETADDR ok? */
595 if (ep == NULL) {
596 error = ENOBUFS;
597 goto fail;
598 }
599 bzero(ep, sizeof(*ep));
600 ep->addrpack = malloc(l, M_NETADDR, M_NOWAIT);
601 if (ep->addrpack == NULL) {
602 error = ENOBUFS;
603 goto gc;
604 }
605 ep->maskpack = malloc(l, M_NETADDR, M_NOWAIT);
606 if (ep->maskpack == NULL) {
607 error = ENOBUFS;
608 goto gc;
609 }
610
611 ep->af = af;
612 ep->proto = proto;
613 ep->addrpack->sa_len = l & 0xff;
614 ep->maskpack->sa_len = l & 0xff;
615 switch (af) {
616 case AF_INET:
617 pack4 = (struct pack4 *)ep->addrpack;
618 ep->src = (struct sockaddr *)&pack4->mine;
619 ep->dst = (struct sockaddr *)&pack4->yours;
620 pack4 = (struct pack4 *)ep->maskpack;
621 ep->srcmask = (struct sockaddr *)&pack4->mine;
622 ep->dstmask = (struct sockaddr *)&pack4->yours;
623 break;
624 #ifdef INET6
625 case AF_INET6:
626 pack6 = (struct pack6 *)ep->addrpack;
627 ep->src = (struct sockaddr *)&pack6->mine;
628 ep->dst = (struct sockaddr *)&pack6->yours;
629 pack6 = (struct pack6 *)ep->maskpack;
630 ep->srcmask = (struct sockaddr *)&pack6->mine;
631 ep->dstmask = (struct sockaddr *)&pack6->yours;
632 break;
633 #endif
634 }
635
636 bcopy(sp, ep->src, sp->sa_len);
637 bcopy(sm, ep->srcmask, sp->sa_len);
638 bcopy(dp, ep->dst, dp->sa_len);
639 bcopy(dm, ep->dstmask, dp->sa_len);
640 ep->psw = psw;
641 ep->arg = arg;
642
643 error = encap_add(ep);
644 if (error)
645 goto gc;
646
647 error = 0;
648 splx(s);
649 return ep;
650
651 gc:
652 if (ep->addrpack)
653 free(ep->addrpack, M_NETADDR);
654 if (ep->maskpack)
655 free(ep->maskpack, M_NETADDR);
656 if (ep)
657 free(ep, M_NETADDR);
658 fail:
659 splx(s);
660 return NULL;
661 }
662
663 const struct encaptab *
664 encap_attach_func(af, proto, func, psw, arg)
665 int af;
666 int proto;
667 int (*func) __P((const struct mbuf *, int, int, void *));
668 const struct protosw *psw;
669 void *arg;
670 {
671 struct encaptab *ep;
672 int error;
673 int s;
674
675 s = splsoftnet();
676 /* sanity check on args */
677 if (!func) {
678 error = EINVAL;
679 goto fail;
680 }
681
682 error = encap_afcheck(af, NULL, NULL);
683 if (error)
684 goto fail;
685
686 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
687 if (ep == NULL) {
688 error = ENOBUFS;
689 goto fail;
690 }
691 bzero(ep, sizeof(*ep));
692
693 ep->af = af;
694 ep->proto = proto;
695 ep->func = func;
696 ep->psw = psw;
697 ep->arg = arg;
698
699 error = encap_add(ep);
700 if (error)
701 goto fail;
702
703 error = 0;
704 splx(s);
705 return ep;
706
707 fail:
708 splx(s);
709 return NULL;
710 }
711
712 /* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */
713
714 #ifdef INET6
715 void
716 encap6_ctlinput(cmd, sa, d0)
717 int cmd;
718 struct sockaddr *sa;
719 void *d0;
720 {
721 void *d = d0;
722 struct ip6_hdr *ip6;
723 struct mbuf *m;
724 int off;
725 struct ip6ctlparam *ip6cp = NULL;
726 int nxt;
727 struct encaptab *ep;
728 const struct ip6protosw *psw;
729
730 if (sa->sa_family != AF_INET6 ||
731 sa->sa_len != sizeof(struct sockaddr_in6))
732 return;
733
734 if ((unsigned)cmd >= PRC_NCMDS)
735 return;
736 if (cmd == PRC_HOSTDEAD)
737 d = NULL;
738 else if (cmd == PRC_MSGSIZE)
739 ; /* special code is present, see below */
740 else if (inet6ctlerrmap[cmd] == 0)
741 return;
742
743 /* if the parameter is from icmp6, decode it. */
744 if (d != NULL) {
745 ip6cp = (struct ip6ctlparam *)d;
746 m = ip6cp->ip6c_m;
747 ip6 = ip6cp->ip6c_ip6;
748 off = ip6cp->ip6c_off;
749 nxt = ip6cp->ip6c_nxt;
750
751 if (ip6 && cmd == PRC_MSGSIZE) {
752 int valid = 0;
753 struct encaptab *match;
754
755 /*
756 * Check to see if we have a valid encap configuration.
757 */
758 match = encap6_lookup(m, off, nxt, OUTBOUND);
759 if (match)
760 valid++;
761
762 /*
763 * Depending on the value of "valid" and routing table
764 * size (mtudisc_{hi,lo}wat), we will:
765 * - recalcurate the new MTU and create the
766 * corresponding routing entry, or
767 * - ignore the MTU change notification.
768 */
769 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
770 }
771 } else {
772 m = NULL;
773 ip6 = NULL;
774 nxt = -1;
775 }
776
777 /* inform all listeners */
778 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
779 if (ep->af != AF_INET6)
780 continue;
781 if (ep->proto >= 0 && ep->proto != nxt)
782 continue;
783
784 /* should optimize by looking at address pairs */
785
786 /* XXX need to pass ep->arg or ep itself to listeners */
787 psw = (const struct ip6protosw *)ep->psw;
788 if (psw && psw->pr_ctlinput)
789 (*psw->pr_ctlinput)(cmd, sa, d);
790 }
791
792 rip6_ctlinput(cmd, sa, d0);
793 }
794 #endif
795
796 int
797 encap_detach(cookie)
798 const struct encaptab *cookie;
799 {
800 const struct encaptab *ep = cookie;
801 struct encaptab *p;
802 int error;
803
804 for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
805 if (p == ep) {
806 error = encap_remove(p);
807 if (error)
808 return error;
809 if (!ep->func) {
810 free(p->addrpack, M_NETADDR);
811 free(p->maskpack, M_NETADDR);
812 }
813 free(p, M_NETADDR); /*XXX*/
814 return 0;
815 }
816 }
817
818 return ENOENT;
819 }
820
821 #ifdef USE_RADIX
822 static struct radix_node_head *
823 encap_rnh(af)
824 int af;
825 {
826
827 switch (af) {
828 case AF_INET:
829 return encap_head[0];
830 #ifdef INET6
831 case AF_INET6:
832 return encap_head[1];
833 #endif
834 default:
835 return NULL;
836 }
837 }
838
839 static int
840 mask_matchlen(sa)
841 const struct sockaddr *sa;
842 {
843 const char *p, *ep;
844 int l;
845
846 p = (const char *)sa;
847 ep = p + sa->sa_len;
848 p += 2; /* sa_len + sa_family */
849
850 l = 0;
851 while (p < ep) {
852 l += (*p ? 8 : 0); /* estimate */
853 p++;
854 }
855 return l;
856 }
857 #endif
858
859 #ifndef USE_RADIX
860 static int
861 mask_match(ep, sp, dp)
862 const struct encaptab *ep;
863 const struct sockaddr *sp;
864 const struct sockaddr *dp;
865 {
866 struct sockaddr_storage s;
867 struct sockaddr_storage d;
868 int i;
869 const u_int8_t *p, *q;
870 u_int8_t *r;
871 int matchlen;
872
873 #ifdef DIAGNOSTIC
874 if (ep->func)
875 panic("wrong encaptab passed to mask_match");
876 #endif
877 if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
878 return 0;
879 if (sp->sa_family != ep->af || dp->sa_family != ep->af)
880 return 0;
881 if (sp->sa_len != ep->src->sa_len || dp->sa_len != ep->dst->sa_len)
882 return 0;
883
884 matchlen = 0;
885
886 p = (const u_int8_t *)sp;
887 q = (const u_int8_t *)ep->srcmask;
888 r = (u_int8_t *)&s;
889 for (i = 0 ; i < sp->sa_len; i++) {
890 r[i] = p[i] & q[i];
891 /* XXX estimate */
892 matchlen += (q[i] ? 8 : 0);
893 }
894
895 p = (const u_int8_t *)dp;
896 q = (const u_int8_t *)ep->dstmask;
897 r = (u_int8_t *)&d;
898 for (i = 0 ; i < dp->sa_len; i++) {
899 r[i] = p[i] & q[i];
900 /* XXX rough estimate */
901 matchlen += (q[i] ? 8 : 0);
902 }
903
904 /* need to overwrite len/family portion as we don't compare them */
905 s.ss_len = sp->sa_len;
906 s.ss_family = sp->sa_family;
907 d.ss_len = dp->sa_len;
908 d.ss_family = dp->sa_family;
909
910 if (bcmp(&s, ep->src, ep->src->sa_len) == 0 &&
911 bcmp(&d, ep->dst, ep->dst->sa_len) == 0) {
912 return matchlen;
913 } else
914 return 0;
915 }
916 #endif
917
918 static void
919 encap_fillarg(m, ep)
920 struct mbuf *m;
921 const struct encaptab *ep;
922 {
923 struct m_tag *mtag;
924
925 mtag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT);
926 if (mtag) {
927 *(void **)(mtag + 1) = ep->arg;
928 m_tag_prepend(m, mtag);
929 }
930 }
931
932 void *
933 encap_getarg(m)
934 struct mbuf *m;
935 {
936 void *p;
937 struct m_tag *mtag;
938
939 p = NULL;
940 mtag = m_tag_find(m, PACKET_TAG_ENCAP, NULL);
941 if (mtag != NULL) {
942 p = *(void **)(mtag + 1);
943 m_tag_delete(m, mtag);
944 }
945 return p;
946 }
Cache object: 146344f0d266231d936abb9c48557239
|