The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/ipsec_output.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 2d8ba1518b3ce96846df388db16e7f58


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.