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

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

1.1     ! nbrk        1: /*     $OpenBSD: ip_ah.c,v 1.89 2007/02/14 00:53:48 jsg 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:  * The original version of this code was written by John Ioannidis
        !             8:  * for BSD/OS in Athens, Greece, 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 and Niklas Hallqvist.
        !            17:  *
        !            18:  * Copyright (c) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
        !            19:  * Angelos D. Keromytis and Niels Provos.
        !            20:  * Copyright (c) 1999 Niklas Hallqvist.
        !            21:  * Copyright (c) 2001 Angelos D. Keromytis.
        !            22:  *
        !            23:  * Permission to use, copy, and modify this software with or without fee
        !            24:  * is hereby granted, provided that this entire notice is included in
        !            25:  * all copies of any software which is or includes a copy or
        !            26:  * modification of this software.
        !            27:  * You may use this code under the GNU public license if you so wish. Please
        !            28:  * contribute changes back to the authors under this freer than GPL license
        !            29:  * so that we may further the use of strong encryption without limitations to
        !            30:  * all.
        !            31:  *
        !            32:  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
        !            33:  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
        !            34:  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
        !            35:  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
        !            36:  * PURPOSE.
        !            37:  */
        !            38:
        !            39: #include "pfsync.h"
        !            40:
        !            41: #include <sys/param.h>
        !            42: #include <sys/systm.h>
        !            43: #include <sys/mbuf.h>
        !            44: #include <sys/socket.h>
        !            45:
        !            46: #include <net/if.h>
        !            47: #include <net/bpf.h>
        !            48:
        !            49: #ifdef INET
        !            50: #include <netinet/in.h>
        !            51: #include <netinet/in_systm.h>
        !            52: #include <netinet/ip.h>
        !            53: #include <netinet/ip_var.h>
        !            54: #endif /* INET */
        !            55:
        !            56: #ifdef INET6
        !            57: #ifndef INET
        !            58: #include <netinet/in.h>
        !            59: #endif /* INET */
        !            60: #include <netinet/ip6.h>
        !            61: #endif /* INET6 */
        !            62:
        !            63: #include <netinet/ip_ipsp.h>
        !            64: #include <netinet/ip_ah.h>
        !            65: #include <net/pfkeyv2.h>
        !            66: #include <net/if_enc.h>
        !            67:
        !            68: #if NPFSYNC > 0
        !            69: #include <net/pfvar.h>
        !            70: #include <net/if_pfsync.h>
        !            71: #endif /* NPFSYNC > 0 */
        !            72:
        !            73: #include <crypto/cryptodev.h>
        !            74: #include <crypto/xform.h>
        !            75:
        !            76: #include "bpfilter.h"
        !            77:
        !            78: #ifdef ENCDEBUG
        !            79: #define DPRINTF(x)     if (encdebug) printf x
        !            80: #else
        !            81: #define DPRINTF(x)
        !            82: #endif
        !            83:
        !            84: struct ahstat ahstat;
        !            85:
        !            86: /*
        !            87:  * ah_attach() is called from the transformation initialization code.
        !            88:  */
        !            89: int
        !            90: ah_attach()
        !            91: {
        !            92:        return 0;
        !            93: }
        !            94:
        !            95: /*
        !            96:  * ah_init() is called when an SPI is being set up.
        !            97:  */
        !            98: int
        !            99: ah_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii)
        !           100: {
        !           101:        struct auth_hash *thash = NULL;
        !           102:        struct cryptoini cria;
        !           103:
        !           104:        /* Authentication operation. */
        !           105:        switch (ii->ii_authalg) {
        !           106:        case SADB_AALG_MD5HMAC:
        !           107:                thash = &auth_hash_hmac_md5_96;
        !           108:                break;
        !           109:
        !           110:        case SADB_AALG_SHA1HMAC:
        !           111:                thash = &auth_hash_hmac_sha1_96;
        !           112:                break;
        !           113:
        !           114:        case SADB_X_AALG_RIPEMD160HMAC:
        !           115:                thash = &auth_hash_hmac_ripemd_160_96;
        !           116:                break;
        !           117:
        !           118:        case SADB_X_AALG_SHA2_256:
        !           119:                thash = &auth_hash_hmac_sha2_256_96;
        !           120:                break;
        !           121:
        !           122:        case SADB_X_AALG_SHA2_384:
        !           123:                thash = &auth_hash_hmac_sha2_384_96;
        !           124:                break;
        !           125:
        !           126:        case SADB_X_AALG_SHA2_512:
        !           127:                thash = &auth_hash_hmac_sha2_512_96;
        !           128:                break;
        !           129:
        !           130:        case SADB_X_AALG_MD5:
        !           131:                thash = &auth_hash_key_md5;
        !           132:                break;
        !           133:
        !           134:        case SADB_X_AALG_SHA1:
        !           135:                thash = &auth_hash_key_sha1;
        !           136:                break;
        !           137:
        !           138:        default:
        !           139:                DPRINTF(("ah_init(): unsupported authentication algorithm %d specified\n", ii->ii_authalg));
        !           140:                return EINVAL;
        !           141:        }
        !           142:
        !           143:        if (ii->ii_authkeylen != thash->keysize && thash->keysize != 0) {
        !           144:                DPRINTF(("ah_init(): keylength %d doesn't match algorithm "
        !           145:                    "%s keysize (%d)\n", ii->ii_authkeylen, thash->name,
        !           146:                    thash->keysize));
        !           147:                return EINVAL;
        !           148:        }
        !           149:
        !           150:        tdbp->tdb_xform = xsp;
        !           151:        tdbp->tdb_authalgxform = thash;
        !           152:        tdbp->tdb_bitmap = 0;
        !           153:        tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL;
        !           154:
        !           155:        DPRINTF(("ah_init(): initialized TDB with hash algorithm %s\n",
        !           156:            thash->name));
        !           157:
        !           158:        tdbp->tdb_amxkeylen = ii->ii_authkeylen;
        !           159:        MALLOC(tdbp->tdb_amxkey, u_int8_t *, tdbp->tdb_amxkeylen, M_XDATA,
        !           160:            M_WAITOK);
        !           161:
        !           162:        bcopy(ii->ii_authkey, tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
        !           163:
        !           164:        /* Initialize crypto session. */
        !           165:        bzero(&cria, sizeof(cria));
        !           166:        cria.cri_alg = tdbp->tdb_authalgxform->type;
        !           167:        cria.cri_klen = ii->ii_authkeylen * 8;
        !           168:        cria.cri_key = ii->ii_authkey;
        !           169:
        !           170:        return crypto_newsession(&tdbp->tdb_cryptoid, &cria, 0);
        !           171: }
        !           172:
        !           173: /*
        !           174:  * Paranoia.
        !           175:  */
        !           176: int
        !           177: ah_zeroize(struct tdb *tdbp)
        !           178: {
        !           179:        int err;
        !           180:
        !           181:        if (tdbp->tdb_amxkey) {
        !           182:                bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
        !           183:                FREE(tdbp->tdb_amxkey, M_XDATA);
        !           184:                tdbp->tdb_amxkey = NULL;
        !           185:        }
        !           186:
        !           187:        err = crypto_freesession(tdbp->tdb_cryptoid);
        !           188:        tdbp->tdb_cryptoid = 0;
        !           189:        return err;
        !           190: }
        !           191:
        !           192: /*
        !           193:  * Massage IPv4/IPv6 headers for AH processing.
        !           194:  */
        !           195: int
        !           196: ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
        !           197: {
        !           198:        struct mbuf *m = *m0;
        !           199:        unsigned char *ptr;
        !           200:        int off, count;
        !           201:
        !           202: #ifdef INET
        !           203:        struct ip *ip;
        !           204: #endif /* INET */
        !           205:
        !           206: #ifdef INET6
        !           207:        struct ip6_ext *ip6e;
        !           208:        struct ip6_hdr ip6;
        !           209:        int ad, alloc, nxt;
        !           210: #endif /* INET6 */
        !           211:
        !           212:        switch (proto) {
        !           213: #ifdef INET
        !           214:        case AF_INET:
        !           215:                /*
        !           216:                 * This is the least painful way of dealing with IPv4 header
        !           217:                 * and option processing -- just make sure they're in
        !           218:                 * contiguous memory.
        !           219:                 */
        !           220:                *m0 = m = m_pullup(m, skip);
        !           221:                if (m == NULL) {
        !           222:                        DPRINTF(("ah_massage_headers(): m_pullup() failed\n"));
        !           223:                        ahstat.ahs_hdrops++;
        !           224:                        return ENOBUFS;
        !           225:                }
        !           226:
        !           227:                /* Fix the IP header */
        !           228:                ip = mtod(m, struct ip *);
        !           229:                ip->ip_tos = 0;
        !           230:                ip->ip_ttl = 0;
        !           231:                ip->ip_sum = 0;
        !           232:
        !           233:                /*
        !           234:                 * On input, fix ip_len which has been byte-swapped
        !           235:                 * at ip_input().
        !           236:                 */
        !           237:                if (alg == CRYPTO_MD5_KPDK || alg == CRYPTO_SHA1_KPDK)
        !           238:                        ip->ip_off &= htons(IP_DF);
        !           239:                else
        !           240:                        ip->ip_off = 0;
        !           241:
        !           242:                ptr = mtod(m, unsigned char *) + sizeof(struct ip);
        !           243:
        !           244:                /* IPv4 option processing */
        !           245:                for (off = sizeof(struct ip); off < skip;) {
        !           246:                        if (ptr[off] == IPOPT_EOL || ptr[off] == IPOPT_NOP ||
        !           247:                            off + 1 < skip)
        !           248:                                ;
        !           249:                        else {
        !           250:                                DPRINTF(("ah_massage_headers(): illegal IPv4 "
        !           251:                                    "option length for option %d\n",
        !           252:                                    ptr[off]));
        !           253:
        !           254:                                ahstat.ahs_hdrops++;
        !           255:                                m_freem(m);
        !           256:                                return EINVAL;
        !           257:                        }
        !           258:
        !           259:                        switch (ptr[off]) {
        !           260:                        case IPOPT_EOL:
        !           261:                                off = skip;  /* End the loop. */
        !           262:                                break;
        !           263:
        !           264:                        case IPOPT_NOP:
        !           265:                                off++;
        !           266:                                break;
        !           267:
        !           268:                        case IPOPT_SECURITY:    /* 0x82 */
        !           269:                        case 0x85:      /* Extended security. */
        !           270:                        case 0x86:      /* Commercial security. */
        !           271:                        case 0x94:      /* Router alert */
        !           272:                        case 0x95:      /* RFC1770 */
        !           273:                                /* Sanity check for option length. */
        !           274:                                if (ptr[off + 1] < 2) {
        !           275:                                        DPRINTF(("ah_massage_headers(): "
        !           276:                                            "illegal IPv4 option length for "
        !           277:                                            "option %d\n", ptr[off]));
        !           278:
        !           279:                                        ahstat.ahs_hdrops++;
        !           280:                                        m_freem(m);
        !           281:                                        return EINVAL;
        !           282:                                }
        !           283:
        !           284:                                off += ptr[off + 1];
        !           285:                                break;
        !           286:
        !           287:                        case IPOPT_LSRR:
        !           288:                        case IPOPT_SSRR:
        !           289:                                /* Sanity check for option length. */
        !           290:                                if (ptr[off + 1] < 2) {
        !           291:                                        DPRINTF(("ah_massage_headers(): "
        !           292:                                            "illegal IPv4 option length for "
        !           293:                                            "option %d\n", ptr[off]));
        !           294:
        !           295:                                        ahstat.ahs_hdrops++;
        !           296:                                        m_freem(m);
        !           297:                                        return EINVAL;
        !           298:                                }
        !           299:
        !           300:                                /*
        !           301:                                 * On output, if we have either of the
        !           302:                                 * source routing options, we should
        !           303:                                 * swap the destination address of the
        !           304:                                 * IP header with the last address
        !           305:                                 * specified in the option, as that is
        !           306:                                 * what the destination's IP header
        !           307:                                 * will look like.
        !           308:                                 */
        !           309:                                if (out)
        !           310:                                        bcopy(ptr + off + ptr[off + 1] -
        !           311:                                            sizeof(struct in_addr),
        !           312:                                            &(ip->ip_dst), sizeof(struct in_addr));
        !           313:
        !           314:                                /* FALLTHROUGH */
        !           315:                        default:
        !           316:                                /* Sanity check for option length. */
        !           317:                                if (ptr[off + 1] < 2) {
        !           318:                                        DPRINTF(("ah_massage_headers(): "
        !           319:                                            "illegal IPv4 option length for "
        !           320:                                            "option %d\n", ptr[off]));
        !           321:                                        ahstat.ahs_hdrops++;
        !           322:                                        m_freem(m);
        !           323:                                        return EINVAL;
        !           324:                                }
        !           325:
        !           326:                                /* Zeroize all other options. */
        !           327:                                count = ptr[off + 1];
        !           328:                                bcopy(ipseczeroes, ptr, count);
        !           329:                                off += count;
        !           330:                                break;
        !           331:                        }
        !           332:
        !           333:                        /* Sanity check. */
        !           334:                        if (off > skip) {
        !           335:                                DPRINTF(("ah_massage_headers(): malformed "
        !           336:                                    "IPv4 options header\n"));
        !           337:
        !           338:                                ahstat.ahs_hdrops++;
        !           339:                                m_freem(m);
        !           340:                                return EINVAL;
        !           341:                        }
        !           342:                }
        !           343:
        !           344:                break;
        !           345: #endif /* INET */
        !           346:
        !           347: #ifdef INET6
        !           348:        case AF_INET6:  /* Ugly... */
        !           349:                /* Copy and "cook" the IPv6 header. */
        !           350:                m_copydata(m, 0, sizeof(ip6), (caddr_t) &ip6);
        !           351:
        !           352:                /* We don't do IPv6 Jumbograms. */
        !           353:                if (ip6.ip6_plen == 0) {
        !           354:                        DPRINTF(("ah_massage_headers(): unsupported IPv6 "
        !           355:                            "jumbogram"));
        !           356:                        ahstat.ahs_hdrops++;
        !           357:                        m_freem(m);
        !           358:                        return EMSGSIZE;
        !           359:                }
        !           360:
        !           361:                ip6.ip6_flow = 0;
        !           362:                ip6.ip6_hlim = 0;
        !           363:                ip6.ip6_vfc &= ~IPV6_VERSION_MASK;
        !           364:                ip6.ip6_vfc |= IPV6_VERSION;
        !           365:
        !           366:                /* Scoped address handling. */
        !           367:                if (IN6_IS_SCOPE_EMBED(&ip6.ip6_src))
        !           368:                        ip6.ip6_src.s6_addr16[1] = 0;
        !           369:                if (IN6_IS_SCOPE_EMBED(&ip6.ip6_dst))
        !           370:                        ip6.ip6_dst.s6_addr16[1] = 0;
        !           371:
        !           372:                /* Done with IPv6 header. */
        !           373:                m_copyback(m, 0, sizeof(struct ip6_hdr), &ip6);
        !           374:
        !           375:                /* Let's deal with the remaining headers (if any). */
        !           376:                if (skip - sizeof(struct ip6_hdr) > 0) {
        !           377:                        if (m->m_len <= skip) {
        !           378:                                MALLOC(ptr, unsigned char *,
        !           379:                                    skip - sizeof(struct ip6_hdr),
        !           380:                                    M_XDATA, M_NOWAIT);
        !           381:                                if (ptr == NULL) {
        !           382:                                        DPRINTF(("ah_massage_headers(): failed to allocate memory for IPv6 headers\n"));
        !           383:                                        ahstat.ahs_hdrops++;
        !           384:                                        m_freem(m);
        !           385:                                        return ENOBUFS;
        !           386:                                }
        !           387:
        !           388:                                /*
        !           389:                                 * Copy all the protocol headers after
        !           390:                                 * the IPv6 header.
        !           391:                                 */
        !           392:                                m_copydata(m, sizeof(struct ip6_hdr),
        !           393:                                    skip - sizeof(struct ip6_hdr), ptr);
        !           394:                                alloc = 1;
        !           395:                        } else {
        !           396:                                /* No need to allocate memory. */
        !           397:                                ptr = mtod(m, unsigned char *) +
        !           398:                                    sizeof(struct ip6_hdr);
        !           399:                                alloc = 0;
        !           400:                        }
        !           401:                } else
        !           402:                        break;
        !           403:
        !           404:                nxt = ip6.ip6_nxt & 0xff; /* Next header type. */
        !           405:
        !           406:                for (off = 0; off < skip - sizeof(struct ip6_hdr);) {
        !           407:                        switch (nxt) {
        !           408:                        case IPPROTO_HOPOPTS:
        !           409:                        case IPPROTO_DSTOPTS:
        !           410:                                ip6e = (struct ip6_ext *) (ptr + off);
        !           411:
        !           412:                                /*
        !           413:                                 * Process the mutable/immutable
        !           414:                                 * options -- borrows heavily from the
        !           415:                                 * KAME code.
        !           416:                                 */
        !           417:                                for (count = off + sizeof(struct ip6_ext);
        !           418:                                     count < off + ((ip6e->ip6e_len + 1) << 3);) {
        !           419:                                        if (ptr[count] == IP6OPT_PAD1) {
        !           420:                                                count++;
        !           421:                                                continue; /* Skip padding. */
        !           422:                                        }
        !           423:
        !           424:                                        /* Sanity check. */
        !           425:                                        if (count > off +
        !           426:                                            ((ip6e->ip6e_len + 1) << 3)) {
        !           427:                                                ahstat.ahs_hdrops++;
        !           428:                                                m_freem(m);
        !           429:
        !           430:                                                /* Free, if we allocated. */
        !           431:                                                if (alloc)
        !           432:                                                        FREE(ptr, M_XDATA);
        !           433:                                                return EINVAL;
        !           434:                                        }
        !           435:
        !           436:                                        ad = ptr[count + 1];
        !           437:
        !           438:                                        /* If mutable option, zeroize. */
        !           439:                                        if (ptr[count] & IP6OPT_MUTABLE)
        !           440:                                                bcopy(ipseczeroes, ptr + count,
        !           441:                                                    ptr[count + 1]);
        !           442:
        !           443:                                        count += ad;
        !           444:
        !           445:                                        /* Sanity check. */
        !           446:                                        if (count >
        !           447:                                            skip - sizeof(struct ip6_hdr)) {
        !           448:                                                ahstat.ahs_hdrops++;
        !           449:                                                m_freem(m);
        !           450:
        !           451:                                                /* Free, if we allocated. */
        !           452:                                                if (alloc)
        !           453:                                                        FREE(ptr, M_XDATA);
        !           454:                                                return EINVAL;
        !           455:                                        }
        !           456:                                }
        !           457:
        !           458:                                /* Advance. */
        !           459:                                off += ((ip6e->ip6e_len + 1) << 3);
        !           460:                                nxt = ip6e->ip6e_nxt;
        !           461:                                break;
        !           462:
        !           463:                        case IPPROTO_ROUTING:
        !           464:                                /*
        !           465:                                 * Always include routing headers in
        !           466:                                 * computation.
        !           467:                                 */
        !           468:                            {
        !           469:                                struct ip6_rthdr *rh;
        !           470:
        !           471:                                ip6e = (struct ip6_ext *) (ptr + off);
        !           472:                                rh = (struct ip6_rthdr *)(ptr + off);
        !           473:                                /*
        !           474:                                 * must adjust content to make it look like
        !           475:                                 * its final form (as seen at the final
        !           476:                                 * destination).
        !           477:                                 * we only know how to massage type 0 routing
        !           478:                                 * header.
        !           479:                                 */
        !           480:                                if (out && rh->ip6r_type == IPV6_RTHDR_TYPE_0) {
        !           481:                                        struct ip6_rthdr0 *rh0;
        !           482:                                        struct in6_addr *addr, finaldst;
        !           483:                                        int i;
        !           484:
        !           485:                                        rh0 = (struct ip6_rthdr0 *)rh;
        !           486:                                        addr = (struct in6_addr *)(rh0 + 1);
        !           487:
        !           488:                                        for (i = 0; i < rh0->ip6r0_segleft; i++)
        !           489:                                                if (IN6_IS_SCOPE_EMBED(&addr[i]))
        !           490:                                                        addr[i].s6_addr16[1] = 0;
        !           491:
        !           492:                                        finaldst = addr[rh0->ip6r0_segleft - 1];
        !           493:                                        ovbcopy(&addr[0], &addr[1],
        !           494:                                            sizeof(struct in6_addr) *
        !           495:                                            (rh0->ip6r0_segleft - 1));
        !           496:
        !           497:                                        m_copydata(m, 0, sizeof(ip6),
        !           498:                                            (caddr_t)&ip6);
        !           499:                                        addr[0] = ip6.ip6_dst;
        !           500:                                        ip6.ip6_dst = finaldst;
        !           501:                                        m_copyback(m, 0, sizeof(ip6), &ip6);
        !           502:
        !           503:                                        rh0->ip6r0_segleft = 0;
        !           504:                                }
        !           505:
        !           506:                                /* advance */
        !           507:                                off += ((ip6e->ip6e_len + 1) << 3);
        !           508:                                nxt = ip6e->ip6e_nxt;
        !           509:                                break;
        !           510:                            }
        !           511:
        !           512:                        default:
        !           513:                                DPRINTF(("ah_massage_headers(): unexpected "
        !           514:                                    "IPv6 header type %d\n", off));
        !           515:                                if (alloc)
        !           516:                                        FREE(ptr, M_XDATA);
        !           517:                                ahstat.ahs_hdrops++;
        !           518:                                m_freem(m);
        !           519:                                return EINVAL;
        !           520:                        }
        !           521:                }
        !           522:
        !           523:                /* Copyback and free, if we allocated. */
        !           524:                if (alloc) {
        !           525:                        m_copyback(m, sizeof(struct ip6_hdr),
        !           526:                            skip - sizeof(struct ip6_hdr), ptr);
        !           527:                        FREE(ptr, M_XDATA);
        !           528:                }
        !           529:
        !           530:                break;
        !           531: #endif /* INET6 */
        !           532:        }
        !           533:
        !           534:        return 0;
        !           535: }
        !           536:
        !           537: /*
        !           538:  * ah_input() gets called to verify that an input packet
        !           539:  * passes authentication.
        !           540:  */
        !           541: int
        !           542: ah_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
        !           543: {
        !           544:        struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform;
        !           545:        struct tdb_crypto *tc;
        !           546:        struct m_tag *mtag;
        !           547:        u_int32_t btsx;
        !           548:        u_int8_t hl;
        !           549:        int rplen;
        !           550:
        !           551:        struct cryptodesc *crda = NULL;
        !           552:        struct cryptop *crp;
        !           553:
        !           554:        if (!(tdb->tdb_flags & TDBF_NOREPLAY))
        !           555:                rplen = AH_FLENGTH + sizeof(u_int32_t);
        !           556:        else
        !           557:                rplen = AH_FLENGTH;
        !           558:
        !           559:        /* Save the AH header, we use it throughout. */
        !           560:        m_copydata(m, skip + offsetof(struct ah, ah_hl), sizeof(u_int8_t),
        !           561:            (caddr_t) &hl);
        !           562:
        !           563:        /* Replay window checking, if applicable. */
        !           564:        if ((tdb->tdb_wnd > 0) && (!(tdb->tdb_flags & TDBF_NOREPLAY))) {
        !           565:                m_copydata(m, skip + offsetof(struct ah, ah_rpl),
        !           566:                    sizeof(u_int32_t), (caddr_t) &btsx);
        !           567:                btsx = ntohl(btsx);
        !           568:
        !           569:                switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl),
        !           570:                    tdb->tdb_wnd, &(tdb->tdb_bitmap), 0)) {
        !           571:                case 0: /* All's well. */
        !           572:                        break;
        !           573:
        !           574:                case 1:
        !           575:                        DPRINTF(("ah_input(): replay counter wrapped for "
        !           576:                            "SA %s/%08x\n", ipsp_address(tdb->tdb_dst),
        !           577:                            ntohl(tdb->tdb_spi)));
        !           578:
        !           579:                        ahstat.ahs_wrap++;
        !           580:                        m_freem(m);
        !           581:                        return ENOBUFS;
        !           582:
        !           583:                case 2:
        !           584:                case 3:
        !           585:                        DPRINTF(("ah_input(): duplicate packet received in "
        !           586:                            "SA %s/%08x\n", ipsp_address(tdb->tdb_dst),
        !           587:                            ntohl(tdb->tdb_spi)));
        !           588:
        !           589:                        m_freem(m);
        !           590:                        return ENOBUFS;
        !           591:
        !           592:                default:
        !           593:                        DPRINTF(("ah_input(): bogus value from "
        !           594:                            "checkreplaywindow32() in SA %s/%08x\n",
        !           595:                            ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
        !           596:
        !           597:                        ahstat.ahs_replay++;
        !           598:                        m_freem(m);
        !           599:                        return ENOBUFS;
        !           600:                }
        !           601:        }
        !           602:
        !           603:        /* Verify AH header length. */
        !           604:        if (hl * sizeof(u_int32_t) != ahx->authsize + rplen - AH_FLENGTH) {
        !           605:                DPRINTF(("ah_input(): bad authenticator length %d for packet "
        !           606:                    "in SA %s/%08x\n", hl * sizeof(u_int32_t),
        !           607:                    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
        !           608:
        !           609:                ahstat.ahs_badauthl++;
        !           610:                m_freem(m);
        !           611:                return EACCES;
        !           612:        }
        !           613:
        !           614:        /* Update the counters. */
        !           615:        tdb->tdb_cur_bytes +=
        !           616:            (m->m_pkthdr.len - skip - hl * sizeof(u_int32_t));
        !           617:        ahstat.ahs_ibytes += (m->m_pkthdr.len - skip - hl * sizeof(u_int32_t));
        !           618:
        !           619:        /* Hard expiration. */
        !           620:        if (tdb->tdb_flags & TDBF_BYTES &&
        !           621:            tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes) {
        !           622:                pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
        !           623:                tdb_delete(tdb);
        !           624:                m_freem(m);
        !           625:                return ENXIO;
        !           626:        }
        !           627:
        !           628:        /* Notify on expiration. */
        !           629:        if (tdb->tdb_flags & TDBF_SOFT_BYTES &&
        !           630:            tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes) {
        !           631:                pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
        !           632:                tdb->tdb_flags &= ~TDBF_SOFT_BYTES;  /* Turn off checking. */
        !           633:        }
        !           634:
        !           635:        /* Get crypto descriptors. */
        !           636:        crp = crypto_getreq(1);
        !           637:        if (crp == NULL) {
        !           638:                m_freem(m);
        !           639:                DPRINTF(("ah_input(): failed to acquire crypto "
        !           640:                    "descriptors\n"));
        !           641:                ahstat.ahs_crypto++;
        !           642:                return ENOBUFS;
        !           643:        }
        !           644:
        !           645:        crda = crp->crp_desc;
        !           646:
        !           647:        crda->crd_skip = 0;
        !           648:        crda->crd_len = m->m_pkthdr.len;
        !           649:        crda->crd_inject = skip + rplen;
        !           650:
        !           651:        /* Authentication operation. */
        !           652:        crda->crd_alg = ahx->type;
        !           653:        crda->crd_key = tdb->tdb_amxkey;
        !           654:        crda->crd_klen = tdb->tdb_amxkeylen * 8;
        !           655:
        !           656: #ifdef notyet
        !           657:        /* Find out if we've already done crypto. */
        !           658:        for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL);
        !           659:             mtag != NULL;
        !           660:             mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) {
        !           661:                struct tdb_ident *tdbi;
        !           662:
        !           663:                tdbi = (struct tdb_ident *) (mtag + 1);
        !           664:                if (tdbi->proto == tdb->tdb_sproto &&
        !           665:                    tdbi->spi == tdb->tdb_spi &&
        !           666:                    !bcmp(&tdbi->dst, &tdb->tdb_dst,
        !           667:                        sizeof(union sockaddr_union)))
        !           668:                        break;
        !           669:        }
        !           670: #else
        !           671:        mtag = NULL;
        !           672: #endif
        !           673:
        !           674:        /* Allocate IPsec-specific opaque crypto info. */
        !           675:        if (mtag == NULL)
        !           676:                MALLOC(tc, struct tdb_crypto *,
        !           677:                    sizeof(struct tdb_crypto) + skip +
        !           678:                    rplen + ahx->authsize, M_XDATA, M_NOWAIT);
        !           679:        else /* Hash verification has already been done successfully. */
        !           680:                MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto),
        !           681:                    M_XDATA, M_NOWAIT);
        !           682:        if (tc == NULL) {
        !           683:                m_freem(m);
        !           684:                crypto_freereq(crp);
        !           685:                DPRINTF(("ah_input(): failed to allocate tdb_crypto\n"));
        !           686:                ahstat.ahs_crypto++;
        !           687:                return ENOBUFS;
        !           688:        }
        !           689:
        !           690:        bzero(tc, sizeof(struct tdb_crypto));
        !           691:
        !           692:        /* Only save information if crypto processing is needed. */
        !           693:        if (mtag == NULL) {
        !           694:                /*
        !           695:                 * Save the authenticator, the skipped portion of the packet,
        !           696:                 * and the AH header.
        !           697:                 */
        !           698:                m_copydata(m, 0, skip + rplen + ahx->authsize,
        !           699:                    (caddr_t) (tc + 1));
        !           700:
        !           701:                /* Zeroize the authenticator on the packet. */
        !           702:                m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes);
        !           703:
        !           704:                /* "Massage" the packet headers for crypto processing. */
        !           705:                if ((btsx = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family,
        !           706:                    skip, ahx->type, 0)) != 0) {
        !           707:                        /* mbuf will be free'd by callee. */
        !           708:                        FREE(tc, M_XDATA);
        !           709:                        crypto_freereq(crp);
        !           710:                        return btsx;
        !           711:                }
        !           712:        }
        !           713:
        !           714:        /* Crypto operation descriptor. */
        !           715:        crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
        !           716:        crp->crp_flags = CRYPTO_F_IMBUF;
        !           717:        crp->crp_buf = (caddr_t) m;
        !           718:        crp->crp_callback = (int (*) (struct cryptop *)) ah_input_cb;
        !           719:        crp->crp_sid = tdb->tdb_cryptoid;
        !           720:        crp->crp_opaque = (caddr_t) tc;
        !           721:
        !           722:        /* These are passed as-is to the callback. */
        !           723:        tc->tc_skip = skip;
        !           724:        tc->tc_protoff = protoff;
        !           725:        tc->tc_spi = tdb->tdb_spi;
        !           726:        tc->tc_proto = tdb->tdb_sproto;
        !           727:        tc->tc_ptr = (caddr_t) mtag; /* Save the mtag we've identified. */
        !           728:        bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union));
        !           729:
        !           730:        if (mtag == NULL)
        !           731:                return crypto_dispatch(crp);
        !           732:        else
        !           733:                return ah_input_cb(crp);
        !           734: }
        !           735:
        !           736: /*
        !           737:  * AH input callback, called directly by the crypto driver.
        !           738:  */
        !           739: int
        !           740: ah_input_cb(void *op)
        !           741: {
        !           742:        int s, roff, rplen, error, skip, protoff;
        !           743:        unsigned char calc[AH_ALEN_MAX];
        !           744:        struct mbuf *m1, *m0, *m;
        !           745:        struct cryptodesc *crd;
        !           746:        struct auth_hash *ahx;
        !           747:        struct tdb_crypto *tc;
        !           748:        struct cryptop *crp;
        !           749:        struct m_tag *mtag;
        !           750:        struct tdb *tdb;
        !           751:        u_int32_t btsx;
        !           752:        u_int8_t prot;
        !           753:        caddr_t ptr;
        !           754:
        !           755:        crp = (struct cryptop *) op;
        !           756:        crd = crp->crp_desc;
        !           757:
        !           758:        tc = (struct tdb_crypto *) crp->crp_opaque;
        !           759:        skip = tc->tc_skip;
        !           760:        protoff = tc->tc_protoff;
        !           761:        mtag = (struct m_tag *) tc->tc_ptr;
        !           762:
        !           763:        m = (struct mbuf *) crp->crp_buf;
        !           764:        if (m == NULL) {
        !           765:                /* Shouldn't happen... */
        !           766:                FREE(tc, M_XDATA);
        !           767:                crypto_freereq(crp);
        !           768:                ahstat.ahs_crypto++;
        !           769:                DPRINTF(("ah_input_cb(): bogus returned buffer from "
        !           770:                    "crypto\n"));
        !           771:                return (EINVAL);
        !           772:        }
        !           773:
        !           774:        s = spltdb();
        !           775:
        !           776:        tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto);
        !           777:        if (tdb == NULL) {
        !           778:                FREE(tc, M_XDATA);
        !           779:                ahstat.ahs_notdb++;
        !           780:                DPRINTF(("ah_input_cb(): TDB is expired while in crypto"));
        !           781:                error = EPERM;
        !           782:                goto baddone;
        !           783:        }
        !           784:
        !           785:        ahx = (struct auth_hash *) tdb->tdb_authalgxform;
        !           786:
        !           787:        /* Check for crypto errors. */
        !           788:        if (crp->crp_etype) {
        !           789:                if (crp->crp_etype == EAGAIN) {
        !           790:                        /* Reset the session ID */
        !           791:                        if (tdb->tdb_cryptoid != 0)
        !           792:                                tdb->tdb_cryptoid = crp->crp_sid;
        !           793:                        splx(s);
        !           794:                        return crypto_dispatch(crp);
        !           795:                }
        !           796:                FREE(tc, M_XDATA);
        !           797:                ahstat.ahs_noxform++;
        !           798:                DPRINTF(("ah_input_cb(): crypto error %d\n", crp->crp_etype));
        !           799:                error = crp->crp_etype;
        !           800:                goto baddone;
        !           801:        } else {
        !           802:                crypto_freereq(crp); /* No longer needed. */
        !           803:                crp = NULL;
        !           804:        }
        !           805:
        !           806:        if (!(tdb->tdb_flags & TDBF_NOREPLAY))
        !           807:                rplen = AH_FLENGTH + sizeof(u_int32_t);
        !           808:        else
        !           809:                rplen = AH_FLENGTH;
        !           810:
        !           811:        /* Copy authenticator off the packet. */
        !           812:        m_copydata(m, skip + rplen, ahx->authsize, calc);
        !           813:
        !           814:        /*
        !           815:         * If we have an mtag, we don't need to verify the authenticator --
        !           816:         * it has been verified by an IPsec-aware NIC.
        !           817:         */
        !           818:        if (mtag == NULL) {
        !           819:                ptr = (caddr_t) (tc + 1);
        !           820:
        !           821:                /* Verify authenticator. */
        !           822:                if (bcmp(ptr + skip + rplen, calc, ahx->authsize)) {
        !           823:                        FREE(tc, M_XDATA);
        !           824:
        !           825:                        DPRINTF(("ah_input(): authentication failed for "
        !           826:                            "packet in SA %s/%08x\n",
        !           827:                            ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
        !           828:
        !           829:                        ahstat.ahs_badauth++;
        !           830:                        error = EACCES;
        !           831:                        goto baddone;
        !           832:                }
        !           833:
        !           834:                /* Fix the Next Protocol field. */
        !           835:                ((u_int8_t *) ptr)[protoff] = ((u_int8_t *) ptr)[skip];
        !           836:
        !           837:                /* Copyback the saved (uncooked) network headers. */
        !           838:                m_copyback(m, 0, skip, ptr);
        !           839:        } else {
        !           840:                /* Fix the Next Protocol field. */
        !           841:                m_copydata(m, skip, sizeof(u_int8_t), &prot);
        !           842:                m_copyback(m, protoff, sizeof(u_int8_t), &prot);
        !           843:        }
        !           844:
        !           845:        FREE(tc, M_XDATA);
        !           846:
        !           847:        /* Replay window checking, if applicable. */
        !           848:        if ((tdb->tdb_wnd > 0) && (!(tdb->tdb_flags & TDBF_NOREPLAY))) {
        !           849:                m_copydata(m, skip + offsetof(struct ah, ah_rpl),
        !           850:                    sizeof(u_int32_t), (caddr_t) &btsx);
        !           851:                btsx = ntohl(btsx);
        !           852:
        !           853:                switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl),
        !           854:                    tdb->tdb_wnd, &(tdb->tdb_bitmap), 1)) {
        !           855:                case 0: /* All's well. */
        !           856: #if NPFSYNC > 0
        !           857:                        pfsync_update_tdb(tdb,0);
        !           858: #endif
        !           859:                        break;
        !           860:
        !           861:                case 1:
        !           862:                        DPRINTF(("ah_input(): replay counter wrapped for "
        !           863:                            "SA %s/%08x\n", ipsp_address(tdb->tdb_dst),
        !           864:                            ntohl(tdb->tdb_spi)));
        !           865:
        !           866:                        ahstat.ahs_wrap++;
        !           867:                        error = ENOBUFS;
        !           868:                        goto baddone;
        !           869:
        !           870:                case 2:
        !           871:                case 3:
        !           872:                        DPRINTF(("ah_input_cb(): duplicate packet received in "
        !           873:                            "SA %s/%08x\n", ipsp_address(tdb->tdb_dst),
        !           874:                            ntohl(tdb->tdb_spi)));
        !           875:
        !           876:                        error = ENOBUFS;
        !           877:                        goto baddone;
        !           878:
        !           879:                default:
        !           880:                        DPRINTF(("ah_input_cb(): bogus value from "
        !           881:                            "checkreplaywindow32() in SA %s/%08x\n",
        !           882:                            ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
        !           883:
        !           884:                        ahstat.ahs_replay++;
        !           885:                        error = ENOBUFS;
        !           886:                        goto baddone;
        !           887:                }
        !           888:        }
        !           889:
        !           890:        /* Record the beginning of the AH header. */
        !           891:        m1 = m_getptr(m, skip, &roff);
        !           892:        if (m1 == NULL) {
        !           893:                ahstat.ahs_hdrops++;
        !           894:                splx(s);
        !           895:                m_freem(m);
        !           896:
        !           897:                DPRINTF(("ah_input(): bad mbuf chain for packet in SA "
        !           898:                    "%s/%08x\n", ipsp_address(tdb->tdb_dst),
        !           899:                    ntohl(tdb->tdb_spi)));
        !           900:
        !           901:                return EINVAL;
        !           902:        }
        !           903:
        !           904:        /* Remove the AH header from the mbuf. */
        !           905:        if (roff == 0) {
        !           906:                /*
        !           907:                 * The AH header was conveniently at the beginning of
        !           908:                 * the mbuf.
        !           909:                 */
        !           910:                m_adj(m1, rplen + ahx->authsize);
        !           911:                if (!(m1->m_flags & M_PKTHDR))
        !           912:                        m->m_pkthdr.len -= rplen + ahx->authsize;
        !           913:        } else
        !           914:                if (roff + rplen + ahx->authsize >= m1->m_len) {
        !           915:                        /*
        !           916:                         * Part or all of the AH header is at the end
        !           917:                         * of this mbuf, so first let's remove the
        !           918:                         * remainder of the AH header from the
        !           919:                         * beginning of the remainder of the mbuf
        !           920:                         * chain, if any.
        !           921:                         */
        !           922:                        if (roff + rplen + ahx->authsize > m1->m_len) {
        !           923:                                /* Adjust the next mbuf by the remainder. */
        !           924:                                m_adj(m1->m_next, roff + rplen +
        !           925:                                    ahx->authsize - m1->m_len);
        !           926:
        !           927:                                /*
        !           928:                                 * The second mbuf is guaranteed not
        !           929:                                 * to have a pkthdr...
        !           930:                                 */
        !           931:                                m->m_pkthdr.len -=
        !           932:                                    (roff + rplen + ahx->authsize - m1->m_len);
        !           933:                        }
        !           934:
        !           935:                        /* Now, let's unlink the mbuf chain for a second... */
        !           936:                        m0 = m1->m_next;
        !           937:                        m1->m_next = NULL;
        !           938:
        !           939:                        /*
        !           940:                         * ...and trim the end of the first part of
        !           941:                         * the chain...sick
        !           942:                         */
        !           943:                        m_adj(m1, -(m1->m_len - roff));
        !           944:                        if (!(m1->m_flags & M_PKTHDR))
        !           945:                                m->m_pkthdr.len -= (m1->m_len - roff);
        !           946:
        !           947:                        /* Finally, let's relink. */
        !           948:                        m1->m_next = m0;
        !           949:                } else {
        !           950:                        /*
        !           951:                         * The AH header lies in the "middle" of the
        !           952:                         * mbuf...do an overlapping copy of the
        !           953:                         * remainder of the mbuf over the ESP header.
        !           954:                         */
        !           955:                        bcopy(mtod(m1, u_char *) + roff + rplen +
        !           956:                            ahx->authsize, mtod(m1, u_char *) + roff,
        !           957:                            m1->m_len - (roff + rplen + ahx->authsize));
        !           958:                        m1->m_len -= rplen + ahx->authsize;
        !           959:                        m->m_pkthdr.len -= rplen + ahx->authsize;
        !           960:                }
        !           961:
        !           962:        error = ipsec_common_input_cb(m, tdb, skip, protoff, mtag);
        !           963:        splx(s);
        !           964:        return (error);
        !           965:
        !           966:  baddone:
        !           967:        splx(s);
        !           968:
        !           969:        if (m != NULL)
        !           970:                m_freem(m);
        !           971:
        !           972:        if (crp != NULL)
        !           973:                crypto_freereq(crp);
        !           974:
        !           975:        return (error);
        !           976: }
        !           977:
        !           978: /*
        !           979:  * AH output routine, called by ipsp_process_packet().
        !           980:  */
        !           981: int
        !           982: ah_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
        !           983:     int protoff)
        !           984: {
        !           985:        struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform;
        !           986:        struct cryptodesc *crda;
        !           987:        struct tdb_crypto *tc;
        !           988:        struct mbuf *mo, *mi;
        !           989:        struct cryptop *crp;
        !           990:        u_int16_t iplen;
        !           991:        int len, rplen;
        !           992:        u_int8_t prot;
        !           993:        struct ah *ah;
        !           994: #if NBPFILTER > 0
        !           995:        struct ifnet *ifn = &(encif[0].sc_if);
        !           996:
        !           997:        ifn->if_opackets++;
        !           998:        ifn->if_obytes += m->m_pkthdr.len;
        !           999:
        !          1000:        if (ifn->if_bpf) {
        !          1001:                struct enchdr hdr;
        !          1002:
        !          1003:                bzero (&hdr, sizeof(hdr));
        !          1004:
        !          1005:                hdr.af = tdb->tdb_dst.sa.sa_family;
        !          1006:                hdr.spi = tdb->tdb_spi;
        !          1007:                hdr.flags |= M_AUTH | M_AUTH_AH;
        !          1008:
        !          1009:                bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, ENC_HDRLEN, m,
        !          1010:                    BPF_DIRECTION_OUT);
        !          1011:        }
        !          1012: #endif
        !          1013:
        !          1014:        ahstat.ahs_output++;
        !          1015:
        !          1016:        /*
        !          1017:         * Check for replay counter wrap-around in automatic (not
        !          1018:         * manual) keying.
        !          1019:         */
        !          1020:        if ((tdb->tdb_rpl == 0) && (tdb->tdb_wnd > 0) &&
        !          1021:            (!(tdb->tdb_flags & TDBF_NOREPLAY))) {
        !          1022:                DPRINTF(("ah_output(): SA %s/%08x should have expired\n",
        !          1023:                    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
        !          1024:                m_freem(m);
        !          1025:                ahstat.ahs_wrap++;
        !          1026:                return EINVAL;
        !          1027:        }
        !          1028:
        !          1029:        if (!(tdb->tdb_flags & TDBF_NOREPLAY))
        !          1030:                rplen = AH_FLENGTH + sizeof(u_int32_t);
        !          1031:        else
        !          1032:                rplen = AH_FLENGTH;
        !          1033:
        !          1034:        switch (tdb->tdb_dst.sa.sa_family) {
        !          1035: #ifdef INET
        !          1036:        case AF_INET:
        !          1037:                /* Check for IP maximum packet size violations. */
        !          1038:                if (rplen + ahx->authsize + m->m_pkthdr.len > IP_MAXPACKET) {
        !          1039:                        DPRINTF(("ah_output(): packet in SA %s/%08x got too "
        !          1040:                            "big\n",
        !          1041:                            ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
        !          1042:                        m_freem(m);
        !          1043:                        ahstat.ahs_toobig++;
        !          1044:                        return EMSGSIZE;
        !          1045:                }
        !          1046:                break;
        !          1047: #endif /* INET */
        !          1048:
        !          1049: #ifdef INET6
        !          1050:        case AF_INET6:
        !          1051:                /* Check for IPv6 maximum packet size violations. */
        !          1052:                if (rplen + ahx->authsize + m->m_pkthdr.len > IPV6_MAXPACKET) {
        !          1053:                        DPRINTF(("ah_output(): packet in SA %s/%08x "
        !          1054:                            "got too big\n", ipsp_address(tdb->tdb_dst),
        !          1055:                            ntohl(tdb->tdb_spi)));
        !          1056:                        m_freem(m);
        !          1057:                        ahstat.ahs_toobig++;
        !          1058:                        return EMSGSIZE;
        !          1059:                }
        !          1060:                break;
        !          1061: #endif /* INET6 */
        !          1062:
        !          1063:        default:
        !          1064:                DPRINTF(("ah_output(): unknown/unsupported protocol "
        !          1065:                    "family %d, SA %s/%08x\n", tdb->tdb_dst.sa.sa_family,
        !          1066:                    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
        !          1067:                m_freem(m);
        !          1068:                ahstat.ahs_nopf++;
        !          1069:                return EPFNOSUPPORT;
        !          1070:        }
        !          1071:
        !          1072:        /* Update the counters. */
        !          1073:        tdb->tdb_cur_bytes += m->m_pkthdr.len - skip;
        !          1074:        ahstat.ahs_obytes += m->m_pkthdr.len - skip;
        !          1075:
        !          1076:        /* Hard expiration. */
        !          1077:        if (tdb->tdb_flags & TDBF_BYTES &&
        !          1078:            tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes) {
        !          1079:                pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
        !          1080:                tdb_delete(tdb);
        !          1081:                m_freem(m);
        !          1082:                return EINVAL;
        !          1083:        }
        !          1084:
        !          1085:        /* Notify on expiration. */
        !          1086:        if (tdb->tdb_flags & TDBF_SOFT_BYTES &&
        !          1087:            tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes) {
        !          1088:                pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
        !          1089:                tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */
        !          1090:        }
        !          1091:
        !          1092:        /*
        !          1093:         * Loop through mbuf chain; if we find a readonly mbuf,
        !          1094:         * replace the rest of the chain.
        !          1095:         */
        !          1096:        mo = NULL;
        !          1097:        mi = m;
        !          1098:        while (mi != NULL && !M_READONLY(mi)) {
        !          1099:                mo = mi;
        !          1100:                mi = mi->m_next;
        !          1101:        }
        !          1102:
        !          1103:        if (mi != NULL) {
        !          1104:                /* Replace the rest of the mbuf chain. */
        !          1105:                struct mbuf *n = m_copym2(mi, 0, M_COPYALL, M_DONTWAIT);
        !          1106:
        !          1107:                if (n == NULL) {
        !          1108:                        ahstat.ahs_hdrops++;
        !          1109:                        m_freem(m);
        !          1110:                        return ENOBUFS;
        !          1111:                }
        !          1112:
        !          1113:                if (mo != NULL)
        !          1114:                        mo->m_next = n;
        !          1115:                else
        !          1116:                        m = n;
        !          1117:
        !          1118:                m_freem(mi);
        !          1119:        }
        !          1120:
        !          1121:        /* Inject AH header. */
        !          1122:        mi = m_inject(m, skip, rplen + ahx->authsize, M_DONTWAIT);
        !          1123:        if (mi == NULL) {
        !          1124:                DPRINTF(("ah_output(): failed to inject AH header for SA "
        !          1125:                    "%s/%08x\n", ipsp_address(tdb->tdb_dst),
        !          1126:                    ntohl(tdb->tdb_spi)));
        !          1127:
        !          1128:                m_freem(m);
        !          1129:                ahstat.ahs_hdrops++;
        !          1130:                return ENOBUFS;
        !          1131:        }
        !          1132:
        !          1133:        /*
        !          1134:         * The AH header is guaranteed by m_inject() to be in
        !          1135:         * contiguous memory, at the beginning of the returned mbuf.
        !          1136:         */
        !          1137:        ah = mtod(mi, struct ah *);
        !          1138:
        !          1139:        /* Initialize the AH header. */
        !          1140:        m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &ah->ah_nh);
        !          1141:        ah->ah_hl = (rplen + ahx->authsize - AH_FLENGTH) / sizeof(u_int32_t);
        !          1142:        ah->ah_rv = 0;
        !          1143:        ah->ah_spi = tdb->tdb_spi;
        !          1144:
        !          1145:        /* Zeroize authenticator. */
        !          1146:        m_copyback(m, skip + rplen, ahx->authsize, ipseczeroes);
        !          1147:
        !          1148:        if (!(tdb->tdb_flags & TDBF_NOREPLAY)) {
        !          1149:                ah->ah_rpl = htonl(tdb->tdb_rpl++);
        !          1150: #if NPFSYNC > 0
        !          1151:                pfsync_update_tdb(tdb,1);
        !          1152: #endif
        !          1153:        }
        !          1154:
        !          1155:        /* Get crypto descriptors. */
        !          1156:        crp = crypto_getreq(1);
        !          1157:        if (crp == NULL) {
        !          1158:                m_freem(m);
        !          1159:                DPRINTF(("ah_output(): failed to acquire crypto "
        !          1160:                    "descriptors\n"));
        !          1161:                ahstat.ahs_crypto++;
        !          1162:                return ENOBUFS;
        !          1163:        }
        !          1164:
        !          1165:        crda = crp->crp_desc;
        !          1166:
        !          1167:        crda->crd_skip = 0;
        !          1168:        crda->crd_inject = skip + rplen;
        !          1169:        crda->crd_len = m->m_pkthdr.len;
        !          1170:
        !          1171:        /* Authentication operation. */
        !          1172:        crda->crd_alg = ahx->type;
        !          1173:        crda->crd_key = tdb->tdb_amxkey;
        !          1174:        crda->crd_klen = tdb->tdb_amxkeylen * 8;
        !          1175:
        !          1176:        /* Allocate IPsec-specific opaque crypto info. */
        !          1177:        if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0)
        !          1178:                MALLOC(tc, struct tdb_crypto *,
        !          1179:                    sizeof(struct tdb_crypto) + skip, M_XDATA, M_NOWAIT);
        !          1180:        else
        !          1181:                MALLOC(tc, struct tdb_crypto *,
        !          1182:                    sizeof(struct tdb_crypto), M_XDATA, M_NOWAIT);
        !          1183:        if (tc == NULL) {
        !          1184:                m_freem(m);
        !          1185:                crypto_freereq(crp);
        !          1186:                DPRINTF(("ah_output(): failed to allocate tdb_crypto\n"));
        !          1187:                ahstat.ahs_crypto++;
        !          1188:                return ENOBUFS;
        !          1189:        }
        !          1190:
        !          1191:        bzero(tc, sizeof(struct tdb_crypto));
        !          1192:
        !          1193:        /* Save the skipped portion of the packet. */
        !          1194:        if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0) {
        !          1195:                m_copydata(m, 0, skip, (caddr_t) (tc + 1));
        !          1196:
        !          1197:                /*
        !          1198:                 * Fix IP header length on the header used for
        !          1199:                 * authentication. We don't need to fix the original
        !          1200:                 * header length as it will be fixed by our caller.
        !          1201:                 */
        !          1202:                switch (tdb->tdb_dst.sa.sa_family) {
        !          1203: #ifdef INET
        !          1204:                case AF_INET:
        !          1205:                        bcopy(((caddr_t)(tc + 1)) +
        !          1206:                            offsetof(struct ip, ip_len),
        !          1207:                            (caddr_t) &iplen, sizeof(u_int16_t));
        !          1208:                        iplen = htons(ntohs(iplen) + rplen + ahx->authsize);
        !          1209:                        m_copyback(m, offsetof(struct ip, ip_len),
        !          1210:                            sizeof(u_int16_t), &iplen);
        !          1211:                        break;
        !          1212: #endif /* INET */
        !          1213:
        !          1214: #ifdef INET6
        !          1215:                case AF_INET6:
        !          1216:                        bcopy(((caddr_t)(tc + 1)) +
        !          1217:                            offsetof(struct ip6_hdr, ip6_plen),
        !          1218:                            (caddr_t) &iplen, sizeof(u_int16_t));
        !          1219:                        iplen = htons(ntohs(iplen) + rplen + ahx->authsize);
        !          1220:                        m_copyback(m, offsetof(struct ip6_hdr, ip6_plen),
        !          1221:                            sizeof(u_int16_t), &iplen);
        !          1222:                        break;
        !          1223: #endif /* INET6 */
        !          1224:                }
        !          1225:
        !          1226:                /* Fix the Next Header field in saved header. */
        !          1227:                ((u_int8_t *) (tc + 1))[protoff] = IPPROTO_AH;
        !          1228:
        !          1229:                /* Update the Next Protocol field in the IP header. */
        !          1230:                prot = IPPROTO_AH;
        !          1231:                m_copyback(m, protoff, sizeof(u_int8_t), &prot);
        !          1232:
        !          1233:                /* "Massage" the packet headers for crypto processing. */
        !          1234:                if ((len = ah_massage_headers(&m, tdb->tdb_dst.sa.sa_family,
        !          1235:                    skip, ahx->type, 1)) != 0) {
        !          1236:                        /* mbuf will be free'd by callee. */
        !          1237:                        FREE(tc, M_XDATA);
        !          1238:                        crypto_freereq(crp);
        !          1239:                        return len;
        !          1240:                }
        !          1241:        } else {
        !          1242:                /* Update the Next Protocol field in the IP header. */
        !          1243:                prot = IPPROTO_AH;
        !          1244:                m_copyback(m, protoff, sizeof(u_int8_t), &prot);
        !          1245:        }
        !          1246:
        !          1247:        /* Crypto operation descriptor. */
        !          1248:        crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
        !          1249:        crp->crp_flags = CRYPTO_F_IMBUF;
        !          1250:        crp->crp_buf = (caddr_t) m;
        !          1251:        crp->crp_callback = (int (*) (struct cryptop *)) ah_output_cb;
        !          1252:        crp->crp_sid = tdb->tdb_cryptoid;
        !          1253:        crp->crp_opaque = (caddr_t) tc;
        !          1254:
        !          1255:        /* These are passed as-is to the callback. */
        !          1256:        tc->tc_skip = skip;
        !          1257:        tc->tc_protoff = protoff;
        !          1258:        tc->tc_spi = tdb->tdb_spi;
        !          1259:        tc->tc_proto = tdb->tdb_sproto;
        !          1260:        bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union));
        !          1261:
        !          1262:        if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0)
        !          1263:                return crypto_dispatch(crp);
        !          1264:        else
        !          1265:                return ah_output_cb(crp);
        !          1266: }
        !          1267:
        !          1268: /*
        !          1269:  * AH output callback, called directly from the crypto handler.
        !          1270:  */
        !          1271: int
        !          1272: ah_output_cb(void *op)
        !          1273: {
        !          1274:        int skip, protoff, error;
        !          1275:        struct tdb_crypto *tc;
        !          1276:        struct cryptop *crp;
        !          1277:        struct tdb *tdb;
        !          1278:        struct mbuf *m;
        !          1279:        caddr_t ptr;
        !          1280:        int err, s;
        !          1281:
        !          1282:        crp = (struct cryptop *) op;
        !          1283:        tc = (struct tdb_crypto *) crp->crp_opaque;
        !          1284:        skip = tc->tc_skip;
        !          1285:        protoff = tc->tc_protoff;
        !          1286:        ptr = (caddr_t) (tc + 1);
        !          1287:
        !          1288:        m = (struct mbuf *) crp->crp_buf;
        !          1289:        if (m == NULL) {
        !          1290:                /* Shouldn't happen... */
        !          1291:                FREE(tc, M_XDATA);
        !          1292:                crypto_freereq(crp);
        !          1293:                ahstat.ahs_crypto++;
        !          1294:                DPRINTF(("ah_output_cb(): bogus returned buffer from "
        !          1295:                    "crypto\n"));
        !          1296:                return (EINVAL);
        !          1297:        }
        !          1298:
        !          1299:        s = spltdb();
        !          1300:
        !          1301:        tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto);
        !          1302:        if (tdb == NULL) {
        !          1303:                FREE(tc, M_XDATA);
        !          1304:                ahstat.ahs_notdb++;
        !          1305:                DPRINTF(("ah_output_cb(): TDB is expired while in crypto\n"));
        !          1306:                error = EPERM;
        !          1307:                goto baddone;
        !          1308:        }
        !          1309:
        !          1310:        /* Check for crypto errors. */
        !          1311:        if (crp->crp_etype) {
        !          1312:                if (crp->crp_etype == EAGAIN) {
        !          1313:                        /* Reset the session ID */
        !          1314:                        if (tdb->tdb_cryptoid != 0)
        !          1315:                                tdb->tdb_cryptoid = crp->crp_sid;
        !          1316:                        splx(s);
        !          1317:                        return crypto_dispatch(crp);
        !          1318:                }
        !          1319:                FREE(tc, M_XDATA);
        !          1320:                ahstat.ahs_noxform++;
        !          1321:                DPRINTF(("ah_output_cb(): crypto error %d\n", crp->crp_etype));
        !          1322:                error = crp->crp_etype;
        !          1323:                goto baddone;
        !          1324:        }
        !          1325:
        !          1326:        /*
        !          1327:         * Copy original headers (with the new protocol number) back
        !          1328:         * in place.
        !          1329:         */
        !          1330:        if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0)
        !          1331:                m_copyback(m, 0, skip, ptr);
        !          1332:
        !          1333:        FREE(tc, M_XDATA);
        !          1334:
        !          1335:        /* No longer needed. */
        !          1336:        crypto_freereq(crp);
        !          1337:
        !          1338:        err =  ipsp_process_done(m, tdb);
        !          1339:        splx(s);
        !          1340:        return err;
        !          1341:
        !          1342:  baddone:
        !          1343:        splx(s);
        !          1344:
        !          1345:        if (m != NULL)
        !          1346:                m_freem(m);
        !          1347:
        !          1348:        crypto_freereq(crp);
        !          1349:
        !          1350:        return error;
        !          1351: }

CVSweb