xref: /netbsd-src/sys/netinet/ip_encap.c (revision a24efa7dea9f1f56c3bdb15a927d3516792ace1c)
1 /*	$NetBSD: ip_encap.c,v 1.53 2016/04/26 08:44:44 ozaki-r 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.53 2016/04/26 08:44:44 ozaki-r 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