ip_encap.c revision 1.13.2.1 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.13.2.1 2004/08/03 10:54:37 skrll 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 encap4_input(struct mbuf *m, ...)
294 {
295 int off, proto;
296 va_list ap;
297 const struct protosw *psw;
298 struct encaptab *match;
299
300 va_start(ap, m);
301 off = va_arg(ap, int);
302 proto = va_arg(ap, int);
303 va_end(ap);
304
305 match = encap4_lookup(m, off, proto, INBOUND);
306
307 if (match) {
308 /* found a match, "match" has the best one */
309 psw = match->psw;
310 if (psw && psw->pr_input) {
311 encap_fillarg(m, match);
312 (*psw->pr_input)(m, off, proto);
313 } else
314 m_freem(m);
315 return;
316 }
317
318 /* last resort: inject to raw socket */
319 rip_input(m, off, proto);
320 }
321 #endif
322
323 #ifdef INET6
324 static struct encaptab *
325 encap6_lookup(m, off, proto, dir)
326 struct mbuf *m;
327 int off;
328 int proto;
329 enum direction dir;
330 {
331 struct ip6_hdr *ip6;
332 struct pack6 pack;
333 int prio, matchprio;
334 struct encaptab *ep, *match;
335 #ifdef USE_RADIX
336 struct radix_node_head *rnh = encap_rnh(AF_INET6);
337 struct radix_node *rn;
338 #endif
339
340 #ifdef DIAGNOSTIC
341 if (m->m_len < sizeof(*ip6))
342 panic("encap6_lookup");
343 #endif
344 ip6 = mtod(m, struct ip6_hdr *);
345
346 bzero(&pack, sizeof(pack));
347 pack.p.sp_len = sizeof(pack);
348 pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6;
349 pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6);
350 if (dir == INBOUND) {
351 pack.mine.sin6_addr = ip6->ip6_dst;
352 pack.yours.sin6_addr = ip6->ip6_src;
353 } else {
354 pack.mine.sin6_addr = ip6->ip6_src;
355 pack.yours.sin6_addr = ip6->ip6_dst;
356 }
357
358 match = NULL;
359 matchprio = 0;
360
361 #ifdef USE_RADIX
362 rn = rnh->rnh_matchaddr((caddr_t)&pack, rnh);
363 if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
364 match = (struct encaptab *)rn;
365 matchprio = mask_matchlen(match->srcmask) +
366 mask_matchlen(match->dstmask);
367 }
368 #endif
369
370 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
371 if (ep->af != AF_INET6)
372 continue;
373 if (ep->proto >= 0 && ep->proto != proto)
374 continue;
375 if (ep->func)
376 prio = (*ep->func)(m, off, proto, ep->arg);
377 else {
378 #ifdef USE_RADIX
379 continue;
380 #else
381 prio = mask_match(ep, (struct sockaddr *)&pack.mine,
382 (struct sockaddr *)&pack.yours);
383 #endif
384 }
385
386 /* see encap4_lookup() for issues here */
387 if (prio <= 0)
388 continue;
389 if (prio > matchprio) {
390 matchprio = prio;
391 match = ep;
392 }
393 }
394
395 return match;
396 #undef s
397 #undef d
398 }
399
400 int
401 encap6_input(mp, offp, proto)
402 struct mbuf **mp;
403 int *offp;
404 int proto;
405 {
406 struct mbuf *m = *mp;
407 const struct ip6protosw *psw;
408 struct encaptab *match;
409
410 match = encap6_lookup(m, *offp, proto, INBOUND);
411
412 if (match) {
413 /* found a match */
414 psw = (const struct ip6protosw *)match->psw;
415 if (psw && psw->pr_input) {
416 encap_fillarg(m, match);
417 return (*psw->pr_input)(mp, offp, proto);
418 } else {
419 m_freem(m);
420 return IPPROTO_DONE;
421 }
422 }
423
424 /* last resort: inject to raw socket */
425 return rip6_input(mp, offp, proto);
426 }
427 #endif
428
429 static int
430 encap_add(ep)
431 struct encaptab *ep;
432 {
433 #ifdef USE_RADIX
434 struct radix_node_head *rnh = encap_rnh(ep->af);
435 #endif
436 int error = 0;
437
438 LIST_INSERT_HEAD(&encaptab, ep, chain);
439 #ifdef USE_RADIX
440 if (!ep->func && rnh) {
441 if (!rnh->rnh_addaddr((caddr_t)ep->addrpack,
442 (caddr_t)ep->maskpack, rnh, ep->nodes)) {
443 error = EEXIST;
444 goto fail;
445 }
446 }
447 #endif
448 return error;
449
450 fail:
451 LIST_REMOVE(ep, chain);
452 return error;
453 }
454
455 static int
456 encap_remove(ep)
457 struct encaptab *ep;
458 {
459 #ifdef USE_RADIX
460 struct radix_node_head *rnh = encap_rnh(ep->af);
461 #endif
462 int error = 0;
463
464 LIST_REMOVE(ep, chain);
465 #ifdef USE_RADIX
466 if (!ep->func && rnh) {
467 if (!rnh->rnh_deladdr((caddr_t)ep->addrpack,
468 (caddr_t)ep->maskpack, rnh))
469 error = ESRCH;
470 }
471 #endif
472 return error;
473 }
474
475 static int
476 encap_afcheck(af, sp, dp)
477 int af;
478 const struct sockaddr *sp;
479 const struct sockaddr *dp;
480 {
481 if (sp && dp) {
482 if (sp->sa_len != dp->sa_len)
483 return EINVAL;
484 if (af != sp->sa_family || af != dp->sa_family)
485 return EINVAL;
486 } else if (!sp && !dp)
487 ;
488 else
489 return EINVAL;
490
491 switch (af) {
492 case AF_INET:
493 if (sp && sp->sa_len != sizeof(struct sockaddr_in))
494 return EINVAL;
495 if (dp && dp->sa_len != sizeof(struct sockaddr_in))
496 return EINVAL;
497 break;
498 #ifdef INET6
499 case AF_INET6:
500 if (sp && sp->sa_len != sizeof(struct sockaddr_in6))
501 return EINVAL;
502 if (dp && dp->sa_len != sizeof(struct sockaddr_in6))
503 return EINVAL;
504 break;
505 #endif
506 default:
507 return EAFNOSUPPORT;
508 }
509
510 return 0;
511 }
512
513 /*
514 * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
515 * length of mask (sm and dm) is assumed to be same as sp/dp.
516 * Return value will be necessary as input (cookie) for encap_detach().
517 */
518 const struct encaptab *
519 encap_attach(af, proto, sp, sm, dp, dm, psw, arg)
520 int af;
521 int proto;
522 const struct sockaddr *sp, *sm;
523 const struct sockaddr *dp, *dm;
524 const struct protosw *psw;
525 void *arg;
526 {
527 struct encaptab *ep;
528 int error;
529 int s;
530 size_t l;
531 struct pack4 *pack4;
532 #ifdef INET6
533 struct pack6 *pack6;
534 #endif
535
536 s = splsoftnet();
537 /* sanity check on args */
538 error = encap_afcheck(af, sp, dp);
539 if (error)
540 goto fail;
541
542 /* check if anyone have already attached with exactly same config */
543 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
544 if (ep->af != af)
545 continue;
546 if (ep->proto != proto)
547 continue;
548 if (ep->func)
549 continue;
550 #ifdef DIAGNOSTIC
551 if (!ep->src || !ep->dst || !ep->srcmask || !ep->dstmask)
552 panic("null pointers in encaptab");
553 #endif
554 if (ep->src->sa_len != sp->sa_len ||
555 bcmp(ep->src, sp, sp->sa_len) != 0 ||
556 bcmp(ep->srcmask, sm, sp->sa_len) != 0)
557 continue;
558 if (ep->dst->sa_len != dp->sa_len ||
559 bcmp(ep->dst, dp, dp->sa_len) != 0 ||
560 bcmp(ep->dstmask, dm, dp->sa_len) != 0)
561 continue;
562
563 error = EEXIST;
564 goto fail;
565 }
566
567 switch (af) {
568 case AF_INET:
569 l = sizeof(*pack4);
570 break;
571 #ifdef INET6
572 case AF_INET6:
573 l = sizeof(*pack6);
574 break;
575 #endif
576 default:
577 goto fail;
578 }
579
580 #ifdef DIAGNOSTIC
581 /* if l exceeds the value sa_len can possibly express, it's wrong. */
582 if (l > (1 << (8 * sizeof(ep->addrpack->sa_len)))) {
583 error = EINVAL;
584 goto fail;
585 }
586 #endif
587
588 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /* M_NETADDR ok? */
589 if (ep == NULL) {
590 error = ENOBUFS;
591 goto fail;
592 }
593 bzero(ep, sizeof(*ep));
594 ep->addrpack = malloc(l, M_NETADDR, M_NOWAIT);
595 if (ep->addrpack == NULL) {
596 error = ENOBUFS;
597 goto gc;
598 }
599 ep->maskpack = malloc(l, M_NETADDR, M_NOWAIT);
600 if (ep->maskpack == NULL) {
601 error = ENOBUFS;
602 goto gc;
603 }
604
605 ep->af = af;
606 ep->proto = proto;
607 ep->addrpack->sa_len = l & 0xff;
608 ep->maskpack->sa_len = l & 0xff;
609 switch (af) {
610 case AF_INET:
611 pack4 = (struct pack4 *)ep->addrpack;
612 ep->src = (struct sockaddr *)&pack4->mine;
613 ep->dst = (struct sockaddr *)&pack4->yours;
614 pack4 = (struct pack4 *)ep->maskpack;
615 ep->srcmask = (struct sockaddr *)&pack4->mine;
616 ep->dstmask = (struct sockaddr *)&pack4->yours;
617 break;
618 #ifdef INET6
619 case AF_INET6:
620 pack6 = (struct pack6 *)ep->addrpack;
621 ep->src = (struct sockaddr *)&pack6->mine;
622 ep->dst = (struct sockaddr *)&pack6->yours;
623 pack6 = (struct pack6 *)ep->maskpack;
624 ep->srcmask = (struct sockaddr *)&pack6->mine;
625 ep->dstmask = (struct sockaddr *)&pack6->yours;
626 break;
627 #endif
628 }
629
630 bcopy(sp, ep->src, sp->sa_len);
631 bcopy(sm, ep->srcmask, sp->sa_len);
632 bcopy(dp, ep->dst, dp->sa_len);
633 bcopy(dm, ep->dstmask, dp->sa_len);
634 ep->psw = psw;
635 ep->arg = arg;
636
637 error = encap_add(ep);
638 if (error)
639 goto gc;
640
641 error = 0;
642 splx(s);
643 return ep;
644
645 gc:
646 if (ep->addrpack)
647 free(ep->addrpack, M_NETADDR);
648 if (ep->maskpack)
649 free(ep->maskpack, M_NETADDR);
650 if (ep)
651 free(ep, M_NETADDR);
652 fail:
653 splx(s);
654 return NULL;
655 }
656
657 const struct encaptab *
658 encap_attach_func(af, proto, func, psw, arg)
659 int af;
660 int proto;
661 int (*func) __P((const struct mbuf *, int, int, void *));
662 const struct protosw *psw;
663 void *arg;
664 {
665 struct encaptab *ep;
666 int error;
667 int s;
668
669 s = splsoftnet();
670 /* sanity check on args */
671 if (!func) {
672 error = EINVAL;
673 goto fail;
674 }
675
676 error = encap_afcheck(af, NULL, NULL);
677 if (error)
678 goto fail;
679
680 ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
681 if (ep == NULL) {
682 error = ENOBUFS;
683 goto fail;
684 }
685 bzero(ep, sizeof(*ep));
686
687 ep->af = af;
688 ep->proto = proto;
689 ep->func = func;
690 ep->psw = psw;
691 ep->arg = arg;
692
693 error = encap_add(ep);
694 if (error)
695 goto fail;
696
697 error = 0;
698 splx(s);
699 return ep;
700
701 fail:
702 splx(s);
703 return NULL;
704 }
705
706 /* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */
707
708 #ifdef INET6
709 void
710 encap6_ctlinput(cmd, sa, d0)
711 int cmd;
712 struct sockaddr *sa;
713 void *d0;
714 {
715 void *d = d0;
716 struct ip6_hdr *ip6;
717 struct mbuf *m;
718 int off;
719 struct ip6ctlparam *ip6cp = NULL;
720 int nxt;
721 struct encaptab *ep;
722 const struct ip6protosw *psw;
723
724 if (sa->sa_family != AF_INET6 ||
725 sa->sa_len != sizeof(struct sockaddr_in6))
726 return;
727
728 if ((unsigned)cmd >= PRC_NCMDS)
729 return;
730 if (cmd == PRC_HOSTDEAD)
731 d = NULL;
732 else if (cmd == PRC_MSGSIZE)
733 ; /* special code is present, see below */
734 else if (inet6ctlerrmap[cmd] == 0)
735 return;
736
737 /* if the parameter is from icmp6, decode it. */
738 if (d != NULL) {
739 ip6cp = (struct ip6ctlparam *)d;
740 m = ip6cp->ip6c_m;
741 ip6 = ip6cp->ip6c_ip6;
742 off = ip6cp->ip6c_off;
743 nxt = ip6cp->ip6c_nxt;
744
745 if (ip6 && cmd == PRC_MSGSIZE) {
746 int valid = 0;
747 struct encaptab *match;
748
749 /*
750 * Check to see if we have a valid encap configuration.
751 */
752 match = encap6_lookup(m, off, nxt, OUTBOUND);
753 if (match)
754 valid++;
755
756 /*
757 * Depending on the value of "valid" and routing table
758 * size (mtudisc_{hi,lo}wat), we will:
759 * - recalcurate the new MTU and create the
760 * corresponding routing entry, or
761 * - ignore the MTU change notification.
762 */
763 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
764 }
765 } else {
766 m = NULL;
767 ip6 = NULL;
768 nxt = -1;
769 }
770
771 /* inform all listeners */
772 for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
773 if (ep->af != AF_INET6)
774 continue;
775 if (ep->proto >= 0 && ep->proto != nxt)
776 continue;
777
778 /* should optimize by looking at address pairs */
779
780 /* XXX need to pass ep->arg or ep itself to listeners */
781 psw = (const struct ip6protosw *)ep->psw;
782 if (psw && psw->pr_ctlinput)
783 (*psw->pr_ctlinput)(cmd, sa, d);
784 }
785
786 rip6_ctlinput(cmd, sa, d0);
787 }
788 #endif
789
790 int
791 encap_detach(cookie)
792 const struct encaptab *cookie;
793 {
794 const struct encaptab *ep = cookie;
795 struct encaptab *p;
796 int error;
797
798 for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
799 if (p == ep) {
800 error = encap_remove(p);
801 if (error)
802 return error;
803 if (!ep->func) {
804 free(p->addrpack, M_NETADDR);
805 free(p->maskpack, M_NETADDR);
806 }
807 free(p, M_NETADDR); /*XXX*/
808 return 0;
809 }
810 }
811
812 return ENOENT;
813 }
814
815 #ifdef USE_RADIX
816 static struct radix_node_head *
817 encap_rnh(af)
818 int af;
819 {
820
821 switch (af) {
822 case AF_INET:
823 return encap_head[0];
824 #ifdef INET6
825 case AF_INET6:
826 return encap_head[1];
827 #endif
828 default:
829 return NULL;
830 }
831 }
832
833 static int
834 mask_matchlen(sa)
835 const struct sockaddr *sa;
836 {
837 const char *p, *ep;
838 int l;
839
840 p = (const char *)sa;
841 ep = p + sa->sa_len;
842 p += 2; /* sa_len + sa_family */
843
844 l = 0;
845 while (p < ep) {
846 l += (*p ? 8 : 0); /* estimate */
847 p++;
848 }
849 return l;
850 }
851 #endif
852
853 #ifndef USE_RADIX
854 static int
855 mask_match(ep, sp, dp)
856 const struct encaptab *ep;
857 const struct sockaddr *sp;
858 const struct sockaddr *dp;
859 {
860 struct sockaddr_storage s;
861 struct sockaddr_storage d;
862 int i;
863 const u_int8_t *p, *q;
864 u_int8_t *r;
865 int matchlen;
866
867 #ifdef DIAGNOSTIC
868 if (ep->func)
869 panic("wrong encaptab passed to mask_match");
870 #endif
871 if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
872 return 0;
873 if (sp->sa_family != ep->af || dp->sa_family != ep->af)
874 return 0;
875 if (sp->sa_len != ep->src->sa_len || dp->sa_len != ep->dst->sa_len)
876 return 0;
877
878 matchlen = 0;
879
880 p = (const u_int8_t *)sp;
881 q = (const u_int8_t *)ep->srcmask;
882 r = (u_int8_t *)&s;
883 for (i = 0 ; i < sp->sa_len; i++) {
884 r[i] = p[i] & q[i];
885 /* XXX estimate */
886 matchlen += (q[i] ? 8 : 0);
887 }
888
889 p = (const u_int8_t *)dp;
890 q = (const u_int8_t *)ep->dstmask;
891 r = (u_int8_t *)&d;
892 for (i = 0 ; i < dp->sa_len; i++) {
893 r[i] = p[i] & q[i];
894 /* XXX rough estimate */
895 matchlen += (q[i] ? 8 : 0);
896 }
897
898 /* need to overwrite len/family portion as we don't compare them */
899 s.ss_len = sp->sa_len;
900 s.ss_family = sp->sa_family;
901 d.ss_len = dp->sa_len;
902 d.ss_family = dp->sa_family;
903
904 if (bcmp(&s, ep->src, ep->src->sa_len) == 0 &&
905 bcmp(&d, ep->dst, ep->dst->sa_len) == 0) {
906 return matchlen;
907 } else
908 return 0;
909 }
910 #endif
911
912 static void
913 encap_fillarg(m, ep)
914 struct mbuf *m;
915 const struct encaptab *ep;
916 {
917 struct m_tag *mtag;
918
919 mtag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT);
920 if (mtag) {
921 *(void **)(mtag + 1) = ep->arg;
922 m_tag_prepend(m, mtag);
923 }
924 }
925
926 void *
927 encap_getarg(m)
928 struct mbuf *m;
929 {
930 void *p;
931 struct m_tag *mtag;
932
933 p = NULL;
934 mtag = m_tag_find(m, PACKET_TAG_ENCAP, NULL);
935 if (mtag != NULL) {
936 p = *(void **)(mtag + 1);
937 m_tag_delete(m, mtag);
938 }
939 return p;
940 }
941