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