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

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

1.1       nbrk        1: /* $OpenBSD: ip_ipcomp.c,v 1.20 2006/03/25 22:41:48 djm Exp $ */
                      2:
                      3: /*
                      4:  * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  *
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *   notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *   notice, this list of conditions and the following disclaimer in the
                     14:  *   documentation and/or other materials provided with the distribution.
                     15:  * 3. The name of the author may not be used to endorse or promote products
                     16:  *   derived from this software without specific prior written permission.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     21:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     23:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     27:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     28:  */
                     29:
                     30: /* IP payload compression protocol (IPComp), see RFC 2393 */
                     31:
                     32: #include <sys/param.h>
                     33: #include <sys/systm.h>
                     34: #include <sys/mbuf.h>
                     35: #include <sys/socket.h>
                     36:
                     37: #include <net/if.h>
                     38: #include <net/bpf.h>
                     39:
                     40: #include <dev/rndvar.h>
                     41:
                     42: #ifdef INET
                     43: #include <netinet/in.h>
                     44: #include <netinet/in_systm.h>
                     45: #include <netinet/ip.h>
                     46: #endif                         /* INET */
                     47:
                     48: #ifdef INET6
                     49: #ifndef INET
                     50: #include <netinet/in.h>
                     51: #endif
                     52: #include <netinet/ip6.h>
                     53: #endif                         /* INET6 */
                     54:
                     55: #include <netinet/ip_ipsp.h>
                     56: #include <netinet/ip_ipcomp.h>
                     57: #include <net/pfkeyv2.h>
                     58: #include <net/if_enc.h>
                     59:
                     60: #include <crypto/cryptodev.h>
                     61: #include <crypto/deflate.h>
                     62: #include <crypto/xform.h>
                     63:
                     64: #include "bpfilter.h"
                     65:
                     66: #ifdef ENCDEBUG
                     67: #define DPRINTF(x)      if (encdebug) printf x
                     68: #else
                     69: #define DPRINTF(x)
                     70: #endif
                     71:
                     72: struct ipcompstat ipcompstat;
                     73:
                     74: /*
                     75:  * ipcomp_attach() is called from the transformation code
                     76:  */
                     77: int
                     78: ipcomp_attach(void)
                     79: {
                     80:        return 0;
                     81: }
                     82:
                     83: /*
                     84:  * ipcomp_init() is called when an CPI is being set up.
                     85:  */
                     86: int
                     87: ipcomp_init(tdbp, xsp, ii)
                     88:        struct tdb     *tdbp;
                     89:        struct xformsw *xsp;
                     90:        struct ipsecinit *ii;
                     91: {
                     92:        struct comp_algo *tcomp = NULL;
                     93:        struct cryptoini cric;
                     94:
                     95:        switch (ii->ii_compalg) {
                     96:        case SADB_X_CALG_DEFLATE:
                     97:                tcomp = &comp_algo_deflate;
                     98:                break;
                     99:        case SADB_X_CALG_LZS:
                    100:                tcomp = &comp_algo_lzs;
                    101:                break;
                    102:
                    103:        default:
                    104:                DPRINTF(("ipcomp_init(): unsupported compression algorithm %d specified\n",
                    105:                    ii->ii_compalg));
                    106:                return EINVAL;
                    107:        }
                    108:
                    109:        tdbp->tdb_compalgxform = tcomp;
                    110:
                    111:        DPRINTF(("ipcomp_init(): initialized TDB with ipcomp algorithm %s\n",
                    112:            tcomp->name));
                    113:
                    114:        tdbp->tdb_xform = xsp;
                    115:        tdbp->tdb_bitmap = 0;
                    116:
                    117:        /* Initialize crypto session */
                    118:        bzero(&cric, sizeof(cric));
                    119:        cric.cri_alg = tdbp->tdb_compalgxform->type;
                    120:
                    121:        return crypto_newsession(&tdbp->tdb_cryptoid, &cric, 0);
                    122: }
                    123:
                    124: /*
                    125:  * ipcomp_zeroize() used when IPCA is deleted
                    126:  */
                    127: int
                    128: ipcomp_zeroize(tdbp)
                    129:        struct tdb *tdbp;
                    130: {
                    131:        int err;
                    132:
                    133:        err = crypto_freesession(tdbp->tdb_cryptoid);
                    134:        tdbp->tdb_cryptoid = 0;
                    135:        return err;
                    136: }
                    137:
                    138: /*
                    139:  * ipcomp_input() gets called to uncompress an input packet
                    140:  */
                    141: int
                    142: ipcomp_input(m, tdb, skip, protoff)
                    143:        struct mbuf    *m;
                    144:        struct tdb     *tdb;
                    145:        int             skip;
                    146:        int             protoff;
                    147: {
                    148:        struct comp_algo *ipcompx = (struct comp_algo *) tdb->tdb_compalgxform;
                    149:        struct tdb_crypto *tc;
                    150:        int hlen;
                    151:
                    152:        struct cryptodesc *crdc = NULL;
                    153:        struct cryptop *crp;
                    154:
                    155:        hlen = IPCOMP_HLENGTH;
                    156:
                    157:        /* Get crypto descriptors */
                    158:        crp = crypto_getreq(1);
                    159:        if (crp == NULL) {
                    160:                m_freem(m);
                    161:                DPRINTF(("ipcomp_input(): failed to acquire crypto descriptors\n"));
                    162:                ipcompstat.ipcomps_crypto++;
                    163:                return ENOBUFS;
                    164:        }
                    165:        /* Get IPsec-specific opaque pointer */
                    166:        MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto),
                    167:            M_XDATA, M_NOWAIT);
                    168:        if (tc == NULL) {
                    169:                m_freem(m);
                    170:                crypto_freereq(crp);
                    171:                DPRINTF(("ipcomp_input(): failed to allocate tdb_crypto\n"));
                    172:                ipcompstat.ipcomps_crypto++;
                    173:                return ENOBUFS;
                    174:        }
                    175:        bzero(tc, sizeof(struct tdb_crypto));
                    176:        crdc = crp->crp_desc;
                    177:
                    178:        crdc->crd_skip = skip + hlen;
                    179:        crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
                    180:        crdc->crd_inject = skip;
                    181:
                    182:        tc->tc_ptr = 0;
                    183:
                    184:        /* Decompression operation */
                    185:        crdc->crd_alg = ipcompx->type;
                    186:
                    187:        /* Crypto operation descriptor */
                    188:        crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
                    189:        crp->crp_flags = CRYPTO_F_IMBUF;
                    190:        crp->crp_buf = (caddr_t) m;
                    191:        crp->crp_callback = (int (*) (struct cryptop *)) ipcomp_input_cb;
                    192:        crp->crp_sid = tdb->tdb_cryptoid;
                    193:        crp->crp_opaque = (caddr_t) tc;
                    194:
                    195:        /* These are passed as-is to the callback */
                    196:        tc->tc_skip = skip;
                    197:        tc->tc_protoff = protoff;
                    198:        tc->tc_spi = tdb->tdb_spi;
                    199:        tc->tc_proto = IPPROTO_IPCOMP;
                    200:        bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union));
                    201:
                    202:        return crypto_dispatch(crp);
                    203: }
                    204:
                    205: /*
                    206:  * IPComp input callback, called directly by the crypto driver
                    207:  */
                    208: int
                    209: ipcomp_input_cb(op)
                    210:        void *op;
                    211: {
                    212:        int error, s, skip, protoff, roff, hlen = IPCOMP_HLENGTH, clen;
                    213:        u_int8_t nproto;
                    214:        struct mbuf *m, *m1, *mo;
                    215:        struct cryptodesc *crd;
                    216:        struct comp_algo *ipcompx;
                    217:        struct tdb_crypto *tc;
                    218:        struct cryptop *crp;
                    219:        struct tdb *tdb;
                    220:        struct ipcomp  *ipcomp;
                    221:        caddr_t addr;
                    222:
                    223:        crp = (struct cryptop *) op;
                    224:        crd = crp->crp_desc;
                    225:
                    226:        tc = (struct tdb_crypto *) crp->crp_opaque;
                    227:        skip = tc->tc_skip;
                    228:        protoff = tc->tc_protoff;
                    229:
                    230:        m = (struct mbuf *) crp->crp_buf;
                    231:        if (m == NULL) {
                    232:                /* Shouldn't happen... */
                    233:                FREE(tc, M_XDATA);
                    234:                crypto_freereq(crp);
                    235:                ipcompstat.ipcomps_crypto++;
                    236:                DPRINTF(("ipcomp_input_cb(): bogus returned buffer from crypto\n"));
                    237:                return (EINVAL);
                    238:        }
                    239:
                    240:        s = spltdb();
                    241:
                    242:        tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto);
                    243:        if (tdb == NULL) {
                    244:                FREE(tc, M_XDATA);
                    245:                ipcompstat.ipcomps_notdb++;
                    246:                DPRINTF(("ipcomp_input_cb(): TDB expired while in crypto"));
                    247:                error = EPERM;
                    248:                goto baddone;
                    249:        }
                    250:        ipcompx = (struct comp_algo *) tdb->tdb_compalgxform;
                    251:
                    252:        /* update the counters */
                    253:        tdb->tdb_cur_bytes += m->m_pkthdr.len - (skip + hlen);
                    254:        ipcompstat.ipcomps_ibytes += m->m_pkthdr.len - (skip + hlen);
                    255:
                    256:        /* Hard expiration */
                    257:        if ((tdb->tdb_flags & TDBF_BYTES) &&
                    258:            (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
                    259:                FREE(tc, M_XDATA);
                    260:                pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
                    261:                tdb_delete(tdb);
                    262:                error = ENXIO;
                    263:                goto baddone;
                    264:        }
                    265:        /* Notify on soft expiration */
                    266:        if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
                    267:            (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
                    268:                pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
                    269:                tdb->tdb_flags &= ~TDBF_SOFT_BYTES;     /* Turn off checking */
                    270:        }
                    271:
                    272:        /* Check for crypto errors */
                    273:        if (crp->crp_etype) {
                    274:                if (crp->crp_etype == EAGAIN) {
                    275:                        /* Reset the session ID */
                    276:                        if (tdb->tdb_cryptoid != 0)
                    277:                                tdb->tdb_cryptoid = crp->crp_sid;
                    278:                        splx(s);
                    279:                        return crypto_dispatch(crp);
                    280:                }
                    281:                FREE(tc, M_XDATA);
                    282:                ipcompstat.ipcomps_noxform++;
                    283:                DPRINTF(("ipcomp_input_cb(): crypto error %d\n",
                    284:                    crp->crp_etype));
                    285:                error = crp->crp_etype;
                    286:                goto baddone;
                    287:        }
                    288:        FREE(tc, M_XDATA);
                    289:
                    290:        /* Length of data after processing */
                    291:        clen = crp->crp_olen;
                    292:
                    293:        /* In case it's not done already, adjust the size of the mbuf chain */
                    294:        m->m_pkthdr.len = clen + hlen + skip;
                    295:
                    296:        if ((m->m_len < skip + hlen) && (m = m_pullup(m, skip + hlen)) == 0) {
                    297:                error = ENOBUFS;
                    298:                goto baddone;
                    299:        }
                    300:
                    301:        /* Find the beginning of the IPCOMP header */
                    302:        m1 = m_getptr(m, skip, &roff);
                    303:        if (m1 == NULL) {
                    304:                ipcompstat.ipcomps_hdrops++;
                    305:                DPRINTF(("ipcomp_input_cb(): bad mbuf chain, IPCA %s/%08x\n",
                    306:                    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
                    307:                error = EINVAL;
                    308:                goto baddone;
                    309:        }
                    310:        /* Keep the next protocol field */
                    311:        addr = (caddr_t) mtod(m, struct ip *) + skip;
                    312:        ipcomp = (struct ipcomp *) addr;
                    313:        nproto = ipcomp->ipcomp_nh;
                    314:
                    315:        /* Remove the IPCOMP header from the mbuf */
                    316:        if (roff == 0) {
                    317:                /* The IPCOMP header is at the beginning of m1 */
                    318:                m_adj(m1, hlen);
                    319:                if (!(m1->m_flags & M_PKTHDR))
                    320:                        m->m_pkthdr.len -= hlen;
                    321:        } else if (roff + hlen >= m1->m_len) {
                    322:                if (roff + hlen > m1->m_len) {
                    323:                        /* Adjust the next mbuf by the remainder */
                    324:                        m_adj(m1->m_next, roff + hlen - m1->m_len);
                    325:
                    326:                        /*
                    327:                         * The second mbuf is guaranteed not to have a
                    328:                         * pkthdr...
                    329:                         */
                    330:                        m->m_pkthdr.len -= (roff + hlen - m1->m_len);
                    331:                }
                    332:                /* Now, let's unlink the mbuf chain for a second... */
                    333:                mo = m1->m_next;
                    334:                m1->m_next = NULL;
                    335:
                    336:                /* ...and trim the end of the first part of the chain...sick */
                    337:                m_adj(m1, -(m1->m_len - roff));
                    338:                if (!(m1->m_flags & M_PKTHDR))
                    339:                        m->m_pkthdr.len -= (m1->m_len - roff);
                    340:
                    341:                /* Finally, let's relink */
                    342:                m1->m_next = mo;
                    343:        } else {
                    344:                bcopy(mtod(m1, u_char *) + roff + hlen,
                    345:                    mtod(m1, u_char *) + roff,
                    346:                    m1->m_len - (roff + hlen));
                    347:                m1->m_len -= hlen;
                    348:                m->m_pkthdr.len -= hlen;
                    349:        }
                    350:
                    351:        /* Release the crypto descriptors */
                    352:        crypto_freereq(crp);
                    353:
                    354:        /* Restore the Next Protocol field */
                    355:        m_copyback(m, protoff, sizeof(u_int8_t), &nproto);
                    356:
                    357:        /* Back to generic IPsec input processing */
                    358:        error = ipsec_common_input_cb(m, tdb, skip, protoff, NULL);
                    359:        splx(s);
                    360:        return error;
                    361:
                    362: baddone:
                    363:        splx(s);
                    364:
                    365:        if (m)
                    366:                m_freem(m);
                    367:
                    368:        crypto_freereq(crp);
                    369:
                    370:        return error;
                    371: }
                    372:
                    373: /*
                    374:  * IPComp output routine, called by ipsp_process_packet()
                    375:  */
                    376: int
                    377: ipcomp_output(m, tdb, mp, skip, protoff)
                    378:        struct mbuf    *m;
                    379:        struct tdb     *tdb;
                    380:        struct mbuf   **mp;
                    381:        int             skip;
                    382:        int             protoff;
                    383: {
                    384:        struct comp_algo *ipcompx = (struct comp_algo *) tdb->tdb_compalgxform;
                    385:        int             hlen;
                    386:        struct cryptodesc *crdc = NULL;
                    387:        struct cryptop *crp;
                    388:        struct tdb_crypto *tc;
                    389:        struct mbuf    *mi, *mo;
                    390: #if NBPFILTER > 0
                    391:        struct ifnet   *ifn = &(encif[0].sc_if);
                    392:
                    393:        if (ifn->if_bpf) {
                    394:                struct enchdr   hdr;
                    395:
                    396:                bzero(&hdr, sizeof(hdr));
                    397:
                    398:                hdr.af = tdb->tdb_dst.sa.sa_family;
                    399:                hdr.spi = tdb->tdb_spi;
                    400:
                    401:                bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, ENC_HDRLEN, m,
                    402:                    BPF_DIRECTION_OUT);
                    403:        }
                    404: #endif
                    405:        hlen = IPCOMP_HLENGTH;
                    406:
                    407:        ipcompstat.ipcomps_output++;
                    408:
                    409:        switch (tdb->tdb_dst.sa.sa_family) {
                    410: #ifdef INET
                    411:        case AF_INET:
                    412:                /* Check for IPv4 maximum packet size violations */
                    413:                /*
                    414:                 * Since compression is going to reduce the size, no need to
                    415:                 * worry
                    416:                 */
                    417:                if (m->m_pkthdr.len + hlen > IP_MAXPACKET) {
                    418:                        DPRINTF(("ipcomp_output(): packet in IPCA %s/%08x got too big\n",
                    419:                            ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
                    420:                        m_freem(m);
                    421:                        ipcompstat.ipcomps_toobig++;
                    422:                        return EMSGSIZE;
                    423:                }
                    424:                break;
                    425: #endif /* INET */
                    426:
                    427: #ifdef INET6
                    428:        case AF_INET6:
                    429:                /* Check for IPv6 maximum packet size violations */
                    430:                if (m->m_pkthdr.len + hlen > IPV6_MAXPACKET) {
                    431:                        DPRINTF(("ipcomp_output(): packet in IPCA %s/%08x got too big\n",
                    432:                            ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
                    433:                        m_freem(m);
                    434:                        ipcompstat.ipcomps_toobig++;
                    435:                        return EMSGSIZE;
                    436:                }
                    437: #endif /* INET6 */
                    438:
                    439:        default:
                    440:                DPRINTF(("ipcomp_output(): unknown/unsupported protocol family %d, IPCA %s/%08x\n",
                    441:                    tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst),
                    442:                    ntohl(tdb->tdb_spi)));
                    443:                m_freem(m);
                    444:                ipcompstat.ipcomps_nopf++;
                    445:                return EPFNOSUPPORT;
                    446:        }
                    447:
                    448:        /* Update the counters */
                    449:
                    450:        tdb->tdb_cur_bytes += m->m_pkthdr.len - skip;
                    451:        ipcompstat.ipcomps_obytes += m->m_pkthdr.len - skip;
                    452:
                    453:        /* Hard byte expiration */
                    454:        if ((tdb->tdb_flags & TDBF_BYTES) &&
                    455:            (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
                    456:                pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
                    457:                tdb_delete(tdb);
                    458:                m_freem(m);
                    459:                return EINVAL;
                    460:        }
                    461:        /* Soft byte expiration */
                    462:        if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
                    463:            (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
                    464:                pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
                    465:                tdb->tdb_flags &= ~TDBF_SOFT_BYTES;     /* Turn off checking */
                    466:        }
                    467:        /*
                    468:         * Loop through mbuf chain; if we find a readonly mbuf,
                    469:         * replace the rest of the chain.
                    470:         */
                    471:        mo = NULL;
                    472:        mi = m;
                    473:        while (mi != NULL && !M_READONLY(mi)) {
                    474:                mo = mi;
                    475:                mi = mi->m_next;
                    476:        }
                    477:
                    478:        if (mi != NULL) {
                    479:                /* Replace the rest of the mbuf chain. */
                    480:                struct mbuf    *n = m_copym2(mi, 0, M_COPYALL, M_DONTWAIT);
                    481:
                    482:                if (n == NULL) {
                    483:                        DPRINTF(("ipcomp_output(): bad mbuf chain, IPCA %s/%08x\n",
                    484:                            ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
                    485:                        ipcompstat.ipcomps_hdrops++;
                    486:                        m_freem(m);
                    487:                        return ENOBUFS;
                    488:                }
                    489:                if (mo != NULL)
                    490:                        mo->m_next = n;
                    491:                else
                    492:                        m = n;
                    493:
                    494:                m_freem(mi);
                    495:        }
                    496:        /* Ok now, we can pass to the crypto processing */
                    497:
                    498:        /* Get crypto descriptors */
                    499:        crp = crypto_getreq(1);
                    500:        if (crp == NULL) {
                    501:                m_freem(m);
                    502:                DPRINTF(("ipcomp_output(): failed to acquire crypto descriptors\n"));
                    503:                ipcompstat.ipcomps_crypto++;
                    504:                return ENOBUFS;
                    505:        }
                    506:        crdc = crp->crp_desc;
                    507:
                    508:        /* Compression descriptor */
                    509:        crdc->crd_skip = skip;
                    510:        crdc->crd_len = m->m_pkthdr.len - skip;
                    511:        crdc->crd_flags = CRD_F_COMP;
                    512:        crdc->crd_inject = skip;
                    513:
                    514:        /* Compression operation */
                    515:        crdc->crd_alg = ipcompx->type;
                    516:
                    517:        /* IPsec-specific opaque crypto info */
                    518:        MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto),
                    519:            M_XDATA, M_NOWAIT);
                    520:        if (tc == NULL) {
                    521:                m_freem(m);
                    522:                crypto_freereq(crp);
                    523:                DPRINTF(("ipcomp_output(): failed to allocate tdb_crypto\n"));
                    524:                ipcompstat.ipcomps_crypto++;
                    525:                return ENOBUFS;
                    526:        }
                    527:        bzero(tc, sizeof(struct tdb_crypto));
                    528:
                    529:        tc->tc_spi = tdb->tdb_spi;
                    530:        tc->tc_proto = tdb->tdb_sproto;
                    531:        tc->tc_skip = skip;
                    532:        bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union));
                    533:
                    534:        /* Crypto operation descriptor */
                    535:        crp->crp_ilen = m->m_pkthdr.len;        /* Total input length */
                    536:        crp->crp_flags = CRYPTO_F_IMBUF;
                    537:        crp->crp_buf = (caddr_t) m;
                    538:        crp->crp_callback = (int (*) (struct cryptop *)) ipcomp_output_cb;
                    539:        crp->crp_opaque = (caddr_t) tc;
                    540:        crp->crp_sid = tdb->tdb_cryptoid;
                    541:
                    542:        return crypto_dispatch(crp);
                    543: }
                    544:
                    545: /*
                    546:  * IPComp output callback, called directly from the crypto driver
                    547:  */
                    548: int
                    549: ipcomp_output_cb(cp)
                    550:        void *cp;
                    551: {
                    552:        struct cryptop *crp = (struct cryptop *) cp;
                    553:        struct tdb_crypto *tc;
                    554:        struct tdb *tdb;
                    555:        struct mbuf *m, *mo;
                    556:        int error, s, skip, rlen;
                    557:        u_int16_t cpi;
                    558: #ifdef INET
                    559:        struct ip *ip;
                    560: #endif
                    561: #ifdef INET6
                    562:        struct ip6_hdr *ip6;
                    563: #endif
                    564:        struct ipcomp  *ipcomp;
                    565:
                    566:        tc = (struct tdb_crypto *) crp->crp_opaque;
                    567:        skip = tc->tc_skip;
                    568:        rlen = crp->crp_ilen - skip;
                    569:
                    570:        m = (struct mbuf *) crp->crp_buf;
                    571:        if (m == NULL) {
                    572:                /* Shouldn't happen... */
                    573:                FREE(tc, M_XDATA);
                    574:                crypto_freereq(crp);
                    575:                ipcompstat.ipcomps_crypto++;
                    576:                DPRINTF(("ipcomp_output_cb(): bogus returned buffer from "
                    577:                    "crypto\n"));
                    578:                return (EINVAL);
                    579:        }
                    580:
                    581:        s = spltdb();
                    582:
                    583:        tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto);
                    584:        if (tdb == NULL) {
                    585:                FREE(tc, M_XDATA);
                    586:                ipcompstat.ipcomps_notdb++;
                    587:                DPRINTF(("ipcomp_output_cb(): TDB expired while in crypto\n"));
                    588:                error = EPERM;
                    589:                goto baddone;
                    590:        }
                    591:
                    592:        /* Check for crypto errors. */
                    593:        if (crp->crp_etype) {
                    594:                if (crp->crp_etype == EAGAIN) {
                    595:                        /* Reset the session ID */
                    596:                        if (tdb->tdb_cryptoid != 0)
                    597:                                tdb->tdb_cryptoid = crp->crp_sid;
                    598:                        splx(s);
                    599:                        return crypto_dispatch(crp);
                    600:                }
                    601:                FREE(tc, M_XDATA);
                    602:                ipcompstat.ipcomps_noxform++;
                    603:                DPRINTF(("ipcomp_output_cb(): crypto error %d\n",
                    604:                    crp->crp_etype));
                    605:                error = crp->crp_etype;
                    606:                goto baddone;
                    607:        }
                    608:        FREE(tc, M_XDATA);
                    609:
                    610:        /* Check sizes. */
                    611:        if (rlen < crp->crp_olen) {
                    612:                /* Compression was useless, we have lost time. */
                    613:                crypto_freereq(crp);
                    614:                error = ipsp_process_done(m, tdb);
                    615:                splx(s);
                    616:                return error;
                    617:        }
                    618:
                    619:        /* Inject IPCOMP header */
                    620:        mo = m_inject(m, skip, IPCOMP_HLENGTH, M_DONTWAIT);
                    621:        if (mo == NULL) {
                    622:                DPRINTF(("ipcomp_output_cb(): failed to inject IPCOMP header "
                    623:                    "for IPCA %s/%08x\n",
                    624:                    ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
                    625:                ipcompstat.ipcomps_wrap++;
                    626:                error = ENOBUFS;
                    627:                goto baddone;
                    628:        }
                    629:
                    630:        /* Initialize the IPCOMP header */
                    631:        ipcomp = mtod(mo, struct ipcomp *);
                    632:        bzero(ipcomp, sizeof(struct ipcomp));
                    633:        cpi = (u_int16_t) ntohl(tdb->tdb_spi);
                    634:        ipcomp->ipcomp_cpi = htons(cpi);
                    635:
                    636:        /* m_pullup before ? */
                    637:        switch (tdb->tdb_dst.sa.sa_family) {
                    638: #ifdef INET
                    639:        case AF_INET:
                    640:                ip = mtod(m, struct ip *);
                    641:                ipcomp->ipcomp_nh = ip->ip_p;
                    642:                ip->ip_p = IPPROTO_IPCOMP;
                    643:                break;
                    644: #endif /* INET */
                    645: #ifdef INET6
                    646:        case AF_INET6:
                    647:                ip6 = mtod(m, struct ip6_hdr *);
                    648:                ipcomp->ipcomp_nh = ip6->ip6_nxt;
                    649:                ip6->ip6_nxt = IPPROTO_IPCOMP;
                    650:                break;
                    651: #endif
                    652:        default:
                    653:                DPRINTF(("ipcomp_output_cb(): unsupported protocol family %d, "
                    654:                    "IPCA %s/%08x\n",
                    655:                    tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst),
                    656:                    ntohl(tdb->tdb_spi)));
                    657:                ipcompstat.ipcomps_nopf++;
                    658:                error = EPFNOSUPPORT;
                    659:                goto baddone;
                    660:                break;
                    661:        }
                    662:
                    663:        /* Release the crypto descriptor. */
                    664:        crypto_freereq(crp);
                    665:
                    666:        error = ipsp_process_done(m, tdb);
                    667:        splx(s);
                    668:        return error;
                    669:
                    670: baddone:
                    671:        splx(s);
                    672:
                    673:        if (m)
                    674:                m_freem(m);
                    675:
                    676:        crypto_freereq(crp);
                    677:
                    678:        return error;
                    679: }

CVSweb