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

Annotation of sys/netinet/ipsec_input.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ipsec_input.c,v 1.84 2007/05/28 17:16:39 henning Exp $        */
        !             2: /*
        !             3:  * The authors of this code are John Ioannidis (ji@tla.org),
        !             4:  * Angelos D. Keromytis (kermit@csd.uch.gr) and
        !             5:  * Niels Provos (provos@physnet.uni-hamburg.de).
        !             6:  *
        !             7:  * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
        !             8:  * in November 1995.
        !             9:  *
        !            10:  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
        !            11:  * by Angelos D. Keromytis.
        !            12:  *
        !            13:  * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
        !            14:  * and Niels Provos.
        !            15:  *
        !            16:  * Additional features in 1999 by Angelos D. Keromytis.
        !            17:  *
        !            18:  * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
        !            19:  * Angelos D. Keromytis and Niels Provos.
        !            20:  * Copyright (c) 2001, Angelos D. Keromytis.
        !            21:  *
        !            22:  * Permission to use, copy, and modify this software with or without fee
        !            23:  * is hereby granted, provided that this entire notice is included in
        !            24:  * all copies of any software which is or includes a copy or
        !            25:  * modification of this software.
        !            26:  * You may use this code under the GNU public license if you so wish. Please
        !            27:  * contribute changes back to the authors under this freer than GPL license
        !            28:  * so that we may further the use of strong encryption without limitations to
        !            29:  * all.
        !            30:  *
        !            31:  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
        !            32:  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
        !            33:  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
        !            34:  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
        !            35:  * PURPOSE.
        !            36:  */
        !            37:
        !            38: #include "pf.h"
        !            39:
        !            40: #include <sys/param.h>
        !            41: #include <sys/systm.h>
        !            42: #include <sys/protosw.h>
        !            43: #include <sys/mbuf.h>
        !            44: #include <sys/socket.h>
        !            45: #include <sys/sysctl.h>
        !            46: #include <sys/kernel.h>
        !            47:
        !            48: #include <net/if.h>
        !            49: #include <net/netisr.h>
        !            50: #include <net/bpf.h>
        !            51:
        !            52: #if NPF > 0
        !            53: #include <net/pfvar.h>
        !            54: #endif
        !            55:
        !            56: #include <netinet/in.h>
        !            57: #include <netinet/in_systm.h>
        !            58: #include <netinet/ip.h>
        !            59: #include <netinet/ip_var.h>
        !            60: #include <netinet/in_var.h>
        !            61: #include <netinet/ip_icmp.h>
        !            62: #include <netinet/tcp.h>
        !            63: #include <netinet/udp.h>
        !            64:
        !            65: #ifdef INET6
        !            66: #ifndef INET
        !            67: #include <netinet/in.h>
        !            68: #endif
        !            69: #include <netinet/ip6.h>
        !            70: #include <netinet6/ip6_var.h>
        !            71: #include <netinet6/ip6protosw.h>
        !            72: #endif /* INET6 */
        !            73:
        !            74: #include <netinet/ip_ipsp.h>
        !            75: #include <netinet/ip_esp.h>
        !            76: #include <netinet/ip_ah.h>
        !            77: #include <netinet/ip_ipcomp.h>
        !            78:
        !            79: #include <net/if_enc.h>
        !            80:
        !            81: #include "bpfilter.h"
        !            82:
        !            83: void *ipsec_common_ctlinput(int, struct sockaddr *, void *, int);
        !            84:
        !            85: #ifdef ENCDEBUG
        !            86: #define DPRINTF(x)     if (encdebug) printf x
        !            87: #else
        !            88: #define DPRINTF(x)
        !            89: #endif
        !            90:
        !            91: /* sysctl variables */
        !            92: int esp_enable = 1;
        !            93: int ah_enable = 1;
        !            94: int ipcomp_enable = 0;
        !            95:
        !            96: int *espctl_vars[ESPCTL_MAXID] = ESPCTL_VARS;
        !            97: int *ahctl_vars[AHCTL_MAXID] = AHCTL_VARS;
        !            98: int *ipcompctl_vars[IPCOMPCTL_MAXID] = IPCOMPCTL_VARS;
        !            99:
        !           100: #ifdef INET6
        !           101: extern struct ip6protosw inet6sw[];
        !           102: extern u_char ip6_protox[];
        !           103: #endif
        !           104:
        !           105: /*
        !           106:  * ipsec_common_input() gets called when we receive an IPsec-protected packet
        !           107:  * in IPv4 or IPv6. All it does is find the right TDB and call the appropriate
        !           108:  * transform. The callback takes care of further processing (like ingress
        !           109:  * filtering).
        !           110:  */
        !           111: int
        !           112: ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto,
        !           113:     int udpencap)
        !           114: {
        !           115: #define IPSEC_ISTAT(x,y,z) (sproto == IPPROTO_ESP ? (x)++ : \
        !           116:                            sproto == IPPROTO_AH ? (y)++ : (z)++)
        !           117:
        !           118:        union sockaddr_union dst_address;
        !           119:        struct timeval tv;
        !           120:        struct tdb *tdbp;
        !           121:        u_int32_t spi;
        !           122:        u_int16_t cpi;
        !           123:        int s, error;
        !           124:
        !           125:        IPSEC_ISTAT(espstat.esps_input, ahstat.ahs_input,
        !           126:            ipcompstat.ipcomps_input);
        !           127:
        !           128:        if (m == 0) {
        !           129:                DPRINTF(("ipsec_common_input(): NULL packet received\n"));
        !           130:                IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
        !           131:                    ipcompstat.ipcomps_hdrops);
        !           132:                return EINVAL;
        !           133:        }
        !           134:
        !           135:        if ((sproto == IPPROTO_ESP && !esp_enable) ||
        !           136:            (sproto == IPPROTO_AH && !ah_enable) ||
        !           137:            (sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
        !           138:                rip_input(m, skip, sproto);
        !           139:                return 0;
        !           140:        }
        !           141:
        !           142:        if (m->m_pkthdr.len - skip < 2 * sizeof(u_int32_t)) {
        !           143:                m_freem(m);
        !           144:                IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
        !           145:                    ipcompstat.ipcomps_hdrops);
        !           146:                DPRINTF(("ipsec_common_input(): packet too small\n"));
        !           147:                return EINVAL;
        !           148:        }
        !           149:
        !           150:        /* Retrieve the SPI from the relevant IPsec header */
        !           151:        if (sproto == IPPROTO_ESP)
        !           152:                m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
        !           153:        else if (sproto == IPPROTO_AH)
        !           154:                m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
        !           155:                    (caddr_t) &spi);
        !           156:        else if (sproto == IPPROTO_IPCOMP) {
        !           157:                m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t),
        !           158:                    (caddr_t) &cpi);
        !           159:                spi = ntohl(htons(cpi));
        !           160:        }
        !           161:
        !           162:        /*
        !           163:         * Find tunnel control block and (indirectly) call the appropriate
        !           164:         * kernel crypto routine. The resulting mbuf chain is a valid
        !           165:         * IP packet ready to go through input processing.
        !           166:         */
        !           167:
        !           168:        bzero(&dst_address, sizeof(dst_address));
        !           169:        dst_address.sa.sa_family = af;
        !           170:
        !           171:        switch (af) {
        !           172: #ifdef INET
        !           173:        case AF_INET:
        !           174:                dst_address.sin.sin_len = sizeof(struct sockaddr_in);
        !           175:                m_copydata(m, offsetof(struct ip, ip_dst),
        !           176:                    sizeof(struct in_addr),
        !           177:                    (caddr_t) &(dst_address.sin.sin_addr));
        !           178:                break;
        !           179: #endif /* INET */
        !           180:
        !           181: #ifdef INET6
        !           182:        case AF_INET6:
        !           183:                dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6);
        !           184:                m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
        !           185:                    sizeof(struct in6_addr),
        !           186:                    (caddr_t) &(dst_address.sin6.sin6_addr));
        !           187:                in6_recoverscope(&dst_address.sin6, &dst_address.sin6.sin6_addr,
        !           188:                    NULL);
        !           189:                break;
        !           190: #endif /* INET6 */
        !           191:
        !           192:        default:
        !           193:                DPRINTF(("ipsec_common_input(): unsupported protocol "
        !           194:                    "family %d\n", af));
        !           195:                m_freem(m);
        !           196:                IPSEC_ISTAT(espstat.esps_nopf, ahstat.ahs_nopf,
        !           197:                    ipcompstat.ipcomps_nopf);
        !           198:                return EPFNOSUPPORT;
        !           199:        }
        !           200:
        !           201:        s = spltdb();
        !           202:        tdbp = gettdb(spi, &dst_address, sproto);
        !           203:        if (tdbp == NULL) {
        !           204:                splx(s);
        !           205:                DPRINTF(("ipsec_common_input(): could not find SA for "
        !           206:                    "packet to %s, spi %08x\n",
        !           207:                    ipsp_address(dst_address), ntohl(spi)));
        !           208:                m_freem(m);
        !           209:                IPSEC_ISTAT(espstat.esps_notdb, ahstat.ahs_notdb,
        !           210:                    ipcompstat.ipcomps_notdb);
        !           211:                return ENOENT;
        !           212:        }
        !           213:
        !           214:        if (tdbp->tdb_flags & TDBF_INVALID) {
        !           215:                splx(s);
        !           216:                DPRINTF(("ipsec_common_input(): attempted to use invalid SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto));
        !           217:                m_freem(m);
        !           218:                IPSEC_ISTAT(espstat.esps_invalid, ahstat.ahs_invalid,
        !           219:                    ipcompstat.ipcomps_invalid);
        !           220:                return EINVAL;
        !           221:        }
        !           222:
        !           223:        if (udpencap && !(tdbp->tdb_flags & TDBF_UDPENCAP)) {
        !           224:                splx(s);
        !           225:                DPRINTF(("ipsec_common_input(): attempted to use non-udpencap SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto));
        !           226:                m_freem(m);
        !           227:                espstat.esps_udpinval++;
        !           228:                return EINVAL;
        !           229:        }
        !           230:
        !           231:        if (tdbp->tdb_xform == NULL) {
        !           232:                splx(s);
        !           233:                DPRINTF(("ipsec_common_input(): attempted to use uninitialized SA %s/%08x/%u\n", ipsp_address(dst_address), ntohl(spi), tdbp->tdb_sproto));
        !           234:                m_freem(m);
        !           235:                IPSEC_ISTAT(espstat.esps_noxform, ahstat.ahs_noxform,
        !           236:                    ipcompstat.ipcomps_noxform);
        !           237:                return ENXIO;
        !           238:        }
        !           239:
        !           240:        if (tdbp->tdb_dst.sa.sa_family == AF_INET &&
        !           241:            sproto != IPPROTO_IPCOMP) {
        !           242:                /*
        !           243:                 * XXX The fragment conflicts with scoped nature of
        !           244:                 * IPv6, so do it for only for IPv4 for now.
        !           245:                 */
        !           246:                m->m_pkthdr.rcvif = &encif[0].sc_if;
        !           247:        }
        !           248:
        !           249:        /* Register first use, setup expiration timer. */
        !           250:        if (tdbp->tdb_first_use == 0) {
        !           251:                tdbp->tdb_first_use = time_second;
        !           252:
        !           253:                tv.tv_usec = 0;
        !           254:
        !           255:                tv.tv_sec = tdbp->tdb_exp_first_use + tdbp->tdb_first_use;
        !           256:                if (tdbp->tdb_flags & TDBF_FIRSTUSE)
        !           257:                        timeout_add(&tdbp->tdb_first_tmo, hzto(&tv));
        !           258:
        !           259:                tv.tv_sec = tdbp->tdb_first_use + tdbp->tdb_soft_first_use;
        !           260:                if (tdbp->tdb_flags & TDBF_SOFT_FIRSTUSE)
        !           261:                        timeout_add(&tdbp->tdb_sfirst_tmo, hzto(&tv));
        !           262:        }
        !           263:
        !           264:        /*
        !           265:         * Call appropriate transform and return -- callback takes care of
        !           266:         * everything else.
        !           267:         */
        !           268:        error = (*(tdbp->tdb_xform->xf_input))(m, tdbp, skip, protoff);
        !           269:        splx(s);
        !           270:        return error;
        !           271: }
        !           272:
        !           273: /*
        !           274:  * IPsec input callback, called by the transform callback. Takes care of
        !           275:  * filtering and other sanity checks on the processed packet.
        !           276:  */
        !           277: int
        !           278: ipsec_common_input_cb(struct mbuf *m, struct tdb *tdbp, int skip, int protoff,
        !           279:     struct m_tag *mt)
        !           280: {
        !           281:        int prot, af, sproto;
        !           282:
        !           283: #if NBPFILTER > 0
        !           284:        struct ifnet *bpfif;
        !           285: #endif
        !           286:
        !           287: #ifdef INET
        !           288:        struct ip *ip, ipn;
        !           289: #endif /* INET */
        !           290:
        !           291: #ifdef INET6
        !           292:        struct ip6_hdr *ip6, ip6n;
        !           293: #endif /* INET6 */
        !           294:        struct m_tag *mtag;
        !           295:        struct tdb_ident *tdbi;
        !           296:
        !           297:        af = tdbp->tdb_dst.sa.sa_family;
        !           298:        sproto = tdbp->tdb_sproto;
        !           299:
        !           300:        tdbp->tdb_last_used = time_second;
        !           301:
        !           302:        /* Sanity check */
        !           303:        if (m == NULL) {
        !           304:                /* The called routine will print a message if necessary */
        !           305:                IPSEC_ISTAT(espstat.esps_badkcr, ahstat.ahs_badkcr,
        !           306:                    ipcompstat.ipcomps_badkcr);
        !           307:                return EINVAL;
        !           308:        }
        !           309:
        !           310: #ifdef INET
        !           311:        /* Fix IPv4 header */
        !           312:        if (tdbp->tdb_dst.sa.sa_family == AF_INET) {
        !           313:                if ((m->m_len < skip) && ((m = m_pullup(m, skip)) == NULL)) {
        !           314:                        DPRINTF(("ipsec_common_input_cb(): processing failed "
        !           315:                            "for SA %s/%08x\n", ipsp_address(tdbp->tdb_dst),
        !           316:                            ntohl(tdbp->tdb_spi)));
        !           317:                        IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
        !           318:                            ipcompstat.ipcomps_hdrops);
        !           319:                        return ENOBUFS;
        !           320:                }
        !           321:
        !           322:                ip = mtod(m, struct ip *);
        !           323:                ip->ip_len = htons(m->m_pkthdr.len);
        !           324:                ip->ip_sum = 0;
        !           325:                ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
        !           326:                prot = ip->ip_p;
        !           327:
        !           328:                /* IP-in-IP encapsulation */
        !           329:                if (prot == IPPROTO_IPIP) {
        !           330:                        if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
        !           331:                                m_freem(m);
        !           332:                                IPSEC_ISTAT(espstat.esps_hdrops,
        !           333:                                    ahstat.ahs_hdrops,
        !           334:                                    ipcompstat.ipcomps_hdrops);
        !           335:                                return EINVAL;
        !           336:                        }
        !           337:                        /* ipn will now contain the inner IPv4 header */
        !           338:                        m_copydata(m, skip, sizeof(struct ip),
        !           339:                            (caddr_t) &ipn);
        !           340:
        !           341:                        /*
        !           342:                         * Check that the inner source address is the same as
        !           343:                         * the proxy address, if available.
        !           344:                         */
        !           345:                        if ((tdbp->tdb_proxy.sa.sa_family == AF_INET &&
        !           346:                            tdbp->tdb_proxy.sin.sin_addr.s_addr !=
        !           347:                            INADDR_ANY &&
        !           348:                            ipn.ip_src.s_addr !=
        !           349:                            tdbp->tdb_proxy.sin.sin_addr.s_addr) ||
        !           350:                            (tdbp->tdb_proxy.sa.sa_family != AF_INET &&
        !           351:                                tdbp->tdb_proxy.sa.sa_family != 0)) {
        !           352:
        !           353:                                DPRINTF(("ipsec_common_input_cb(): inner "
        !           354:                                    "source address %s doesn't correspond to "
        !           355:                                    "expected proxy source %s, SA %s/%08x\n",
        !           356:                                    inet_ntoa4(ipn.ip_src),
        !           357:                                    ipsp_address(tdbp->tdb_proxy),
        !           358:                                    ipsp_address(tdbp->tdb_dst),
        !           359:                                    ntohl(tdbp->tdb_spi)));
        !           360:
        !           361:                                m_freem(m);
        !           362:                                IPSEC_ISTAT(espstat.esps_pdrops,
        !           363:                                    ahstat.ahs_pdrops,
        !           364:                                    ipcompstat.ipcomps_pdrops);
        !           365:                                return EACCES;
        !           366:                        }
        !           367:                }
        !           368:
        !           369: #if INET6
        !           370:                /* IPv6-in-IP encapsulation. */
        !           371:                if (prot == IPPROTO_IPV6) {
        !           372:                        if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
        !           373:                                m_freem(m);
        !           374:                                IPSEC_ISTAT(espstat.esps_hdrops,
        !           375:                                    ahstat.ahs_hdrops,
        !           376:                                    ipcompstat.ipcomps_hdrops);
        !           377:                                return EINVAL;
        !           378:                        }
        !           379:                        /* ip6n will now contain the inner IPv6 header. */
        !           380:                        m_copydata(m, skip, sizeof(struct ip6_hdr),
        !           381:                            (caddr_t) &ip6n);
        !           382:
        !           383:                        /*
        !           384:                         * Check that the inner source address is the same as
        !           385:                         * the proxy address, if available.
        !           386:                         */
        !           387:                        if ((tdbp->tdb_proxy.sa.sa_family == AF_INET6 &&
        !           388:                            !IN6_IS_ADDR_UNSPECIFIED(&tdbp->tdb_proxy.sin6.sin6_addr) &&
        !           389:                            !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
        !           390:                                &tdbp->tdb_proxy.sin6.sin6_addr)) ||
        !           391:                            (tdbp->tdb_proxy.sa.sa_family != AF_INET6 &&
        !           392:                                tdbp->tdb_proxy.sa.sa_family != 0)) {
        !           393:
        !           394:                                DPRINTF(("ipsec_common_input_cb(): inner "
        !           395:                                    "source address %s doesn't correspond to "
        !           396:                                    "expected proxy source %s, SA %s/%08x\n",
        !           397:                                    ip6_sprintf(&ip6n.ip6_src),
        !           398:                                    ipsp_address(tdbp->tdb_proxy),
        !           399:                                    ipsp_address(tdbp->tdb_dst),
        !           400:                                    ntohl(tdbp->tdb_spi)));
        !           401:
        !           402:                                m_freem(m);
        !           403:                                IPSEC_ISTAT(espstat.esps_pdrops,
        !           404:                                    ahstat.ahs_pdrops,
        !           405:                                    ipcompstat.ipcomps_pdrops);
        !           406:                                return EACCES;
        !           407:                        }
        !           408:                }
        !           409: #endif /* INET6 */
        !           410:        }
        !           411: #endif /* INET */
        !           412:
        !           413: #ifdef INET6
        !           414:        /* Fix IPv6 header */
        !           415:        if (af == INET6)
        !           416:        {
        !           417:                if (m->m_len < sizeof(struct ip6_hdr) &&
        !           418:                    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
        !           419:
        !           420:                        DPRINTF(("ipsec_common_input_cb(): processing failed "
        !           421:                            "for SA %s/%08x\n", ipsp_address(tdbp->tdb_dst),
        !           422:                            ntohl(tdbp->tdb_spi)));
        !           423:
        !           424:                        IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
        !           425:                            ipcompstat.ipcomps_hdrops);
        !           426:                        return EACCES;
        !           427:                }
        !           428:
        !           429:                ip6 = mtod(m, struct ip6_hdr *);
        !           430:                ip6->ip6_plen = htons(m->m_pkthdr.len -
        !           431:                    sizeof(struct ip6_hdr));
        !           432:
        !           433:                /* Save protocol */
        !           434:                m_copydata(m, protoff, 1, (unsigned char *) &prot);
        !           435:
        !           436: #ifdef INET
        !           437:                /* IP-in-IP encapsulation */
        !           438:                if (prot == IPPROTO_IPIP) {
        !           439:                        if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
        !           440:                                m_freem(m);
        !           441:                                IPSEC_ISTAT(espstat.esps_hdrops,
        !           442:                                    ahstat.ahs_hdrops,
        !           443:                                    ipcompstat.ipcomps_hdrops);
        !           444:                                return EINVAL;
        !           445:                        }
        !           446:                        /* ipn will now contain the inner IPv4 header */
        !           447:                        m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn);
        !           448:
        !           449:                        /*
        !           450:                         * Check that the inner source address is the same as
        !           451:                         * the proxy address, if available.
        !           452:                         */
        !           453:                        if ((tdbp->tdb_proxy.sa.sa_family == AF_INET &&
        !           454:                            tdbp->tdb_proxy.sin.sin_addr.s_addr !=
        !           455:                            INADDR_ANY &&
        !           456:                            ipn.ip_src.s_addr !=
        !           457:                                tdbp->tdb_proxy.sin.sin_addr.s_addr) ||
        !           458:                            (tdbp->tdb_proxy.sa.sa_family != AF_INET &&
        !           459:                                tdbp->tdb_proxy.sa.sa_family != 0)) {
        !           460:
        !           461:                                DPRINTF(("ipsec_common_input_cb(): inner "
        !           462:                                    "source address %s doesn't correspond to "
        !           463:                                    "expected proxy source %s, SA %s/%08x\n",
        !           464:                                    inet_ntoa4(ipn.ip_src),
        !           465:                                    ipsp_address(tdbp->tdb_proxy),
        !           466:                                    ipsp_address(tdbp->tdb_dst),
        !           467:                                    ntohl(tdbp->tdb_spi)));
        !           468:
        !           469:                                m_freem(m);
        !           470:                                IPSEC_ISTAT(espstat.esps_pdrops,
        !           471:                                    ahstat.ahs_pdrops,
        !           472:                                    ipcompstat.ipcomps_pdrops);
        !           473:                                return EACCES;
        !           474:                        }
        !           475:                }
        !           476: #endif /* INET */
        !           477:
        !           478:                /* IPv6-in-IP encapsulation */
        !           479:                if (prot == IPPROTO_IPV6) {
        !           480:                        if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
        !           481:                                m_freem(m);
        !           482:                                IPSEC_ISTAT(espstat.esps_hdrops,
        !           483:                                    ahstat.ahs_hdrops,
        !           484:                                    ipcompstat.ipcomps_hdrops);
        !           485:                                return EINVAL;
        !           486:                        }
        !           487:                        /* ip6n will now contain the inner IPv6 header. */
        !           488:                        m_copydata(m, skip, sizeof(struct ip6_hdr),
        !           489:                            (caddr_t) &ip6n);
        !           490:
        !           491:                        /*
        !           492:                         * Check that the inner source address is the same as
        !           493:                         * the proxy address, if available.
        !           494:                         */
        !           495:                        if ((tdbp->tdb_proxy.sa.sa_family == AF_INET6 &&
        !           496:                            !IN6_IS_ADDR_UNSPECIFIED(&tdbp->tdb_proxy.sin6.sin6_addr) &&
        !           497:                            !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
        !           498:                                &tdbp->tdb_proxy.sin6.sin6_addr)) ||
        !           499:                            (tdbp->tdb_proxy.sa.sa_family != AF_INET6 &&
        !           500:                                tdbp->tdb_proxy.sa.sa_family != 0)) {
        !           501:
        !           502:                                DPRINTF(("ipsec_common_input_cb(): inner "
        !           503:                                    "source address %s doesn't correspond to "
        !           504:                                    "expected proxy source %s, SA %s/%08x\n",
        !           505:                                    ip6_sprintf(&ip6n.ip6_src),
        !           506:                                    ipsp_address(tdbp->tdb_proxy),
        !           507:                                    ipsp_address(tdbp->tdb_dst),
        !           508:                                    ntohl(tdbp->tdb_spi)));
        !           509:
        !           510:                                m_freem(m);
        !           511:                                IPSEC_ISTAT(espstat.esps_pdrops,
        !           512:                                    ahstat.ahs_pdrops,
        !           513:                                    ipcompstat.ipcomps_pdrops);
        !           514:                                return EACCES;
        !           515:                        }
        !           516:                }
        !           517:        }
        !           518: #endif /* INET6 */
        !           519:
        !           520:        /*
        !           521:         * Record what we've done to the packet (under what SA it was
        !           522:         * processed). If we've been passed an mtag, it means the packet
        !           523:         * was already processed by an ethernet/crypto combo card and
        !           524:         * thus has a tag attached with all the right information, but
        !           525:         * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
        !           526:         * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
        !           527:         */
        !           528:        if (mt == NULL && tdbp->tdb_sproto != IPPROTO_IPCOMP) {
        !           529:                mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
        !           530:                    sizeof(struct tdb_ident), M_NOWAIT);
        !           531:                if (mtag == NULL) {
        !           532:                        m_freem(m);
        !           533:                        DPRINTF(("ipsec_common_input_cb(): failed to "
        !           534:                            "get tag\n"));
        !           535:                        IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops,
        !           536:                            ipcompstat.ipcomps_hdrops);
        !           537:                        return ENOMEM;
        !           538:                }
        !           539:
        !           540:                tdbi = (struct tdb_ident *)(mtag + 1);
        !           541:                bcopy(&tdbp->tdb_dst, &tdbi->dst,
        !           542:                    sizeof(union sockaddr_union));
        !           543:                tdbi->proto = tdbp->tdb_sproto;
        !           544:                tdbi->spi = tdbp->tdb_spi;
        !           545:
        !           546:                m_tag_prepend(m, mtag);
        !           547:        } else {
        !           548:                if (mt != NULL)
        !           549:                        mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
        !           550:        }
        !           551:
        !           552:        if (sproto == IPPROTO_ESP) {
        !           553:                /* Packet is confidential ? */
        !           554:                if (tdbp->tdb_encalgxform)
        !           555:                        m->m_flags |= M_CONF;
        !           556:
        !           557:                /* Check if we had authenticated ESP. */
        !           558:                if (tdbp->tdb_authalgxform)
        !           559:                        m->m_flags |= M_AUTH;
        !           560:        } else if (sproto == IPPROTO_AH)
        !           561:                m->m_flags |= M_AUTH | M_AUTH_AH;
        !           562:
        !           563: #if NPF > 0
        !           564:        /* Add pf tag if requested. */
        !           565:        if (pf_tag_packet(m, tdbp->tdb_tag, -1))
        !           566:                DPRINTF(("failed to tag ipsec packet\n"));
        !           567: #endif
        !           568:
        !           569:        if (tdbp->tdb_flags & TDBF_TUNNELING)
        !           570:                m->m_flags |= M_TUNNEL;
        !           571:
        !           572: #if NBPFILTER > 0
        !           573:        bpfif = &encif[0].sc_if;
        !           574:        bpfif->if_ipackets++;
        !           575:        bpfif->if_ibytes += m->m_pkthdr.len;
        !           576:
        !           577:        if (bpfif->if_bpf) {
        !           578:                struct enchdr hdr;
        !           579:
        !           580:                hdr.af = af;
        !           581:                hdr.spi = tdbp->tdb_spi;
        !           582:                hdr.flags = m->m_flags & (M_AUTH|M_CONF|M_AUTH_AH);
        !           583:
        !           584:                bpf_mtap_hdr(bpfif->if_bpf, (char *)&hdr, ENC_HDRLEN, m,
        !           585:                    BPF_DIRECTION_IN);
        !           586:        }
        !           587: #endif
        !           588:
        !           589:        /* Call the appropriate IPsec transform callback. */
        !           590:        switch (af) {
        !           591: #ifdef INET
        !           592:        case AF_INET:
        !           593:                switch (sproto)
        !           594:                {
        !           595:                case IPPROTO_ESP:
        !           596:                        return esp4_input_cb(m);
        !           597:
        !           598:                case IPPROTO_AH:
        !           599:                        return ah4_input_cb(m);
        !           600:
        !           601:                case IPPROTO_IPCOMP:
        !           602:                        return ipcomp4_input_cb(m);
        !           603:
        !           604:                default:
        !           605:                        DPRINTF(("ipsec_common_input_cb(): unknown/unsupported"
        !           606:                            " security protocol %d\n", sproto));
        !           607:                        m_freem(m);
        !           608:                        return EPFNOSUPPORT;
        !           609:                }
        !           610:                break;
        !           611: #endif /* INET */
        !           612:
        !           613: #ifdef INET6
        !           614:        case AF_INET6:
        !           615:                switch (sproto) {
        !           616:                case IPPROTO_ESP:
        !           617:                        return esp6_input_cb(m, skip, protoff);
        !           618:
        !           619:                case IPPROTO_AH:
        !           620:                        return ah6_input_cb(m, skip, protoff);
        !           621:
        !           622:                case IPPROTO_IPCOMP:
        !           623:                        return ipcomp6_input_cb(m, skip, protoff);
        !           624:
        !           625:                default:
        !           626:                        DPRINTF(("ipsec_common_input_cb(): unknown/unsupported"
        !           627:                            " security protocol %d\n", sproto));
        !           628:                        m_freem(m);
        !           629:                        return EPFNOSUPPORT;
        !           630:                }
        !           631:                break;
        !           632: #endif /* INET6 */
        !           633:
        !           634:        default:
        !           635:                DPRINTF(("ipsec_common_input_cb(): unknown/unsupported "
        !           636:                    "protocol family %d\n", af));
        !           637:                m_freem(m);
        !           638:                return EPFNOSUPPORT;
        !           639:        }
        !           640: #undef IPSEC_ISTAT
        !           641: }
        !           642:
        !           643: int
        !           644: esp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
        !           645:     size_t newlen)
        !           646: {
        !           647:        if (name[0] < ESPCTL_MAXID)
        !           648:                return (sysctl_int_arr(espctl_vars, name, namelen,
        !           649:                    oldp, oldlenp, newp, newlen));
        !           650:        return (ENOPROTOOPT);
        !           651: }
        !           652:
        !           653: int
        !           654: ah_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
        !           655:     size_t newlen)
        !           656: {
        !           657:        if (name[0] < AHCTL_MAXID)
        !           658:                return (sysctl_int_arr(ahctl_vars, name, namelen,
        !           659:                    oldp, oldlenp, newp, newlen));
        !           660:        return (ENOPROTOOPT);
        !           661: }
        !           662:
        !           663: int
        !           664: ipcomp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
        !           665:     size_t newlen)
        !           666: {
        !           667:        if (name[0] < IPCOMPCTL_MAXID)
        !           668:                return (sysctl_int_arr(ipcompctl_vars, name, namelen,
        !           669:                    oldp, oldlenp, newp, newlen));
        !           670:        return (ENOPROTOOPT);
        !           671: }
        !           672:
        !           673: #ifdef INET
        !           674: /* IPv4 AH wrapper. */
        !           675: void
        !           676: ah4_input(struct mbuf *m, ...)
        !           677: {
        !           678:        int skip;
        !           679:
        !           680:        va_list ap;
        !           681:        va_start(ap, m);
        !           682:        skip = va_arg(ap, int);
        !           683:        va_end(ap);
        !           684:
        !           685:        ipsec_common_input(m, skip, offsetof(struct ip, ip_p), AF_INET,
        !           686:            IPPROTO_AH, 0);
        !           687:        return;
        !           688: }
        !           689:
        !           690: /* IPv4 AH callback. */
        !           691: int
        !           692: ah4_input_cb(struct mbuf *m, ...)
        !           693: {
        !           694:        struct ifqueue *ifq = &ipintrq;
        !           695:        int s = splnet();
        !           696:
        !           697:        /*
        !           698:         * Interface pointer is already in first mbuf; chop off the
        !           699:         * `outer' header and reschedule.
        !           700:         */
        !           701:
        !           702:        if (IF_QFULL(ifq)) {
        !           703:                IF_DROP(ifq);
        !           704:                ahstat.ahs_qfull++;
        !           705:                splx(s);
        !           706:
        !           707:                m_freem(m);
        !           708:                DPRINTF(("ah4_input_cb(): dropped packet because of full "
        !           709:                    "IP queue\n"));
        !           710:                return ENOBUFS;
        !           711:        }
        !           712:
        !           713:        IF_ENQUEUE(ifq, m);
        !           714:        schednetisr(NETISR_IP);
        !           715:        splx(s);
        !           716:        return 0;
        !           717: }
        !           718:
        !           719:
        !           720: void *
        !           721: ah4_ctlinput(int cmd, struct sockaddr *sa, void *v)
        !           722: {
        !           723:        if (sa->sa_family != AF_INET ||
        !           724:            sa->sa_len != sizeof(struct sockaddr_in))
        !           725:                return (NULL);
        !           726:
        !           727:        return (ipsec_common_ctlinput(cmd, sa, v, IPPROTO_AH));
        !           728: }
        !           729:
        !           730: /* IPv4 ESP wrapper. */
        !           731: void
        !           732: esp4_input(struct mbuf *m, ...)
        !           733: {
        !           734:        int skip;
        !           735:
        !           736:        va_list ap;
        !           737:        va_start(ap, m);
        !           738:        skip = va_arg(ap, int);
        !           739:        va_end(ap);
        !           740:
        !           741:        ipsec_common_input(m, skip, offsetof(struct ip, ip_p), AF_INET,
        !           742:            IPPROTO_ESP, 0);
        !           743: }
        !           744:
        !           745: /* IPv4 ESP callback. */
        !           746: int
        !           747: esp4_input_cb(struct mbuf *m, ...)
        !           748: {
        !           749:        struct ifqueue *ifq = &ipintrq;
        !           750:        int s = splnet();
        !           751:
        !           752:        /*
        !           753:         * Interface pointer is already in first mbuf; chop off the
        !           754:         * `outer' header and reschedule.
        !           755:         */
        !           756:        if (IF_QFULL(ifq)) {
        !           757:                IF_DROP(ifq);
        !           758:                espstat.esps_qfull++;
        !           759:                splx(s);
        !           760:
        !           761:                m_freem(m);
        !           762:                DPRINTF(("esp4_input_cb(): dropped packet because of full "
        !           763:                    "IP queue\n"));
        !           764:                return ENOBUFS;
        !           765:        }
        !           766:
        !           767:        IF_ENQUEUE(ifq, m);
        !           768:        schednetisr(NETISR_IP);
        !           769:        splx(s);
        !           770:        return 0;
        !           771: }
        !           772:
        !           773: /* IPv4 IPCOMP wrapper */
        !           774: void
        !           775: ipcomp4_input(struct mbuf *m, ...)
        !           776: {
        !           777:        int skip;
        !           778:        va_list ap;
        !           779:        va_start(ap, m);
        !           780:        skip = va_arg(ap, int);
        !           781:        va_end(ap);
        !           782:
        !           783:        ipsec_common_input(m, skip, offsetof(struct ip, ip_p), AF_INET,
        !           784:            IPPROTO_IPCOMP, 0);
        !           785: }
        !           786:
        !           787: /* IPv4 IPCOMP callback */
        !           788: int
        !           789: ipcomp4_input_cb(struct mbuf *m, ...)
        !           790: {
        !           791:        struct ifqueue *ifq = &ipintrq;
        !           792:        int s = splnet();
        !           793:
        !           794:        /*
        !           795:         * Interface pointer is already in first mbuf; chop off the
        !           796:         * `outer' header and reschedule.
        !           797:         */
        !           798:        if (IF_QFULL(ifq)) {
        !           799:                IF_DROP(ifq);
        !           800:                ipcompstat.ipcomps_qfull++;
        !           801:                splx(s);
        !           802:
        !           803:                m_freem(m);
        !           804:                DPRINTF(("ipcomp4_input_cb(): dropped packet because of full IP queue\n"));
        !           805:                return ENOBUFS;
        !           806:        }
        !           807:
        !           808:        IF_ENQUEUE(ifq, m);
        !           809:        schednetisr(NETISR_IP);
        !           810:        splx(s);
        !           811:
        !           812:        return 0;
        !           813: }
        !           814:
        !           815: void *
        !           816: ipsec_common_ctlinput(int cmd, struct sockaddr *sa, void *v, int proto)
        !           817: {
        !           818:        extern u_int ip_mtudisc_timeout;
        !           819:        struct ip *ip = v;
        !           820:        int s;
        !           821:
        !           822:        if (cmd == PRC_MSGSIZE && ip && ip_mtudisc && ip->ip_v == 4) {
        !           823:                struct tdb *tdbp;
        !           824:                struct sockaddr_in dst;
        !           825:                struct icmp *icp;
        !           826:                int hlen = ip->ip_hl << 2;
        !           827:                u_int32_t spi, mtu;
        !           828:                ssize_t adjust;
        !           829:
        !           830:                /* Find the right MTU. */
        !           831:                icp = (struct icmp *)((caddr_t) ip -
        !           832:                    offsetof(struct icmp, icmp_ip));
        !           833:                mtu = ntohs(icp->icmp_nextmtu);
        !           834:
        !           835:                /*
        !           836:                 * Ignore the packet, if we do not receive a MTU
        !           837:                 * or the MTU is too small to be acceptable.
        !           838:                 */
        !           839:                if (mtu < 296)
        !           840:                        return (NULL);
        !           841:
        !           842:                bzero(&dst, sizeof(struct sockaddr_in));
        !           843:                dst.sin_family = AF_INET;
        !           844:                dst.sin_len = sizeof(struct sockaddr_in);
        !           845:                dst.sin_addr.s_addr = ip->ip_dst.s_addr;
        !           846:
        !           847:                bcopy((caddr_t)ip + hlen, &spi, sizeof(u_int32_t));
        !           848:
        !           849:                s = spltdb();
        !           850:                tdbp = gettdb(spi, (union sockaddr_union *)&dst, proto);
        !           851:                if (tdbp == NULL || tdbp->tdb_flags & TDBF_INVALID) {
        !           852:                        splx(s);
        !           853:                        return (NULL);
        !           854:                }
        !           855:
        !           856:                /* Walk the chain backswards to the first tdb */
        !           857:                for (; tdbp; tdbp = tdbp->tdb_inext) {
        !           858:                        if (tdbp->tdb_flags & TDBF_INVALID ||
        !           859:                            (adjust = ipsec_hdrsz(tdbp)) == -1) {
        !           860:                                splx(s);
        !           861:                                return (NULL);
        !           862:                        }
        !           863:
        !           864:                        mtu -= adjust;
        !           865:
        !           866:                        /* Store adjusted MTU in tdb */
        !           867:                        tdbp->tdb_mtu = mtu;
        !           868:                        tdbp->tdb_mtutimeout = time_second +
        !           869:                            ip_mtudisc_timeout;
        !           870:                        DPRINTF(("ipsec_common_ctlinput: "
        !           871:                            "spi %08x mtu %d adjust %d\n",
        !           872:                            ntohl(tdbp->tdb_spi), tdbp->tdb_mtu,
        !           873:                            adjust));
        !           874:                }
        !           875:                splx(s);
        !           876:                return (NULL);
        !           877:        }
        !           878:        return (NULL);
        !           879: }
        !           880:
        !           881: void *
        !           882: udpencap_ctlinput(int cmd, struct sockaddr *sa, void *v)
        !           883: {
        !           884:        struct ip *ip = v;
        !           885:        struct tdb *tdbp;
        !           886:        struct icmp *icp;
        !           887:        u_int32_t mtu;
        !           888:        ssize_t adjust;
        !           889:        struct sockaddr_in dst, src;
        !           890:        union sockaddr_union *su_dst, *su_src;
        !           891:        int s;
        !           892:
        !           893:        icp = (struct icmp *)((caddr_t) ip - offsetof(struct icmp, icmp_ip));
        !           894:        mtu = ntohs(icp->icmp_nextmtu);
        !           895:
        !           896:        /*
        !           897:         * Ignore the packet, if we do not receive a MTU
        !           898:         * or the MTU is too small to be acceptable.
        !           899:         */
        !           900:        if (mtu < 296)
        !           901:                return (NULL);
        !           902:
        !           903:        bzero(&dst, sizeof(dst));
        !           904:        dst.sin_family = AF_INET;
        !           905:        dst.sin_len = sizeof(struct sockaddr_in);
        !           906:        dst.sin_addr.s_addr = ip->ip_dst.s_addr;
        !           907:        su_dst = (union sockaddr_union *)&dst;
        !           908:        bzero(&src, sizeof(src));
        !           909:        src.sin_family = AF_INET;
        !           910:        src.sin_len = sizeof(struct sockaddr_in);
        !           911:        src.sin_addr.s_addr = ip->ip_src.s_addr;
        !           912:        su_src = (union sockaddr_union *)&src;
        !           913:
        !           914:        s = spltdb();
        !           915:        tdbp = gettdbbysrcdst(0, su_src, su_dst, IPPROTO_ESP);
        !           916:
        !           917:        for (; tdbp != NULL; tdbp = tdbp->tdb_snext) {
        !           918:                if (tdbp->tdb_sproto == IPPROTO_ESP &&
        !           919:                    ((tdbp->tdb_flags & (TDBF_INVALID|TDBF_UDPENCAP))
        !           920:                    == TDBF_UDPENCAP) &&
        !           921:                    !bcmp(&tdbp->tdb_dst, &dst, SA_LEN(&su_dst->sa)) &&
        !           922:                    !bcmp(&tdbp->tdb_src, &src, SA_LEN(&su_src->sa))) {
        !           923:                        if ((adjust = ipsec_hdrsz(tdbp)) != -1) {
        !           924:                                /* Store adjusted MTU in tdb */
        !           925:                                tdbp->tdb_mtu = mtu - adjust;
        !           926:                                tdbp->tdb_mtutimeout = time_second +
        !           927:                                    ip_mtudisc_timeout;
        !           928:                                DPRINTF(("udpencap_ctlinput: "
        !           929:                                    "spi %08x mtu %d adjust %d\n",
        !           930:                                    ntohl(tdbp->tdb_spi), tdbp->tdb_mtu,
        !           931:                                    adjust));
        !           932:                        }
        !           933:                }
        !           934:        }
        !           935:        splx(s);
        !           936:        return (NULL);
        !           937: }
        !           938:
        !           939: void *
        !           940: esp4_ctlinput(int cmd, struct sockaddr *sa, void *v)
        !           941: {
        !           942:        if (sa->sa_family != AF_INET ||
        !           943:            sa->sa_len != sizeof(struct sockaddr_in))
        !           944:                return (NULL);
        !           945:
        !           946:        return (ipsec_common_ctlinput(cmd, sa, v, IPPROTO_ESP));
        !           947: }
        !           948: #endif /* INET */
        !           949:
        !           950: #ifdef INET6
        !           951: /* IPv6 AH wrapper. */
        !           952: int
        !           953: ah6_input(struct mbuf **mp, int *offp, int proto)
        !           954: {
        !           955:        int l = 0;
        !           956:        int protoff, nxt;
        !           957:        struct ip6_ext ip6e;
        !           958:
        !           959:        if (*offp < sizeof(struct ip6_hdr)) {
        !           960:                DPRINTF(("ah6_input(): bad offset\n"));
        !           961:                return IPPROTO_DONE;
        !           962:        } else if (*offp == sizeof(struct ip6_hdr)) {
        !           963:                protoff = offsetof(struct ip6_hdr, ip6_nxt);
        !           964:        } else {
        !           965:                /* Chase down the header chain... */
        !           966:                protoff = sizeof(struct ip6_hdr);
        !           967:                nxt = (mtod(*mp, struct ip6_hdr *))->ip6_nxt;
        !           968:
        !           969:                do {
        !           970:                        protoff += l;
        !           971:                        m_copydata(*mp, protoff, sizeof(ip6e),
        !           972:                            (caddr_t) &ip6e);
        !           973:
        !           974:                        if (nxt == IPPROTO_AH)
        !           975:                                l = (ip6e.ip6e_len + 2) << 2;
        !           976:                        else
        !           977:                                l = (ip6e.ip6e_len + 1) << 3;
        !           978: #ifdef DIAGNOSTIC
        !           979:                        if (l <= 0)
        !           980:                                panic("ah6_input: l went zero or negative");
        !           981: #endif
        !           982:
        !           983:                        nxt = ip6e.ip6e_nxt;
        !           984:                } while (protoff + l < *offp);
        !           985:
        !           986:                /* Malformed packet check */
        !           987:                if (protoff + l != *offp) {
        !           988:                        DPRINTF(("ah6_input(): bad packet header chain\n"));
        !           989:                        ahstat.ahs_hdrops++;
        !           990:                        m_freem(*mp);
        !           991:                        *mp = NULL;
        !           992:                        return IPPROTO_DONE;
        !           993:                }
        !           994:                protoff += offsetof(struct ip6_ext, ip6e_nxt);
        !           995:        }
        !           996:        ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto, 0);
        !           997:        return IPPROTO_DONE;
        !           998: }
        !           999:
        !          1000: /* IPv6 AH callback. */
        !          1001: int
        !          1002: ah6_input_cb(struct mbuf *m, int off, int protoff)
        !          1003: {
        !          1004:        int nxt;
        !          1005:        u_int8_t nxt8;
        !          1006:        int nest = 0;
        !          1007:
        !          1008:        /* Retrieve new protocol */
        !          1009:        m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &nxt8);
        !          1010:        nxt = nxt8;
        !          1011:
        !          1012:        /*
        !          1013:         * see the end of ip6_input for this logic.
        !          1014:         * IPPROTO_IPV[46] case will be processed just like other ones
        !          1015:         */
        !          1016:        while (nxt != IPPROTO_DONE) {
        !          1017:                if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
        !          1018:                        ip6stat.ip6s_toomanyhdr++;
        !          1019:                        goto bad;
        !          1020:                }
        !          1021:
        !          1022:                /*
        !          1023:                 * Protection against faulty packet - there should be
        !          1024:                 * more sanity checks in header chain processing.
        !          1025:                 */
        !          1026:                if (m->m_pkthdr.len < off) {
        !          1027:                        ip6stat.ip6s_tooshort++;
        !          1028:                        in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
        !          1029:                        goto bad;
        !          1030:                }
        !          1031:                nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);
        !          1032:        }
        !          1033:        return 0;
        !          1034:
        !          1035:  bad:
        !          1036:        m_freem(m);
        !          1037:        return EINVAL;
        !          1038: }
        !          1039:
        !          1040: /* IPv6 ESP wrapper. */
        !          1041: int
        !          1042: esp6_input(struct mbuf **mp, int *offp, int proto)
        !          1043: {
        !          1044:        int l = 0;
        !          1045:        int protoff, nxt;
        !          1046:        struct ip6_ext ip6e;
        !          1047:
        !          1048:        if (*offp < sizeof(struct ip6_hdr)) {
        !          1049:                DPRINTF(("esp6_input(): bad offset\n"));
        !          1050:                return IPPROTO_DONE;
        !          1051:        } else if (*offp == sizeof(struct ip6_hdr)) {
        !          1052:                protoff = offsetof(struct ip6_hdr, ip6_nxt);
        !          1053:        } else {
        !          1054:                /* Chase down the header chain... */
        !          1055:                protoff = sizeof(struct ip6_hdr);
        !          1056:                nxt = (mtod(*mp, struct ip6_hdr *))->ip6_nxt;
        !          1057:
        !          1058:                do {
        !          1059:                        protoff += l;
        !          1060:                        m_copydata(*mp, protoff, sizeof(ip6e),
        !          1061:                            (caddr_t) &ip6e);
        !          1062:
        !          1063:                        if (nxt == IPPROTO_AH)
        !          1064:                                l = (ip6e.ip6e_len + 2) << 2;
        !          1065:                        else
        !          1066:                                l = (ip6e.ip6e_len + 1) << 3;
        !          1067: #ifdef DIAGNOSTIC
        !          1068:                        if (l <= 0)
        !          1069:                                panic("esp6_input: l went zero or negative");
        !          1070: #endif
        !          1071:
        !          1072:                        nxt = ip6e.ip6e_nxt;
        !          1073:                } while (protoff + l < *offp);
        !          1074:
        !          1075:                /* Malformed packet check */
        !          1076:                if (protoff + l != *offp) {
        !          1077:                        DPRINTF(("esp6_input(): bad packet header chain\n"));
        !          1078:                        espstat.esps_hdrops++;
        !          1079:                        m_freem(*mp);
        !          1080:                        *mp = NULL;
        !          1081:                        return IPPROTO_DONE;
        !          1082:                }
        !          1083:                protoff += offsetof(struct ip6_ext, ip6e_nxt);
        !          1084:        }
        !          1085:        ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto, 0);
        !          1086:        return IPPROTO_DONE;
        !          1087:
        !          1088: }
        !          1089:
        !          1090: /* IPv6 ESP callback */
        !          1091: int
        !          1092: esp6_input_cb(struct mbuf *m, int skip, int protoff)
        !          1093: {
        !          1094:        return ah6_input_cb(m, skip, protoff);
        !          1095: }
        !          1096:
        !          1097: /* IPv6 IPcomp wrapper */
        !          1098: int
        !          1099: ipcomp6_input(struct mbuf **mp, int *offp, int proto)
        !          1100: {
        !          1101:        int l = 0;
        !          1102:        int protoff, nxt;
        !          1103:        struct ip6_ext ip6e;
        !          1104:
        !          1105:        if (*offp < sizeof(struct ip6_hdr)) {
        !          1106:                DPRINTF(("ipcomp6_input(): bad offset\n"));
        !          1107:                return IPPROTO_DONE;
        !          1108:        } else if (*offp == sizeof(struct ip6_hdr)) {
        !          1109:                protoff = offsetof(struct ip6_hdr, ip6_nxt);
        !          1110:        } else {
        !          1111:                /* Chase down the header chain... */
        !          1112:                protoff = sizeof(struct ip6_hdr);
        !          1113:                nxt = (mtod(*mp, struct ip6_hdr *))->ip6_nxt;
        !          1114:
        !          1115:                do {
        !          1116:                        protoff += l;
        !          1117:                        m_copydata(*mp, protoff, sizeof(ip6e),
        !          1118:                            (caddr_t) &ip6e);
        !          1119:                        if (nxt == IPPROTO_AH)
        !          1120:                                l = (ip6e.ip6e_len + 2) << 2;
        !          1121:                        else
        !          1122:                                l = (ip6e.ip6e_len + 1) << 3;
        !          1123: #ifdef DIAGNOSTIC
        !          1124:                        if (l <= 0)
        !          1125:                                panic("ipcomp6_input: l went zero or negative");
        !          1126: #endif
        !          1127:
        !          1128:                        nxt = ip6e.ip6e_nxt;
        !          1129:                } while (protoff + l < *offp);
        !          1130:
        !          1131:                /* Malformed packet check */
        !          1132:                if (protoff + l != *offp) {
        !          1133:                        DPRINTF(("ipcomp6_input(): bad packet header chain\n"));
        !          1134:                        ipcompstat.ipcomps_hdrops++;
        !          1135:                        m_freem(*mp);
        !          1136:                        *mp = NULL;
        !          1137:                        return IPPROTO_DONE;
        !          1138:                }
        !          1139:
        !          1140:                protoff += offsetof(struct ip6_ext, ip6e_nxt);
        !          1141:        }
        !          1142:        ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto, 0);
        !          1143:        return IPPROTO_DONE;
        !          1144: }
        !          1145:
        !          1146: /* IPv6 IPcomp callback */
        !          1147: int
        !          1148: ipcomp6_input_cb(struct mbuf *m, int skip, int protoff)
        !          1149: {
        !          1150:        return ah6_input_cb(m, skip, protoff);
        !          1151: }
        !          1152:
        !          1153: #endif /* INET6 */

CVSweb