ip_encap.c revision 1.51 1 /* $NetBSD: ip_encap.c,v 1.51 2016/01/26 05:58:05 knakahara 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
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: ip_encap.c,v 1.51 2016/01/26 05:58:05 knakahara Exp $");
71
72 #ifdef _KERNEL_OPT
73 #include "opt_mrouting.h"
74 #include "opt_inet.h"
75 #endif
76
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/socket.h>
80 #include <sys/sockio.h>
81 #include <sys/mbuf.h>
82 #include <sys/errno.h>
83 #include <sys/queue.h>
84 #include <sys/kmem.h>
85
86 #include <net/if.h>
87 #include <net/route.h>
88
89 #include <netinet/in.h>
90 #include <netinet/in_systm.h>
91 #include <netinet/ip.h>
92 #include <netinet/ip_var.h>
93 #include <netinet/ip_encap.h>
94 #ifdef MROUTING
95 #include <netinet/ip_mroute.h>
96 #endif /* MROUTING */
97
98 #ifdef INET6
99 #include <netinet/ip6.h>
100 #include <netinet6/ip6_var.h>
101 #include <netinet6/ip6protosw.h> /* for struct ip6ctlparam */
102 #include <netinet6/in6_var.h>
103 #include <netinet6/in6_pcb.h>
104 #include <netinet/icmp6.h>
105 #endif
106
107 #include <net/net_osdep.h>
108
109 enum direction { INBOUND, OUTBOUND };
110
111 #ifdef INET
112 static struct encaptab *encap4_lookup(struct mbuf *, int, int, enum direction);
113 #endif
114 #ifdef INET6
115 static struct encaptab *encap6_lookup(struct mbuf *, int, int, enum direction);
116 #endif
117 static int encap_add(struct encaptab *);
118 static int encap_remove(struct encaptab *);
119 static int encap_afcheck(int, const struct sockaddr *, const struct sockaddr *);
120 static struct radix_node_head *encap_rnh(int);
121 static int mask_matchlen(const struct sockaddr *);
122 static void encap_fillarg(struct mbuf *, const struct encaptab *);
123
124 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
125
126 struct radix_node_head *encap_head[2]; /* 0 for AF_INET, 1 for AF_INET6 */
127
128 void
129 encap_init(void)
130 {
131 static int initialized = 0;
132
133 if (initialized)
134 return;
135 initialized++;
136 #if 0
137 /*
138 * we cannot use LIST_INIT() here, since drivers may want to call
139 * encap_attach(), on driver attach. encap_init() will be called
140 * on AF_INET{,6} initialization, which happens after driver
141 * initialization - using LIST_INIT() here can nuke encap_attach()
142 * from drivers.
143 */
144 LIST_INIT(&encaptab);
145 #endif
146
147 /*
148 * initialize radix lookup table when the radix subsystem is inited.
149 */
150 rn_delayedinit((void *)&encap_head[0],
151 sizeof(struct sockaddr_pack) << 3);
152 #ifdef INET6
153 rn_delayedinit((void *)&encap_head[1],
154 sizeof(struct sockaddr_pack) << 3);
155 #endif
156 }
157
158 #ifdef INET
159 static struct encaptab *
160 encap4_lookup(struct mbuf *m, int off, int proto, enum direction dir)
161 {
162 struct ip *ip;
163 struct ip_pack4 pack;
164 struct encaptab *ep, *match;
165 int prio, matchprio;
166 struct radix_node_head *rnh = encap_rnh(AF_INET);
167 struct radix_node *rn;
168
169 KASSERT(m->m_len >= sizeof(*ip));
170
171 ip = mtod(m, struct ip *);
172
173 memset(&pack, 0, sizeof(pack));
174 pack.p.sp_len = sizeof(pack);
175 pack.mine.sin_family = pack.yours.sin_family = AF_INET;
176 pack.mine.sin_len = pack.yours.sin_len = sizeof(struct sockaddr_in);
177 if (dir == INBOUND) {
178 pack.mine.sin_addr = ip->ip_dst;
179 pack.yours.sin_addr = ip->ip_src;
180 } else {
181 pack.mine.sin_addr = ip->ip_src;
182 pack.yours.sin_addr = ip->ip_dst;
183 }
184
185 match = NULL;
186 matchprio = 0;
187
188 rn = rnh->rnh_matchaddr((void *)&pack, rnh);
189 if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
190 match = (struct encaptab *)rn;
191 matchprio = mask_matchlen(match->srcmask) +
192 mask_matchlen(match->dstmask);
193 }
194
195 LIST_FOREACH(ep, &encaptab, chain) {
196 if (ep->af != AF_INET)
197 continue;
198 if (ep->proto >= 0 && ep->proto != proto)
199 continue;
200 if (ep->func)
201 prio = (*ep->func)(m, off, proto, ep->arg);
202 else
203 continue;
204
205 /*
206 * We prioritize the matches by using bit length of the
207 * matches. mask_match() and user-supplied matching function
208 * should return the bit length of the matches (for example,
209 * if both src/dst are matched for IPv4, 64 should be returned).
210 * 0 or negative return value means "it did not match".
211 *
212 * The question is, since we have two "mask" portion, we
213 * cannot really define total order between entries.
214 * For example, which of these should be preferred?
215 * mask_match() returns 48 (32 + 16) for both of them.
216 * src=3ffe::/16, dst=3ffe:501::/32
217 * src=3ffe:501::/32, dst=3ffe::/16
218 *
219 * We need to loop through all the possible candidates
220 * to get the best match - the search takes O(n) for
221 * n attachments (i.e. interfaces).
222 *
223 * For radix-based lookup, I guess source takes precedence.
224 * See rn_{refines,lexobetter} for the correct answer.
225 */
226 if (prio <= 0)
227 continue;
228 if (prio > matchprio) {
229 matchprio = prio;
230 match = ep;
231 }
232 }
233
234 return match;
235 }
236
237 void
238 encap4_input(struct mbuf *m, ...)
239 {
240 int off, proto;
241 va_list ap;
242 const struct encapsw *esw;
243 struct encaptab *match;
244
245 va_start(ap, m);
246 off = va_arg(ap, int);
247 proto = va_arg(ap, int);
248 va_end(ap);
249
250 match = encap4_lookup(m, off, proto, INBOUND);
251
252 if (match) {
253 /* found a match, "match" has the best one */
254 esw = match->esw;
255 if (esw && esw->encapsw4.pr_input) {
256 encap_fillarg(m, match);
257 (*esw->encapsw4.pr_input)(m, off, proto);
258 } else
259 m_freem(m);
260 return;
261 }
262
263 /* last resort: inject to raw socket */
264 rip_input(m, off, proto);
265 }
266 #endif
267
268 #ifdef INET6
269 static struct encaptab *
270 encap6_lookup(struct mbuf *m, int off, int proto, enum direction dir)
271 {
272 struct ip6_hdr *ip6;
273 struct ip_pack6 pack;
274 int prio, matchprio;
275 struct encaptab *ep, *match;
276 struct radix_node_head *rnh = encap_rnh(AF_INET6);
277 struct radix_node *rn;
278
279 KASSERT(m->m_len >= sizeof(*ip6));
280
281 ip6 = mtod(m, struct ip6_hdr *);
282
283 memset(&pack, 0, sizeof(pack));
284 pack.p.sp_len = sizeof(pack);
285 pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6;
286 pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6);
287 if (dir == INBOUND) {
288 pack.mine.sin6_addr = ip6->ip6_dst;
289 pack.yours.sin6_addr = ip6->ip6_src;
290 } else {
291 pack.mine.sin6_addr = ip6->ip6_src;
292 pack.yours.sin6_addr = ip6->ip6_dst;
293 }
294
295 match = NULL;
296 matchprio = 0;
297
298 rn = rnh->rnh_matchaddr((void *)&pack, rnh);
299 if (rn && (rn->rn_flags & RNF_ROOT) == 0) {
300 match = (struct encaptab *)rn;
301 matchprio = mask_matchlen(match->srcmask) +
302 mask_matchlen(match->dstmask);
303 }
304
305 LIST_FOREACH(ep, &encaptab, chain) {
306 if (ep->af != AF_INET6)
307 continue;
308 if (ep->proto >= 0 && ep->proto != proto)
309 continue;
310 if (ep->func)
311 prio = (*ep->func)(m, off, proto, ep->arg);
312 else
313 continue;
314
315 /* see encap4_lookup() for issues here */
316 if (prio <= 0)
317 continue;
318 if (prio > matchprio) {
319 matchprio = prio;
320 match = ep;
321 }
322 }
323
324 return match;
325 }
326
327 int
328 encap6_input(struct mbuf **mp, int *offp, int proto)
329 {
330 struct mbuf *m = *mp;
331 const struct encapsw *esw;
332 struct encaptab *match;
333
334 match = encap6_lookup(m, *offp, proto, INBOUND);
335
336 if (match) {
337 /* found a match */
338 esw = match->esw;
339 if (esw && esw->encapsw6.pr_input) {
340 encap_fillarg(m, match);
341 return (*esw->encapsw6.pr_input)(mp, offp, proto);
342 } else {
343 m_freem(m);
344 return IPPROTO_DONE;
345 }
346 }
347
348 /* last resort: inject to raw socket */
349 return rip6_input(mp, offp, proto);
350 }
351 #endif
352
353 static int
354 encap_add(struct encaptab *ep)
355 {
356 struct radix_node_head *rnh = encap_rnh(ep->af);
357 int error = 0;
358
359 LIST_INSERT_HEAD(&encaptab, ep, chain);
360 if (!ep->func && rnh) {
361 if (!rnh->rnh_addaddr((void *)ep->addrpack,
362 (void *)ep->maskpack, rnh, ep->nodes)) {
363 error = EEXIST;
364 goto fail;
365 }
366 }
367 return error;
368
369 fail:
370 LIST_REMOVE(ep, chain);
371 return error;
372 }
373
374 static int
375 encap_remove(struct encaptab *ep)
376 {
377 struct radix_node_head *rnh = encap_rnh(ep->af);
378 int error = 0;
379
380 LIST_REMOVE(ep, chain);
381 if (!ep->func && rnh) {
382 if (!rnh->rnh_deladdr((void *)ep->addrpack,
383 (void *)ep->maskpack, rnh))
384 error = ESRCH;
385 }
386 return error;
387 }
388
389 static int
390 encap_afcheck(int af, const struct sockaddr *sp, const struct sockaddr *dp)
391 {
392 if (sp && dp) {
393 if (sp->sa_len != dp->sa_len)
394 return EINVAL;
395 if (af != sp->sa_family || af != dp->sa_family)
396 return EINVAL;
397 } else if (!sp && !dp)
398 ;
399 else
400 return EINVAL;
401
402 switch (af) {
403 case AF_INET:
404 if (sp && sp->sa_len != sizeof(struct sockaddr_in))
405 return EINVAL;
406 if (dp && dp->sa_len != sizeof(struct sockaddr_in))
407 return EINVAL;
408 break;
409 #ifdef INET6
410 case AF_INET6:
411 if (sp && sp->sa_len != sizeof(struct sockaddr_in6))
412 return EINVAL;
413 if (dp && dp->sa_len != sizeof(struct sockaddr_in6))
414 return EINVAL;
415 break;
416 #endif
417 default:
418 return EAFNOSUPPORT;
419 }
420
421 return 0;
422 }
423
424 /*
425 * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
426 * length of mask (sm and dm) is assumed to be same as sp/dp.
427 * Return value will be necessary as input (cookie) for encap_detach().
428 */
429 const struct encaptab *
430 encap_attach(int af, int proto,
431 const struct sockaddr *sp, const struct sockaddr *sm,
432 const struct sockaddr *dp, const struct sockaddr *dm,
433 const struct encapsw *esw, void *arg)
434 {
435 struct encaptab *ep;
436 int error;
437 int s;
438 size_t l;
439 struct ip_pack4 *pack4;
440 #ifdef INET6
441 struct ip_pack6 *pack6;
442 #endif
443
444 s = splsoftnet();
445 /* sanity check on args */
446 error = encap_afcheck(af, sp, dp);
447 if (error)
448 goto fail;
449
450 /* check if anyone have already attached with exactly same config */
451 LIST_FOREACH(ep, &encaptab, chain) {
452 if (ep->af != af)
453 continue;
454 if (ep->proto != proto)
455 continue;
456 if (ep->func)
457 continue;
458
459 KASSERT(ep->src != NULL);
460 KASSERT(ep->dst != NULL);
461 KASSERT(ep->srcmask != NULL);
462 KASSERT(ep->dstmask != NULL);
463
464 if (ep->src->sa_len != sp->sa_len ||
465 memcmp(ep->src, sp, sp->sa_len) != 0 ||
466 memcmp(ep->srcmask, sm, sp->sa_len) != 0)
467 continue;
468 if (ep->dst->sa_len != dp->sa_len ||
469 memcmp(ep->dst, dp, dp->sa_len) != 0 ||
470 memcmp(ep->dstmask, dm, dp->sa_len) != 0)
471 continue;
472
473 error = EEXIST;
474 goto fail;
475 }
476
477 switch (af) {
478 case AF_INET:
479 l = sizeof(*pack4);
480 break;
481 #ifdef INET6
482 case AF_INET6:
483 l = sizeof(*pack6);
484 break;
485 #endif
486 default:
487 goto fail;
488 }
489
490 /* M_NETADDR ok? */
491 ep = kmem_zalloc(sizeof(*ep), KM_NOSLEEP);
492 if (ep == NULL) {
493 error = ENOBUFS;
494 goto fail;
495 }
496 ep->addrpack = kmem_zalloc(l, KM_NOSLEEP);
497 if (ep->addrpack == NULL) {
498 error = ENOBUFS;
499 goto gc;
500 }
501 ep->maskpack = kmem_zalloc(l, KM_NOSLEEP);
502 if (ep->maskpack == NULL) {
503 error = ENOBUFS;
504 goto gc;
505 }
506
507 ep->af = af;
508 ep->proto = proto;
509 ep->addrpack->sa_len = l & 0xff;
510 ep->maskpack->sa_len = l & 0xff;
511 switch (af) {
512 case AF_INET:
513 pack4 = (struct ip_pack4 *)ep->addrpack;
514 ep->src = (struct sockaddr *)&pack4->mine;
515 ep->dst = (struct sockaddr *)&pack4->yours;
516 pack4 = (struct ip_pack4 *)ep->maskpack;
517 ep->srcmask = (struct sockaddr *)&pack4->mine;
518 ep->dstmask = (struct sockaddr *)&pack4->yours;
519 break;
520 #ifdef INET6
521 case AF_INET6:
522 pack6 = (struct ip_pack6 *)ep->addrpack;
523 ep->src = (struct sockaddr *)&pack6->mine;
524 ep->dst = (struct sockaddr *)&pack6->yours;
525 pack6 = (struct ip_pack6 *)ep->maskpack;
526 ep->srcmask = (struct sockaddr *)&pack6->mine;
527 ep->dstmask = (struct sockaddr *)&pack6->yours;
528 break;
529 #endif
530 }
531
532 memcpy(ep->src, sp, sp->sa_len);
533 memcpy(ep->srcmask, sm, sp->sa_len);
534 memcpy(ep->dst, dp, dp->sa_len);
535 memcpy(ep->dstmask, dm, dp->sa_len);
536 ep->esw = esw;
537 ep->arg = arg;
538
539 error = encap_add(ep);
540 if (error)
541 goto gc;
542
543 error = 0;
544 splx(s);
545 return ep;
546
547 gc:
548 if (ep->addrpack)
549 kmem_free(ep->addrpack, l);
550 if (ep->maskpack)
551 kmem_free(ep->maskpack, l);
552 if (ep)
553 kmem_free(ep, sizeof(*ep));
554 fail:
555 splx(s);
556 return NULL;
557 }
558
559 const struct encaptab *
560 encap_attach_func(int af, int proto,
561 int (*func)(struct mbuf *, int, int, void *),
562 const struct encapsw *esw, void *arg)
563 {
564 struct encaptab *ep;
565 int error;
566 int s;
567
568 s = splsoftnet();
569 /* sanity check on args */
570 if (!func) {
571 error = EINVAL;
572 goto fail;
573 }
574
575 error = encap_afcheck(af, NULL, NULL);
576 if (error)
577 goto fail;
578
579 ep = kmem_alloc(sizeof(*ep), KM_NOSLEEP); /*XXX*/
580 if (ep == NULL) {
581 error = ENOBUFS;
582 goto fail;
583 }
584 memset(ep, 0, sizeof(*ep));
585
586 ep->af = af;
587 ep->proto = proto;
588 ep->func = func;
589 ep->esw = esw;
590 ep->arg = arg;
591
592 error = encap_add(ep);
593 if (error)
594 goto fail;
595
596 error = 0;
597 splx(s);
598 return ep;
599
600 fail:
601 splx(s);
602 return NULL;
603 }
604
605 /* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */
606
607 #ifdef INET6
608 void *
609 encap6_ctlinput(int cmd, const struct sockaddr *sa, void *d0)
610 {
611 void *d = d0;
612 struct ip6_hdr *ip6;
613 struct mbuf *m;
614 int off;
615 struct ip6ctlparam *ip6cp = NULL;
616 int nxt;
617 struct encaptab *ep;
618 const struct encapsw *esw;
619
620 if (sa->sa_family != AF_INET6 ||
621 sa->sa_len != sizeof(struct sockaddr_in6))
622 return NULL;
623
624 if ((unsigned)cmd >= PRC_NCMDS)
625 return NULL;
626 if (cmd == PRC_HOSTDEAD)
627 d = NULL;
628 else if (cmd == PRC_MSGSIZE)
629 ; /* special code is present, see below */
630 else if (inet6ctlerrmap[cmd] == 0)
631 return NULL;
632
633 /* if the parameter is from icmp6, decode it. */
634 if (d != NULL) {
635 ip6cp = (struct ip6ctlparam *)d;
636 m = ip6cp->ip6c_m;
637 ip6 = ip6cp->ip6c_ip6;
638 off = ip6cp->ip6c_off;
639 nxt = ip6cp->ip6c_nxt;
640
641 if (ip6 && cmd == PRC_MSGSIZE) {
642 int valid = 0;
643 struct encaptab *match;
644
645 /*
646 * Check to see if we have a valid encap configuration.
647 */
648 match = encap6_lookup(m, off, nxt, OUTBOUND);
649 if (match)
650 valid++;
651
652 /*
653 * Depending on the value of "valid" and routing table
654 * size (mtudisc_{hi,lo}wat), we will:
655 * - recalcurate the new MTU and create the
656 * corresponding routing entry, or
657 * - ignore the MTU change notification.
658 */
659 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
660 }
661 } else {
662 m = NULL;
663 ip6 = NULL;
664 nxt = -1;
665 }
666
667 /* inform all listeners */
668 LIST_FOREACH(ep, &encaptab, chain) {
669 if (ep->af != AF_INET6)
670 continue;
671 if (ep->proto >= 0 && ep->proto != nxt)
672 continue;
673
674 /* should optimize by looking at address pairs */
675
676 /* XXX need to pass ep->arg or ep itself to listeners */
677 esw = ep->esw;
678 if (esw && esw->encapsw6.pr_ctlinput) {
679 (*esw->encapsw6.pr_ctlinput)(cmd, sa, d);
680 }
681 }
682
683 rip6_ctlinput(cmd, sa, d0);
684 return NULL;
685 }
686 #endif
687
688 int
689 encap_detach(const struct encaptab *cookie)
690 {
691 const struct encaptab *ep = cookie;
692 struct encaptab *p, *np;
693 int error;
694
695 LIST_FOREACH_SAFE(p, &encaptab, chain, np) {
696 if (p == ep) {
697 error = encap_remove(p);
698 if (error)
699 return error;
700 if (!ep->func) {
701 kmem_free(p->addrpack, ep->addrpack->sa_len);
702 kmem_free(p->maskpack, ep->maskpack->sa_len);
703 }
704 kmem_free(p, sizeof(*p)); /*XXX*/
705 return 0;
706 }
707 }
708
709 return ENOENT;
710 }
711
712 static struct radix_node_head *
713 encap_rnh(int af)
714 {
715
716 switch (af) {
717 case AF_INET:
718 return encap_head[0];
719 #ifdef INET6
720 case AF_INET6:
721 return encap_head[1];
722 #endif
723 default:
724 return NULL;
725 }
726 }
727
728 static int
729 mask_matchlen(const struct sockaddr *sa)
730 {
731 const char *p, *ep;
732 int l;
733
734 p = (const char *)sa;
735 ep = p + sa->sa_len;
736 p += 2; /* sa_len + sa_family */
737
738 l = 0;
739 while (p < ep) {
740 l += (*p ? 8 : 0); /* estimate */
741 p++;
742 }
743 return l;
744 }
745
746 static void
747 encap_fillarg(struct mbuf *m, const struct encaptab *ep)
748 {
749 struct m_tag *mtag;
750
751 mtag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT);
752 if (mtag) {
753 *(void **)(mtag + 1) = ep->arg;
754 m_tag_prepend(m, mtag);
755 }
756 }
757
758 void *
759 encap_getarg(struct mbuf *m)
760 {
761 void *p;
762 struct m_tag *mtag;
763
764 p = NULL;
765 mtag = m_tag_find(m, PACKET_TAG_ENCAP, NULL);
766 if (mtag != NULL) {
767 p = *(void **)(mtag + 1);
768 m_tag_delete(m, mtag);
769 }
770 return p;
771 }
772