[BACK]Return to ipsec_output.c CVS log [TXT][DIR] Up to [local] / sys / netinet

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