ip_encap.c revision 1.4.2.2 1 1.4.2.2 bouyer /* $NetBSD: ip_encap.c,v 1.4.2.2 2000/11/20 18:10:25 bouyer Exp $ */
2 1.4.2.2 bouyer /* $KAME: ip_encap.c,v 1.39 2000/10/01 12:37:18 itojun Exp $ */
3 1.4.2.2 bouyer
4 1.4.2.2 bouyer /*
5 1.4.2.2 bouyer * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 1.4.2.2 bouyer * All rights reserved.
7 1.4.2.2 bouyer *
8 1.4.2.2 bouyer * Redistribution and use in source and binary forms, with or without
9 1.4.2.2 bouyer * modification, are permitted provided that the following conditions
10 1.4.2.2 bouyer * are met:
11 1.4.2.2 bouyer * 1. Redistributions of source code must retain the above copyright
12 1.4.2.2 bouyer * notice, this list of conditions and the following disclaimer.
13 1.4.2.2 bouyer * 2. Redistributions in binary form must reproduce the above copyright
14 1.4.2.2 bouyer * notice, this list of conditions and the following disclaimer in the
15 1.4.2.2 bouyer * documentation and/or other materials provided with the distribution.
16 1.4.2.2 bouyer * 3. Neither the name of the project nor the names of its contributors
17 1.4.2.2 bouyer * may be used to endorse or promote products derived from this software
18 1.4.2.2 bouyer * without specific prior written permission.
19 1.4.2.2 bouyer *
20 1.4.2.2 bouyer * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 1.4.2.2 bouyer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 1.4.2.2 bouyer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 1.4.2.2 bouyer * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 1.4.2.2 bouyer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 1.4.2.2 bouyer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 1.4.2.2 bouyer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 1.4.2.2 bouyer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 1.4.2.2 bouyer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 1.4.2.2 bouyer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 1.4.2.2 bouyer * SUCH DAMAGE.
31 1.4.2.2 bouyer */
32 1.4.2.2 bouyer /*
33 1.4.2.2 bouyer * My grandfather said that there's a devil inside tunnelling technology...
34 1.4.2.2 bouyer *
35 1.4.2.2 bouyer * We have surprisingly many protocols that want packets with IP protocol
36 1.4.2.2 bouyer * #4 or #41. Here's a list of protocols that want protocol #41:
37 1.4.2.2 bouyer * RFC1933 configured tunnel
38 1.4.2.2 bouyer * RFC1933 automatic tunnel
39 1.4.2.2 bouyer * RFC2401 IPsec tunnel
40 1.4.2.2 bouyer * RFC2473 IPv6 generic packet tunnelling
41 1.4.2.2 bouyer * RFC2529 6over4 tunnel
42 1.4.2.2 bouyer * mobile-ip6 (uses RFC2473)
43 1.4.2.2 bouyer * 6to4 tunnel
44 1.4.2.2 bouyer * Here's a list of protocol that want protocol #4:
45 1.4.2.2 bouyer * RFC1853 IPv4-in-IPv4 tunnelling
46 1.4.2.2 bouyer * RFC2003 IPv4 encapsulation within IPv4
47 1.4.2.2 bouyer * RFC2344 reverse tunnelling for mobile-ip4
48 1.4.2.2 bouyer * RFC2401 IPsec tunnel
49 1.4.2.2 bouyer * Well, what can I say. They impose different en/decapsulation mechanism
50 1.4.2.2 bouyer * from each other, so they need separate protocol handler. The only one
51 1.4.2.2 bouyer * we can easily determine by protocol # is IPsec, which always has
52 1.4.2.2 bouyer * AH/ESP/IPComp header right after outer IP header.
53 1.4.2.2 bouyer *
54 1.4.2.2 bouyer * So, clearly good old protosw does not work for protocol #4 and #41.
55 1.4.2.2 bouyer * The code will let you match protocol via src/dst address pair.
56 1.4.2.2 bouyer */
57 1.4.2.2 bouyer /* XXX is M_NETADDR correct? */
58 1.4.2.2 bouyer
59 1.4.2.2 bouyer #include "opt_mrouting.h"
60 1.4.2.2 bouyer #include "opt_inet.h"
61 1.4.2.2 bouyer
62 1.4.2.2 bouyer #include <sys/param.h>
63 1.4.2.2 bouyer #include <sys/systm.h>
64 1.4.2.2 bouyer #include <sys/socket.h>
65 1.4.2.2 bouyer #include <sys/sockio.h>
66 1.4.2.2 bouyer #include <sys/mbuf.h>
67 1.4.2.2 bouyer #include <sys/errno.h>
68 1.4.2.2 bouyer #include <sys/protosw.h>
69 1.4.2.2 bouyer #include <sys/queue.h>
70 1.4.2.2 bouyer
71 1.4.2.2 bouyer #include <net/if.h>
72 1.4.2.2 bouyer #include <net/route.h>
73 1.4.2.2 bouyer
74 1.4.2.2 bouyer #include <netinet/in.h>
75 1.4.2.2 bouyer #include <netinet/in_systm.h>
76 1.4.2.2 bouyer #include <netinet/ip.h>
77 1.4.2.2 bouyer #include <netinet/ip_var.h>
78 1.4.2.2 bouyer #include <netinet/ip_encap.h>
79 1.4.2.2 bouyer #ifdef MROUTING
80 1.4.2.2 bouyer #include <netinet/ip_mroute.h>
81 1.4.2.2 bouyer #endif /* MROUTING */
82 1.4.2.2 bouyer
83 1.4.2.2 bouyer #ifdef INET6
84 1.4.2.2 bouyer #include <netinet/ip6.h>
85 1.4.2.2 bouyer #include <netinet6/ip6_var.h>
86 1.4.2.2 bouyer #include <netinet6/ip6protosw.h>
87 1.4.2.2 bouyer #endif
88 1.4.2.2 bouyer
89 1.4.2.2 bouyer #include <machine/stdarg.h>
90 1.4.2.2 bouyer
91 1.4.2.2 bouyer #include "ipip.h"
92 1.4.2.2 bouyer #if NIPIP > 0
93 1.4.2.2 bouyer # include <netinet/ip_ipip.h>
94 1.4.2.2 bouyer #else
95 1.4.2.2 bouyer # ifdef MROUTING
96 1.4.2.2 bouyer # include <netinet/ip_mroute.h>
97 1.4.2.2 bouyer # endif
98 1.4.2.2 bouyer #endif
99 1.4.2.2 bouyer
100 1.4.2.2 bouyer #include <net/net_osdep.h>
101 1.4.2.2 bouyer
102 1.4.2.2 bouyer static void encap_add __P((struct encaptab *));
103 1.4.2.2 bouyer static int mask_match __P((const struct encaptab *, const struct sockaddr *,
104 1.4.2.2 bouyer const struct sockaddr *));
105 1.4.2.2 bouyer static void encap_fillarg __P((struct mbuf *, const struct encaptab *));
106 1.4.2.2 bouyer
107 1.4.2.2 bouyer /* rely upon BSS initialization */
108 1.4.2.2 bouyer LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
109 1.4.2.2 bouyer
110 1.4.2.2 bouyer void
111 1.4.2.2 bouyer encap_init()
112 1.4.2.2 bouyer {
113 1.4.2.2 bouyer #if 0
114 1.4.2.2 bouyer /*
115 1.4.2.2 bouyer * we cannot use LIST_INIT() here, since drivers may want to call
116 1.4.2.2 bouyer * encap_attach(), on driver attach. encap_init() will be called
117 1.4.2.2 bouyer * on AF_INET{,6} initialization, which happens after driver
118 1.4.2.2 bouyer * initialization - using LIST_INIT() here can nuke encap_attach()
119 1.4.2.2 bouyer * from drivers.
120 1.4.2.2 bouyer */
121 1.4.2.2 bouyer LIST_INIT(&encaptab);
122 1.4.2.2 bouyer #endif
123 1.4.2.2 bouyer }
124 1.4.2.2 bouyer
125 1.4.2.2 bouyer #ifdef INET
126 1.4.2.2 bouyer void
127 1.4.2.2 bouyer #if __STDC__
128 1.4.2.2 bouyer encap4_input(struct mbuf *m, ...)
129 1.4.2.2 bouyer #else
130 1.4.2.2 bouyer encap4_input(m, va_alist)
131 1.4.2.2 bouyer struct mbuf *m;
132 1.4.2.2 bouyer va_dcl
133 1.4.2.2 bouyer #endif
134 1.4.2.2 bouyer {
135 1.4.2.2 bouyer int off, proto;
136 1.4.2.2 bouyer struct ip *ip;
137 1.4.2.2 bouyer struct sockaddr_in s, d;
138 1.4.2.2 bouyer const struct protosw *psw;
139 1.4.2.2 bouyer struct encaptab *ep, *match;
140 1.4.2.2 bouyer va_list ap;
141 1.4.2.2 bouyer int prio, matchprio;
142 1.4.2.2 bouyer
143 1.4.2.2 bouyer va_start(ap, m);
144 1.4.2.2 bouyer off = va_arg(ap, int);
145 1.4.2.2 bouyer proto = va_arg(ap, int);
146 1.4.2.2 bouyer va_end(ap);
147 1.4.2.2 bouyer
148 1.4.2.2 bouyer ip = mtod(m, struct ip *);
149 1.4.2.2 bouyer
150 1.4.2.2 bouyer bzero(&s, sizeof(s));
151 1.4.2.2 bouyer s.sin_family = AF_INET;
152 1.4.2.2 bouyer s.sin_len = sizeof(struct sockaddr_in);
153 1.4.2.2 bouyer s.sin_addr = ip->ip_src;
154 1.4.2.2 bouyer bzero(&d, sizeof(d));
155 1.4.2.2 bouyer d.sin_family = AF_INET;
156 1.4.2.2 bouyer d.sin_len = sizeof(struct sockaddr_in);
157 1.4.2.2 bouyer d.sin_addr = ip->ip_dst;
158 1.4.2.2 bouyer
159 1.4.2.2 bouyer match = NULL;
160 1.4.2.2 bouyer matchprio = 0;
161 1.4.2.2 bouyer for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
162 1.4.2.2 bouyer if (ep->af != AF_INET)
163 1.4.2.2 bouyer continue;
164 1.4.2.2 bouyer if (ep->proto >= 0 && ep->proto != proto)
165 1.4.2.2 bouyer continue;
166 1.4.2.2 bouyer if (ep->func)
167 1.4.2.2 bouyer prio = (*ep->func)(m, off, proto, ep->arg);
168 1.4.2.2 bouyer else {
169 1.4.2.2 bouyer /*
170 1.4.2.2 bouyer * it's inbound traffic, we need to match in reverse
171 1.4.2.2 bouyer * order
172 1.4.2.2 bouyer */
173 1.4.2.2 bouyer prio = mask_match(ep, (struct sockaddr *)&d,
174 1.4.2.2 bouyer (struct sockaddr *)&s);
175 1.4.2.2 bouyer }
176 1.4.2.2 bouyer
177 1.4.2.2 bouyer /*
178 1.4.2.2 bouyer * We prioritize the matches by using bit length of the
179 1.4.2.2 bouyer * matches. mask_match() and user-supplied matching function
180 1.4.2.2 bouyer * should return the bit length of the matches (for example,
181 1.4.2.2 bouyer * if both src/dst are matched for IPv4, 64 should be returned).
182 1.4.2.2 bouyer * 0 or negative return value means "it did not match".
183 1.4.2.2 bouyer *
184 1.4.2.2 bouyer * The question is, since we have two "mask" portion, we
185 1.4.2.2 bouyer * cannot really define total order between entries.
186 1.4.2.2 bouyer * For example, which of these should be preferred?
187 1.4.2.2 bouyer * mask_match() returns 48 (32 + 16) for both of them.
188 1.4.2.2 bouyer * src=3ffe::/16, dst=3ffe:501::/32
189 1.4.2.2 bouyer * src=3ffe:501::/32, dst=3ffe::/16
190 1.4.2.2 bouyer *
191 1.4.2.2 bouyer * We need to loop through all the possible candidates
192 1.4.2.2 bouyer * to get the best match - the search takes O(n) for
193 1.4.2.2 bouyer * n attachments (i.e. interfaces).
194 1.4.2.2 bouyer */
195 1.4.2.2 bouyer if (prio <= 0)
196 1.4.2.2 bouyer continue;
197 1.4.2.2 bouyer if (prio > matchprio) {
198 1.4.2.2 bouyer matchprio = prio;
199 1.4.2.2 bouyer match = ep;
200 1.4.2.2 bouyer }
201 1.4.2.2 bouyer }
202 1.4.2.2 bouyer
203 1.4.2.2 bouyer if (match) {
204 1.4.2.2 bouyer /* found a match, "match" has the best one */
205 1.4.2.2 bouyer psw = match->psw;
206 1.4.2.2 bouyer if (psw && psw->pr_input) {
207 1.4.2.2 bouyer encap_fillarg(m, match);
208 1.4.2.2 bouyer (*psw->pr_input)(m, off, proto);
209 1.4.2.2 bouyer } else
210 1.4.2.2 bouyer m_freem(m);
211 1.4.2.2 bouyer return;
212 1.4.2.2 bouyer }
213 1.4.2.2 bouyer
214 1.4.2.2 bouyer /* for backward compatibility */
215 1.4.2.2 bouyer #ifdef MROUTING
216 1.4.2.2 bouyer if (proto == IPPROTO_IPV4 && mrt_ipip_input(m, off)) {
217 1.4.2.2 bouyer /*
218 1.4.2.2 bouyer * Multicast routing code claimed this one. No
219 1.4.2.2 bouyer * more processing at this level.
220 1.4.2.2 bouyer */
221 1.4.2.2 bouyer return;
222 1.4.2.2 bouyer }
223 1.4.2.2 bouyer #endif
224 1.4.2.2 bouyer
225 1.4.2.2 bouyer /* last resort: inject to raw socket */
226 1.4.2.2 bouyer rip_input(m, off, proto);
227 1.4.2.2 bouyer }
228 1.4.2.2 bouyer #endif
229 1.4.2.2 bouyer
230 1.4.2.2 bouyer #ifdef INET6
231 1.4.2.2 bouyer int
232 1.4.2.2 bouyer encap6_input(mp, offp, proto)
233 1.4.2.2 bouyer struct mbuf **mp;
234 1.4.2.2 bouyer int *offp;
235 1.4.2.2 bouyer int proto;
236 1.4.2.2 bouyer {
237 1.4.2.2 bouyer struct mbuf *m = *mp;
238 1.4.2.2 bouyer struct ip6_hdr *ip6;
239 1.4.2.2 bouyer struct sockaddr_in6 s, d;
240 1.4.2.2 bouyer const struct ip6protosw *psw;
241 1.4.2.2 bouyer struct encaptab *ep, *match;
242 1.4.2.2 bouyer int prio, matchprio;
243 1.4.2.2 bouyer
244 1.4.2.2 bouyer ip6 = mtod(m, struct ip6_hdr *);
245 1.4.2.2 bouyer
246 1.4.2.2 bouyer bzero(&s, sizeof(s));
247 1.4.2.2 bouyer s.sin6_family = AF_INET6;
248 1.4.2.2 bouyer s.sin6_len = sizeof(struct sockaddr_in6);
249 1.4.2.2 bouyer s.sin6_addr = ip6->ip6_src;
250 1.4.2.2 bouyer bzero(&d, sizeof(d));
251 1.4.2.2 bouyer d.sin6_family = AF_INET6;
252 1.4.2.2 bouyer d.sin6_len = sizeof(struct sockaddr_in6);
253 1.4.2.2 bouyer d.sin6_addr = ip6->ip6_dst;
254 1.4.2.2 bouyer
255 1.4.2.2 bouyer match = NULL;
256 1.4.2.2 bouyer matchprio = 0;
257 1.4.2.2 bouyer for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
258 1.4.2.2 bouyer if (ep->af != AF_INET6)
259 1.4.2.2 bouyer continue;
260 1.4.2.2 bouyer if (ep->proto >= 0 && ep->proto != proto)
261 1.4.2.2 bouyer continue;
262 1.4.2.2 bouyer if (ep->func)
263 1.4.2.2 bouyer prio = (*ep->func)(m, *offp, proto, ep->arg);
264 1.4.2.2 bouyer else {
265 1.4.2.2 bouyer /*
266 1.4.2.2 bouyer * it's inbound traffic, we need to match in reverse
267 1.4.2.2 bouyer * order
268 1.4.2.2 bouyer */
269 1.4.2.2 bouyer prio = mask_match(ep, (struct sockaddr *)&d,
270 1.4.2.2 bouyer (struct sockaddr *)&s);
271 1.4.2.2 bouyer }
272 1.4.2.2 bouyer
273 1.4.2.2 bouyer /* see encap4_input() for issues here */
274 1.4.2.2 bouyer if (prio <= 0)
275 1.4.2.2 bouyer continue;
276 1.4.2.2 bouyer if (prio > matchprio) {
277 1.4.2.2 bouyer matchprio = prio;
278 1.4.2.2 bouyer match = ep;
279 1.4.2.2 bouyer }
280 1.4.2.2 bouyer }
281 1.4.2.2 bouyer
282 1.4.2.2 bouyer if (match) {
283 1.4.2.2 bouyer /* found a match */
284 1.4.2.2 bouyer psw = (const struct ip6protosw *)match->psw;
285 1.4.2.2 bouyer if (psw && psw->pr_input) {
286 1.4.2.2 bouyer encap_fillarg(m, match);
287 1.4.2.2 bouyer return (*psw->pr_input)(mp, offp, proto);
288 1.4.2.2 bouyer } else {
289 1.4.2.2 bouyer m_freem(m);
290 1.4.2.2 bouyer return IPPROTO_DONE;
291 1.4.2.2 bouyer }
292 1.4.2.2 bouyer }
293 1.4.2.2 bouyer
294 1.4.2.2 bouyer /* last resort: inject to raw socket */
295 1.4.2.2 bouyer return rip6_input(mp, offp, proto);
296 1.4.2.2 bouyer }
297 1.4.2.2 bouyer #endif
298 1.4.2.2 bouyer
299 1.4.2.2 bouyer static void
300 1.4.2.2 bouyer encap_add(ep)
301 1.4.2.2 bouyer struct encaptab *ep;
302 1.4.2.2 bouyer {
303 1.4.2.2 bouyer
304 1.4.2.2 bouyer LIST_INSERT_HEAD(&encaptab, ep, chain);
305 1.4.2.2 bouyer }
306 1.4.2.2 bouyer
307 1.4.2.2 bouyer /*
308 1.4.2.2 bouyer * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
309 1.4.2.2 bouyer * length of mask (sm and dm) is assumed to be same as sp/dp.
310 1.4.2.2 bouyer * Return value will be necessary as input (cookie) for encap_detach().
311 1.4.2.2 bouyer */
312 1.4.2.2 bouyer const struct encaptab *
313 1.4.2.2 bouyer encap_attach(af, proto, sp, sm, dp, dm, psw, arg)
314 1.4.2.2 bouyer int af;
315 1.4.2.2 bouyer int proto;
316 1.4.2.2 bouyer const struct sockaddr *sp, *sm;
317 1.4.2.2 bouyer const struct sockaddr *dp, *dm;
318 1.4.2.2 bouyer const struct protosw *psw;
319 1.4.2.2 bouyer void *arg;
320 1.4.2.2 bouyer {
321 1.4.2.2 bouyer struct encaptab *ep;
322 1.4.2.2 bouyer int error;
323 1.4.2.2 bouyer int s;
324 1.4.2.2 bouyer
325 1.4.2.2 bouyer s = splsoftnet();
326 1.4.2.2 bouyer /* sanity check on args */
327 1.4.2.2 bouyer if (sp->sa_len > sizeof(ep->src) || dp->sa_len > sizeof(ep->dst)) {
328 1.4.2.2 bouyer error = EINVAL;
329 1.4.2.2 bouyer goto fail;
330 1.4.2.2 bouyer }
331 1.4.2.2 bouyer if (sp->sa_len != dp->sa_len) {
332 1.4.2.2 bouyer error = EINVAL;
333 1.4.2.2 bouyer goto fail;
334 1.4.2.2 bouyer }
335 1.4.2.2 bouyer if (af != sp->sa_family || af != dp->sa_family) {
336 1.4.2.2 bouyer error = EINVAL;
337 1.4.2.2 bouyer goto fail;
338 1.4.2.2 bouyer }
339 1.4.2.2 bouyer
340 1.4.2.2 bouyer /* check if anyone have already attached with exactly same config */
341 1.4.2.2 bouyer for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
342 1.4.2.2 bouyer if (ep->af != af)
343 1.4.2.2 bouyer continue;
344 1.4.2.2 bouyer if (ep->proto != proto)
345 1.4.2.2 bouyer continue;
346 1.4.2.2 bouyer if (ep->src.ss_len != sp->sa_len ||
347 1.4.2.2 bouyer bcmp(&ep->src, sp, sp->sa_len) != 0 ||
348 1.4.2.2 bouyer bcmp(&ep->srcmask, sm, sp->sa_len) != 0)
349 1.4.2.2 bouyer continue;
350 1.4.2.2 bouyer if (ep->dst.ss_len != dp->sa_len ||
351 1.4.2.2 bouyer bcmp(&ep->dst, dp, dp->sa_len) != 0 ||
352 1.4.2.2 bouyer bcmp(&ep->dstmask, dm, dp->sa_len) != 0)
353 1.4.2.2 bouyer continue;
354 1.4.2.2 bouyer
355 1.4.2.2 bouyer error = EEXIST;
356 1.4.2.2 bouyer goto fail;
357 1.4.2.2 bouyer }
358 1.4.2.2 bouyer
359 1.4.2.2 bouyer /*
360 1.4.2.2 bouyer * XXX NEED TO CHECK viftable IN THE ip_mroute CODE!!!
361 1.4.2.2 bouyer * XXX Actually, that code needs to be replaced with
362 1.4.2.2 bouyer * XXX new code that uses `gif' tunnels.
363 1.4.2.2 bouyer */
364 1.4.2.2 bouyer
365 1.4.2.2 bouyer ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
366 1.4.2.2 bouyer if (ep == NULL) {
367 1.4.2.2 bouyer error = ENOBUFS;
368 1.4.2.2 bouyer goto fail;
369 1.4.2.2 bouyer }
370 1.4.2.2 bouyer bzero(ep, sizeof(*ep));
371 1.4.2.2 bouyer
372 1.4.2.2 bouyer ep->af = af;
373 1.4.2.2 bouyer ep->proto = proto;
374 1.4.2.2 bouyer bcopy(sp, &ep->src, sp->sa_len);
375 1.4.2.2 bouyer bcopy(sm, &ep->srcmask, sp->sa_len);
376 1.4.2.2 bouyer bcopy(dp, &ep->dst, dp->sa_len);
377 1.4.2.2 bouyer bcopy(dm, &ep->dstmask, dp->sa_len);
378 1.4.2.2 bouyer ep->psw = psw;
379 1.4.2.2 bouyer ep->arg = arg;
380 1.4.2.2 bouyer
381 1.4.2.2 bouyer encap_add(ep);
382 1.4.2.2 bouyer
383 1.4.2.2 bouyer error = 0;
384 1.4.2.2 bouyer splx(s);
385 1.4.2.2 bouyer return ep;
386 1.4.2.2 bouyer
387 1.4.2.2 bouyer fail:
388 1.4.2.2 bouyer splx(s);
389 1.4.2.2 bouyer return NULL;
390 1.4.2.2 bouyer }
391 1.4.2.2 bouyer
392 1.4.2.2 bouyer const struct encaptab *
393 1.4.2.2 bouyer encap_attach_func(af, proto, func, psw, arg)
394 1.4.2.2 bouyer int af;
395 1.4.2.2 bouyer int proto;
396 1.4.2.2 bouyer int (*func) __P((const struct mbuf *, int, int, void *));
397 1.4.2.2 bouyer const struct protosw *psw;
398 1.4.2.2 bouyer void *arg;
399 1.4.2.2 bouyer {
400 1.4.2.2 bouyer struct encaptab *ep;
401 1.4.2.2 bouyer int error;
402 1.4.2.2 bouyer int s;
403 1.4.2.2 bouyer
404 1.4.2.2 bouyer s = splsoftnet();
405 1.4.2.2 bouyer /* sanity check on args */
406 1.4.2.2 bouyer if (!func) {
407 1.4.2.2 bouyer error = EINVAL;
408 1.4.2.2 bouyer goto fail;
409 1.4.2.2 bouyer }
410 1.4.2.2 bouyer
411 1.4.2.2 bouyer ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
412 1.4.2.2 bouyer if (ep == NULL) {
413 1.4.2.2 bouyer error = ENOBUFS;
414 1.4.2.2 bouyer goto fail;
415 1.4.2.2 bouyer }
416 1.4.2.2 bouyer bzero(ep, sizeof(*ep));
417 1.4.2.2 bouyer
418 1.4.2.2 bouyer ep->af = af;
419 1.4.2.2 bouyer ep->proto = proto;
420 1.4.2.2 bouyer ep->func = func;
421 1.4.2.2 bouyer ep->psw = psw;
422 1.4.2.2 bouyer ep->arg = arg;
423 1.4.2.2 bouyer
424 1.4.2.2 bouyer encap_add(ep);
425 1.4.2.2 bouyer
426 1.4.2.2 bouyer error = 0;
427 1.4.2.2 bouyer splx(s);
428 1.4.2.2 bouyer return ep;
429 1.4.2.2 bouyer
430 1.4.2.2 bouyer fail:
431 1.4.2.2 bouyer splx(s);
432 1.4.2.2 bouyer return NULL;
433 1.4.2.2 bouyer }
434 1.4.2.2 bouyer
435 1.4.2.2 bouyer int
436 1.4.2.2 bouyer encap_detach(cookie)
437 1.4.2.2 bouyer const struct encaptab *cookie;
438 1.4.2.2 bouyer {
439 1.4.2.2 bouyer const struct encaptab *ep = cookie;
440 1.4.2.2 bouyer struct encaptab *p;
441 1.4.2.2 bouyer
442 1.4.2.2 bouyer for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
443 1.4.2.2 bouyer if (p == ep) {
444 1.4.2.2 bouyer LIST_REMOVE(p, chain);
445 1.4.2.2 bouyer free(p, M_NETADDR); /*XXX*/
446 1.4.2.2 bouyer return 0;
447 1.4.2.2 bouyer }
448 1.4.2.2 bouyer }
449 1.4.2.2 bouyer
450 1.4.2.2 bouyer return EINVAL;
451 1.4.2.2 bouyer }
452 1.4.2.2 bouyer
453 1.4.2.2 bouyer static int
454 1.4.2.2 bouyer mask_match(ep, sp, dp)
455 1.4.2.2 bouyer const struct encaptab *ep;
456 1.4.2.2 bouyer const struct sockaddr *sp;
457 1.4.2.2 bouyer const struct sockaddr *dp;
458 1.4.2.2 bouyer {
459 1.4.2.2 bouyer struct sockaddr_storage s;
460 1.4.2.2 bouyer struct sockaddr_storage d;
461 1.4.2.2 bouyer int i;
462 1.4.2.2 bouyer const u_int8_t *p, *q;
463 1.4.2.2 bouyer u_int8_t *r;
464 1.4.2.2 bouyer int matchlen;
465 1.4.2.2 bouyer
466 1.4.2.2 bouyer if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
467 1.4.2.2 bouyer return 0;
468 1.4.2.2 bouyer if (sp->sa_family != ep->af || dp->sa_family != ep->af)
469 1.4.2.2 bouyer return 0;
470 1.4.2.2 bouyer if (sp->sa_len != ep->src.ss_len || dp->sa_len != ep->dst.ss_len)
471 1.4.2.2 bouyer return 0;
472 1.4.2.2 bouyer
473 1.4.2.2 bouyer matchlen = 0;
474 1.4.2.2 bouyer
475 1.4.2.2 bouyer p = (const u_int8_t *)sp;
476 1.4.2.2 bouyer q = (const u_int8_t *)&ep->srcmask;
477 1.4.2.2 bouyer r = (u_int8_t *)&s;
478 1.4.2.2 bouyer for (i = 0 ; i < sp->sa_len; i++) {
479 1.4.2.2 bouyer r[i] = p[i] & q[i];
480 1.4.2.2 bouyer /* XXX estimate */
481 1.4.2.2 bouyer matchlen += (q[i] ? 8 : 0);
482 1.4.2.2 bouyer }
483 1.4.2.2 bouyer
484 1.4.2.2 bouyer p = (const u_int8_t *)dp;
485 1.4.2.2 bouyer q = (const u_int8_t *)&ep->dstmask;
486 1.4.2.2 bouyer r = (u_int8_t *)&d;
487 1.4.2.2 bouyer for (i = 0 ; i < dp->sa_len; i++) {
488 1.4.2.2 bouyer r[i] = p[i] & q[i];
489 1.4.2.2 bouyer /* XXX rough estimate */
490 1.4.2.2 bouyer matchlen += (q[i] ? 8 : 0);
491 1.4.2.2 bouyer }
492 1.4.2.2 bouyer
493 1.4.2.2 bouyer /* need to overwrite len/family portion as we don't compare them */
494 1.4.2.2 bouyer s.ss_len = sp->sa_len;
495 1.4.2.2 bouyer s.ss_family = sp->sa_family;
496 1.4.2.2 bouyer d.ss_len = dp->sa_len;
497 1.4.2.2 bouyer d.ss_family = dp->sa_family;
498 1.4.2.2 bouyer
499 1.4.2.2 bouyer if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 &&
500 1.4.2.2 bouyer bcmp(&d, &ep->dst, ep->dst.ss_len) == 0) {
501 1.4.2.2 bouyer return matchlen;
502 1.4.2.2 bouyer } else
503 1.4.2.2 bouyer return 0;
504 1.4.2.2 bouyer }
505 1.4.2.2 bouyer
506 1.4.2.2 bouyer static void
507 1.4.2.2 bouyer encap_fillarg(m, ep)
508 1.4.2.2 bouyer struct mbuf *m;
509 1.4.2.2 bouyer const struct encaptab *ep;
510 1.4.2.2 bouyer {
511 1.4.2.2 bouyer #if 0
512 1.4.2.2 bouyer m->m_pkthdr.aux = ep->arg;
513 1.4.2.2 bouyer #else
514 1.4.2.2 bouyer struct mbuf *n;
515 1.4.2.2 bouyer
516 1.4.2.2 bouyer n = m_aux_add(m, AF_INET, IPPROTO_IPV4);
517 1.4.2.2 bouyer if (n) {
518 1.4.2.2 bouyer *mtod(n, void **) = ep->arg;
519 1.4.2.2 bouyer n->m_len = sizeof(void *);
520 1.4.2.2 bouyer }
521 1.4.2.2 bouyer #endif
522 1.4.2.2 bouyer }
523 1.4.2.2 bouyer
524 1.4.2.2 bouyer void *
525 1.4.2.2 bouyer encap_getarg(m)
526 1.4.2.2 bouyer struct mbuf *m;
527 1.4.2.2 bouyer {
528 1.4.2.2 bouyer void *p;
529 1.4.2.2 bouyer #if 0
530 1.4.2.2 bouyer p = m->m_pkthdr.aux;
531 1.4.2.2 bouyer m->m_pkthdr.aux = NULL;
532 1.4.2.2 bouyer return p;
533 1.4.2.2 bouyer #else
534 1.4.2.2 bouyer struct mbuf *n;
535 1.4.2.2 bouyer
536 1.4.2.2 bouyer p = NULL;
537 1.4.2.2 bouyer n = m_aux_find(m, AF_INET, IPPROTO_IPV4);
538 1.4.2.2 bouyer if (n) {
539 1.4.2.2 bouyer if (n->m_len == sizeof(void *))
540 1.4.2.2 bouyer p = *mtod(n, void **);
541 1.4.2.2 bouyer m_aux_delete(m, n);
542 1.4.2.2 bouyer }
543 1.4.2.2 bouyer return p;
544 1.4.2.2 bouyer #endif
545 1.4.2.2 bouyer }
546