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