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