Annotation of sys/netinet/ip_ipcomp.c, Revision 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