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