[BACK]Return to ip_gre.c CVS log [TXT][DIR] Up to [local] / sys / netinet

Annotation of sys/netinet/ip_gre.c, Revision 1.1.1.1

1.1       nbrk        1: /*      $OpenBSD: ip_gre.c,v 1.31 2007/05/27 21:20:52 claudio Exp $ */
                      2: /*     $NetBSD: ip_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by Heiko W.Rupp <hwr@pilhuhn.de>
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: /*
                     41:  * decapsulate tunneled packets and send them on
                     42:  * output half is in net/if_gre.[ch]
                     43:  * This currently handles IPPROTO_GRE, IPPROTO_MOBILE
                     44:  */
                     45:
                     46:
                     47: #include "gre.h"
                     48: #if NGRE > 0
                     49:
                     50: #include <sys/param.h>
                     51: #include <sys/systm.h>
                     52: #include <sys/mbuf.h>
                     53: #include <sys/socket.h>
                     54: #include <sys/sysctl.h>
                     55: #include <net/if.h>
                     56: #include <net/netisr.h>
                     57: #include <net/route.h>
                     58: #include <net/bpf.h>
                     59:
                     60: #ifdef INET
                     61: #include <netinet/in.h>
                     62: #include <netinet/in_var.h>
                     63: #include <netinet/in_systm.h>
                     64: #include <netinet/ip.h>
                     65: #include <netinet/ip_var.h>
                     66: #include <netinet/ip_gre.h>
                     67: #include <netinet/if_ether.h>
                     68: #else
                     69: #error "ip_gre used without inet"
                     70: #endif
                     71:
                     72: #ifdef NETATALK
                     73: #include <netatalk/at.h>
                     74: #include <netatalk/at_var.h>
                     75: #include <netatalk/at_extern.h>
                     76: #endif
                     77:
                     78: #include "bpfilter.h"
                     79:
                     80: /* Needs IP headers. */
                     81: #include <net/if_gre.h>
                     82:
                     83: struct gre_softc *gre_lookup(struct mbuf *, u_int8_t);
                     84: int gre_input2(struct mbuf *, int, u_char);
                     85:
                     86: /*
                     87:  * Decapsulate.
                     88:  * Does the real work and is called from gre_input() (above)
                     89:  * returns 0 if packet is not yet processed
                     90:  * and 1 if it needs no further processing
                     91:  * proto is the protocol number of the "calling" foo_input()
                     92:  * routine.
                     93:  */
                     94:
                     95: int
                     96: gre_input2(m , hlen, proto)
                     97:         struct mbuf *m;
                     98:        int hlen;
                     99:        u_char proto;
                    100: {
                    101:        struct greip *gip;
                    102:        int s;
                    103:        struct ifqueue *ifq;
                    104:        struct gre_softc *sc;
                    105:        u_short flags;
                    106:        u_int af;
                    107:
                    108:        if ((sc = gre_lookup(m, proto)) == NULL) {
                    109:                /* No matching tunnel or tunnel is down. */
                    110:                return (0);
                    111:        }
                    112:
                    113:        if (m->m_len < sizeof(*gip)) {
                    114:                m = m_pullup(m, sizeof(*gip));
                    115:                if (m == NULL)
                    116:                        return (ENOBUFS);
                    117:        }
                    118:        gip = mtod(m, struct greip *);
                    119:
                    120:        m->m_pkthdr.rcvif = &sc->sc_if;
                    121:
                    122:        sc->sc_if.if_ipackets++;
                    123:        sc->sc_if.if_ibytes += m->m_pkthdr.len;
                    124:
                    125:        switch (proto) {
                    126:        case IPPROTO_GRE:
                    127:                hlen += sizeof (struct gre_h);
                    128:
                    129:                /* process GRE flags as packet can be of variable len */
                    130:                flags = ntohs(gip->gi_flags);
                    131:
                    132:                /* Checksum & Offset are present */
                    133:                if ((flags & GRE_CP) | (flags & GRE_RP))
                    134:                        hlen += 4;
                    135:
                    136:                /* We don't support routing fields (variable length) */
                    137:                if (flags & GRE_RP)
                    138:                        return (0);
                    139:
                    140:                if (flags & GRE_KP)
                    141:                        hlen += 4;
                    142:
                    143:                if (flags & GRE_SP)
                    144:                        hlen += 4;
                    145:
                    146:                switch (ntohs(gip->gi_ptype)) { /* ethertypes */
                    147:                case GREPROTO_WCCP:
                    148:                        /* WCCP/GRE:
                    149:                         *   So far as I can see (and test) it seems that Cisco's WCCP
                    150:                         *   GRE tunnel is precisely a IP-in-GRE tunnel that differs
                    151:                         *   only in its protocol number.  At least, it works for me.
                    152:                         *
                    153:                         *   The Internet Draft can be found if you look for
                    154:                         *     draft-forster-wrec-wccp-v1-00.txt
                    155:                         *
                    156:                         *   So yes, we're doing a fall-through (unless, of course,
                    157:                         *   net.inet.gre.wccp is 0).
                    158:                         */
                    159:                        if (!gre_wccp)
                    160:                                return (0);
                    161:                case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */
                    162:                        ifq = &ipintrq;          /* we are in ip_input */
                    163:                        af = AF_INET;
                    164:                        break;
                    165: #ifdef NETATALK
                    166:                case ETHERTYPE_AT:
                    167:                        ifq = &atintrq1;
                    168:                        schednetisr(NETISR_ATALK);
                    169:                        af = AF_APPLETALK;
                    170:                        break;
                    171: #endif
                    172: #ifdef INET6
                    173:                case ETHERTYPE_IPV6:
                    174:                        ifq = &ip6intrq;
                    175:                        schednetisr(NETISR_IPV6);
                    176:                        af = AF_INET6;
                    177:                        break;
                    178: #endif /* INET6 */
                    179:                default:           /* others not yet supported */
                    180:                        return (0);
                    181:                }
                    182:                break;
                    183:        default:
                    184:                /* others not yet supported */
                    185:                return (0);
                    186:        }
                    187:
                    188:        if (hlen > m->m_pkthdr.len) {
                    189:                m_freem(m);
                    190:                return (EINVAL);
                    191:        }
                    192:        m_adj(m, hlen);
                    193:
                    194: #if NBPFILTER > 0
                    195:         if (sc->sc_if.if_bpf)
                    196:                bpf_mtap_af(sc->sc_if.if_bpf, af, m, BPF_DIRECTION_IN);
                    197: #endif
                    198:
                    199:        s = splnet();           /* possible */
                    200:        IF_INPUT_ENQUEUE(ifq, m);
                    201:        splx(s);
                    202:
                    203:        return (1);     /* packet is done, no further processing needed */
                    204: }
                    205:
                    206: /*
                    207:  * Decapsulate a packet and feed it back through ip_input (this
                    208:  * routine is called whenever IP gets a packet with proto type
                    209:  * IPPROTO_GRE and a local destination address).
                    210:  */
                    211: void
                    212: gre_input(struct mbuf *m, ...)
                    213: {
                    214:        int hlen, ret;
                    215:        va_list ap;
                    216:
                    217:        va_start(ap, m);
                    218:        hlen = va_arg(ap, int);
                    219:        va_end(ap);
                    220:
                    221:        if (!gre_allow) {
                    222:                m_freem(m);
                    223:                return;
                    224:        }
                    225:
                    226:        ret = gre_input2(m, hlen, IPPROTO_GRE);
                    227:        /*
                    228:         * ret == 0: packet not processed, but input from here
                    229:         * means no matching tunnel that is up is found.
                    230:         * we inject it to raw ip socket to see if anyone picks it up.
                    231:         * possible that we received a WCCPv1-style GRE packet
                    232:         * but we're not set to accept them.
                    233:         */
                    234:        if (!ret)
                    235:                rip_input(m, hlen, IPPROTO_GRE);
                    236: }
                    237:
                    238: /*
                    239:  * Input routine for IPPRPOTO_MOBILE.
                    240:  * This is a little bit diffrent from the other modes, as the
                    241:  * encapsulating header was not prepended, but instead inserted
                    242:  * between IP header and payload.
                    243:  */
                    244:
                    245: void
                    246: gre_mobile_input(struct mbuf *m, ...)
                    247: {
                    248:        struct ip *ip;
                    249:        struct mobip_h *mip;
                    250:        struct ifqueue *ifq;
                    251:        struct gre_softc *sc;
                    252:        int hlen, s;
                    253:        va_list ap;
                    254:        u_char osrc = 0;
                    255:        int msiz;
                    256:
                    257:        va_start(ap, m);
                    258:        hlen = va_arg(ap, int);
                    259:        va_end(ap);
                    260:
                    261:        if (!ip_mobile_allow) {
                    262:                m_freem(m);
                    263:                return;
                    264:        }
                    265:
                    266:        if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) {
                    267:                /* No matching tunnel or tunnel is down. */
                    268:                m_freem(m);
                    269:                return;
                    270:        }
                    271:
                    272:        if (m->m_len < sizeof(*mip)) {
                    273:                m = m_pullup(m, sizeof(*mip));
                    274:                if (m == NULL)
                    275:                        return;
                    276:        }
                    277:        ip = mtod(m, struct ip *);
                    278:        mip = mtod(m, struct mobip_h *);
                    279:
                    280:        m->m_pkthdr.rcvif = &sc->sc_if;
                    281:
                    282:        sc->sc_if.if_ipackets++;
                    283:        sc->sc_if.if_ibytes += m->m_pkthdr.len;
                    284:
                    285:        if (ntohs(mip->mh.proto) & MOB_H_SBIT) {
                    286:                osrc = 1;
                    287:                msiz = MOB_H_SIZ_L;
                    288:                mip->mi.ip_src.s_addr = mip->mh.osrc;
                    289:        } else
                    290:                msiz = MOB_H_SIZ_S;
                    291:
                    292:        if (m->m_len < (ip->ip_hl << 2) + msiz) {
                    293:                m = m_pullup(m, (ip->ip_hl << 2) + msiz);
                    294:                if (m == NULL)
                    295:                        return;
                    296:                ip = mtod(m, struct ip *);
                    297:                mip = mtod(m, struct mobip_h *);
                    298:        }
                    299:
                    300:        mip->mi.ip_dst.s_addr = mip->mh.odst;
                    301:        mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8);
                    302:
                    303:        if (gre_in_cksum((u_short *) &mip->mh, msiz) != 0) {
                    304:                m_freem(m);
                    305:                return;
                    306:        }
                    307:
                    308:        bcopy(ip + (ip->ip_hl << 2) + msiz, ip + (ip->ip_hl << 2),
                    309:              m->m_len - msiz - (ip->ip_hl << 2));
                    310:
                    311:        m->m_len -= msiz;
                    312:        ip->ip_len = htons(ntohs(ip->ip_len) - msiz);
                    313:        m->m_pkthdr.len -= msiz;
                    314:
                    315:        ip->ip_sum = 0;
                    316:        ip->ip_sum = in_cksum(m,(ip->ip_hl << 2));
                    317:
                    318:        ifq = &ipintrq;
                    319:
                    320: #if NBPFILTER > 0
                    321:         if (sc->sc_if.if_bpf)
                    322:                bpf_mtap_af(sc->sc_if.if_bpf, AF_INET, m, BPF_DIRECTION_IN);
                    323: #endif
                    324:
                    325:        s = splnet();       /* possible */
                    326:        IF_INPUT_ENQUEUE(ifq, m);
                    327:        splx(s);
                    328: }
                    329:
                    330: /*
                    331:  * Find the gre interface associated with our src/dst/proto set.
                    332:  */
                    333: struct gre_softc *
                    334: gre_lookup(m, proto)
                    335:        struct mbuf *m;
                    336:        u_int8_t proto;
                    337: {
                    338:        struct ip *ip = mtod(m, struct ip *);
                    339:        struct gre_softc *sc;
                    340:
                    341:        LIST_FOREACH(sc, &gre_softc_list, sc_list) {
                    342:                if ((sc->g_dst.s_addr == ip->ip_src.s_addr) &&
                    343:                    (sc->g_src.s_addr == ip->ip_dst.s_addr) &&
                    344:                    (sc->g_proto == proto) &&
                    345:                    ((sc->sc_if.if_flags & IFF_UP) != 0))
                    346:                        return (sc);
                    347:        }
                    348:
                    349:        return (NULL);
                    350: }
                    351:
                    352: int
                    353: gre_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
                    354:         int *name;
                    355:         u_int namelen;
                    356:         void *oldp;
                    357:         size_t *oldlenp;
                    358:         void *newp;
                    359:         size_t newlen;
                    360: {
                    361:         /* All sysctl names at this level are terminal. */
                    362:         if (namelen != 1)
                    363:                 return (ENOTDIR);
                    364:
                    365:         switch (name[0]) {
                    366:         case GRECTL_ALLOW:
                    367:                 return (sysctl_int(oldp, oldlenp, newp, newlen, &gre_allow));
                    368:         case GRECTL_WCCP:
                    369:                 return (sysctl_int(oldp, oldlenp, newp, newlen, &gre_wccp));
                    370:         default:
                    371:                 return (ENOPROTOOPT);
                    372:         }
                    373:         /* NOTREACHED */
                    374: }
                    375:
                    376: int
                    377: ipmobile_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
                    378:         int *name;
                    379:         u_int namelen;
                    380:         void *oldp;
                    381:         size_t *oldlenp;
                    382:         void *newp;
                    383:         size_t newlen;
                    384: {
                    385:         /* All sysctl names at this level are terminal. */
                    386:         if (namelen != 1)
                    387:                 return (ENOTDIR);
                    388:
                    389:         switch (name[0]) {
                    390:         case MOBILEIPCTL_ALLOW:
                    391:                 return (sysctl_int(oldp, oldlenp, newp, newlen,
                    392:                                   &ip_mobile_allow));
                    393:         default:
                    394:                 return (ENOPROTOOPT);
                    395:         }
                    396:         /* NOTREACHED */
                    397: }
                    398: #endif /* if NGRE > 0 */

CVSweb