Annotation of sys/netinet/ipsec_output.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ipsec_output.c,v 1.39 2007/06/01 00:52:38 henning Exp $ */
! 2: /*
! 3: * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
! 4: *
! 5: * Copyright (c) 2000-2001 Angelos D. Keromytis.
! 6: *
! 7: * Permission to use, copy, and modify this software with or without fee
! 8: * is hereby granted, provided that this entire notice is included in
! 9: * all copies of any software which is or includes a copy or
! 10: * modification of this software.
! 11: * You may use this code under the GNU public license if you so wish. Please
! 12: * contribute changes back to the authors under this freer than GPL license
! 13: * so that we may further the use of strong encryption without limitations to
! 14: * all.
! 15: *
! 16: * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
! 17: * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
! 18: * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
! 19: * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
! 20: * PURPOSE.
! 21: */
! 22:
! 23: #include "pf.h"
! 24:
! 25: #include <sys/param.h>
! 26: #include <sys/systm.h>
! 27: #include <sys/mbuf.h>
! 28: #include <sys/socket.h>
! 29: #include <sys/kernel.h>
! 30:
! 31: #include <net/if.h>
! 32: #include <net/route.h>
! 33:
! 34: #if NPF > 0
! 35: #include <net/pfvar.h>
! 36: #endif
! 37:
! 38: #ifdef INET
! 39: #include <netinet/in.h>
! 40: #include <netinet/in_systm.h>
! 41: #include <netinet/ip.h>
! 42: #include <netinet/in_pcb.h>
! 43: #include <netinet/ip_var.h>
! 44: #endif /* INET */
! 45:
! 46: #ifdef INET6
! 47: #ifndef INET
! 48: #include <netinet/in.h>
! 49: #endif
! 50: #include <netinet6/in6_var.h>
! 51: #endif /* INET6 */
! 52:
! 53: #include <netinet/udp.h>
! 54: #include <netinet/ip_ipsp.h>
! 55: #include <netinet/ip_ah.h>
! 56: #include <netinet/ip_esp.h>
! 57: #include <netinet/ip_ipcomp.h>
! 58: #include <crypto/xform.h>
! 59:
! 60: #ifdef ENCDEBUG
! 61: #define DPRINTF(x) if (encdebug) printf x
! 62: #else
! 63: #define DPRINTF(x)
! 64: #endif
! 65:
! 66: int udpencap_enable = 1; /* enabled by default */
! 67: int udpencap_port = 4500; /* triggers decapsulation */
! 68:
! 69: /*
! 70: * Loop over a tdb chain, taking into consideration protocol tunneling. The
! 71: * fourth argument is set if the first encapsulation header is already in
! 72: * place.
! 73: */
! 74: int
! 75: ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready)
! 76: {
! 77: struct timeval tv;
! 78: int i, off, error;
! 79: struct mbuf *mp;
! 80: #ifdef INET6
! 81: struct ip6_ext ip6e;
! 82: int nxt;
! 83: int dstopt = 0;
! 84: #endif
! 85:
! 86: #ifdef INET
! 87: int setdf = 0;
! 88: struct ip *ip;
! 89: #endif /* INET */
! 90: #ifdef INET6
! 91: struct ip6_hdr *ip6;
! 92: #endif /* INET6 */
! 93:
! 94: /* Check that the transform is allowed by the administrator. */
! 95: if ((tdb->tdb_sproto == IPPROTO_ESP && !esp_enable) ||
! 96: (tdb->tdb_sproto == IPPROTO_AH && !ah_enable) ||
! 97: (tdb->tdb_sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
! 98: DPRINTF(("ipsp_process_packet(): IPsec outbound packet "
! 99: "dropped due to policy (check your sysctls)\n"));
! 100: m_freem(m);
! 101: return EHOSTUNREACH;
! 102: }
! 103:
! 104: /* Sanity check. */
! 105: if (!tdb->tdb_xform) {
! 106: DPRINTF(("ipsp_process_packet(): uninitialized TDB\n"));
! 107: m_freem(m);
! 108: return EHOSTUNREACH;
! 109: }
! 110:
! 111: /* Check if the SPI is invalid. */
! 112: if (tdb->tdb_flags & TDBF_INVALID) {
! 113: DPRINTF(("ipsp_process_packet(): attempt to use invalid "
! 114: "SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst),
! 115: ntohl(tdb->tdb_spi), tdb->tdb_sproto));
! 116: m_freem(m);
! 117: return ENXIO;
! 118: }
! 119:
! 120: /* Check that the network protocol is supported */
! 121: switch (tdb->tdb_dst.sa.sa_family) {
! 122: #ifdef INET
! 123: case AF_INET:
! 124: break;
! 125: #endif /* INET */
! 126:
! 127: #ifdef INET6
! 128: case AF_INET6:
! 129: break;
! 130: #endif /* INET6 */
! 131:
! 132: default:
! 133: DPRINTF(("ipsp_process_packet(): attempt to use "
! 134: "SA %s/%08x/%u for protocol family %d\n",
! 135: ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi),
! 136: tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family));
! 137: m_freem(m);
! 138: return ENXIO;
! 139: }
! 140:
! 141: /*
! 142: * Register first use if applicable, setup relevant expiration timer.
! 143: */
! 144: if (tdb->tdb_first_use == 0) {
! 145: tdb->tdb_first_use = time_second;
! 146:
! 147: tv.tv_usec = 0;
! 148:
! 149: tv.tv_sec = tdb->tdb_first_use + tdb->tdb_exp_first_use;
! 150: if (tdb->tdb_flags & TDBF_FIRSTUSE)
! 151: timeout_add(&tdb->tdb_first_tmo,
! 152: hzto(&tv));
! 153:
! 154: tv.tv_sec = tdb->tdb_first_use + tdb->tdb_soft_first_use;
! 155: if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
! 156: timeout_add(&tdb->tdb_sfirst_tmo,
! 157: hzto(&tv));
! 158: }
! 159:
! 160: /*
! 161: * Check for tunneling if we don't have the first header in place.
! 162: * When doing Ethernet-over-IP, we are handed an already-encapsulated
! 163: * frame, so we don't need to re-encapsulate.
! 164: */
! 165: if (tunalready == 0) {
! 166: /*
! 167: * If the target protocol family is different, we know we'll be
! 168: * doing tunneling.
! 169: */
! 170: if (af == tdb->tdb_dst.sa.sa_family) {
! 171: #ifdef INET
! 172: if (af == AF_INET)
! 173: i = sizeof(struct ip);
! 174: #endif /* INET */
! 175:
! 176: #ifdef INET6
! 177: if (af == AF_INET6)
! 178: i = sizeof(struct ip6_hdr);
! 179: #endif /* INET6 */
! 180:
! 181: /* Bring the network header in the first mbuf. */
! 182: if (m->m_len < i) {
! 183: if ((m = m_pullup(m, i)) == NULL)
! 184: return ENOBUFS;
! 185: }
! 186:
! 187: #ifdef INET
! 188: ip = mtod(m, struct ip *);
! 189:
! 190: /*
! 191: * This is not a bridge packet, remember if we
! 192: * had IP_DF.
! 193: */
! 194: setdf = ip->ip_off & htons(IP_DF);
! 195: #endif /* INET */
! 196:
! 197: #ifdef INET6
! 198: ip6 = mtod(m, struct ip6_hdr *);
! 199: #endif /* INET6 */
! 200: }
! 201:
! 202: /* Do the appropriate encapsulation, if necessary. */
! 203: if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */
! 204: (tdb->tdb_flags & TDBF_TUNNELING) || /* Tunneling needed */
! 205: (tdb->tdb_xform->xf_type == XF_IP4) || /* ditto */
! 206: #ifdef INET
! 207: ((tdb->tdb_dst.sa.sa_family == AF_INET) &&
! 208: (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) &&
! 209: (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) ||
! 210: #endif /* INET */
! 211: #ifdef INET6
! 212: ((tdb->tdb_dst.sa.sa_family == AF_INET6) &&
! 213: (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) &&
! 214: (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
! 215: &ip6->ip6_dst))) ||
! 216: #endif /* INET6 */
! 217: 0) {
! 218: #ifdef INET
! 219: /* Fix IPv4 header checksum and length. */
! 220: if (af == AF_INET) {
! 221: if (m->m_len < sizeof(struct ip))
! 222: if ((m = m_pullup(m,
! 223: sizeof(struct ip))) == NULL)
! 224: return ENOBUFS;
! 225:
! 226: ip = mtod(m, struct ip *);
! 227: ip->ip_len = htons(m->m_pkthdr.len);
! 228: ip->ip_sum = 0;
! 229: ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
! 230: }
! 231: #endif /* INET */
! 232:
! 233: #ifdef INET6
! 234: /* Fix IPv6 header payload length. */
! 235: if (af == AF_INET6) {
! 236: if (m->m_len < sizeof(struct ip6_hdr))
! 237: if ((m = m_pullup(m,
! 238: sizeof(struct ip6_hdr))) == NULL)
! 239: return ENOBUFS;
! 240:
! 241: if (m->m_pkthdr.len - sizeof(*ip6) >
! 242: IPV6_MAXPACKET) {
! 243: /* No jumbogram support. */
! 244: m_freem(m);
! 245: return ENXIO; /*?*/
! 246: }
! 247: ip6 = mtod(m, struct ip6_hdr *);
! 248: ip6->ip6_plen = htons(m->m_pkthdr.len
! 249: - sizeof(*ip6));
! 250: }
! 251: #endif /* INET6 */
! 252:
! 253: /* Encapsulate -- the last two arguments are unused. */
! 254: error = ipip_output(m, tdb, &mp, 0, 0);
! 255: if ((mp == NULL) && (!error))
! 256: error = EFAULT;
! 257: if (error) {
! 258: if (mp) {
! 259: m_freem(mp);
! 260: mp = NULL;
! 261: }
! 262: return error;
! 263: }
! 264:
! 265: m = mp;
! 266: mp = NULL;
! 267:
! 268: #ifdef INET
! 269: if (tdb->tdb_dst.sa.sa_family == AF_INET && setdf) {
! 270: if (m->m_len < sizeof(struct ip))
! 271: if ((m = m_pullup(m,
! 272: sizeof(struct ip))) == NULL)
! 273: return ENOBUFS;
! 274:
! 275: ip = mtod(m, struct ip *);
! 276: ip->ip_off |= htons(IP_DF);
! 277: }
! 278: #endif
! 279:
! 280: /* Remember that we appended a tunnel header. */
! 281: tdb->tdb_flags |= TDBF_USEDTUNNEL;
! 282: }
! 283:
! 284: /* We may be done with this TDB */
! 285: if (tdb->tdb_xform->xf_type == XF_IP4)
! 286: return ipsp_process_done(m, tdb);
! 287: } else {
! 288: /*
! 289: * If this is just an IP-IP TDB and we're told there's
! 290: * already an encapsulation header, move on.
! 291: */
! 292: if (tdb->tdb_xform->xf_type == XF_IP4)
! 293: return ipsp_process_done(m, tdb);
! 294: }
! 295:
! 296: /* Extract some information off the headers. */
! 297: switch (tdb->tdb_dst.sa.sa_family) {
! 298: #ifdef INET
! 299: case AF_INET:
! 300: ip = mtod(m, struct ip *);
! 301: i = ip->ip_hl << 2;
! 302: off = offsetof(struct ip, ip_p);
! 303: break;
! 304: #endif /* INET */
! 305:
! 306: #ifdef INET6
! 307: case AF_INET6:
! 308: ip6 = mtod(m, struct ip6_hdr *);
! 309: i = sizeof(struct ip6_hdr);
! 310: off = offsetof(struct ip6_hdr, ip6_nxt);
! 311: nxt = ip6->ip6_nxt;
! 312: /*
! 313: * chase mbuf chain to find the appropriate place to
! 314: * put AH/ESP/IPcomp header.
! 315: * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
! 316: */
! 317: do {
! 318: switch (nxt) {
! 319: case IPPROTO_AH:
! 320: case IPPROTO_ESP:
! 321: case IPPROTO_IPCOMP:
! 322: /*
! 323: * we should not skip security header added
! 324: * beforehand.
! 325: */
! 326: goto exitip6loop;
! 327:
! 328: case IPPROTO_HOPOPTS:
! 329: case IPPROTO_DSTOPTS:
! 330: case IPPROTO_ROUTING:
! 331: /*
! 332: * if we see 2nd destination option header,
! 333: * we should stop there.
! 334: */
! 335: if (nxt == IPPROTO_DSTOPTS && dstopt)
! 336: goto exitip6loop;
! 337:
! 338: if (nxt == IPPROTO_DSTOPTS) {
! 339: /*
! 340: * seen 1st or 2nd destination option.
! 341: * next time we see one, it must be 2nd.
! 342: */
! 343: dstopt = 1;
! 344: } else if (nxt == IPPROTO_ROUTING) {
! 345: /*
! 346: * if we see destionation option next
! 347: * time, it must be dest2.
! 348: */
! 349: dstopt = 2;
! 350: }
! 351:
! 352: /* skip this header */
! 353: m_copydata(m, i, sizeof(ip6e), (caddr_t)&ip6e);
! 354: nxt = ip6e.ip6e_nxt;
! 355: off = i + offsetof(struct ip6_ext, ip6e_nxt);
! 356: /*
! 357: * we will never see nxt == IPPROTO_AH
! 358: * so it is safe to omit AH case.
! 359: */
! 360: i += (ip6e.ip6e_len + 1) << 3;
! 361: break;
! 362: default:
! 363: goto exitip6loop;
! 364: }
! 365: } while (i < m->m_pkthdr.len);
! 366: exitip6loop:;
! 367: break;
! 368: #endif /* INET6 */
! 369: }
! 370:
! 371: /* Non expansion policy for IPCOMP */
! 372: if (tdb->tdb_sproto == IPPROTO_IPCOMP) {
! 373: if ((m->m_pkthdr.len - i) < tdb->tdb_compalgxform->minlen) {
! 374: extern struct ipcompstat ipcompstat;
! 375:
! 376: /* No need to compress, leave the packet untouched */
! 377: ipcompstat.ipcomps_minlen++;
! 378: return ipsp_process_done(m, tdb);
! 379: }
! 380: }
! 381:
! 382: /* Invoke the IPsec transform. */
! 383: return (*(tdb->tdb_xform->xf_output))(m, tdb, NULL, i, off);
! 384: }
! 385:
! 386: /*
! 387: * Called by the IPsec output transform callbacks, to transmit the packet
! 388: * or do further processing, as necessary.
! 389: */
! 390: int
! 391: ipsp_process_done(struct mbuf *m, struct tdb *tdb)
! 392: {
! 393: #ifdef INET
! 394: struct ip *ip;
! 395: #endif /* INET */
! 396:
! 397: #ifdef INET6
! 398: struct ip6_hdr *ip6;
! 399: #endif /* INET6 */
! 400:
! 401: struct tdb_ident *tdbi;
! 402: struct m_tag *mtag;
! 403:
! 404: tdb->tdb_last_used = time_second;
! 405:
! 406: if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0) {
! 407: struct mbuf *mi;
! 408: struct udphdr *uh;
! 409:
! 410: if (!udpencap_enable || !udpencap_port) {
! 411: m_freem(m);
! 412: return ENXIO;
! 413: }
! 414: mi = m_inject(m, sizeof(struct ip), sizeof(struct udphdr),
! 415: M_DONTWAIT);
! 416: if (mi == NULL) {
! 417: m_freem(m);
! 418: return ENOMEM;
! 419: }
! 420: uh = mtod(mi, struct udphdr *);
! 421: uh->uh_sport = uh->uh_dport = htons(udpencap_port);
! 422: if (tdb->tdb_udpencap_port)
! 423: uh->uh_dport = tdb->tdb_udpencap_port;
! 424:
! 425: uh->uh_ulen = htons(m->m_pkthdr.len - sizeof(struct ip));
! 426: uh->uh_sum = 0;
! 427: espstat.esps_udpencout++;
! 428: }
! 429:
! 430: switch (tdb->tdb_dst.sa.sa_family) {
! 431: #ifdef INET
! 432: case AF_INET:
! 433: /* Fix the header length, for AH processing. */
! 434: ip = mtod(m, struct ip *);
! 435: ip->ip_len = htons(m->m_pkthdr.len);
! 436: if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0)
! 437: ip->ip_p = IPPROTO_UDP;
! 438: break;
! 439: #endif /* INET */
! 440:
! 441: #ifdef INET6
! 442: case AF_INET6:
! 443: /* Fix the header length, for AH processing. */
! 444: if (m->m_pkthdr.len < sizeof(*ip6)) {
! 445: m_freem(m);
! 446: return ENXIO;
! 447: }
! 448: if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
! 449: /* No jumbogram support. */
! 450: m_freem(m);
! 451: return ENXIO;
! 452: }
! 453: ip6 = mtod(m, struct ip6_hdr *);
! 454: ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
! 455: if ((tdb->tdb_flags & TDBF_UDPENCAP) != 0)
! 456: ip6->ip6_nxt = IPPROTO_UDP;
! 457: break;
! 458: #endif /* INET6 */
! 459:
! 460: default:
! 461: m_freem(m);
! 462: DPRINTF(("ipsp_process_done(): unknown protocol family (%d)\n",
! 463: tdb->tdb_dst.sa.sa_family));
! 464: return ENXIO;
! 465: }
! 466:
! 467: /*
! 468: * Add a record of what we've done or what needs to be done to the
! 469: * packet.
! 470: */
! 471: if ((tdb->tdb_flags & TDBF_SKIPCRYPTO) == 0)
! 472: mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE,
! 473: sizeof(struct tdb_ident),
! 474: M_NOWAIT);
! 475: else
! 476: mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED,
! 477: sizeof(struct tdb_ident), M_NOWAIT);
! 478:
! 479: if (mtag == NULL) {
! 480: m_freem(m);
! 481: DPRINTF(("ipsp_process_done(): could not allocate packet "
! 482: "tag\n"));
! 483: return ENOMEM;
! 484: }
! 485:
! 486: tdbi = (struct tdb_ident *)(mtag + 1);
! 487: bcopy(&tdb->tdb_dst, &tdbi->dst, sizeof(union sockaddr_union));
! 488: tdbi->proto = tdb->tdb_sproto;
! 489: tdbi->spi = tdb->tdb_spi;
! 490:
! 491: m_tag_prepend(m, mtag);
! 492:
! 493: /* If there's another (bundled) TDB to apply, do so. */
! 494: if (tdb->tdb_onext)
! 495: return ipsp_process_packet(m, tdb->tdb_onext,
! 496: tdb->tdb_dst.sa.sa_family, 0);
! 497:
! 498: #if NPF > 0
! 499: /* Add pf tag if requested. */
! 500: if (pf_tag_packet(m, tdb->tdb_tag, -1))
! 501: DPRINTF(("failed to tag ipsec packet\n"));
! 502: #endif
! 503:
! 504: /*
! 505: * We're done with IPsec processing, transmit the packet using the
! 506: * appropriate network protocol (IP or IPv6). SPD lookup will be
! 507: * performed again there.
! 508: */
! 509: switch (tdb->tdb_dst.sa.sa_family) {
! 510: #ifdef INET
! 511: case AF_INET:
! 512: return ip_output(m, (void *)NULL, (void *)NULL, IP_RAWOUTPUT, (void *)NULL, (void *)NULL);
! 513: #endif /* INET */
! 514:
! 515: #ifdef INET6
! 516: case AF_INET6:
! 517: /*
! 518: * We don't need massage, IPv6 header fields are always in
! 519: * net endian.
! 520: */
! 521: return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
! 522: #endif /* INET6 */
! 523: }
! 524: return EINVAL; /* Not reached. */
! 525: }
! 526:
! 527: ssize_t
! 528: ipsec_hdrsz(struct tdb *tdbp)
! 529: {
! 530: ssize_t adjust;
! 531:
! 532: switch (tdbp->tdb_sproto) {
! 533: case IPPROTO_IPIP:
! 534: adjust = 0;
! 535: break;
! 536:
! 537: case IPPROTO_ESP:
! 538: if (tdbp->tdb_encalgxform == NULL)
! 539: return (-1);
! 540:
! 541: /* Header length */
! 542: if (tdbp->tdb_flags & TDBF_NOREPLAY)
! 543: adjust = sizeof(u_int32_t) + tdbp->tdb_ivlen;
! 544: else
! 545: adjust = 2 * sizeof(u_int32_t) + tdbp->tdb_ivlen;
! 546: if (tdbp->tdb_flags & TDBF_UDPENCAP)
! 547: adjust += sizeof(struct udphdr);
! 548: /* Authenticator */
! 549: if (tdbp->tdb_authalgxform != NULL)
! 550: adjust += AH_HMAC_HASHLEN;
! 551: /* Padding */
! 552: adjust += tdbp->tdb_encalgxform->blocksize;
! 553: break;
! 554:
! 555: case IPPROTO_AH:
! 556: if (tdbp->tdb_authalgxform == NULL)
! 557: return (-1);
! 558:
! 559: if (!(tdbp->tdb_flags & TDBF_NOREPLAY))
! 560: adjust = AH_FLENGTH + sizeof(u_int32_t);
! 561: else
! 562: adjust = AH_FLENGTH;
! 563: adjust += tdbp->tdb_authalgxform->authsize;
! 564: break;
! 565:
! 566: default:
! 567: return (-1);
! 568: }
! 569:
! 570: if (!(tdbp->tdb_flags & TDBF_TUNNELING) &&
! 571: !(tdbp->tdb_flags & TDBF_USEDTUNNEL))
! 572: return (adjust);
! 573:
! 574: switch (tdbp->tdb_dst.sa.sa_family) {
! 575: #ifdef INET
! 576: case AF_INET:
! 577: adjust += sizeof(struct ip);
! 578: break;
! 579: #endif /* INET */
! 580: #ifdef INET6
! 581: case AF_INET6:
! 582: adjust += sizeof(struct ip6_hdr);
! 583: break;
! 584: #endif /* INET6 */
! 585: }
! 586:
! 587: return (adjust);
! 588: }
! 589:
! 590: void
! 591: ipsec_adjust_mtu(struct mbuf *m, u_int32_t mtu)
! 592: {
! 593: struct tdb_ident *tdbi;
! 594: struct tdb *tdbp;
! 595: struct m_tag *mtag;
! 596: ssize_t adjust;
! 597: int s;
! 598:
! 599: s = spltdb();
! 600:
! 601: for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL); mtag;
! 602: mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, mtag)) {
! 603: tdbi = (struct tdb_ident *)(mtag + 1);
! 604: tdbp = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
! 605: if (tdbp == NULL)
! 606: break;
! 607:
! 608: if ((adjust = ipsec_hdrsz(tdbp)) == -1)
! 609: break;
! 610:
! 611: mtu -= adjust;
! 612: tdbp->tdb_mtu = mtu;
! 613: tdbp->tdb_mtutimeout = time_second + ip_mtudisc_timeout;
! 614: DPRINTF(("ipsec_adjust_mtu: "
! 615: "spi %08x mtu %d adjust %d mbuf %p\n",
! 616: ntohl(tdbp->tdb_spi), tdbp->tdb_mtu,
! 617: adjust, m));
! 618: }
! 619:
! 620: splx(s);
! 621: }
CVSweb