[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     ! 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