1 /* $OpenBSD: ip_ipcomp.c,v 1.14 2003/04/02 20:09:26 millert 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), (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 u_int8_t prot; 387 u_int16_t cpi; 388 struct cryptodesc *crdc = NULL; 389 struct cryptop *crp; 390 struct tdb_crypto *tc; 391 struct mbuf *mi, *mo; 392 struct ipcomp *ipcomp; 393 #ifdef INET 394 struct ip *ip; 395 #endif 396 #ifdef INET6 397 struct ip6_hdr *ip6; 398 #endif 399 400 #if NBPFILTER > 0 401 { 402 struct ifnet *ifn; 403 struct enchdr hdr; 404 struct mbuf m1; 405 406 bzero(&hdr, sizeof(hdr)); 407 408 hdr.af = tdb->tdb_dst.sa.sa_family; 409 hdr.spi = tdb->tdb_spi; 410 hdr.flags |= M_COMP; 411 412 m1.m_next = m; 413 m1.m_len = ENC_HDRLEN; 414 m1.m_data = (char *) &hdr; 415 416 ifn = &(encif[0].sc_if); 417 418 if (ifn->if_bpf) 419 bpf_mtap(ifn->if_bpf, &m1); 420 } 421 #endif 422 423 hlen = IPCOMP_HLENGTH; 424 425 ipcompstat.ipcomps_output++; 426 427 switch (tdb->tdb_dst.sa.sa_family) { 428 #ifdef INET 429 case AF_INET: 430 /* Check for IPv4 maximum packet size violations */ 431 /* 432 * Since compression is going to reduce the size, no need to 433 * worry 434 */ 435 if (m->m_pkthdr.len + hlen > IP_MAXPACKET) { 436 DPRINTF(("ipcomp_output(): packet in IPCA %s/%08x got too big\n", 437 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); 438 m_freem(m); 439 ipcompstat.ipcomps_toobig++; 440 return EMSGSIZE; 441 } 442 break; 443 #endif /* INET */ 444 445 #ifdef INET6 446 case AF_INET6: 447 /* Check for IPv6 maximum packet size violations */ 448 if (m->m_pkthdr.len + hlen > IPV6_MAXPACKET) { 449 DPRINTF(("ipcomp_output(): packet in IPCA %s/%08x got too big\n", 450 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); 451 m_freem(m); 452 ipcompstat.ipcomps_toobig++; 453 return EMSGSIZE; 454 } 455 #endif /* INET6 */ 456 457 default: 458 DPRINTF(("ipcomp_output(): unknown/unsupported protocol family %d, IPCA %s/%08x\n", 459 tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst), 460 ntohl(tdb->tdb_spi))); 461 m_freem(m); 462 ipcompstat.ipcomps_nopf++; 463 return EPFNOSUPPORT; 464 } 465 466 /* Update the counters */ 467 468 tdb->tdb_cur_bytes += m->m_pkthdr.len - skip; 469 ipcompstat.ipcomps_obytes += m->m_pkthdr.len - skip; 470 471 /* Hard byte expiration */ 472 if ((tdb->tdb_flags & TDBF_BYTES) && 473 (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) { 474 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD); 475 tdb_delete(tdb); 476 m_freem(m); 477 return EINVAL; 478 } 479 /* Soft byte expiration */ 480 if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && 481 (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) { 482 pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT); 483 tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ 484 } 485 /* 486 * Loop through mbuf chain; if we find an M_EXT mbuf with 487 * more than one reference, replace the rest of the chain. 488 */ 489 mo = NULL; 490 mi = m; 491 while (mi != NULL && 492 (!(mi->m_flags & M_EXT) || !MCLISREFERENCED(mi))) { 493 mo = mi; 494 mi = mi->m_next; 495 } 496 497 if (mi != NULL) { 498 /* Replace the rest of the mbuf chain. */ 499 struct mbuf *n = m_copym2(mi, 0, M_COPYALL, M_DONTWAIT); 500 501 if (n == NULL) { 502 DPRINTF(("ipcomp_output(): bad mbuf chain, IPCA %s/%08x\n", 503 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); 504 ipcompstat.ipcomps_hdrops++; 505 m_freem(m); 506 return ENOBUFS; 507 } 508 if (mo != NULL) 509 mo->m_next = n; 510 else 511 m = n; 512 513 m_freem(mi); 514 } 515 /* Inject IPCOMP header */ 516 mo = m_inject(m, skip, hlen, M_DONTWAIT); 517 if (mo == NULL) { 518 DPRINTF(("ipcomp_output(): failed to inject IPCOMP header for IPCA %s/%08x\n", 519 ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); 520 m_freem(m); 521 ipcompstat.ipcomps_wrap++; 522 return ENOBUFS; 523 } 524 ipcomp = mtod(mo, struct ipcomp *); 525 526 /* Initialize the IPCOMP header */ 527 528 bzero(ipcomp, sizeof(struct ipcomp)); 529 530 cpi = (u_int16_t) ntohl(tdb->tdb_spi); 531 ipcomp->ipcomp_cpi = htons(cpi); 532 533 /* m_pullup before ? */ 534 535 switch (tdb->tdb_dst.sa.sa_family) { 536 #ifdef INET 537 case AF_INET: 538 ip = mtod(m, struct ip *); 539 ipcomp->ipcomp_nh = ip->ip_p; 540 break; 541 #endif /* INET */ 542 543 #ifdef INET6 544 case AF_INET6: 545 ip6 = mtod(m, struct ip6_hdr *); 546 ipcomp->ipcomp_nh = ip6->ip6_nxt; 547 break; 548 #endif 549 550 default: 551 DPRINTF(("ipcomp_output(): unknown/unsupported protocol family %d, IPCA %s/%08x\n", 552 tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst), 553 ntohl(tdb->tdb_spi))); 554 m_freem(m); 555 ipcompstat.ipcomps_nopf++; 556 return EPFNOSUPPORT; 557 break; 558 } 559 560 /* Fix Next Protocol in IPv4/IPv6 header */ 561 prot = IPPROTO_IPCOMP; 562 m_copyback(m, protoff, sizeof(u_int8_t), (u_char *) & prot); 563 564 /* Ok now, we can pass to the crypto processing */ 565 566 /* Get crypto descriptors */ 567 crp = crypto_getreq(1); 568 if (crp == NULL) { 569 m_freem(m); 570 DPRINTF(("ipcomp_output(): failed to acquire crypto descriptors\n")); 571 ipcompstat.ipcomps_crypto++; 572 return ENOBUFS; 573 } 574 crdc = crp->crp_desc; 575 576 /* Compression descriptor */ 577 crdc->crd_skip = skip + hlen; 578 crdc->crd_len = m->m_pkthdr.len - (skip + hlen); 579 crdc->crd_flags = CRD_F_COMP; 580 crdc->crd_inject = skip + hlen; 581 582 /* Compression operation */ 583 crdc->crd_alg = ipcompx->type; 584 585 /* IPsec-specific opaque crypto info */ 586 MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto), 587 M_XDATA, M_NOWAIT); 588 if (tc == NULL) { 589 m_freem(m); 590 crypto_freereq(crp); 591 DPRINTF(("ipcomp_output(): failed to allocate tdb_crypto\n")); 592 ipcompstat.ipcomps_crypto++; 593 return ENOBUFS; 594 } 595 bzero(tc, sizeof(struct tdb_crypto)); 596 597 tc->tc_spi = tdb->tdb_spi; 598 tc->tc_proto = tdb->tdb_sproto; 599 tc->tc_skip = skip + hlen; 600 bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union)); 601 602 /* Crypto operation descriptor */ 603 crp->crp_ilen = m->m_pkthdr.len; /* Total input length */ 604 crp->crp_flags = CRYPTO_F_IMBUF; 605 crp->crp_buf = (caddr_t) m; 606 crp->crp_callback = (int (*) (struct cryptop *)) ipcomp_output_cb; 607 crp->crp_opaque = (caddr_t) tc; 608 crp->crp_sid = tdb->tdb_cryptoid; 609 610 return crypto_dispatch(crp); 611 } 612 613 /* 614 * IPComp output callback, called directly from the crypto driver 615 */ 616 int 617 ipcomp_output_cb(cp) 618 void *cp; 619 { 620 struct cryptop *crp = (struct cryptop *) cp; 621 struct tdb_crypto *tc; 622 struct tdb *tdb; 623 struct mbuf *m; 624 int error, s, skip, rlen; 625 #ifdef INET 626 struct ip *ip; 627 #endif 628 #ifdef INET6 629 struct ip6_hdr *ip6; 630 #endif 631 632 tc = (struct tdb_crypto *) crp->crp_opaque; 633 skip = tc->tc_skip; 634 rlen = crp->crp_ilen - skip; 635 636 m = (struct mbuf *) crp->crp_buf; 637 if (m == NULL) { 638 /* Shouldn't happen... */ 639 FREE(tc, M_XDATA); 640 crypto_freereq(crp); 641 ipcompstat.ipcomps_crypto++; 642 DPRINTF(("ipcomp_output_cb(): bogus returned buffer from " 643 "crypto\n")); 644 return (EINVAL); 645 } 646 647 s = spltdb(); 648 649 tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto); 650 if (tdb == NULL) { 651 FREE(tc, M_XDATA); 652 ipcompstat.ipcomps_notdb++; 653 DPRINTF(("ipcomp_output_cb(): TDB expired while in crypto\n")); 654 error = EPERM; 655 goto baddone; 656 } 657 658 /* Check for crypto errors. */ 659 if (crp->crp_etype) { 660 if (crp->crp_etype == EAGAIN) { 661 /* Reset the session ID */ 662 if (tdb->tdb_cryptoid != 0) 663 tdb->tdb_cryptoid = crp->crp_sid; 664 splx(s); 665 return crypto_dispatch(crp); 666 } 667 FREE(tc, M_XDATA); 668 ipcompstat.ipcomps_noxform++; 669 DPRINTF(("ipcomp_output_cb(): crypto error %d\n", 670 crp->crp_etype)); 671 error = crp->crp_etype; 672 goto baddone; 673 } 674 FREE(tc, M_XDATA); 675 676 /* Check sizes. */ 677 if (rlen < crp->crp_olen) { 678 /* Compression was useless, we have lost time. */ 679 crypto_freereq(crp); 680 error = ipsp_process_done(m, tdb); 681 splx(s); 682 return error; 683 } 684 685 /* Adjust the length in the IP header. */ 686 switch (tdb->tdb_dst.sa.sa_family) { 687 #ifdef INET 688 case AF_INET: 689 ip = mtod(m, struct ip *); 690 ip->ip_len = htons(m->m_pkthdr.len); 691 break; 692 #endif /* INET */ 693 694 #ifdef INET6 695 case AF_INET6: 696 ip6 = mtod(m, struct ip6_hdr *); 697 ip6->ip6_plen = htons(m->m_pkthdr.len) - sizeof(struct ip6_hdr); 698 break; 699 #endif /* INET6 */ 700 701 default: 702 m_freem(m); 703 DPRINTF(("ipcomp_output(): unknown/unsupported protocol " 704 "family %d, IPCA %s/%08x\n", 705 tdb->tdb_dst.sa.sa_family, ipsp_address(tdb->tdb_dst), 706 ntohl(tdb->tdb_spi))); 707 crypto_freereq(crp); 708 ipcompstat.ipcomps_nopf++; 709 splx(s); 710 return EPFNOSUPPORT; 711 break; 712 } 713 714 /* Release the crypto descriptor. */ 715 crypto_freereq(crp); 716 717 error = ipsp_process_done(m, tdb); 718 splx(s); 719 return error; 720 721 baddone: 722 splx(s); 723 724 if (m) 725 m_freem(m); 726 727 crypto_freereq(crp); 728 729 return error; 730 } 731