[BACK]Return to in6_gif.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Annotation of src/sys/netinet6/in6_gif.c, Revision 1.73

1.73    ! knakahar    1: /*     $NetBSD: in6_gif.c,v 1.72 2016/02/26 07:35:17 knakahara Exp $   */
1.21      itojun      2: /*     $KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 itojun Exp $        */
1.3       thorpej     3:
1.2       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
1.14      itojun      7:  *
1.2       itojun      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.
1.14      itojun     19:  *
1.2       itojun     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:  */
1.23      lukem      32:
                     33: #include <sys/cdefs.h>
1.73    ! knakahar   34: __KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.72 2016/02/26 07:35:17 knakahara Exp $");
1.2       itojun     35:
1.62      pooka      36: #ifdef _KERNEL_OPT
1.2       itojun     37: #include "opt_inet.h"
1.62      pooka      38: #endif
1.2       itojun     39:
                     40: #include <sys/param.h>
                     41: #include <sys/systm.h>
                     42: #include <sys/socket.h>
                     43: #include <sys/sockio.h>
                     44: #include <sys/mbuf.h>
                     45: #include <sys/errno.h>
                     46: #include <sys/ioctl.h>
1.15      itojun     47: #include <sys/queue.h>
                     48: #include <sys/syslog.h>
1.43      mlelstv    49: #include <sys/kernel.h>
1.14      itojun     50:
1.2       itojun     51: #include <net/if.h>
                     52: #include <net/route.h>
                     53:
                     54: #include <netinet/in.h>
                     55: #include <netinet/in_systm.h>
                     56: #ifdef INET
                     57: #include <netinet/ip.h>
                     58: #endif
1.14      itojun     59: #include <netinet/ip_encap.h>
1.11      itojun     60: #ifdef INET6
                     61: #include <netinet/ip6.h>
1.2       itojun     62: #include <netinet6/ip6_var.h>
1.55      thorpej    63: #include <netinet6/ip6_private.h>
1.2       itojun     64: #include <netinet6/in6_gif.h>
1.14      itojun     65: #include <netinet6/in6_var.h>
1.68      riastrad   66: #endif
1.71      knakahar   67: #include <netinet6/ip6protosw.h> /* for struct ip6ctlparam */
1.2       itojun     68: #include <netinet/ip_ecn.h>
                     69:
                     70: #include <net/if_gif.h>
                     71:
1.8       itojun     72: #include <net/net_osdep.h>
                     73:
1.58      dsl        74: static int gif_validate6(const struct ip6_hdr *, struct gif_softc *,
                     75:        struct ifnet *);
1.26      itojun     76:
                     77: int    ip6_gif_hlim = GIF_HLIM;
1.21      itojun     78:
1.71      knakahar   79: static const struct encapsw in6_gif_encapsw;
1.27      itojun     80:
1.52      christos   81: /*
                     82:  * family - family of the packet to be encapsulate.
                     83:  */
                     84:
1.2       itojun     85: int
1.52      christos   86: in6_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
1.2       itojun     87: {
1.53      dyoung     88:        struct rtentry *rt;
1.57      dyoung     89:        struct gif_softc *sc = ifp->if_softc;
1.64      knakahar   90:        struct sockaddr_in6 *sin6_src = satosin6(sc->gif_psrc);
                     91:        struct sockaddr_in6 *sin6_dst = satosin6(sc->gif_pdst);
1.2       itojun     92:        struct ip6_hdr *ip6;
1.24      itojun     93:        int proto, error;
1.2       itojun     94:        u_int8_t itos, otos;
1.51      dyoung     95:        union {
                     96:                struct sockaddr         dst;
                     97:                struct sockaddr_in6     dst6;
                     98:        } u;
1.2       itojun     99:
                    100:        if (sin6_src == NULL || sin6_dst == NULL ||
                    101:            sin6_src->sin6_family != AF_INET6 ||
                    102:            sin6_dst->sin6_family != AF_INET6) {
                    103:                m_freem(m);
                    104:                return EAFNOSUPPORT;
                    105:        }
                    106:
                    107:        switch (family) {
                    108: #ifdef INET
                    109:        case AF_INET:
                    110:            {
                    111:                struct ip *ip;
                    112:
                    113:                proto = IPPROTO_IPV4;
                    114:                if (m->m_len < sizeof(*ip)) {
                    115:                        m = m_pullup(m, sizeof(*ip));
                    116:                        if (!m)
                    117:                                return ENOBUFS;
                    118:                }
                    119:                ip = mtod(m, struct ip *);
                    120:                itos = ip->ip_tos;
                    121:                break;
                    122:            }
                    123: #endif
                    124: #ifdef INET6
                    125:        case AF_INET6:
                    126:            {
                    127:                proto = IPPROTO_IPV6;
                    128:                if (m->m_len < sizeof(*ip6)) {
                    129:                        m = m_pullup(m, sizeof(*ip6));
                    130:                        if (!m)
                    131:                                return ENOBUFS;
                    132:                }
                    133:                ip6 = mtod(m, struct ip6_hdr *);
                    134:                itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
                    135:                break;
                    136:            }
1.18      itojun    137: #endif
1.2       itojun    138:        default:
1.12      itojun    139: #ifdef DEBUG
1.2       itojun    140:                printf("in6_gif_output: warning: unknown family %d passed\n",
                    141:                        family);
                    142: #endif
                    143:                m_freem(m);
                    144:                return EAFNOSUPPORT;
                    145:        }
1.29      itojun    146:
1.2       itojun    147:        /* prepend new IP header */
                    148:        M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
                    149:        if (m && m->m_len < sizeof(struct ip6_hdr))
                    150:                m = m_pullup(m, sizeof(struct ip6_hdr));
1.21      itojun    151:        if (m == NULL)
1.2       itojun    152:                return ENOBUFS;
                    153:
                    154:        ip6 = mtod(m, struct ip6_hdr *);
                    155:        ip6->ip6_flow   = 0;
1.9       itojun    156:        ip6->ip6_vfc    &= ~IPV6_VERSION_MASK;
                    157:        ip6->ip6_vfc    |= IPV6_VERSION;
1.36      itojun    158: #if 0  /* ip6->ip6_plen will be filled by ip6_output */
                    159:        ip6->ip6_plen   = htons((u_int16_t)m->m_pkthdr.len);
                    160: #endif
1.2       itojun    161:        ip6->ip6_nxt    = proto;
                    162:        ip6->ip6_hlim   = ip6_gif_hlim;
                    163:        ip6->ip6_src    = sin6_src->sin6_addr;
1.20      itojun    164:        /* bidirectional configured tunnel mode */
                    165:        if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
                    166:                ip6->ip6_dst = sin6_dst->sin6_addr;
                    167:        else  {
                    168:                m_freem(m);
                    169:                return ENETUNREACH;
1.2       itojun    170:        }
1.19      itojun    171:        if (ifp->if_flags & IFF_LINK1)
1.2       itojun    172:                ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
1.19      itojun    173:        else
                    174:                ip_ecn_ingress(ECN_NOCARE, &otos, &itos);
                    175:        ip6->ip6_flow &= ~ntohl(0xff00000);
                    176:        ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
1.2       itojun    177:
1.51      dyoung    178:        sockaddr_in6_init(&u.dst6, &sin6_dst->sin6_addr, 0, 0, 0);
1.53      dyoung    179:        if ((rt = rtcache_lookup(&sc->gif_ro, &u.dst)) == NULL) {
1.51      dyoung    180:                m_freem(m);
                    181:                return ENETUNREACH;
1.47      joerg     182:        }
1.14      itojun    183:
1.47      joerg     184:        /* If the route constitutes infinite encapsulation, punt. */
1.53      dyoung    185:        if (rt->rt_ifp == ifp) {
1.61      ozaki-r   186:                rtcache_free(&sc->gif_ro);
1.47      joerg     187:                m_freem(m);
                    188:                return ENETUNREACH;     /* XXX */
1.2       itojun    189:        }
1.29      itojun    190:
1.14      itojun    191: #ifdef IPV6_MINMTU
                    192:        /*
                    193:         * force fragmentation to minimum MTU, to avoid path MTU discovery.
                    194:         * it is too painful to ask for resend of inner packet, to achieve
                    195:         * path MTU discovery for encapsulated packets.
                    196:         */
1.57      dyoung    197:        error = ip6_output(m, 0, &sc->gif_ro, IPV6_MINMTU, NULL, NULL, NULL);
1.14      itojun    198: #else
1.57      dyoung    199:        error = ip6_output(m, 0, &sc->gif_ro, 0, NULL, NULL, NULL);
1.14      itojun    200: #endif
1.24      itojun    201:
1.30      itojun    202:        return (error);
1.2       itojun    203: }
                    204:
1.57      dyoung    205: int
                    206: in6_gif_input(struct mbuf **mp, int *offp, int proto)
1.2       itojun    207: {
                    208:        struct mbuf *m = *mp;
                    209:        struct ifnet *gifp = NULL;
                    210:        struct ip6_hdr *ip6;
                    211:        int af = 0;
                    212:        u_int32_t otos;
                    213:
                    214:        ip6 = mtod(m, struct ip6_hdr *);
                    215:
1.14      itojun    216:        gifp = (struct ifnet *)encap_getarg(m);
1.2       itojun    217:
1.14      itojun    218:        if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
1.2       itojun    219:                m_freem(m);
1.55      thorpej   220:                IP6_STATINC(IP6_STAT_NOGIF);
1.2       itojun    221:                return IPPROTO_DONE;
                    222:        }
1.32      itojun    223: #ifndef GIF_ENCAPCHECK
1.63      knakahar  224:        struct gif_softc *sc = (struct gif_softc *)gifp->if_softc;
                    225:        /* other CPU do delete_tunnel */
                    226:        if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
                    227:                m_freem(m);
                    228:                IP6_STATINC(IP6_STAT_NOGIF);
                    229:                return IPPROTO_DONE;
                    230:        }
                    231:
                    232:        if (!gif_validate6(ip6, sc, m->m_pkthdr.rcvif)) {
1.21      itojun    233:                m_freem(m);
1.55      thorpej   234:                IP6_STATINC(IP6_STAT_NOGIF);
1.21      itojun    235:                return IPPROTO_DONE;
                    236:        }
                    237: #endif
1.14      itojun    238:
1.2       itojun    239:        otos = ip6->ip6_flow;
                    240:        m_adj(m, *offp);
                    241:
                    242:        switch (proto) {
                    243: #ifdef INET
                    244:        case IPPROTO_IPV4:
                    245:            {
                    246:                struct ip *ip;
                    247:                u_int8_t otos8;
                    248:                af = AF_INET;
                    249:                otos8 = (ntohl(otos) >> 20) & 0xff;
                    250:                if (m->m_len < sizeof(*ip)) {
                    251:                        m = m_pullup(m, sizeof(*ip));
                    252:                        if (!m)
                    253:                                return IPPROTO_DONE;
                    254:                }
                    255:                ip = mtod(m, struct ip *);
                    256:                if (gifp->if_flags & IFF_LINK1)
                    257:                        ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos);
1.19      itojun    258:                else
                    259:                        ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos);
1.2       itojun    260:                break;
                    261:            }
                    262: #endif /* INET */
                    263: #ifdef INET6
                    264:        case IPPROTO_IPV6:
                    265:            {
1.40      christos  266:                struct ip6_hdr *ip6x;
1.2       itojun    267:                af = AF_INET6;
1.40      christos  268:                if (m->m_len < sizeof(*ip6x)) {
                    269:                        m = m_pullup(m, sizeof(*ip6x));
1.2       itojun    270:                        if (!m)
                    271:                                return IPPROTO_DONE;
                    272:                }
1.40      christos  273:                ip6x = mtod(m, struct ip6_hdr *);
1.2       itojun    274:                if (gifp->if_flags & IFF_LINK1)
1.40      christos  275:                        ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6x->ip6_flow);
1.19      itojun    276:                else
1.40      christos  277:                        ip6_ecn_egress(ECN_NOCARE, &otos, &ip6x->ip6_flow);
1.2       itojun    278:                break;
                    279:            }
1.17      itojun    280: #endif
1.2       itojun    281:        default:
1.55      thorpej   282:                IP6_STATINC(IP6_STAT_NOGIF);
1.2       itojun    283:                m_freem(m);
                    284:                return IPPROTO_DONE;
                    285:        }
1.29      itojun    286:
1.2       itojun    287:        gif_input(m, af, gifp);
                    288:        return IPPROTO_DONE;
1.14      itojun    289: }
                    290:
                    291: /*
1.21      itojun    292:  * validate outer address.
1.14      itojun    293:  */
1.21      itojun    294: static int
1.52      christos  295: gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc,
                    296:        struct ifnet *ifp)
1.14      itojun    297: {
1.49      dyoung    298:        const struct sockaddr_in6 *src, *dst;
1.14      itojun    299:
1.64      knakahar  300:        src = satosin6(sc->gif_psrc);
                    301:        dst = satosin6(sc->gif_pdst);
1.14      itojun    302:
                    303:        /* check for address match */
1.21      itojun    304:        if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
                    305:            !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
1.14      itojun    306:                return 0;
                    307:
                    308:        /* martian filters on outer source - done in ip6_input */
                    309:
                    310:        /* ingress filters on outer source */
1.21      itojun    311:        if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
1.57      dyoung    312:                union {
                    313:                        struct sockaddr sa;
                    314:                        struct sockaddr_in6 sin6;
                    315:                } u;
1.14      itojun    316:                struct rtentry *rt;
                    317:
                    318:                /* XXX scopeid */
1.57      dyoung    319:                sockaddr_in6_init(&u.sin6, &ip6->ip6_src, 0, 0, 0);
                    320:                rt = rtalloc1(&u.sa, 0);
                    321:                if (rt == NULL || rt->rt_ifp != ifp) {
1.15      itojun    322: #if 0
                    323:                        log(LOG_WARNING, "%s: packet from %s dropped "
                    324:                            "due to ingress filter\n", if_name(&sc->gif_if),
1.57      dyoung    325:                            ip6_sprintf(&u.sin6.sin6_addr));
1.15      itojun    326: #endif
1.57      dyoung    327:                        if (rt != NULL)
1.15      itojun    328:                                rtfree(rt);
1.14      itojun    329:                        return 0;
                    330:                }
                    331:                rtfree(rt);
                    332:        }
                    333:
1.20      itojun    334:        return 128 * 2;
1.21      itojun    335: }
                    336:
1.32      itojun    337: #ifdef GIF_ENCAPCHECK
1.21      itojun    338: /*
                    339:  * we know that we are in IFF_UP, outer address available, and outer family
                    340:  * matched the physical addr family.  see gif_encapcheck().
                    341:  */
                    342: int
1.52      christos  343: gif_encapcheck6(struct mbuf *m, int off, int proto, void *arg)
1.21      itojun    344: {
                    345:        struct ip6_hdr ip6;
                    346:        struct gif_softc *sc;
                    347:        struct ifnet *ifp;
                    348:
                    349:        /* sanity check done in caller */
1.57      dyoung    350:        sc = arg;
1.21      itojun    351:
1.50      christos  352:        m_copydata(m, 0, sizeof(ip6), (void *)&ip6);
1.21      itojun    353:        ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
                    354:
                    355:        return gif_validate6(&ip6, sc, ifp);
                    356: }
1.32      itojun    357: #endif
1.21      itojun    358:
                    359: int
1.52      christos  360: in6_gif_attach(struct gif_softc *sc)
1.21      itojun    361: {
1.32      itojun    362: #ifndef GIF_ENCAPCHECK
1.21      itojun    363:        struct sockaddr_in6 mask6;
                    364:
1.57      dyoung    365:        memset(&mask6, 0, sizeof(mask6));
1.21      itojun    366:        mask6.sin6_len = sizeof(struct sockaddr_in6);
1.28      itojun    367:        mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] =
1.21      itojun    368:            mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0;
                    369:
                    370:        if (!sc->gif_psrc || !sc->gif_pdst)
                    371:                return EINVAL;
                    372:        sc->encap_cookie6 = encap_attach(AF_INET6, -1, sc->gif_psrc,
                    373:            (struct sockaddr *)&mask6, sc->gif_pdst, (struct sockaddr *)&mask6,
1.71      knakahar  374:            (const void *)&in6_gif_encapsw, sc);
1.21      itojun    375: #else
                    376:        sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
1.71      knakahar  377:            &in6_gif_encapsw, sc);
1.21      itojun    378: #endif
                    379:        if (sc->encap_cookie6 == NULL)
                    380:                return EEXIST;
                    381:        return 0;
                    382: }
                    383:
                    384: int
1.70      riastrad  385: in6_gif_detach(struct gif_softc *sc)
1.21      itojun    386: {
                    387:        int error;
                    388:
                    389:        error = encap_detach(sc->encap_cookie6);
                    390:        if (error == 0)
                    391:                sc->encap_cookie6 = NULL;
1.43      mlelstv   392:
1.51      dyoung    393:        rtcache_free(&sc->gif_ro);
1.43      mlelstv   394:
1.70      riastrad  395:        return error;
1.27      itojun    396: }
                    397:
1.56      ad        398: void *
1.72      knakahar  399: in6_gif_ctlinput(int cmd, const struct sockaddr *sa, void *d, void *eparg)
1.27      itojun    400: {
1.73    ! knakahar  401:        struct gif_softc *sc = eparg;
1.27      itojun    402:        struct ip6ctlparam *ip6cp = NULL;
                    403:        struct ip6_hdr *ip6;
1.49      dyoung    404:        const struct sockaddr_in6 *dst6;
1.27      itojun    405:
                    406:        if (sa->sa_family != AF_INET6 ||
                    407:            sa->sa_len != sizeof(struct sockaddr_in6))
1.56      ad        408:                return NULL;
1.27      itojun    409:
                    410:        if ((unsigned)cmd >= PRC_NCMDS)
1.56      ad        411:                return NULL;
1.27      itojun    412:        if (cmd == PRC_HOSTDEAD)
                    413:                d = NULL;
                    414:        else if (inet6ctlerrmap[cmd] == 0)
1.56      ad        415:                return NULL;
1.27      itojun    416:
                    417:        /* if the parameter is from icmp6, decode it. */
                    418:        if (d != NULL) {
                    419:                ip6cp = (struct ip6ctlparam *)d;
                    420:                ip6 = ip6cp->ip6c_ip6;
                    421:        } else {
                    422:                ip6 = NULL;
                    423:        }
                    424:
                    425:        if (!ip6)
1.56      ad        426:                return NULL;
1.27      itojun    427:
1.72      knakahar  428:        if ((sc->gif_if.if_flags & IFF_RUNNING) == 0)
                    429:                return NULL;
                    430:        if (sc->gif_psrc->sa_family != AF_INET6)
                    431:                return NULL;
                    432:
                    433:        dst6 = satocsin6(rtcache_getdst(&sc->gif_ro));
                    434:        /* XXX scope */
                    435:        if (dst6 == NULL)
                    436:                ;
                    437:        else if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr))
                    438:                rtcache_free(&sc->gif_ro);
1.56      ad        439:
                    440:        return NULL;
1.2       itojun    441: }
1.56      ad        442:
1.72      knakahar  443: ENCAP_PR_WRAP_CTLINPUT(in6_gif_ctlinput)
1.56      ad        444: #define        in6_gif_ctlinput        in6_gif_ctlinput_wrapper
1.68      riastrad  445:
1.71      knakahar  446: static const struct encapsw in6_gif_encapsw = {
                    447:        .encapsw6 = {
                    448:                .pr_input       = in6_gif_input,
                    449:                .pr_ctlinput    = in6_gif_ctlinput,
                    450:        }
1.56      ad        451: };

CVSweb <webmaster@jp.NetBSD.org>