[BACK]Return to if_gre.c CVS log [TXT][DIR] Up to [local] / sys / net

Annotation of sys/net/if_gre.c, Revision 1.1.1.1

1.1       nbrk        1: /*      $OpenBSD: if_gre.c,v 1.41 2006/05/28 04:30:16 claudio Exp $ */
                      2: /*     $NetBSD: if_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:  * IPv6-over-GRE contributed by Gert Doering <gert@greenie.muc.de>
                     12:  *
                     13:  * Redistribution and use in source and binary forms, with or without
                     14:  * modification, are permitted provided that the following conditions
                     15:  * are met:
                     16:  * 1. Redistributions of source code must retain the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer.
                     18:  * 2. Redistributions in binary form must reproduce the above copyright
                     19:  *    notice, this list of conditions and the following disclaimer in the
                     20:  *    documentation and/or other materials provided with the distribution.
                     21:  * 3. All advertising materials mentioning features or use of this software
                     22:  *    must display the following acknowledgement:
                     23:  *        This product includes software developed by the NetBSD
                     24:  *        Foundation, Inc. and its contributors.
                     25:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     26:  *    contributors may be used to endorse or promote products derived
                     27:  *    from this software without specific prior written permission.
                     28:  *
                     29:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     30:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     31:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     32:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     33:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     34:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     35:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     36:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     37:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     38:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     39:  * POSSIBILITY OF SUCH DAMAGE.
                     40:  */
                     41:
                     42: /*
                     43:  * Encapsulate L3 protocols into IP, per RFC 1701 and 1702.
                     44:  * See gre(4) for more details.
                     45:  * Also supported: IP in IP encapsulation (proto 55) per RFC 2004.
                     46:  */
                     47:
                     48: #include "gre.h"
                     49: #if NGRE > 0
                     50:
                     51: #include "bpfilter.h"
                     52:
                     53: #include <sys/param.h>
                     54: #include <sys/proc.h>
                     55: #include <sys/mbuf.h>
                     56: #include <sys/socket.h>
                     57: #include <sys/sockio.h>
                     58: #include <sys/kernel.h>
                     59: #include <sys/systm.h>
                     60:
                     61: #include <net/if.h>
                     62: #include <net/if_types.h>
                     63: #include <net/netisr.h>
                     64: #include <net/route.h>
                     65:
                     66: #ifdef INET
                     67: #include <netinet/in.h>
                     68: #include <netinet/in_systm.h>
                     69: #include <netinet/in_var.h>
                     70: #include <netinet/ip.h>
                     71: #include <netinet/ip_var.h>
                     72: #include <netinet/if_ether.h>
                     73: #else
                     74: #error "if_gre used without inet"
                     75: #endif
                     76:
                     77: #ifdef NETATALK
                     78: #include <netatalk/at.h>
                     79: #include <netatalk/at_var.h>
                     80: #include <netatalk/at_extern.h>
                     81: #endif
                     82:
                     83: #if NBPFILTER > 0
                     84: #include <net/bpf.h>
                     85: #endif
                     86:
                     87: #include <net/if_gre.h>
                     88:
                     89: #ifndef GRE_RECURSION_LIMIT
                     90: #define GRE_RECURSION_LIMIT    3   /* How many levels of recursion allowed */
                     91: #endif /* GRE_RECURSION_LIMIT */
                     92:
                     93: /*
                     94:  * It is not easy to calculate the right value for a GRE MTU.
                     95:  * We leave this task to the admin and use the same default that
                     96:  * other vendors use.
                     97:  */
                     98: #define GREMTU 1476
                     99:
                    100: int    gre_clone_create(struct if_clone *, int);
                    101: int    gre_clone_destroy(struct ifnet *);
                    102:
                    103: struct gre_softc_head gre_softc_list;
                    104: struct if_clone gre_cloner =
                    105:     IF_CLONE_INITIALIZER("gre", gre_clone_create, gre_clone_destroy);
                    106:
                    107: /*
                    108:  * We can control the acceptance of GRE and MobileIP packets by
                    109:  * altering the sysctl net.inet.gre.allow and net.inet.mobileip.allow values
                    110:  * respectively. Zero means drop them, all else is acceptance.  We can also
                    111:  * control acceptance of WCCPv1-style GRE packets through the
                    112:  * net.inet.gre.wccp value, but be aware it depends upon normal GRE being
                    113:  * allowed as well.
                    114:  *
                    115:  */
                    116: int gre_allow = 0;
                    117: int gre_wccp = 0;
                    118: int ip_mobile_allow = 0;
                    119:
                    120: static void gre_compute_route(struct gre_softc *sc);
                    121:
                    122: void
                    123: greattach(int n)
                    124: {
                    125:        LIST_INIT(&gre_softc_list);
                    126:        if_clone_attach(&gre_cloner);
                    127: }
                    128:
                    129: int
                    130: gre_clone_create(struct if_clone *ifc, int unit)
                    131: {
                    132:        struct gre_softc *sc;
                    133:        int s;
                    134:
                    135:        sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
                    136:        if (!sc)
                    137:                return (ENOMEM);
                    138:        bzero(sc, sizeof(*sc));
                    139:        snprintf(sc->sc_if.if_xname, sizeof sc->sc_if.if_xname, "%s%d",
                    140:            ifc->ifc_name, unit);
                    141:        sc->sc_if.if_softc = sc;
                    142:        sc->sc_if.if_type = IFT_TUNNEL;
                    143:        sc->sc_if.if_addrlen = 0;
                    144:        sc->sc_if.if_hdrlen = 24; /* IP + GRE */
                    145:        sc->sc_if.if_mtu = GREMTU;
                    146:        sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
                    147:        sc->sc_if.if_output = gre_output;
                    148:        sc->sc_if.if_ioctl = gre_ioctl;
                    149:        sc->sc_if.if_collisions = 0;
                    150:        sc->sc_if.if_ierrors = 0;
                    151:        sc->sc_if.if_oerrors = 0;
                    152:        sc->sc_if.if_ipackets = 0;
                    153:        sc->sc_if.if_opackets = 0;
                    154:        sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY;
                    155:        sc->g_proto = IPPROTO_GRE;
                    156:        sc->sc_if.if_flags |= IFF_LINK0;
                    157:
                    158:        if_attach(&sc->sc_if);
                    159:        if_alloc_sadl(&sc->sc_if);
                    160:
                    161: #if NBPFILTER > 0
                    162:        bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_NULL,
                    163:            sizeof(u_int32_t));
                    164: #endif
                    165:        s = splnet();
                    166:        LIST_INSERT_HEAD(&gre_softc_list, sc, sc_list);
                    167:        splx(s);
                    168:
                    169:        return (0);
                    170: }
                    171:
                    172: int
                    173: gre_clone_destroy(struct ifnet *ifp)
                    174: {
                    175:        struct gre_softc *sc = ifp->if_softc;
                    176:        int s;
                    177:
                    178:        s = splnet();
                    179:        LIST_REMOVE(sc, sc_list);
                    180:        splx(s);
                    181:
                    182:        if_detach(ifp);
                    183:
                    184:        free(sc, M_DEVBUF);
                    185:        return (0);
                    186: }
                    187:
                    188: /*
                    189:  * The output routine. Takes a packet and encapsulates it in the protocol
                    190:  * given by sc->g_proto. See also RFC 1701 and RFC 2004.
                    191:  */
                    192:
                    193: int
                    194: gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
                    195:           struct rtentry *rt)
                    196: {
                    197:        int error = 0;
                    198:        struct gre_softc *sc = (struct gre_softc *) (ifp->if_softc);
                    199:        struct greip *gh = NULL;
                    200:        struct ip *inp = NULL;
                    201:        u_int8_t ip_tos = 0;
                    202:        u_int16_t etype = 0;
                    203:        struct mobile_h mob_h;
                    204:        struct m_tag *mtag;
                    205:
                    206:        if ((ifp->if_flags & IFF_UP) == 0 ||
                    207:            sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
                    208:                m_freem(m);
                    209:                error = ENETDOWN;
                    210:                goto end;
                    211:        }
                    212:
                    213:        /* Try to limit infinite recursion through misconfiguration. */
                    214:        for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag;
                    215:             mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) {
                    216:                if (!bcmp((caddr_t)(mtag + 1), &ifp, sizeof(struct ifnet *))) {
                    217:                        IF_DROP(&ifp->if_snd);
                    218:                        m_freem(m);
                    219:                        error = EIO;
                    220:                        goto end;
                    221:                }
                    222:        }
                    223:
                    224:        mtag = m_tag_get(PACKET_TAG_GRE, sizeof(struct ifnet *), M_NOWAIT);
                    225:        if (mtag == NULL) {
                    226:                IF_DROP(&ifp->if_snd);
                    227:                m_freem(m);
                    228:                error = ENOBUFS;
                    229:                goto end;
                    230:        }
                    231:        bcopy(&ifp, (caddr_t)(mtag + 1), sizeof(struct ifnet *));
                    232:        m_tag_prepend(m, mtag);
                    233:
                    234:        m->m_flags &= ~(M_BCAST|M_MCAST);
                    235:
                    236: #if NBPFILTER >0
                    237:        if (ifp->if_bpf)
                    238:                bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT);
                    239: #endif
                    240:
                    241:        if (sc->g_proto == IPPROTO_MOBILE) {
                    242:                if (ip_mobile_allow == 0) {
                    243:                        IF_DROP(&ifp->if_snd);
                    244:                        m_freem(m);
                    245:                        error = EACCES;
                    246:                        goto end;
                    247:                }
                    248:
                    249:                if (dst->sa_family == AF_INET) {
                    250:                        struct mbuf *m0;
                    251:                        int msiz;
                    252:
                    253:                        /*
                    254:                         * Make sure the complete IP header (with options)
                    255:                         * is in the first mbuf.
                    256:                         */
                    257:                        if (m->m_len < sizeof(struct ip)) {
                    258:                                m = m_pullup(m, sizeof(struct ip));
                    259:                                if (m == NULL) {
                    260:                                        IF_DROP(&ifp->if_snd);
                    261:                                        error = ENOBUFS;
                    262:                                        goto end;
                    263:                                } else
                    264:                                        inp = mtod(m, struct ip *);
                    265:
                    266:                                if (m->m_len < inp->ip_hl << 2) {
                    267:                                        m = m_pullup(m, inp->ip_hl << 2);
                    268:                                        if (m == NULL) {
                    269:                                                IF_DROP(&ifp->if_snd);
                    270:                                                error = ENOBUFS;
                    271:                                                goto end;
                    272:                                        }
                    273:                                }
                    274:                        }
                    275:
                    276:                        inp = mtod(m, struct ip *);
                    277:
                    278:                        bzero(&mob_h, MOB_H_SIZ_L);
                    279:                        mob_h.proto = (inp->ip_p) << 8;
                    280:                        mob_h.odst = inp->ip_dst.s_addr;
                    281:                        inp->ip_dst.s_addr = sc->g_dst.s_addr;
                    282:
                    283:                        /*
                    284:                         * If the packet comes from our host, we only change
                    285:                         * the destination address in the IP header.
                    286:                         * Otherwise we need to save and change the source.
                    287:                         */
                    288:                        if (inp->ip_src.s_addr == sc->g_src.s_addr) {
                    289:                                msiz = MOB_H_SIZ_S;
                    290:                        } else {
                    291:                                mob_h.proto |= MOB_H_SBIT;
                    292:                                mob_h.osrc = inp->ip_src.s_addr;
                    293:                                inp->ip_src.s_addr = sc->g_src.s_addr;
                    294:                                msiz = MOB_H_SIZ_L;
                    295:                        }
                    296:
                    297:                        HTONS(mob_h.proto);
                    298:                        mob_h.hcrc = gre_in_cksum((u_int16_t *) &mob_h, msiz);
                    299:
                    300:                        /* Squeeze in the mobility header */
                    301:                        if ((m->m_data - msiz) < m->m_pktdat) {
                    302:                                /* Need new mbuf */
                    303:                                MGETHDR(m0, M_DONTWAIT, MT_HEADER);
                    304:                                if (m0 == NULL) {
                    305:                                        IF_DROP(&ifp->if_snd);
                    306:                                        m_freem(m);
                    307:                                        error = ENOBUFS;
                    308:                                        goto end;
                    309:                                }
                    310:                                M_MOVE_HDR(m0, m);
                    311:
                    312:                                m0->m_len = msiz + (inp->ip_hl << 2);
                    313:                                m0->m_data += max_linkhdr;
                    314:                                m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
                    315:                                m->m_data += inp->ip_hl << 2;
                    316:                                m->m_len -= inp->ip_hl << 2;
                    317:
                    318:                                bcopy((caddr_t) inp, mtod(m0, caddr_t),
                    319:                                    sizeof(struct ip));
                    320:
                    321:                                m0->m_next = m;
                    322:                                m = m0;
                    323:                        } else {  /* we have some space left in the old one */
                    324:                                m->m_data -= msiz;
                    325:                                m->m_len += msiz;
                    326:                                m->m_pkthdr.len += msiz;
                    327:                                bcopy(inp, mtod(m, caddr_t),
                    328:                                    inp->ip_hl << 2);
                    329:                        }
                    330:
                    331:                        /* Copy Mobility header */
                    332:                        inp = mtod(m, struct ip *);
                    333:                        bcopy(&mob_h, (caddr_t)(inp + 1), (unsigned) msiz);
                    334:                        inp->ip_len = htons(ntohs(inp->ip_len) + msiz);
                    335:                } else {  /* AF_INET */
                    336:                        IF_DROP(&ifp->if_snd);
                    337:                        m_freem(m);
                    338:                        error = EINVAL;
                    339:                        goto end;
                    340:                }
                    341:        } else if (sc->g_proto == IPPROTO_GRE) {
                    342:                if (gre_allow == 0) {
                    343:                        IF_DROP(&ifp->if_snd);
                    344:                        m_freem(m);
                    345:                        error = EACCES;
                    346:                        goto end;
                    347:                }
                    348:
                    349:                switch(dst->sa_family) {
                    350:                case AF_INET:
                    351:                        if (m->m_len < sizeof(struct ip)) {
                    352:                                m = m_pullup(m, sizeof(struct ip));
                    353:                                if (m == NULL) {
                    354:                                        IF_DROP(&ifp->if_snd);
                    355:                                        error = ENOBUFS;
                    356:                                        goto end;
                    357:                                }
                    358:                        }
                    359:
                    360:                        inp = mtod(m, struct ip *);
                    361:                        ip_tos = inp->ip_tos;
                    362:                        etype = ETHERTYPE_IP;
                    363:                        break;
                    364: #ifdef NETATALK
                    365:                case AF_APPLETALK:
                    366:                        etype = ETHERTYPE_AT;
                    367:                        break;
                    368: #endif
                    369: #ifdef INET6
                    370:                case AF_INET6:
                    371:                        etype = ETHERTYPE_IPV6;
                    372:                        break;
                    373: #endif
                    374:                default:
                    375:                        IF_DROP(&ifp->if_snd);
                    376:                        m_freem(m);
                    377:                        error = EAFNOSUPPORT;
                    378:                        goto end;
                    379:                }
                    380:
                    381:                M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
                    382:        } else {
                    383:                IF_DROP(&ifp->if_snd);
                    384:                m_freem(m);
                    385:                error = EINVAL;
                    386:                goto end;
                    387:        }
                    388:
                    389:        if (m == NULL) {
                    390:                IF_DROP(&ifp->if_snd);
                    391:                error = ENOBUFS;
                    392:                goto end;
                    393:        }
                    394:
                    395:        gh = mtod(m, struct greip *);
                    396:        if (sc->g_proto == IPPROTO_GRE) {
                    397:                /* We don't support any GRE flags for now */
                    398:
                    399:                bzero((void *) &gh->gi_g, sizeof(struct gre_h));
                    400:                gh->gi_ptype = htons(etype);
                    401:        }
                    402:
                    403:        gh->gi_pr = sc->g_proto;
                    404:        if (sc->g_proto != IPPROTO_MOBILE) {
                    405:                gh->gi_src = sc->g_src;
                    406:                gh->gi_dst = sc->g_dst;
                    407:                ((struct ip *) gh)->ip_hl = (sizeof(struct ip)) >> 2;
                    408:                ((struct ip *) gh)->ip_ttl = ip_defttl;
                    409:                ((struct ip *) gh)->ip_tos = ip_tos;
                    410:                gh->gi_len = htons(m->m_pkthdr.len);
                    411:        }
                    412:
                    413:        ifp->if_opackets++;
                    414:        ifp->if_obytes += m->m_pkthdr.len;
                    415:
                    416:        /* Send it off */
                    417:        error = ip_output(m, (void *)NULL, &sc->route, 0, (void *)NULL, (void *)NULL);
                    418:   end:
                    419:        if (error)
                    420:                ifp->if_oerrors++;
                    421:        return (error);
                    422: }
                    423:
                    424: int
                    425: gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
                    426: {
                    427:
                    428:        struct ifreq *ifr = (struct ifreq *) data;
                    429:        struct if_laddrreq *lifr = (struct if_laddrreq *)data;
                    430:        struct gre_softc *sc = ifp->if_softc;
                    431:        int s;
                    432:        struct sockaddr_in si;
                    433:        struct sockaddr *sa = NULL;
                    434:        int error = 0;
                    435:        struct proc *prc = curproc;             /* XXX */
                    436:
                    437:        s = splnet();
                    438:        switch(cmd) {
                    439:        case SIOCSIFADDR:
                    440:                ifp->if_flags |= IFF_UP;
                    441:                break;
                    442:        case SIOCSIFDSTADDR:
                    443:                break;
                    444:        case SIOCSIFFLAGS:
                    445:                if ((ifr->ifr_flags & IFF_LINK0) != 0)
                    446:                        sc->g_proto = IPPROTO_GRE;
                    447:                else
                    448:                        sc->g_proto = IPPROTO_MOBILE;
                    449:                break;
                    450:        case SIOCSIFMTU:
                    451:                if (ifr->ifr_mtu < 576) {
                    452:                        error = EINVAL;
                    453:                        break;
                    454:                }
                    455:                ifp->if_mtu = ifr->ifr_mtu;
                    456:                break;
                    457:        case SIOCGIFMTU:
                    458:                ifr->ifr_mtu = sc->sc_if.if_mtu;
                    459:                break;
                    460:        case SIOCADDMULTI:
                    461:        case SIOCDELMULTI:
                    462:                if (ifr == 0) {
                    463:                        error = EAFNOSUPPORT;
                    464:                        break;
                    465:                }
                    466:                switch (ifr->ifr_addr.sa_family) {
                    467: #ifdef INET
                    468:                case AF_INET:
                    469:                        break;
                    470: #endif
                    471: #ifdef INET6
                    472:                case AF_INET6:
                    473:                        break;
                    474: #endif
                    475:                default:
                    476:                        error = EAFNOSUPPORT;
                    477:                        break;
                    478:                }
                    479:                break;
                    480:        case GRESPROTO:
                    481:                /* Check for superuser */
                    482:                if ((error = suser(prc, 0)) != 0)
                    483:                        break;
                    484:
                    485:                sc->g_proto = ifr->ifr_flags;
                    486:                switch (sc->g_proto) {
                    487:                case IPPROTO_GRE:
                    488:                        ifp->if_flags |= IFF_LINK0;
                    489:                        break;
                    490:                case IPPROTO_MOBILE:
                    491:                        ifp->if_flags &= ~IFF_LINK0;
                    492:                        break;
                    493:                default:
                    494:                        error = EPROTONOSUPPORT;
                    495:                        break;
                    496:                }
                    497:                break;
                    498:        case GREGPROTO:
                    499:                ifr->ifr_flags = sc->g_proto;
                    500:                break;
                    501:        case GRESADDRS:
                    502:        case GRESADDRD:
                    503:                /* Check for superuser */
                    504:                if ((error = suser(prc, 0)) != 0)
                    505:                        break;
                    506:
                    507:                /*
                    508:                 * set tunnel endpoints, compute a less specific route
                    509:                 * to the remote end and mark if as up
                    510:                 */
                    511:                sa = &ifr->ifr_addr;
                    512:                if (cmd == GRESADDRS )
                    513:                        sc->g_src = (satosin(sa))->sin_addr;
                    514:                if (cmd == GRESADDRD )
                    515:                        sc->g_dst = (satosin(sa))->sin_addr;
                    516:        recompute:
                    517:                if ((sc->g_src.s_addr != INADDR_ANY) &&
                    518:                    (sc->g_dst.s_addr != INADDR_ANY)) {
                    519:                        if (sc->route.ro_rt != 0) {
                    520:                                /* free old route */
                    521:                                RTFREE(sc->route.ro_rt);
                    522:                                sc->route.ro_rt = (struct rtentry *) 0;
                    523:                        }
                    524:                        gre_compute_route(sc);
                    525:                        ifp->if_flags |= IFF_UP;
                    526:                }
                    527:                break;
                    528:        case GREGADDRS:
                    529:                bzero(&si, sizeof(si));
                    530:                si.sin_family = AF_INET;
                    531:                si.sin_len = sizeof(struct sockaddr_in);
                    532:                si.sin_addr.s_addr = sc->g_src.s_addr;
                    533:                sa = sintosa(&si);
                    534:                ifr->ifr_addr = *sa;
                    535:                break;
                    536:        case GREGADDRD:
                    537:                bzero(&si, sizeof(si));
                    538:                si.sin_family = AF_INET;
                    539:                si.sin_len = sizeof(struct sockaddr_in);
                    540:                si.sin_addr.s_addr = sc->g_dst.s_addr;
                    541:                sa = sintosa(&si);
                    542:                ifr->ifr_addr = *sa;
                    543:                break;
                    544:        case SIOCSLIFPHYADDR:
                    545:                if ((error = suser(prc, 0)) != 0)
                    546:                        break;
                    547:                if (lifr->addr.ss_family != AF_INET ||
                    548:                    lifr->dstaddr.ss_family != AF_INET) {
                    549:                        error = EAFNOSUPPORT;
                    550:                        break;
                    551:                }
                    552:                if (lifr->addr.ss_len != sizeof(si) ||
                    553:                    lifr->dstaddr.ss_len != sizeof(si)) {
                    554:                        error = EINVAL;
                    555:                        break;
                    556:                }
                    557:                sc->g_src = (satosin((struct sockadrr *)&lifr->addr))->sin_addr;
                    558:                sc->g_dst =
                    559:                    (satosin((struct sockadrr *)&lifr->dstaddr))->sin_addr;
                    560:                goto recompute;
                    561:        case SIOCDIFPHYADDR:
                    562:                if ((error = suser(prc, 0)) != 0)
                    563:                        break;
                    564:                sc->g_src.s_addr = INADDR_ANY;
                    565:                sc->g_dst.s_addr = INADDR_ANY;
                    566:                break;
                    567:        case SIOCGLIFPHYADDR:
                    568:                if (sc->g_src.s_addr == INADDR_ANY ||
                    569:                    sc->g_dst.s_addr == INADDR_ANY) {
                    570:                        error = EADDRNOTAVAIL;
                    571:                        break;
                    572:                }
                    573:                bzero(&si, sizeof(si));
                    574:                si.sin_family = AF_INET;
                    575:                si.sin_len = sizeof(struct sockaddr_in);
                    576:                si.sin_addr.s_addr = sc->g_src.s_addr;
                    577:                memcpy(&lifr->addr, &si, sizeof(si));
                    578:                si.sin_addr.s_addr = sc->g_dst.s_addr;
                    579:                memcpy(&lifr->dstaddr, &si, sizeof(si));
                    580:                break;
                    581:        default:
                    582:                error = EINVAL;
                    583:        }
                    584:
                    585:        splx(s);
                    586:        return (error);
                    587: }
                    588:
                    589: /*
                    590:  * computes a route to our destination that is not the one
                    591:  * which would be taken by ip_output(), as this one will loop back to
                    592:  * us. If the interface is p2p as  a--->b, then a routing entry exists
                    593:  * If we now send a packet to b (e.g. ping b), this will come down here
                    594:  * gets src=a, dst=b tacked on and would from ip_output() sent back to
                    595:  * if_gre.
                    596:  * Goal here is to compute a route to b that is less specific than
                    597:  * a-->b. We know that this one exists as in normal operation we have
                    598:  * at least a default route which matches.
                    599:  */
                    600:
                    601: static void
                    602: gre_compute_route(struct gre_softc *sc)
                    603: {
                    604:        struct route *ro;
                    605:        u_int32_t a, b, c;
                    606:
                    607:        ro = &sc->route;
                    608:
                    609:        bzero(ro, sizeof(struct route));
                    610:        ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = sc->g_dst;
                    611:        ro->ro_dst.sa_family = AF_INET;
                    612:        ro->ro_dst.sa_len = sizeof(ro->ro_dst);
                    613:
                    614:        /*
                    615:         * toggle last bit, so our interface is not found, but a less
                    616:         * specific route. I'd rather like to specify a shorter mask,
                    617:         * but this is not possible. Should work though. XXX
                    618:         * there is a simpler way ...
                    619:         */
                    620:        if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
                    621:                a = ntohl(sc->g_dst.s_addr);
                    622:                b = a & 0x01;
                    623:                c = a & 0xfffffffe;
                    624:                b = b ^ 0x01;
                    625:                a = b | c;
                    626:                ((struct sockaddr_in *) &ro->ro_dst)->sin_addr.s_addr = htonl(a);
                    627:        }
                    628:
                    629:        rtalloc(ro);
                    630:        if (ro->ro_rt == 0)
                    631:                return;
                    632:
                    633:        /*
                    634:         * Check whether we just created a loop. An even more paranoid
                    635:         * check would be against all GRE interfaces, but that would
                    636:         * not allow people to link GRE tunnels.
                    637:         */
                    638:        if (ro->ro_rt->rt_ifp == &sc->sc_if) {
                    639:                RTFREE(ro->ro_rt);
                    640:                ro->ro_rt = (struct rtentry *) 0;
                    641:                return;
                    642:        }
                    643:
                    644:        /*
                    645:         * now change it back - else ip_output will just drop
                    646:         * the route and search one to this interface ...
                    647:         */
                    648:        if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
                    649:                ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = sc->g_dst;
                    650: }
                    651:
                    652: /*
                    653:  * do a checksum of a buffer - much like in_cksum, which operates on
                    654:  * mbufs.
                    655:  */
                    656: u_int16_t
                    657: gre_in_cksum(u_int16_t *p, u_int len)
                    658: {
                    659:        u_int32_t sum = 0;
                    660:        int nwords = len >> 1;
                    661:
                    662:        while (nwords-- != 0)
                    663:                sum += *p++;
                    664:
                    665:                if (len & 1) {
                    666:                        union {
                    667:                                u_short w;
                    668:                                u_char c[2];
                    669:                        } u;
                    670:                        u.c[0] = *(u_char *) p;
                    671:                        u.c[1] = 0;
                    672:                        sum += u.w;
                    673:                }
                    674:
                    675:                /* end-around-carry */
                    676:                sum = (sum >> 16) + (sum & 0xffff);
                    677:                sum += (sum >> 16);
                    678:                return (~sum);
                    679: }
                    680: #endif

CVSweb