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