Annotation of sys/netinet/ip_esp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ip_esp.c,v 1.100 2006/12/15 09:32:30 otto 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.
! 17: *
! 18: * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
! 19: * Angelos D. Keromytis and Niels Provos.
! 20: * Copyright (c) 2001 Angelos D. Keromytis.
! 21: *
! 22: * Permission to use, copy, and modify this software with or without fee
! 23: * is hereby granted, provided that this entire notice is included in
! 24: * all copies of any software which is or includes a copy or
! 25: * modification of this software.
! 26: * You may use this code under the GNU public license if you so wish. Please
! 27: * contribute changes back to the authors under this freer than GPL license
! 28: * so that we may further the use of strong encryption without limitations to
! 29: * all.
! 30: *
! 31: * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
! 32: * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
! 33: * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
! 34: * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
! 35: * PURPOSE.
! 36: */
! 37:
! 38: #include "pfsync.h"
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/mbuf.h>
! 43: #include <sys/socket.h>
! 44:
! 45: #include <net/if.h>
! 46: #include <net/bpf.h>
! 47:
! 48: #include <dev/rndvar.h>
! 49:
! 50: #ifdef INET
! 51: #include <netinet/in.h>
! 52: #include <netinet/in_systm.h>
! 53: #include <netinet/ip.h>
! 54: #include <netinet/ip_var.h>
! 55: #endif /* INET */
! 56:
! 57: #ifdef INET6
! 58: #ifndef INET
! 59: #include <netinet/in.h>
! 60: #endif
! 61: #include <netinet/ip6.h>
! 62: #endif /* INET6 */
! 63:
! 64: #include <netinet/ip_ipsp.h>
! 65: #include <netinet/ip_esp.h>
! 66: #include <net/pfkeyv2.h>
! 67: #include <net/if_enc.h>
! 68:
! 69: #if NPFSYNC > 0
! 70: #include <net/pfvar.h>
! 71: #include <net/if_pfsync.h>
! 72: #endif /* NPFSYNC > 0 */
! 73:
! 74: #include <crypto/cryptodev.h>
! 75: #include <crypto/xform.h>
! 76:
! 77: #include "bpfilter.h"
! 78:
! 79: #ifdef ENCDEBUG
! 80: #define DPRINTF(x) if (encdebug) printf x
! 81: #else
! 82: #define DPRINTF(x)
! 83: #endif
! 84:
! 85: struct espstat espstat;
! 86:
! 87: /*
! 88: * esp_attach() is called from the transformation initialization code.
! 89: */
! 90: int
! 91: esp_attach()
! 92: {
! 93: return 0;
! 94: }
! 95:
! 96: /*
! 97: * esp_init() is called when an SPI is being set up.
! 98: */
! 99: int
! 100: esp_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii)
! 101: {
! 102: struct enc_xform *txform = NULL;
! 103: struct auth_hash *thash = NULL;
! 104: struct cryptoini cria, crie;
! 105:
! 106: if (!ii->ii_encalg && !ii->ii_authalg) {
! 107: DPRINTF(("esp_init(): neither authentication nor encryption "
! 108: "algorithm given"));
! 109: return EINVAL;
! 110: }
! 111:
! 112: if (ii->ii_encalg) {
! 113: switch (ii->ii_encalg) {
! 114: case SADB_EALG_NULL:
! 115: txform = &enc_xform_null;
! 116: break;
! 117:
! 118: case SADB_EALG_DESCBC:
! 119: txform = &enc_xform_des;
! 120: break;
! 121:
! 122: case SADB_EALG_3DESCBC:
! 123: txform = &enc_xform_3des;
! 124: break;
! 125:
! 126: case SADB_X_EALG_AES:
! 127: txform = &enc_xform_rijndael128;
! 128: break;
! 129:
! 130: case SADB_X_EALG_AESCTR:
! 131: txform = &enc_xform_aes_ctr;
! 132: break;
! 133:
! 134: case SADB_X_EALG_BLF:
! 135: txform = &enc_xform_blf;
! 136: break;
! 137:
! 138: case SADB_X_EALG_CAST:
! 139: txform = &enc_xform_cast5;
! 140: break;
! 141:
! 142: case SADB_X_EALG_SKIPJACK:
! 143: txform = &enc_xform_skipjack;
! 144: break;
! 145:
! 146: default:
! 147: DPRINTF(("esp_init(): unsupported encryption algorithm %d specified\n", ii->ii_encalg));
! 148: return EINVAL;
! 149: }
! 150:
! 151: if (ii->ii_enckeylen < txform->minkey) {
! 152: DPRINTF(("esp_init(): keylength %d too small (min length is %d) for algorithm %s\n", ii->ii_enckeylen, txform->minkey, txform->name));
! 153: return EINVAL;
! 154: }
! 155:
! 156: if (ii->ii_enckeylen > txform->maxkey) {
! 157: DPRINTF(("esp_init(): keylength %d too large (max length is %d) for algorithm %s\n", ii->ii_enckeylen, txform->maxkey, txform->name));
! 158: return EINVAL;
! 159: }
! 160:
! 161: tdbp->tdb_encalgxform = txform;
! 162:
! 163: DPRINTF(("esp_init(): initialized TDB with enc algorithm %s\n",
! 164: txform->name));
! 165:
! 166: tdbp->tdb_ivlen = txform->ivsize;
! 167: if (tdbp->tdb_flags & TDBF_HALFIV)
! 168: tdbp->tdb_ivlen /= 2;
! 169: }
! 170:
! 171: if (ii->ii_authalg) {
! 172: switch (ii->ii_authalg) {
! 173: case SADB_AALG_MD5HMAC:
! 174: thash = &auth_hash_hmac_md5_96;
! 175: break;
! 176:
! 177: case SADB_AALG_SHA1HMAC:
! 178: thash = &auth_hash_hmac_sha1_96;
! 179: break;
! 180:
! 181: case SADB_X_AALG_RIPEMD160HMAC:
! 182: thash = &auth_hash_hmac_ripemd_160_96;
! 183: break;
! 184:
! 185: case SADB_X_AALG_SHA2_256:
! 186: thash = &auth_hash_hmac_sha2_256_96;
! 187: break;
! 188:
! 189: case SADB_X_AALG_SHA2_384:
! 190: thash = &auth_hash_hmac_sha2_384_96;
! 191: break;
! 192:
! 193: case SADB_X_AALG_SHA2_512:
! 194: thash = &auth_hash_hmac_sha2_512_96;
! 195: break;
! 196:
! 197: default:
! 198: DPRINTF(("esp_init(): unsupported authentication algorithm %d specified\n", ii->ii_authalg));
! 199: return EINVAL;
! 200: }
! 201:
! 202: if (ii->ii_authkeylen != thash->keysize) {
! 203: DPRINTF(("esp_init(): keylength %d doesn't match algorithm %s keysize (%d)\n", ii->ii_authkeylen, thash->name, thash->keysize));
! 204: return EINVAL;
! 205: }
! 206:
! 207: tdbp->tdb_authalgxform = thash;
! 208:
! 209: DPRINTF(("esp_init(): initialized TDB with hash algorithm %s\n",
! 210: thash->name));
! 211: }
! 212:
! 213: tdbp->tdb_xform = xsp;
! 214: tdbp->tdb_bitmap = 0;
! 215: tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL;
! 216:
! 217: /* Initialize crypto session */
! 218: if (tdbp->tdb_encalgxform) {
! 219: /* Save the raw keys */
! 220: tdbp->tdb_emxkeylen = ii->ii_enckeylen;
! 221: MALLOC(tdbp->tdb_emxkey, u_int8_t *, tdbp->tdb_emxkeylen,
! 222: M_XDATA, M_WAITOK);
! 223: bcopy(ii->ii_enckey, tdbp->tdb_emxkey, tdbp->tdb_emxkeylen);
! 224:
! 225: bzero(&crie, sizeof(crie));
! 226:
! 227: crie.cri_alg = tdbp->tdb_encalgxform->type;
! 228:
! 229: if (tdbp->tdb_authalgxform)
! 230: crie.cri_next = &cria;
! 231: else
! 232: crie.cri_next = NULL;
! 233:
! 234: crie.cri_klen = ii->ii_enckeylen * 8;
! 235: crie.cri_key = ii->ii_enckey;
! 236: /* XXX Rounds ? */
! 237: }
! 238:
! 239: if (tdbp->tdb_authalgxform) {
! 240: /* Save the raw keys */
! 241: tdbp->tdb_amxkeylen = ii->ii_authkeylen;
! 242: MALLOC(tdbp->tdb_amxkey, u_int8_t *, tdbp->tdb_amxkeylen, M_XDATA,
! 243: M_WAITOK);
! 244: bcopy(ii->ii_authkey, tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
! 245:
! 246: bzero(&cria, sizeof(cria));
! 247:
! 248: cria.cri_alg = tdbp->tdb_authalgxform->type;
! 249: cria.cri_next = NULL;
! 250: cria.cri_klen = ii->ii_authkeylen * 8;
! 251: cria.cri_key = ii->ii_authkey;
! 252: }
! 253:
! 254: return crypto_newsession(&tdbp->tdb_cryptoid,
! 255: (tdbp->tdb_encalgxform ? &crie : &cria), 0);
! 256: }
! 257:
! 258: /*
! 259: * Paranoia.
! 260: */
! 261: int
! 262: esp_zeroize(struct tdb *tdbp)
! 263: {
! 264: int err;
! 265:
! 266: if (tdbp->tdb_amxkey) {
! 267: bzero(tdbp->tdb_amxkey, tdbp->tdb_amxkeylen);
! 268: FREE(tdbp->tdb_amxkey, M_XDATA);
! 269: tdbp->tdb_amxkey = NULL;
! 270: }
! 271:
! 272: if (tdbp->tdb_emxkey) {
! 273: bzero(tdbp->tdb_emxkey, tdbp->tdb_emxkeylen);
! 274: FREE(tdbp->tdb_emxkey, M_XDATA);
! 275: tdbp->tdb_emxkey = NULL;
! 276: }
! 277:
! 278: err = crypto_freesession(tdbp->tdb_cryptoid);
! 279: tdbp->tdb_cryptoid = 0;
! 280: return err;
! 281: }
! 282:
! 283: #define MAXBUFSIZ (AH_ALEN_MAX > ESP_MAX_IVS ? AH_ALEN_MAX : ESP_MAX_IVS)
! 284:
! 285: /*
! 286: * ESP input processing, called (eventually) through the protocol switch.
! 287: */
! 288: int
! 289: esp_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
! 290: {
! 291: struct auth_hash *esph = (struct auth_hash *) tdb->tdb_authalgxform;
! 292: struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform;
! 293: struct tdb_crypto *tc;
! 294: int plen, alen, hlen;
! 295: struct m_tag *mtag;
! 296: u_int32_t btsx;
! 297:
! 298: struct cryptodesc *crde = NULL, *crda = NULL;
! 299: struct cryptop *crp;
! 300:
! 301: /* Determine the ESP header length */
! 302: if (tdb->tdb_flags & TDBF_NOREPLAY)
! 303: hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; /* "old" ESP */
! 304: else
! 305: hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; /* "new" ESP */
! 306:
! 307: if (esph)
! 308: alen = AH_HMAC_HASHLEN;
! 309: else
! 310: alen = 0;
! 311:
! 312: plen = m->m_pkthdr.len - (skip + hlen + alen);
! 313: if (plen <= 0) {
! 314: DPRINTF(("esp_input: invalid payload length\n"));
! 315: espstat.esps_badilen++;
! 316: m_freem(m);
! 317: return EINVAL;
! 318: }
! 319:
! 320: if (espx) {
! 321: /*
! 322: * Verify payload length is multiple of encryption algorithm
! 323: * block size.
! 324: */
! 325: if (plen & (espx->blocksize - 1)) {
! 326: DPRINTF(("esp_input(): payload of %d octets not a multiple of %d octets, SA %s/%08x\n", plen, espx->blocksize, ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 327: espstat.esps_badilen++;
! 328: m_freem(m);
! 329: return EINVAL;
! 330: }
! 331: }
! 332:
! 333: /* Replay window checking, if appropriate -- no value commitment. */
! 334: if ((tdb->tdb_wnd > 0) && (!(tdb->tdb_flags & TDBF_NOREPLAY))) {
! 335: m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
! 336: (unsigned char *) &btsx);
! 337: btsx = ntohl(btsx);
! 338:
! 339: switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl),
! 340: tdb->tdb_wnd, &(tdb->tdb_bitmap), 0)) {
! 341: case 0: /* All's well */
! 342: break;
! 343:
! 344: case 1:
! 345: m_freem(m);
! 346: DPRINTF(("esp_input(): replay counter wrapped for SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 347: espstat.esps_wrap++;
! 348: return EACCES;
! 349:
! 350: case 2:
! 351: case 3:
! 352: DPRINTF(("esp_input(): duplicate packet received in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 353: m_freem(m);
! 354: return EACCES;
! 355:
! 356: default:
! 357: m_freem(m);
! 358: DPRINTF(("esp_input(): bogus value from checkreplaywindow32() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 359: espstat.esps_replay++;
! 360: return EACCES;
! 361: }
! 362: }
! 363:
! 364: /* Update the counters */
! 365: tdb->tdb_cur_bytes += m->m_pkthdr.len - skip - hlen - alen;
! 366: espstat.esps_ibytes += m->m_pkthdr.len - skip - hlen - alen;
! 367:
! 368: /* Hard expiration */
! 369: if ((tdb->tdb_flags & TDBF_BYTES) &&
! 370: (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) {
! 371: pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
! 372: tdb_delete(tdb);
! 373: m_freem(m);
! 374: return ENXIO;
! 375: }
! 376:
! 377: /* Notify on soft expiration */
! 378: if ((tdb->tdb_flags & TDBF_SOFT_BYTES) &&
! 379: (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) {
! 380: pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
! 381: tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */
! 382: }
! 383:
! 384: #ifdef notyet
! 385: /* Find out if we've already done crypto */
! 386: for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL);
! 387: mtag != NULL;
! 388: mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) {
! 389: struct tdb_ident *tdbi;
! 390:
! 391: tdbi = (struct tdb_ident *) (mtag + 1);
! 392: if (tdbi->proto == tdb->tdb_sproto && tdbi->spi == tdb->tdb_spi &&
! 393: !bcmp(&tdbi->dst, &tdb->tdb_dst, sizeof(union sockaddr_union)))
! 394: break;
! 395: }
! 396: #else
! 397: mtag = NULL;
! 398: #endif
! 399:
! 400: /* Get crypto descriptors */
! 401: crp = crypto_getreq(esph && espx ? 2 : 1);
! 402: if (crp == NULL) {
! 403: m_freem(m);
! 404: DPRINTF(("esp_input(): failed to acquire crypto descriptors\n"));
! 405: espstat.esps_crypto++;
! 406: return ENOBUFS;
! 407: }
! 408:
! 409: /* Get IPsec-specific opaque pointer */
! 410: if (esph == NULL || mtag != NULL)
! 411: MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto),
! 412: M_XDATA, M_NOWAIT);
! 413: else
! 414: MALLOC(tc, struct tdb_crypto *,
! 415: sizeof(struct tdb_crypto) + alen, M_XDATA, M_NOWAIT);
! 416: if (tc == NULL) {
! 417: m_freem(m);
! 418: crypto_freereq(crp);
! 419: DPRINTF(("esp_input(): failed to allocate tdb_crypto\n"));
! 420: espstat.esps_crypto++;
! 421: return ENOBUFS;
! 422: }
! 423:
! 424: bzero(tc, sizeof(struct tdb_crypto));
! 425: tc->tc_ptr = (caddr_t) mtag;
! 426:
! 427: if (esph) {
! 428: crda = crp->crp_desc;
! 429: crde = crda->crd_next;
! 430:
! 431: /* Authentication descriptor */
! 432: crda->crd_skip = skip;
! 433: crda->crd_len = m->m_pkthdr.len - (skip + alen);
! 434: crda->crd_inject = m->m_pkthdr.len - alen;
! 435:
! 436: crda->crd_alg = esph->type;
! 437: crda->crd_key = tdb->tdb_amxkey;
! 438: crda->crd_klen = tdb->tdb_amxkeylen * 8;
! 439:
! 440: /* Copy the authenticator */
! 441: if (mtag == NULL)
! 442: m_copydata(m, m->m_pkthdr.len - alen, alen, (caddr_t) (tc + 1));
! 443: } else
! 444: crde = crp->crp_desc;
! 445:
! 446: /* Crypto operation descriptor */
! 447: crp->crp_ilen = m->m_pkthdr.len; /* Total input length */
! 448: crp->crp_flags = CRYPTO_F_IMBUF;
! 449: crp->crp_buf = (caddr_t) m;
! 450: crp->crp_callback = (int (*) (struct cryptop *)) esp_input_cb;
! 451: crp->crp_sid = tdb->tdb_cryptoid;
! 452: crp->crp_opaque = (caddr_t) tc;
! 453:
! 454: /* These are passed as-is to the callback */
! 455: tc->tc_skip = skip;
! 456: tc->tc_protoff = protoff;
! 457: tc->tc_spi = tdb->tdb_spi;
! 458: tc->tc_proto = tdb->tdb_sproto;
! 459: bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union));
! 460:
! 461: /* Decryption descriptor */
! 462: if (espx) {
! 463: crde->crd_skip = skip + hlen;
! 464: crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
! 465: crde->crd_inject = skip + hlen - tdb->tdb_ivlen;
! 466:
! 467: if (tdb->tdb_flags & TDBF_HALFIV) {
! 468: /* Copy half-IV from packet */
! 469: m_copydata(m, crde->crd_inject, tdb->tdb_ivlen, crde->crd_iv);
! 470:
! 471: /* Cook IV */
! 472: for (btsx = 0; btsx < tdb->tdb_ivlen; btsx++)
! 473: crde->crd_iv[tdb->tdb_ivlen + btsx] = ~crde->crd_iv[btsx];
! 474:
! 475: crde->crd_flags |= CRD_F_IV_EXPLICIT;
! 476: }
! 477:
! 478: crde->crd_alg = espx->type;
! 479: crde->crd_key = tdb->tdb_emxkey;
! 480: crde->crd_klen = tdb->tdb_emxkeylen * 8;
! 481: /* XXX Rounds ? */
! 482: }
! 483:
! 484: if (mtag == NULL)
! 485: return crypto_dispatch(crp);
! 486: else
! 487: return esp_input_cb(crp);
! 488: }
! 489:
! 490: /*
! 491: * ESP input callback, called directly by the crypto driver.
! 492: */
! 493: int
! 494: esp_input_cb(void *op)
! 495: {
! 496: u_int8_t lastthree[3], aalg[AH_HMAC_HASHLEN];
! 497: int s, hlen, roff, skip, protoff, error;
! 498: struct mbuf *m1, *mo, *m;
! 499: struct auth_hash *esph;
! 500: struct tdb_crypto *tc;
! 501: struct cryptop *crp;
! 502: struct m_tag *mtag;
! 503: struct tdb *tdb;
! 504: u_int32_t btsx;
! 505: caddr_t ptr;
! 506:
! 507: crp = (struct cryptop *) op;
! 508:
! 509: tc = (struct tdb_crypto *) crp->crp_opaque;
! 510: skip = tc->tc_skip;
! 511: protoff = tc->tc_protoff;
! 512: mtag = (struct m_tag *) tc->tc_ptr;
! 513:
! 514: m = (struct mbuf *) crp->crp_buf;
! 515: if (m == NULL) {
! 516: /* Shouldn't happen... */
! 517: FREE(tc, M_XDATA);
! 518: crypto_freereq(crp);
! 519: espstat.esps_crypto++;
! 520: DPRINTF(("esp_input_cb(): bogus returned buffer from crypto\n"));
! 521: return (EINVAL);
! 522: }
! 523:
! 524: s = spltdb();
! 525:
! 526: tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto);
! 527: if (tdb == NULL) {
! 528: FREE(tc, M_XDATA);
! 529: espstat.esps_notdb++;
! 530: DPRINTF(("esp_input_cb(): TDB is expired while in crypto"));
! 531: error = EPERM;
! 532: goto baddone;
! 533: }
! 534:
! 535: esph = (struct auth_hash *) tdb->tdb_authalgxform;
! 536:
! 537: /* Check for crypto errors */
! 538: if (crp->crp_etype) {
! 539: if (crp->crp_etype == EAGAIN) {
! 540: /* Reset the session ID */
! 541: if (tdb->tdb_cryptoid != 0)
! 542: tdb->tdb_cryptoid = crp->crp_sid;
! 543: splx(s);
! 544: return crypto_dispatch(crp);
! 545: }
! 546: FREE(tc, M_XDATA);
! 547: espstat.esps_noxform++;
! 548: DPRINTF(("esp_input_cb(): crypto error %d\n", crp->crp_etype));
! 549: error = crp->crp_etype;
! 550: goto baddone;
! 551: }
! 552:
! 553: /* If authentication was performed, check now. */
! 554: if (esph != NULL) {
! 555: /*
! 556: * If we have a tag, it means an IPsec-aware NIC did the verification
! 557: * for us.
! 558: */
! 559: if (mtag == NULL) {
! 560: /* Copy the authenticator from the packet */
! 561: m_copydata(m, m->m_pkthdr.len - esph->authsize,
! 562: esph->authsize, aalg);
! 563:
! 564: ptr = (caddr_t) (tc + 1);
! 565:
! 566: /* Verify authenticator */
! 567: if (bcmp(ptr, aalg, esph->authsize)) {
! 568: FREE(tc, M_XDATA);
! 569: DPRINTF(("esp_input_cb(): authentication failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 570: espstat.esps_badauth++;
! 571: error = EACCES;
! 572: goto baddone;
! 573: }
! 574: }
! 575:
! 576: /* Remove trailing authenticator */
! 577: m_adj(m, -(esph->authsize));
! 578: }
! 579: FREE(tc, M_XDATA);
! 580:
! 581: /* Replay window checking, if appropriate */
! 582: if ((tdb->tdb_wnd > 0) && (!(tdb->tdb_flags & TDBF_NOREPLAY))) {
! 583: m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
! 584: (unsigned char *) &btsx);
! 585: btsx = ntohl(btsx);
! 586:
! 587: switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl),
! 588: tdb->tdb_wnd, &(tdb->tdb_bitmap), 1)) {
! 589: case 0: /* All's well */
! 590: #if NPFSYNC > 0
! 591: pfsync_update_tdb(tdb,0);
! 592: #endif
! 593: break;
! 594:
! 595: case 1:
! 596: DPRINTF(("esp_input_cb(): replay counter wrapped for SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 597: espstat.esps_wrap++;
! 598: error = EACCES;
! 599: goto baddone;
! 600:
! 601: case 2:
! 602: case 3:
! 603: DPRINTF(("esp_input_cb(): duplicate packet received in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 604: error = EACCES;
! 605: goto baddone;
! 606:
! 607: default:
! 608: DPRINTF(("esp_input_cb(): bogus value from checkreplaywindow32() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 609: espstat.esps_replay++;
! 610: error = EACCES;
! 611: goto baddone;
! 612: }
! 613: }
! 614:
! 615: /* Release the crypto descriptors */
! 616: crypto_freereq(crp);
! 617:
! 618: /* Determine the ESP header length */
! 619: if (tdb->tdb_flags & TDBF_NOREPLAY)
! 620: hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; /* "old" ESP */
! 621: else
! 622: hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; /* "new" ESP */
! 623:
! 624: /* Find beginning of ESP header */
! 625: m1 = m_getptr(m, skip, &roff);
! 626: if (m1 == NULL) {
! 627: espstat.esps_hdrops++;
! 628: splx(s);
! 629: DPRINTF(("esp_input_cb(): bad mbuf chain, SA %s/%08x\n",
! 630: ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 631: m_freem(m);
! 632: return EINVAL;
! 633: }
! 634:
! 635: /* Remove the ESP header and IV from the mbuf. */
! 636: if (roff == 0) {
! 637: /* The ESP header was conveniently at the beginning of the mbuf */
! 638: m_adj(m1, hlen);
! 639: if (!(m1->m_flags & M_PKTHDR))
! 640: m->m_pkthdr.len -= hlen;
! 641: } else if (roff + hlen >= m1->m_len) {
! 642: /*
! 643: * Part or all of the ESP header is at the end of this mbuf, so
! 644: * first let's remove the remainder of the ESP header from the
! 645: * beginning of the remainder of the mbuf chain, if any.
! 646: */
! 647: if (roff + hlen > m1->m_len) {
! 648: /* Adjust the next mbuf by the remainder */
! 649: m_adj(m1->m_next, roff + hlen - m1->m_len);
! 650:
! 651: /* The second mbuf is guaranteed not to have a pkthdr... */
! 652: m->m_pkthdr.len -= (roff + hlen - m1->m_len);
! 653: }
! 654:
! 655: /* Now, let's unlink the mbuf chain for a second...*/
! 656: mo = m1->m_next;
! 657: m1->m_next = NULL;
! 658:
! 659: /* ...and trim the end of the first part of the chain...sick */
! 660: m_adj(m1, -(m1->m_len - roff));
! 661: if (!(m1->m_flags & M_PKTHDR))
! 662: m->m_pkthdr.len -= (m1->m_len - roff);
! 663:
! 664: /* Finally, let's relink */
! 665: m1->m_next = mo;
! 666: } else {
! 667: /*
! 668: * The ESP header lies in the "middle" of the mbuf...do an
! 669: * overlapping copy of the remainder of the mbuf over the ESP
! 670: * header.
! 671: */
! 672: bcopy(mtod(m1, u_char *) + roff + hlen,
! 673: mtod(m1, u_char *) + roff, m1->m_len - (roff + hlen));
! 674: m1->m_len -= hlen;
! 675: m->m_pkthdr.len -= hlen;
! 676: }
! 677:
! 678: /* Save the last three bytes of decrypted data */
! 679: m_copydata(m, m->m_pkthdr.len - 3, 3, lastthree);
! 680:
! 681: /* Verify pad length */
! 682: if (lastthree[1] + 2 > m->m_pkthdr.len - skip) {
! 683: espstat.esps_badilen++;
! 684: splx(s);
! 685: DPRINTF(("esp_input_cb(): invalid padding length %d for packet in SA %s/%08x\n", lastthree[1], ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 686: m_freem(m);
! 687: return EINVAL;
! 688: }
! 689:
! 690: /* Verify correct decryption by checking the last padding bytes */
! 691: if (!(tdb->tdb_flags & TDBF_RANDOMPADDING)) {
! 692: if ((lastthree[1] != lastthree[0]) && (lastthree[1] != 0)) {
! 693: espstat.esps_badenc++;
! 694: splx(s);
! 695: DPRINTF(("esp_input(): decryption failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 696: m_freem(m);
! 697: return EINVAL;
! 698: }
! 699: }
! 700:
! 701: /* Trim the mbuf chain to remove the trailing authenticator and padding */
! 702: m_adj(m, -(lastthree[1] + 2));
! 703:
! 704: /* Restore the Next Protocol field */
! 705: m_copyback(m, protoff, sizeof(u_int8_t), lastthree + 2);
! 706:
! 707: /* Back to generic IPsec input processing */
! 708: error = ipsec_common_input_cb(m, tdb, skip, protoff, mtag);
! 709: splx(s);
! 710: return (error);
! 711:
! 712: baddone:
! 713: splx(s);
! 714:
! 715: if (m != NULL)
! 716: m_freem(m);
! 717:
! 718: crypto_freereq(crp);
! 719:
! 720: return (error);
! 721: }
! 722:
! 723: /*
! 724: * ESP output routine, called by ipsp_process_packet().
! 725: */
! 726: int
! 727: esp_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
! 728: int protoff)
! 729: {
! 730: struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform;
! 731: struct auth_hash *esph = (struct auth_hash *) tdb->tdb_authalgxform;
! 732: int ilen, hlen, rlen, padding, blks, alen;
! 733: struct mbuf *mi, *mo = (struct mbuf *) NULL;
! 734: struct tdb_crypto *tc;
! 735: unsigned char *pad;
! 736: u_int8_t prot;
! 737:
! 738: struct cryptodesc *crde = NULL, *crda = NULL;
! 739: struct cryptop *crp;
! 740: #if NBPFILTER > 0
! 741: struct ifnet *ifn = &(encif[0].sc_if);
! 742:
! 743: ifn->if_opackets++;
! 744: ifn->if_obytes += m->m_pkthdr.len;
! 745:
! 746: if (ifn->if_bpf) {
! 747: struct enchdr hdr;
! 748:
! 749: bzero (&hdr, sizeof(hdr));
! 750:
! 751: hdr.af = tdb->tdb_dst.sa.sa_family;
! 752: hdr.spi = tdb->tdb_spi;
! 753: if (espx)
! 754: hdr.flags |= M_CONF;
! 755: if (esph)
! 756: hdr.flags |= M_AUTH;
! 757:
! 758: bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, ENC_HDRLEN, m,
! 759: BPF_DIRECTION_OUT);
! 760: }
! 761: #endif
! 762:
! 763: if (tdb->tdb_flags & TDBF_NOREPLAY)
! 764: hlen = sizeof(u_int32_t) + tdb->tdb_ivlen;
! 765: else
! 766: hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen;
! 767:
! 768: rlen = m->m_pkthdr.len - skip; /* Raw payload length. */
! 769: if (espx)
! 770: blks = espx->blocksize;
! 771: else
! 772: blks = 4; /* If no encryption, we have to be 4-byte aligned. */
! 773:
! 774: padding = ((blks - ((rlen + 2) % blks)) % blks) + 2;
! 775:
! 776: if (esph)
! 777: alen = AH_HMAC_HASHLEN;
! 778: else
! 779: alen = 0;
! 780:
! 781: espstat.esps_output++;
! 782:
! 783: switch (tdb->tdb_dst.sa.sa_family) {
! 784: #ifdef INET
! 785: case AF_INET:
! 786: /* Check for IP maximum packet size violations. */
! 787: if (skip + hlen + rlen + padding + alen > IP_MAXPACKET) {
! 788: DPRINTF(("esp_output(): packet in SA %s/%08x got "
! 789: "too big\n", ipsp_address(tdb->tdb_dst),
! 790: ntohl(tdb->tdb_spi)));
! 791: m_freem(m);
! 792: espstat.esps_toobig++;
! 793: return EMSGSIZE;
! 794: }
! 795: break;
! 796: #endif /* INET */
! 797:
! 798: #ifdef INET6
! 799: case AF_INET6:
! 800: /* Check for IPv6 maximum packet size violations. */
! 801: if (skip + hlen + rlen + padding + alen > IPV6_MAXPACKET) {
! 802: DPRINTF(("esp_output(): packet in SA %s/%08x got too "
! 803: "big\n", ipsp_address(tdb->tdb_dst),
! 804: ntohl(tdb->tdb_spi)));
! 805: m_freem(m);
! 806: espstat.esps_toobig++;
! 807: return EMSGSIZE;
! 808: }
! 809: break;
! 810: #endif /* INET6 */
! 811:
! 812: default:
! 813: DPRINTF(("esp_output(): unknown/unsupported protocol "
! 814: "family %d, SA %s/%08x\n", tdb->tdb_dst.sa.sa_family
! 815: , ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 816: m_freem(m);
! 817: espstat.esps_nopf++;
! 818: return EPFNOSUPPORT;
! 819: }
! 820:
! 821: /* Update the counters. */
! 822: tdb->tdb_cur_bytes += m->m_pkthdr.len - skip;
! 823: espstat.esps_obytes += m->m_pkthdr.len - skip;
! 824:
! 825: /* Hard byte expiration. */
! 826: if (tdb->tdb_flags & TDBF_BYTES &&
! 827: tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes) {
! 828: pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
! 829: tdb_delete(tdb);
! 830: m_freem(m);
! 831: return EINVAL;
! 832: }
! 833:
! 834: /* Soft byte expiration. */
! 835: if (tdb->tdb_flags & TDBF_SOFT_BYTES &&
! 836: tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes) {
! 837: pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
! 838: tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking. */
! 839: }
! 840:
! 841: /*
! 842: * Loop through mbuf chain; if we find a readonly mbuf,
! 843: * replace the rest of the chain.
! 844: */
! 845: mo = NULL;
! 846: mi = m;
! 847: while (mi != NULL && !M_READONLY(mi)) {
! 848: mo = mi;
! 849: mi = mi->m_next;
! 850: }
! 851:
! 852: if (mi != NULL) {
! 853: /* Replace the rest of the mbuf chain. */
! 854: struct mbuf *n = m_copym2(mi, 0, M_COPYALL, M_DONTWAIT);
! 855:
! 856: if (n == NULL) {
! 857: DPRINTF(("esp_output(): bad mbuf chain, SA %s/%08x\n",
! 858: ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 859: espstat.esps_hdrops++;
! 860: m_freem(m);
! 861: return ENOBUFS;
! 862: }
! 863:
! 864: if (mo != NULL)
! 865: mo->m_next = n;
! 866: else
! 867: m = n;
! 868:
! 869: m_freem(mi);
! 870: }
! 871:
! 872: /* Inject ESP header. */
! 873: mo = m_inject(m, skip, hlen, M_DONTWAIT);
! 874: if (mo == NULL) {
! 875: DPRINTF(("esp_output(): failed to inject ESP header for "
! 876: "SA %s/%08x\n", ipsp_address(tdb->tdb_dst),
! 877: ntohl(tdb->tdb_spi)));
! 878: m_freem(m);
! 879: espstat.esps_hdrops++;
! 880: return ENOBUFS;
! 881: }
! 882:
! 883: /* Initialize ESP header. */
! 884: bcopy((caddr_t) &tdb->tdb_spi, mtod(mo, caddr_t), sizeof(u_int32_t));
! 885: if (!(tdb->tdb_flags & TDBF_NOREPLAY)) {
! 886: u_int32_t replay = htonl(tdb->tdb_rpl++);
! 887: bcopy((caddr_t) &replay, mtod(mo, caddr_t) + sizeof(u_int32_t),
! 888: sizeof(u_int32_t));
! 889: #if NPFSYNC > 0
! 890: pfsync_update_tdb(tdb,1);
! 891: #endif
! 892: }
! 893:
! 894: /*
! 895: * Add padding -- better to do it ourselves than use the crypto engine,
! 896: * although if/when we support compression, we'd have to do that.
! 897: */
! 898: pad = (u_char *) m_pad(m, padding + alen);
! 899: if (pad == NULL) {
! 900: DPRINTF(("esp_output(): m_pad() failed for SA %s/%08x\n",
! 901: ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi)));
! 902: return ENOBUFS;
! 903: }
! 904:
! 905: /* Self-describing or random padding ? */
! 906: if (!(tdb->tdb_flags & TDBF_RANDOMPADDING))
! 907: for (ilen = 0; ilen < padding - 2; ilen++)
! 908: pad[ilen] = ilen + 1;
! 909: else
! 910: arc4random_bytes((void *) pad, padding - 2);
! 911:
! 912: /* Fix padding length and Next Protocol in padding itself. */
! 913: pad[padding - 2] = padding - 2;
! 914: m_copydata(m, protoff, sizeof(u_int8_t), pad + padding - 1);
! 915:
! 916: /* Fix Next Protocol in IPv4/IPv6 header. */
! 917: prot = IPPROTO_ESP;
! 918: m_copyback(m, protoff, sizeof(u_int8_t), &prot);
! 919:
! 920: /* Get crypto descriptors. */
! 921: crp = crypto_getreq(esph && espx ? 2 : 1);
! 922: if (crp == NULL) {
! 923: m_freem(m);
! 924: DPRINTF(("esp_output(): failed to acquire crypto "
! 925: "descriptors\n"));
! 926: espstat.esps_crypto++;
! 927: return ENOBUFS;
! 928: }
! 929:
! 930: if (espx) {
! 931: crde = crp->crp_desc;
! 932: crda = crde->crd_next;
! 933:
! 934: /* Encryption descriptor. */
! 935: crde->crd_skip = skip + hlen;
! 936: crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
! 937: crde->crd_flags = CRD_F_ENCRYPT;
! 938: crde->crd_inject = skip + hlen - tdb->tdb_ivlen;
! 939:
! 940: if (tdb->tdb_flags & TDBF_HALFIV) {
! 941: /* Copy half-iv in the packet. */
! 942: m_copyback(m, crde->crd_inject, tdb->tdb_ivlen,
! 943: tdb->tdb_iv);
! 944:
! 945: /* Cook half-iv. */
! 946: bcopy(tdb->tdb_iv, crde->crd_iv, tdb->tdb_ivlen);
! 947: for (ilen = 0; ilen < tdb->tdb_ivlen; ilen++)
! 948: crde->crd_iv[tdb->tdb_ivlen + ilen] =
! 949: ~crde->crd_iv[ilen];
! 950:
! 951: crde->crd_flags |=
! 952: CRD_F_IV_PRESENT | CRD_F_IV_EXPLICIT;
! 953: }
! 954:
! 955: /* Encryption operation. */
! 956: crde->crd_alg = espx->type;
! 957: crde->crd_key = tdb->tdb_emxkey;
! 958: crde->crd_klen = tdb->tdb_emxkeylen * 8;
! 959: /* XXX Rounds ? */
! 960: } else
! 961: crda = crp->crp_desc;
! 962:
! 963: /* IPsec-specific opaque crypto info. */
! 964: MALLOC(tc, struct tdb_crypto *, sizeof(struct tdb_crypto),
! 965: M_XDATA, M_NOWAIT);
! 966: if (tc == NULL) {
! 967: m_freem(m);
! 968: crypto_freereq(crp);
! 969: DPRINTF(("esp_output(): failed to allocate tdb_crypto\n"));
! 970: espstat.esps_crypto++;
! 971: return ENOBUFS;
! 972: }
! 973:
! 974: bzero(tc, sizeof(struct tdb_crypto));
! 975: tc->tc_spi = tdb->tdb_spi;
! 976: tc->tc_proto = tdb->tdb_sproto;
! 977: bcopy(&tdb->tdb_dst, &tc->tc_dst, sizeof(union sockaddr_union));
! 978:
! 979: /* Crypto operation descriptor. */
! 980: crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
! 981: crp->crp_flags = CRYPTO_F_IMBUF;
! 982: crp->crp_buf = (caddr_t) m;
! 983: crp->crp_callback = (int (*) (struct cryptop *)) esp_output_cb;
! 984: crp->crp_opaque = (caddr_t) tc;
! 985: crp->crp_sid = tdb->tdb_cryptoid;
! 986:
! 987: if (esph) {
! 988: /* Authentication descriptor. */
! 989: crda->crd_skip = skip;
! 990: crda->crd_len = m->m_pkthdr.len - (skip + alen);
! 991: crda->crd_inject = m->m_pkthdr.len - alen;
! 992:
! 993: /* Authentication operation. */
! 994: crda->crd_alg = esph->type;
! 995: crda->crd_key = tdb->tdb_amxkey;
! 996: crda->crd_klen = tdb->tdb_amxkeylen * 8;
! 997: }
! 998:
! 999: if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0)
! 1000: return crypto_dispatch(crp);
! 1001: else
! 1002: return esp_output_cb(crp);
! 1003: }
! 1004:
! 1005: /*
! 1006: * ESP output callback, called directly by the crypto driver.
! 1007: */
! 1008: int
! 1009: esp_output_cb(void *op)
! 1010: {
! 1011: struct cryptop *crp = (struct cryptop *) op;
! 1012: struct tdb_crypto *tc;
! 1013: struct tdb *tdb;
! 1014: struct mbuf *m;
! 1015: int error, s;
! 1016:
! 1017: tc = (struct tdb_crypto *) crp->crp_opaque;
! 1018:
! 1019: m = (struct mbuf *) crp->crp_buf;
! 1020: if (m == NULL) {
! 1021: /* Shouldn't happen... */
! 1022: FREE(tc, M_XDATA);
! 1023: crypto_freereq(crp);
! 1024: espstat.esps_crypto++;
! 1025: DPRINTF(("esp_output_cb(): bogus returned buffer from "
! 1026: "crypto\n"));
! 1027: return (EINVAL);
! 1028: }
! 1029:
! 1030:
! 1031: s = spltdb();
! 1032:
! 1033: tdb = gettdb(tc->tc_spi, &tc->tc_dst, tc->tc_proto);
! 1034: if (tdb == NULL) {
! 1035: FREE(tc, M_XDATA);
! 1036: espstat.esps_notdb++;
! 1037: DPRINTF(("esp_output_cb(): TDB is expired while in crypto\n"));
! 1038: error = EPERM;
! 1039: goto baddone;
! 1040: }
! 1041:
! 1042: /* Check for crypto errors. */
! 1043: if (crp->crp_etype) {
! 1044: if (crp->crp_etype == EAGAIN) {
! 1045: /* Reset the session ID */
! 1046: if (tdb->tdb_cryptoid != 0)
! 1047: tdb->tdb_cryptoid = crp->crp_sid;
! 1048: splx(s);
! 1049: return crypto_dispatch(crp);
! 1050: }
! 1051: FREE(tc, M_XDATA);
! 1052: espstat.esps_noxform++;
! 1053: DPRINTF(("esp_output_cb(): crypto error %d\n",
! 1054: crp->crp_etype));
! 1055: error = crp->crp_etype;
! 1056: goto baddone;
! 1057: }
! 1058: FREE(tc, M_XDATA);
! 1059:
! 1060: /* Release crypto descriptors. */
! 1061: crypto_freereq(crp);
! 1062:
! 1063: /*
! 1064: * If we're doing half-iv, keep a copy of the last few bytes of the
! 1065: * encrypted part, for use as the next IV. Note that HALF-IV is only
! 1066: * supposed to be used without authentication (the old ESP specs).
! 1067: */
! 1068: if (tdb->tdb_flags & TDBF_HALFIV)
! 1069: m_copydata(m, m->m_pkthdr.len - tdb->tdb_ivlen, tdb->tdb_ivlen,
! 1070: tdb->tdb_iv);
! 1071:
! 1072: /* Call the IPsec input callback. */
! 1073: error = ipsp_process_done(m, tdb);
! 1074: splx(s);
! 1075: return error;
! 1076:
! 1077: baddone:
! 1078: splx(s);
! 1079:
! 1080: if (m != NULL)
! 1081: m_freem(m);
! 1082:
! 1083: crypto_freereq(crp);
! 1084:
! 1085: return error;
! 1086: }
! 1087:
! 1088: /*
! 1089: * return 0 on success
! 1090: * return 1 for counter == 0
! 1091: * return 2 for very old packet
! 1092: * return 3 for packet within current window but already received
! 1093: */
! 1094: int
! 1095: checkreplaywindow32(u_int32_t seq, u_int32_t initial, u_int32_t *lastseq,
! 1096: u_int32_t window, u_int32_t *bitmap, int commit)
! 1097: {
! 1098: u_int32_t diff, llseq, lbitmap;
! 1099:
! 1100: /* Just do the checking, without "committing" any changes. */
! 1101: if (commit == 0) {
! 1102: llseq = *lastseq;
! 1103: lbitmap = *bitmap;
! 1104:
! 1105: lastseq = &llseq;
! 1106: bitmap = &lbitmap;
! 1107: }
! 1108:
! 1109: seq -= initial;
! 1110:
! 1111: if (seq == 0)
! 1112: return 1;
! 1113:
! 1114: if (seq > *lastseq - initial) {
! 1115: diff = seq - (*lastseq - initial);
! 1116: if (diff < window)
! 1117: *bitmap = ((*bitmap) << diff) | 1;
! 1118: else
! 1119: *bitmap = 1;
! 1120: *lastseq = seq + initial;
! 1121: return 0;
! 1122: }
! 1123:
! 1124: diff = *lastseq - initial - seq;
! 1125: if (diff >= window) {
! 1126: espstat.esps_wrap++;
! 1127: return 2;
! 1128: }
! 1129:
! 1130: if ((*bitmap) & (((u_int32_t) 1) << diff)) {
! 1131: espstat.esps_replay++;
! 1132: return 3;
! 1133: }
! 1134:
! 1135: *bitmap |= (((u_int32_t) 1) << diff);
! 1136: return 0;
! 1137: }
! 1138:
! 1139: /*
! 1140: * m_pad(m, n) pads <m> with <n> bytes at the end. The packet header
! 1141: * length is updated, and a pointer to the first byte of the padding
! 1142: * (which is guaranteed to be all in one mbuf) is returned.
! 1143: */
! 1144:
! 1145: caddr_t
! 1146: m_pad(struct mbuf *m, int n)
! 1147: {
! 1148: struct mbuf *m0, *m1;
! 1149: int len, pad;
! 1150: caddr_t retval;
! 1151:
! 1152: if (n <= 0) { /* No stupid arguments. */
! 1153: DPRINTF(("m_pad(): pad length invalid (%d)\n", n));
! 1154: m_freem(m);
! 1155: return NULL;
! 1156: }
! 1157:
! 1158: len = m->m_pkthdr.len;
! 1159: pad = n;
! 1160: m0 = m;
! 1161:
! 1162: while (m0->m_len < len) {
! 1163: len -= m0->m_len;
! 1164: m0 = m0->m_next;
! 1165: }
! 1166:
! 1167: if (m0->m_len != len) {
! 1168: DPRINTF(("m_pad(): length mismatch (should be %d instead of "
! 1169: "%d)\n", m->m_pkthdr.len,
! 1170: m->m_pkthdr.len + m0->m_len - len));
! 1171:
! 1172: m_freem(m);
! 1173: return NULL;
! 1174: }
! 1175:
! 1176: /* Check for zero-length trailing mbufs, and find the last one. */
! 1177: for (m1 = m0; m1->m_next; m1 = m1->m_next) {
! 1178: if (m1->m_next->m_len != 0) {
! 1179: DPRINTF(("m_pad(): length mismatch (should be %d "
! 1180: "instead of %d)\n", m->m_pkthdr.len,
! 1181: m->m_pkthdr.len + m1->m_next->m_len));
! 1182:
! 1183: m_freem(m);
! 1184: return NULL;
! 1185: }
! 1186:
! 1187: m0 = m1->m_next;
! 1188: }
! 1189:
! 1190: if ((m0->m_flags & M_EXT) ||
! 1191: m0->m_data + m0->m_len + pad >= &(m0->m_dat[MLEN])) {
! 1192: /* Add an mbuf to the chain. */
! 1193: MGET(m1, M_DONTWAIT, MT_DATA);
! 1194: if (m1 == 0) {
! 1195: m_freem(m0);
! 1196: DPRINTF(("m_pad(): cannot append\n"));
! 1197: return NULL;
! 1198: }
! 1199:
! 1200: m0->m_next = m1;
! 1201: m0 = m1;
! 1202: m0->m_len = 0;
! 1203: }
! 1204:
! 1205: retval = m0->m_data + m0->m_len;
! 1206: m0->m_len += pad;
! 1207: m->m_pkthdr.len += pad;
! 1208:
! 1209: return retval;
! 1210: }
CVSweb