xref: /xnu-11215.41.3/bsd/netinet/ip_encap.c (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1*33de042dSApple OSS Distributions /*
2*33de042dSApple OSS Distributions  * Copyright (c) 2000-2024 Apple Inc. All rights reserved.
3*33de042dSApple OSS Distributions  *
4*33de042dSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*33de042dSApple OSS Distributions  *
6*33de042dSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*33de042dSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*33de042dSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*33de042dSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*33de042dSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*33de042dSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*33de042dSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*33de042dSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*33de042dSApple OSS Distributions  *
15*33de042dSApple OSS Distributions  * Please obtain a copy of the License at
16*33de042dSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*33de042dSApple OSS Distributions  *
18*33de042dSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*33de042dSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*33de042dSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*33de042dSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*33de042dSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*33de042dSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*33de042dSApple OSS Distributions  * limitations under the License.
25*33de042dSApple OSS Distributions  *
26*33de042dSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*33de042dSApple OSS Distributions  */
28*33de042dSApple OSS Distributions /*	$FreeBSD: src/sys/netinet/ip_encap.c,v 1.1.2.2 2001/07/03 11:01:46 ume Exp $	*/
29*33de042dSApple OSS Distributions /*	$KAME: ip_encap.c,v 1.41 2001/03/15 08:35:08 itojun Exp $	*/
30*33de042dSApple OSS Distributions 
31*33de042dSApple OSS Distributions /*
32*33de042dSApple OSS Distributions  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
33*33de042dSApple OSS Distributions  * All rights reserved.
34*33de042dSApple OSS Distributions  *
35*33de042dSApple OSS Distributions  * Redistribution and use in source and binary forms, with or without
36*33de042dSApple OSS Distributions  * modification, are permitted provided that the following conditions
37*33de042dSApple OSS Distributions  * are met:
38*33de042dSApple OSS Distributions  * 1. Redistributions of source code must retain the above copyright
39*33de042dSApple OSS Distributions  *    notice, this list of conditions and the following disclaimer.
40*33de042dSApple OSS Distributions  * 2. Redistributions in binary form must reproduce the above copyright
41*33de042dSApple OSS Distributions  *    notice, this list of conditions and the following disclaimer in the
42*33de042dSApple OSS Distributions  *    documentation and/or other materials provided with the distribution.
43*33de042dSApple OSS Distributions  * 3. Neither the name of the project nor the names of its contributors
44*33de042dSApple OSS Distributions  *    may be used to endorse or promote products derived from this software
45*33de042dSApple OSS Distributions  *    without specific prior written permission.
46*33de042dSApple OSS Distributions  *
47*33de042dSApple OSS Distributions  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
48*33de042dSApple OSS Distributions  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49*33de042dSApple OSS Distributions  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50*33de042dSApple OSS Distributions  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
51*33de042dSApple OSS Distributions  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52*33de042dSApple OSS Distributions  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53*33de042dSApple OSS Distributions  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54*33de042dSApple OSS Distributions  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55*33de042dSApple OSS Distributions  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56*33de042dSApple OSS Distributions  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57*33de042dSApple OSS Distributions  * SUCH DAMAGE.
58*33de042dSApple OSS Distributions  */
59*33de042dSApple OSS Distributions /*
60*33de042dSApple OSS Distributions  * My grandfather said that there's a devil inside tunnelling technology...
61*33de042dSApple OSS Distributions  *
62*33de042dSApple OSS Distributions  * We have surprisingly many protocols that want packets with IP protocol
63*33de042dSApple OSS Distributions  * #4 or #41.  Here's a list of protocols that want protocol #41:
64*33de042dSApple OSS Distributions  *	RFC1933 configured tunnel
65*33de042dSApple OSS Distributions  *	RFC1933 automatic tunnel
66*33de042dSApple OSS Distributions  *	RFC2401 IPsec tunnel
67*33de042dSApple OSS Distributions  *	RFC2473 IPv6 generic packet tunnelling
68*33de042dSApple OSS Distributions  *	RFC2529 6over4 tunnel
69*33de042dSApple OSS Distributions  *	mobile-ip6 (uses RFC2473)
70*33de042dSApple OSS Distributions  *	6to4 tunnel
71*33de042dSApple OSS Distributions  * Here's a list of protocol that want protocol #4:
72*33de042dSApple OSS Distributions  *	RFC1853 IPv4-in-IPv4 tunnelling
73*33de042dSApple OSS Distributions  *	RFC2003 IPv4 encapsulation within IPv4
74*33de042dSApple OSS Distributions  *	RFC2344 reverse tunnelling for mobile-ip4
75*33de042dSApple OSS Distributions  *	RFC2401 IPsec tunnel
76*33de042dSApple OSS Distributions  * Well, what can I say.  They impose different en/decapsulation mechanism
77*33de042dSApple OSS Distributions  * from each other, so they need separate protocol handler.  The only one
78*33de042dSApple OSS Distributions  * we can easily determine by protocol # is IPsec, which always has
79*33de042dSApple OSS Distributions  * AH/ESP header right after outer IP header.
80*33de042dSApple OSS Distributions  *
81*33de042dSApple OSS Distributions  * So, clearly good old protosw does not work for protocol #4 and #41.
82*33de042dSApple OSS Distributions  * The code will let you match protocol via src/dst address pair.
83*33de042dSApple OSS Distributions  */
84*33de042dSApple OSS Distributions /* XXX is M_NETADDR correct? */
85*33de042dSApple OSS Distributions 
86*33de042dSApple OSS Distributions #include <sys/param.h>
87*33de042dSApple OSS Distributions #include <sys/systm.h>
88*33de042dSApple OSS Distributions #include <sys/socket.h>
89*33de042dSApple OSS Distributions #include <sys/sockio.h>
90*33de042dSApple OSS Distributions #include <sys/mbuf.h>
91*33de042dSApple OSS Distributions #include <sys/mcache.h>
92*33de042dSApple OSS Distributions #include <sys/errno.h>
93*33de042dSApple OSS Distributions #include <sys/domain.h>
94*33de042dSApple OSS Distributions #include <sys/protosw.h>
95*33de042dSApple OSS Distributions #include <sys/queue.h>
96*33de042dSApple OSS Distributions 
97*33de042dSApple OSS Distributions #include <net/if.h>
98*33de042dSApple OSS Distributions #include <net/route.h>
99*33de042dSApple OSS Distributions 
100*33de042dSApple OSS Distributions #include <netinet/in.h>
101*33de042dSApple OSS Distributions #include <netinet/in_systm.h>
102*33de042dSApple OSS Distributions #include <netinet/ip.h>
103*33de042dSApple OSS Distributions #include <netinet/ip_var.h>
104*33de042dSApple OSS Distributions #include <netinet/ip_encap.h>
105*33de042dSApple OSS Distributions 
106*33de042dSApple OSS Distributions #include <netinet/ip6.h>
107*33de042dSApple OSS Distributions #include <netinet6/ip6_var.h>
108*33de042dSApple OSS Distributions #include <netinet6/ip6protosw.h>
109*33de042dSApple OSS Distributions 
110*33de042dSApple OSS Distributions #include <net/net_osdep.h>
111*33de042dSApple OSS Distributions #include <net/sockaddr_utils.h>
112*33de042dSApple OSS Distributions 
113*33de042dSApple OSS Distributions #ifndef __APPLE__
114*33de042dSApple OSS Distributions #include <sys/kernel.h>
115*33de042dSApple OSS Distributions #include <sys/malloc.h>
116*33de042dSApple OSS Distributions MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
117*33de042dSApple OSS Distributions #endif
118*33de042dSApple OSS Distributions 
119*33de042dSApple OSS Distributions static void encap_add_locked(struct encaptab *);
120*33de042dSApple OSS Distributions static int mask_match(const struct encaptab *, const struct sockaddr *,
121*33de042dSApple OSS Distributions     const struct sockaddr *);
122*33de042dSApple OSS Distributions static void encap_fillarg(struct mbuf *, void *arg);
123*33de042dSApple OSS Distributions 
124*33de042dSApple OSS Distributions LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
125*33de042dSApple OSS Distributions 
126*33de042dSApple OSS Distributions static LCK_GRP_DECLARE(encaptab_lock_grp, "encaptab lock");
127*33de042dSApple OSS Distributions static LCK_RW_DECLARE(encaptab_lock, &encaptab_lock_grp);
128*33de042dSApple OSS Distributions 
129*33de042dSApple OSS Distributions #if INET
130*33de042dSApple OSS Distributions void
encap4_input(struct mbuf * m,int off)131*33de042dSApple OSS Distributions encap4_input(struct mbuf *m, int off)
132*33de042dSApple OSS Distributions {
133*33de042dSApple OSS Distributions 	int proto;
134*33de042dSApple OSS Distributions 	struct ip *__single ip;
135*33de042dSApple OSS Distributions 	struct sockaddr_in s, d;
136*33de042dSApple OSS Distributions 	const struct protosw *psw;
137*33de042dSApple OSS Distributions 	struct encaptab *__single ep, *__single match;
138*33de042dSApple OSS Distributions 	int prio, matchprio;
139*33de042dSApple OSS Distributions 	void *__single match_arg = NULL;
140*33de042dSApple OSS Distributions 
141*33de042dSApple OSS Distributions #ifndef __APPLE__
142*33de042dSApple OSS Distributions 	va_start(ap, m);
143*33de042dSApple OSS Distributions 	off = va_arg(ap, int);
144*33de042dSApple OSS Distributions 	proto = va_arg(ap, int);
145*33de042dSApple OSS Distributions 	va_end(ap);
146*33de042dSApple OSS Distributions #endif
147*33de042dSApple OSS Distributions 
148*33de042dSApple OSS Distributions 	/* Expect 32-bit aligned data pointer on strict-align platforms */
149*33de042dSApple OSS Distributions 	MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
150*33de042dSApple OSS Distributions 
151*33de042dSApple OSS Distributions 	ip = mtod(m, struct ip *);
152*33de042dSApple OSS Distributions #ifdef __APPLE__
153*33de042dSApple OSS Distributions 	proto = ip->ip_p;
154*33de042dSApple OSS Distributions #endif
155*33de042dSApple OSS Distributions 
156*33de042dSApple OSS Distributions 	SOCKADDR_ZERO(&s, sizeof(s));
157*33de042dSApple OSS Distributions 	s.sin_family = AF_INET;
158*33de042dSApple OSS Distributions 	s.sin_len = sizeof(struct sockaddr_in);
159*33de042dSApple OSS Distributions 	s.sin_addr = ip->ip_src;
160*33de042dSApple OSS Distributions 	SOCKADDR_ZERO(&d, sizeof(d));
161*33de042dSApple OSS Distributions 	d.sin_family = AF_INET;
162*33de042dSApple OSS Distributions 	d.sin_len = sizeof(struct sockaddr_in);
163*33de042dSApple OSS Distributions 	d.sin_addr = ip->ip_dst;
164*33de042dSApple OSS Distributions 
165*33de042dSApple OSS Distributions 	match = NULL;
166*33de042dSApple OSS Distributions 	matchprio = 0;
167*33de042dSApple OSS Distributions 
168*33de042dSApple OSS Distributions 	lck_rw_lock_shared(&encaptab_lock);
169*33de042dSApple OSS Distributions 	for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
170*33de042dSApple OSS Distributions 		if (ep->af != AF_INET) {
171*33de042dSApple OSS Distributions 			continue;
172*33de042dSApple OSS Distributions 		}
173*33de042dSApple OSS Distributions 		if (ep->proto >= 0 && ep->proto != proto) {
174*33de042dSApple OSS Distributions 			continue;
175*33de042dSApple OSS Distributions 		}
176*33de042dSApple OSS Distributions 		if (ep->func) {
177*33de042dSApple OSS Distributions 			prio = (*ep->func)(m, off, proto, ep->arg);
178*33de042dSApple OSS Distributions 		} else {
179*33de042dSApple OSS Distributions 			/*
180*33de042dSApple OSS Distributions 			 * it's inbound traffic, we need to match in reverse
181*33de042dSApple OSS Distributions 			 * order
182*33de042dSApple OSS Distributions 			 */
183*33de042dSApple OSS Distributions 			prio = mask_match(ep, SA(&d), SA(&s));
184*33de042dSApple OSS Distributions 		}
185*33de042dSApple OSS Distributions 
186*33de042dSApple OSS Distributions 		/*
187*33de042dSApple OSS Distributions 		 * We prioritize the matches by using bit length of the
188*33de042dSApple OSS Distributions 		 * matches.  mask_match() and user-supplied matching function
189*33de042dSApple OSS Distributions 		 * should return the bit length of the matches (for example,
190*33de042dSApple OSS Distributions 		 * if both src/dst are matched for IPv4, 64 should be returned).
191*33de042dSApple OSS Distributions 		 * 0 or negative return value means "it did not match".
192*33de042dSApple OSS Distributions 		 *
193*33de042dSApple OSS Distributions 		 * The question is, since we have two "mask" portion, we
194*33de042dSApple OSS Distributions 		 * cannot really define total order between entries.
195*33de042dSApple OSS Distributions 		 * For example, which of these should be preferred?
196*33de042dSApple OSS Distributions 		 * mask_match() returns 48 (32 + 16) for both of them.
197*33de042dSApple OSS Distributions 		 *	src=3ffe::/16, dst=3ffe:501::/32
198*33de042dSApple OSS Distributions 		 *	src=3ffe:501::/32, dst=3ffe::/16
199*33de042dSApple OSS Distributions 		 *
200*33de042dSApple OSS Distributions 		 * We need to loop through all the possible candidates
201*33de042dSApple OSS Distributions 		 * to get the best match - the search takes O(n) for
202*33de042dSApple OSS Distributions 		 * n attachments (i.e. interfaces).
203*33de042dSApple OSS Distributions 		 */
204*33de042dSApple OSS Distributions 		if (prio <= 0) {
205*33de042dSApple OSS Distributions 			continue;
206*33de042dSApple OSS Distributions 		}
207*33de042dSApple OSS Distributions 		if (prio > matchprio) {
208*33de042dSApple OSS Distributions 			matchprio = prio;
209*33de042dSApple OSS Distributions 			match = ep;
210*33de042dSApple OSS Distributions 			psw = (const struct protosw *)match->psw;
211*33de042dSApple OSS Distributions 			match_arg = ep->arg;
212*33de042dSApple OSS Distributions 		}
213*33de042dSApple OSS Distributions 	}
214*33de042dSApple OSS Distributions 	lck_rw_unlock_shared(&encaptab_lock);
215*33de042dSApple OSS Distributions 
216*33de042dSApple OSS Distributions 	if (match) {
217*33de042dSApple OSS Distributions 		/* found a match, "match" has the best one */
218*33de042dSApple OSS Distributions 		if (psw && psw->pr_input) {
219*33de042dSApple OSS Distributions 			encap_fillarg(m, match_arg);
220*33de042dSApple OSS Distributions 			(*psw->pr_input)(m, off);
221*33de042dSApple OSS Distributions 		} else {
222*33de042dSApple OSS Distributions 			m_freem(m);
223*33de042dSApple OSS Distributions 		}
224*33de042dSApple OSS Distributions 		return;
225*33de042dSApple OSS Distributions 	}
226*33de042dSApple OSS Distributions 
227*33de042dSApple OSS Distributions 	/* last resort: inject to raw socket */
228*33de042dSApple OSS Distributions 	rip_input(m, off);
229*33de042dSApple OSS Distributions }
230*33de042dSApple OSS Distributions #endif
231*33de042dSApple OSS Distributions 
232*33de042dSApple OSS Distributions int
encap6_input(struct mbuf ** mp,int * offp,int proto)233*33de042dSApple OSS Distributions encap6_input(struct mbuf **mp, int *offp, int proto)
234*33de042dSApple OSS Distributions {
235*33de042dSApple OSS Distributions 	mbuf_ref_t m = *mp;
236*33de042dSApple OSS Distributions 	struct ip6_hdr *__single ip6;
237*33de042dSApple OSS Distributions 	struct sockaddr_in6 s, d;
238*33de042dSApple OSS Distributions 	const struct ip6protosw *__single psw;
239*33de042dSApple OSS Distributions 	struct encaptab *__single ep, *__single match;
240*33de042dSApple OSS Distributions 	int prio, matchprio;
241*33de042dSApple OSS Distributions 	void *__single match_arg = NULL;
242*33de042dSApple OSS Distributions 
243*33de042dSApple OSS Distributions 	/* Expect 32-bit aligned data pointer on strict-align platforms */
244*33de042dSApple OSS Distributions 	MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
245*33de042dSApple OSS Distributions 
246*33de042dSApple OSS Distributions 	ip6 = mtod(m, struct ip6_hdr *);
247*33de042dSApple OSS Distributions 	SOCKADDR_ZERO(&s, sizeof(s));
248*33de042dSApple OSS Distributions 	s.sin6_family = AF_INET6;
249*33de042dSApple OSS Distributions 	s.sin6_len = sizeof(struct sockaddr_in6);
250*33de042dSApple OSS Distributions 	s.sin6_addr = ip6->ip6_src;
251*33de042dSApple OSS Distributions 	SOCKADDR_ZERO(&d, sizeof(d));
252*33de042dSApple OSS Distributions 	d.sin6_family = AF_INET6;
253*33de042dSApple OSS Distributions 	d.sin6_len = sizeof(struct sockaddr_in6);
254*33de042dSApple OSS Distributions 	d.sin6_addr = ip6->ip6_dst;
255*33de042dSApple OSS Distributions 
256*33de042dSApple OSS Distributions 	match = NULL;
257*33de042dSApple OSS Distributions 	matchprio = 0;
258*33de042dSApple OSS Distributions 
259*33de042dSApple OSS Distributions 	lck_rw_lock_shared(&encaptab_lock);
260*33de042dSApple OSS Distributions 	for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
261*33de042dSApple OSS Distributions 		if (ep->af != AF_INET6) {
262*33de042dSApple OSS Distributions 			continue;
263*33de042dSApple OSS Distributions 		}
264*33de042dSApple OSS Distributions 		if (ep->proto >= 0 && ep->proto != proto) {
265*33de042dSApple OSS Distributions 			continue;
266*33de042dSApple OSS Distributions 		}
267*33de042dSApple OSS Distributions 		if (ep->func) {
268*33de042dSApple OSS Distributions 			prio = (*ep->func)(m, *offp, proto, ep->arg);
269*33de042dSApple OSS Distributions 		} else {
270*33de042dSApple OSS Distributions 			/*
271*33de042dSApple OSS Distributions 			 * it's inbound traffic, we need to match in reverse
272*33de042dSApple OSS Distributions 			 * order
273*33de042dSApple OSS Distributions 			 */
274*33de042dSApple OSS Distributions 			prio = mask_match(ep, SA(&d), SA(&s));
275*33de042dSApple OSS Distributions 		}
276*33de042dSApple OSS Distributions 
277*33de042dSApple OSS Distributions 		/* see encap4_input() for issues here */
278*33de042dSApple OSS Distributions 		if (prio <= 0) {
279*33de042dSApple OSS Distributions 			continue;
280*33de042dSApple OSS Distributions 		}
281*33de042dSApple OSS Distributions 		if (prio > matchprio) {
282*33de042dSApple OSS Distributions 			matchprio = prio;
283*33de042dSApple OSS Distributions 			match = ep;
284*33de042dSApple OSS Distributions 			psw = (const struct ip6protosw *)match->psw;
285*33de042dSApple OSS Distributions 			match_arg = ep->arg;
286*33de042dSApple OSS Distributions 		}
287*33de042dSApple OSS Distributions 	}
288*33de042dSApple OSS Distributions 	lck_rw_unlock_shared(&encaptab_lock);
289*33de042dSApple OSS Distributions 
290*33de042dSApple OSS Distributions 	if (match) {
291*33de042dSApple OSS Distributions 		/* found a match */
292*33de042dSApple OSS Distributions 		if (psw && psw->pr_input) {
293*33de042dSApple OSS Distributions 			encap_fillarg(m, match_arg);
294*33de042dSApple OSS Distributions 			return (*psw->pr_input)(mp, offp, proto);
295*33de042dSApple OSS Distributions 		} else {
296*33de042dSApple OSS Distributions 			m_freem(m);
297*33de042dSApple OSS Distributions 			return IPPROTO_DONE;
298*33de042dSApple OSS Distributions 		}
299*33de042dSApple OSS Distributions 	}
300*33de042dSApple OSS Distributions 
301*33de042dSApple OSS Distributions 	/* last resort: inject to raw socket */
302*33de042dSApple OSS Distributions 	return rip6_input(mp, offp, proto);
303*33de042dSApple OSS Distributions }
304*33de042dSApple OSS Distributions 
305*33de042dSApple OSS Distributions static void
encap_add_locked(struct encaptab * ep)306*33de042dSApple OSS Distributions encap_add_locked(struct encaptab *ep)
307*33de042dSApple OSS Distributions {
308*33de042dSApple OSS Distributions 	LCK_RW_ASSERT(&encaptab_lock, LCK_RW_ASSERT_EXCLUSIVE);
309*33de042dSApple OSS Distributions 	LIST_INSERT_HEAD(&encaptab, ep, chain);
310*33de042dSApple OSS Distributions }
311*33de042dSApple OSS Distributions 
312*33de042dSApple OSS Distributions /*
313*33de042dSApple OSS Distributions  * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
314*33de042dSApple OSS Distributions  * length of mask (sm and dm) is assumed to be same as sp/dp.
315*33de042dSApple OSS Distributions  * Return value will be necessary as input (cookie) for encap_detach().
316*33de042dSApple OSS Distributions  */
317*33de042dSApple OSS Distributions const struct encaptab *
encap_attach(int af,int proto,const struct sockaddr * sp,const struct sockaddr * sm,const struct sockaddr * dp,const struct sockaddr * dm,const struct protosw * psw,void * arg)318*33de042dSApple OSS Distributions encap_attach(int af, int proto, const struct sockaddr *sp,
319*33de042dSApple OSS Distributions     const struct sockaddr *sm, const struct sockaddr *dp,
320*33de042dSApple OSS Distributions     const struct sockaddr *dm, const struct protosw *psw, void *arg)
321*33de042dSApple OSS Distributions {
322*33de042dSApple OSS Distributions 	struct encaptab *ep = NULL;
323*33de042dSApple OSS Distributions 	struct encaptab *new_ep = NULL;
324*33de042dSApple OSS Distributions 	int error;
325*33de042dSApple OSS Distributions 
326*33de042dSApple OSS Distributions 	/* sanity check on args */
327*33de042dSApple OSS Distributions 	if (sp->sa_len > sizeof(new_ep->src) || dp->sa_len > sizeof(new_ep->dst)) {
328*33de042dSApple OSS Distributions 		error = EINVAL;
329*33de042dSApple OSS Distributions 		goto fail;
330*33de042dSApple OSS Distributions 	}
331*33de042dSApple OSS Distributions 	if (sp->sa_len != dp->sa_len) {
332*33de042dSApple OSS Distributions 		error = EINVAL;
333*33de042dSApple OSS Distributions 		goto fail;
334*33de042dSApple OSS Distributions 	}
335*33de042dSApple OSS Distributions 	if (af != sp->sa_family || af != dp->sa_family) {
336*33de042dSApple OSS Distributions 		error = EINVAL;
337*33de042dSApple OSS Distributions 		goto fail;
338*33de042dSApple OSS Distributions 	}
339*33de042dSApple OSS Distributions 
340*33de042dSApple OSS Distributions 	new_ep = kalloc_type(struct encaptab, Z_WAITOK | Z_ZERO | Z_NOFAIL);
341*33de042dSApple OSS Distributions 
342*33de042dSApple OSS Distributions 	/* check if anyone have already attached with exactly same config */
343*33de042dSApple OSS Distributions 	lck_rw_lock_exclusive(&encaptab_lock);
344*33de042dSApple OSS Distributions 	for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
345*33de042dSApple OSS Distributions 		if (ep->af != af) {
346*33de042dSApple OSS Distributions 			continue;
347*33de042dSApple OSS Distributions 		}
348*33de042dSApple OSS Distributions 		if (ep->proto != proto) {
349*33de042dSApple OSS Distributions 			continue;
350*33de042dSApple OSS Distributions 		}
351*33de042dSApple OSS Distributions 		if (ep->src.ss_len != sp->sa_len ||
352*33de042dSApple OSS Distributions 		    SOCKADDR_CMP(&ep->src, sp, sp->sa_len) != 0 ||
353*33de042dSApple OSS Distributions 		    SOCKADDR_CMP(&ep->srcmask, sm, sp->sa_len) != 0) {
354*33de042dSApple OSS Distributions 			continue;
355*33de042dSApple OSS Distributions 		}
356*33de042dSApple OSS Distributions 		if (ep->dst.ss_len != dp->sa_len ||
357*33de042dSApple OSS Distributions 		    SOCKADDR_CMP(&ep->dst, dp, dp->sa_len) != 0 ||
358*33de042dSApple OSS Distributions 		    SOCKADDR_CMP(&ep->dstmask, dm, dp->sa_len) != 0) {
359*33de042dSApple OSS Distributions 			continue;
360*33de042dSApple OSS Distributions 		}
361*33de042dSApple OSS Distributions 
362*33de042dSApple OSS Distributions 		error = EEXIST;
363*33de042dSApple OSS Distributions 		goto fail_locked;
364*33de042dSApple OSS Distributions 	}
365*33de042dSApple OSS Distributions 
366*33de042dSApple OSS Distributions 	new_ep->af = af;
367*33de042dSApple OSS Distributions 	new_ep->proto = proto;
368*33de042dSApple OSS Distributions 	SOCKADDR_COPY(sp, &new_ep->src, sp->sa_len);
369*33de042dSApple OSS Distributions 	SOCKADDR_COPY(sm, &new_ep->srcmask, sp->sa_len);
370*33de042dSApple OSS Distributions 	SOCKADDR_COPY(dp, &new_ep->dst, dp->sa_len);
371*33de042dSApple OSS Distributions 	SOCKADDR_COPY(dm, &new_ep->dstmask, dp->sa_len);
372*33de042dSApple OSS Distributions 	new_ep->psw = psw;
373*33de042dSApple OSS Distributions 	new_ep->arg = arg;
374*33de042dSApple OSS Distributions 
375*33de042dSApple OSS Distributions 	encap_add_locked(new_ep);
376*33de042dSApple OSS Distributions 	lck_rw_unlock_exclusive(&encaptab_lock);
377*33de042dSApple OSS Distributions 
378*33de042dSApple OSS Distributions 	error = 0;
379*33de042dSApple OSS Distributions 	return new_ep;
380*33de042dSApple OSS Distributions 
381*33de042dSApple OSS Distributions fail_locked:
382*33de042dSApple OSS Distributions 	lck_rw_unlock_exclusive(&encaptab_lock);
383*33de042dSApple OSS Distributions 	if (new_ep != NULL) {
384*33de042dSApple OSS Distributions 		kfree_type(struct encaptab, new_ep);
385*33de042dSApple OSS Distributions 	}
386*33de042dSApple OSS Distributions fail:
387*33de042dSApple OSS Distributions 	return NULL;
388*33de042dSApple OSS Distributions }
389*33de042dSApple OSS Distributions 
390*33de042dSApple OSS Distributions const struct encaptab *
encap_attach_func(int af,int proto,int (* func)(const struct mbuf *,int,int,void *),const struct protosw * psw,void * arg)391*33de042dSApple OSS Distributions encap_attach_func( int af, int proto,
392*33de042dSApple OSS Distributions     int (*func)(const struct mbuf *, int, int, void *),
393*33de042dSApple OSS Distributions     const struct protosw *psw, void *arg)
394*33de042dSApple OSS Distributions {
395*33de042dSApple OSS Distributions 	struct encaptab *ep;
396*33de042dSApple OSS Distributions 	int error;
397*33de042dSApple OSS Distributions 
398*33de042dSApple OSS Distributions 	/* sanity check on args */
399*33de042dSApple OSS Distributions 	if (!func) {
400*33de042dSApple OSS Distributions 		error = EINVAL;
401*33de042dSApple OSS Distributions 		goto fail;
402*33de042dSApple OSS Distributions 	}
403*33de042dSApple OSS Distributions 
404*33de042dSApple OSS Distributions 	ep = kalloc_type(struct encaptab, Z_WAITOK | Z_ZERO | Z_NOFAIL); /* XXX */
405*33de042dSApple OSS Distributions 
406*33de042dSApple OSS Distributions 	ep->af = af;
407*33de042dSApple OSS Distributions 	ep->proto = proto;
408*33de042dSApple OSS Distributions 	ep->func = func;
409*33de042dSApple OSS Distributions 	ep->psw = psw;
410*33de042dSApple OSS Distributions 	ep->arg = arg;
411*33de042dSApple OSS Distributions 
412*33de042dSApple OSS Distributions 	lck_rw_lock_exclusive(&encaptab_lock);
413*33de042dSApple OSS Distributions 	encap_add_locked(ep);
414*33de042dSApple OSS Distributions 	lck_rw_unlock_exclusive(&encaptab_lock);
415*33de042dSApple OSS Distributions 
416*33de042dSApple OSS Distributions 	error = 0;
417*33de042dSApple OSS Distributions 	return ep;
418*33de042dSApple OSS Distributions 
419*33de042dSApple OSS Distributions fail:
420*33de042dSApple OSS Distributions 	return NULL;
421*33de042dSApple OSS Distributions }
422*33de042dSApple OSS Distributions 
423*33de042dSApple OSS Distributions int
encap_detach(const struct encaptab * cookie)424*33de042dSApple OSS Distributions encap_detach(const struct encaptab *cookie)
425*33de042dSApple OSS Distributions {
426*33de042dSApple OSS Distributions 	const struct encaptab *ep = cookie;
427*33de042dSApple OSS Distributions 	struct encaptab *p;
428*33de042dSApple OSS Distributions 
429*33de042dSApple OSS Distributions 	lck_rw_lock_exclusive(&encaptab_lock);
430*33de042dSApple OSS Distributions 	for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
431*33de042dSApple OSS Distributions 		if (p == ep) {
432*33de042dSApple OSS Distributions 			LIST_REMOVE(p, chain);
433*33de042dSApple OSS Distributions 			lck_rw_unlock_exclusive(&encaptab_lock);
434*33de042dSApple OSS Distributions 			kfree_type(struct encaptab, p);    /*XXX*/
435*33de042dSApple OSS Distributions 			return 0;
436*33de042dSApple OSS Distributions 		}
437*33de042dSApple OSS Distributions 	}
438*33de042dSApple OSS Distributions 	lck_rw_unlock_exclusive(&encaptab_lock);
439*33de042dSApple OSS Distributions 
440*33de042dSApple OSS Distributions 	return EINVAL;
441*33de042dSApple OSS Distributions }
442*33de042dSApple OSS Distributions 
443*33de042dSApple OSS Distributions static int
mask_match(const struct encaptab * ep,const struct sockaddr * sp,const struct sockaddr * dp)444*33de042dSApple OSS Distributions mask_match(const struct encaptab *ep, const struct sockaddr *sp,
445*33de042dSApple OSS Distributions     const struct sockaddr *dp)
446*33de042dSApple OSS Distributions {
447*33de042dSApple OSS Distributions 	struct sockaddr_storage s;
448*33de042dSApple OSS Distributions 	struct sockaddr_storage d;
449*33de042dSApple OSS Distributions 	int i;
450*33de042dSApple OSS Distributions 	const u_int8_t *p, *q;
451*33de042dSApple OSS Distributions 	u_int8_t *r;
452*33de042dSApple OSS Distributions 	int matchlen;
453*33de042dSApple OSS Distributions 
454*33de042dSApple OSS Distributions 	if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d)) {
455*33de042dSApple OSS Distributions 		return 0;
456*33de042dSApple OSS Distributions 	}
457*33de042dSApple OSS Distributions 	if (sp->sa_family != ep->af || dp->sa_family != ep->af) {
458*33de042dSApple OSS Distributions 		return 0;
459*33de042dSApple OSS Distributions 	}
460*33de042dSApple OSS Distributions 	if (sp->sa_len != ep->src.ss_len || dp->sa_len != ep->dst.ss_len) {
461*33de042dSApple OSS Distributions 		return 0;
462*33de042dSApple OSS Distributions 	}
463*33de042dSApple OSS Distributions 
464*33de042dSApple OSS Distributions 	matchlen = 0;
465*33de042dSApple OSS Distributions 
466*33de042dSApple OSS Distributions 	p = SA_BYTES(sp);
467*33de042dSApple OSS Distributions 	q = SA_BYTES(&ep->srcmask);
468*33de042dSApple OSS Distributions 	r = SA_BYTES(&s);
469*33de042dSApple OSS Distributions 	for (i = 0; i < sp->sa_len; i++) {
470*33de042dSApple OSS Distributions 		r[i] = p[i] & q[i];
471*33de042dSApple OSS Distributions 		/* XXX estimate */
472*33de042dSApple OSS Distributions 		matchlen += (q[i] ? 8 : 0);
473*33de042dSApple OSS Distributions 	}
474*33de042dSApple OSS Distributions 
475*33de042dSApple OSS Distributions 	p = SA_BYTES(dp);
476*33de042dSApple OSS Distributions 	q = SA_BYTES(&ep->dstmask);
477*33de042dSApple OSS Distributions 	r = SA_BYTES(&s);
478*33de042dSApple OSS Distributions 	for (i = 0; i < dp->sa_len; i++) {
479*33de042dSApple OSS Distributions 		r[i] = p[i] & q[i];
480*33de042dSApple OSS Distributions 		/* XXX rough estimate */
481*33de042dSApple OSS Distributions 		matchlen += (q[i] ? 8 : 0);
482*33de042dSApple OSS Distributions 	}
483*33de042dSApple OSS Distributions 
484*33de042dSApple OSS Distributions 	/* need to overwrite len/family portion as we don't compare them */
485*33de042dSApple OSS Distributions 	s.ss_len = sp->sa_len;
486*33de042dSApple OSS Distributions 	s.ss_family = sp->sa_family;
487*33de042dSApple OSS Distributions 	d.ss_len = dp->sa_len;
488*33de042dSApple OSS Distributions 	d.ss_family = dp->sa_family;
489*33de042dSApple OSS Distributions 
490*33de042dSApple OSS Distributions 	if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 &&
491*33de042dSApple OSS Distributions 	    bcmp(&d, &ep->dst, ep->dst.ss_len) == 0) {
492*33de042dSApple OSS Distributions 		return matchlen;
493*33de042dSApple OSS Distributions 	} else {
494*33de042dSApple OSS Distributions 		return 0;
495*33de042dSApple OSS Distributions 	}
496*33de042dSApple OSS Distributions }
497*33de042dSApple OSS Distributions 
498*33de042dSApple OSS Distributions struct encaptabtag {
499*33de042dSApple OSS Distributions 	void*                   *arg;
500*33de042dSApple OSS Distributions };
501*33de042dSApple OSS Distributions 
502*33de042dSApple OSS Distributions static void
encap_fillarg(struct mbuf * m,void * arg)503*33de042dSApple OSS Distributions encap_fillarg(
504*33de042dSApple OSS Distributions 	struct mbuf *m,
505*33de042dSApple OSS Distributions 	void *arg)
506*33de042dSApple OSS Distributions {
507*33de042dSApple OSS Distributions 	struct m_tag    *tag;
508*33de042dSApple OSS Distributions 	struct encaptabtag *et;
509*33de042dSApple OSS Distributions 
510*33de042dSApple OSS Distributions 	tag = m_tag_create(KERNEL_MODULE_TAG_ID, KERNEL_TAG_TYPE_ENCAP,
511*33de042dSApple OSS Distributions 	    sizeof(struct encaptabtag), M_WAITOK, m);
512*33de042dSApple OSS Distributions 
513*33de042dSApple OSS Distributions 	if (tag != NULL) {
514*33de042dSApple OSS Distributions 		et = (struct encaptabtag*)(tag->m_tag_data);
515*33de042dSApple OSS Distributions 		et->arg = arg;
516*33de042dSApple OSS Distributions 		m_tag_prepend(m, tag);
517*33de042dSApple OSS Distributions 	}
518*33de042dSApple OSS Distributions }
519*33de042dSApple OSS Distributions 
520*33de042dSApple OSS Distributions void *
encap_getarg(struct mbuf * m)521*33de042dSApple OSS Distributions encap_getarg(struct mbuf *m)
522*33de042dSApple OSS Distributions {
523*33de042dSApple OSS Distributions 	struct m_tag *__single tag;
524*33de042dSApple OSS Distributions 	struct encaptabtag *__single et;
525*33de042dSApple OSS Distributions 	void *__single p = NULL;
526*33de042dSApple OSS Distributions 
527*33de042dSApple OSS Distributions 	tag = m_tag_locate(m, KERNEL_MODULE_TAG_ID, KERNEL_TAG_TYPE_ENCAP);
528*33de042dSApple OSS Distributions 	if (tag) {
529*33de042dSApple OSS Distributions 		et = (struct encaptabtag*)(tag->m_tag_data);
530*33de042dSApple OSS Distributions 		p = et->arg;
531*33de042dSApple OSS Distributions 		m_tag_delete(m, tag);
532*33de042dSApple OSS Distributions 	}
533*33de042dSApple OSS Distributions 
534*33de042dSApple OSS Distributions 	return p;
535*33de042dSApple OSS Distributions }
536*33de042dSApple OSS Distributions 
537*33de042dSApple OSS Distributions struct encaptab_tag_container {
538*33de042dSApple OSS Distributions 	struct m_tag            encaptab_m_tag;
539*33de042dSApple OSS Distributions 	struct encaptabtag      encaptab_tag;
540*33de042dSApple OSS Distributions };
541*33de042dSApple OSS Distributions 
542*33de042dSApple OSS Distributions static struct m_tag *
m_tag_kalloc_encap(u_int32_t id,u_int16_t type,uint16_t len,int wait)543*33de042dSApple OSS Distributions m_tag_kalloc_encap(u_int32_t id, u_int16_t type, uint16_t len, int wait)
544*33de042dSApple OSS Distributions {
545*33de042dSApple OSS Distributions 	struct encaptab_tag_container *tag_container;
546*33de042dSApple OSS Distributions 	struct m_tag *tag = NULL;
547*33de042dSApple OSS Distributions 
548*33de042dSApple OSS Distributions 	assert3u(id, ==, KERNEL_MODULE_TAG_ID);
549*33de042dSApple OSS Distributions 	assert3u(type, ==, KERNEL_TAG_TYPE_ENCAP);
550*33de042dSApple OSS Distributions 	assert3u(len, ==, sizeof(struct encaptabtag));
551*33de042dSApple OSS Distributions 
552*33de042dSApple OSS Distributions 	if (len != sizeof(struct encaptabtag)) {
553*33de042dSApple OSS Distributions 		return NULL;
554*33de042dSApple OSS Distributions 	}
555*33de042dSApple OSS Distributions 
556*33de042dSApple OSS Distributions 	tag_container = kalloc_type(struct encaptab_tag_container, wait | M_ZERO);
557*33de042dSApple OSS Distributions 	if (tag_container != NULL) {
558*33de042dSApple OSS Distributions 		tag = &tag_container->encaptab_m_tag;
559*33de042dSApple OSS Distributions 
560*33de042dSApple OSS Distributions 		assert3p(tag, ==, tag_container);
561*33de042dSApple OSS Distributions 
562*33de042dSApple OSS Distributions 		M_TAG_INIT(tag, id, type, len, &tag_container->encaptab_tag, NULL);
563*33de042dSApple OSS Distributions 	}
564*33de042dSApple OSS Distributions 
565*33de042dSApple OSS Distributions 	return tag;
566*33de042dSApple OSS Distributions }
567*33de042dSApple OSS Distributions 
568*33de042dSApple OSS Distributions static void
m_tag_kfree_encap(struct m_tag * tag)569*33de042dSApple OSS Distributions m_tag_kfree_encap(struct m_tag *tag)
570*33de042dSApple OSS Distributions {
571*33de042dSApple OSS Distributions 	struct encaptab_tag_container *__single tag_container = (struct encaptab_tag_container *)tag;
572*33de042dSApple OSS Distributions 
573*33de042dSApple OSS Distributions 	assert3u(tag->m_tag_len, ==, sizeof(struct encaptabtag));
574*33de042dSApple OSS Distributions 
575*33de042dSApple OSS Distributions 	kfree_type(struct encaptab_tag_container, tag_container);
576*33de042dSApple OSS Distributions }
577*33de042dSApple OSS Distributions 
578*33de042dSApple OSS Distributions void
encap_register_m_tag(void)579*33de042dSApple OSS Distributions encap_register_m_tag(void)
580*33de042dSApple OSS Distributions {
581*33de042dSApple OSS Distributions 	int error;
582*33de042dSApple OSS Distributions 
583*33de042dSApple OSS Distributions 	error = m_register_internal_tag_type(KERNEL_TAG_TYPE_ENCAP, sizeof(struct encaptabtag),
584*33de042dSApple OSS Distributions 	    m_tag_kalloc_encap, m_tag_kfree_encap);
585*33de042dSApple OSS Distributions 
586*33de042dSApple OSS Distributions 	assert3u(error, ==, 0);
587*33de042dSApple OSS Distributions }
588