LCOV - code coverage report
Current view: top level - net/xfrm - xfrm_output.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 311 0.0 %
Date: 2022-04-01 14:58:12 Functions: 0 17 0.0 %
Branches: 0 211 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * xfrm_output.c - Common IPsec encapsulation code.
       4                 :            :  *
       5                 :            :  * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/errno.h>
       9                 :            : #include <linux/module.h>
      10                 :            : #include <linux/netdevice.h>
      11                 :            : #include <linux/netfilter.h>
      12                 :            : #include <linux/skbuff.h>
      13                 :            : #include <linux/slab.h>
      14                 :            : #include <linux/spinlock.h>
      15                 :            : #include <net/dst.h>
      16                 :            : #include <net/inet_ecn.h>
      17                 :            : #include <net/xfrm.h>
      18                 :            : 
      19                 :            : #include "xfrm_inout.h"
      20                 :            : 
      21                 :            : static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb);
      22                 :            : static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb);
      23                 :            : 
      24                 :          0 : static int xfrm_skb_check_space(struct sk_buff *skb)
      25                 :            : {
      26         [ #  # ]:          0 :         struct dst_entry *dst = skb_dst(skb);
      27                 :          0 :         int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev)
      28         [ #  # ]:          0 :                 - skb_headroom(skb);
      29         [ #  # ]:          0 :         int ntail = dst->dev->needed_tailroom - skb_tailroom(skb);
      30                 :            : 
      31         [ #  # ]:          0 :         if (nhead <= 0) {
      32         [ #  # ]:          0 :                 if (ntail <= 0)
      33                 :            :                         return 0;
      34                 :            :                 nhead = 0;
      35                 :          0 :         } else if (ntail < 0)
      36                 :            :                 ntail = 0;
      37                 :            : 
      38                 :          0 :         return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
      39                 :            : }
      40                 :            : 
      41                 :            : /* Children define the path of the packet through the
      42                 :            :  * Linux networking.  Thus, destinations are stackable.
      43                 :            :  */
      44                 :            : 
      45                 :          0 : static struct dst_entry *skb_dst_pop(struct sk_buff *skb)
      46                 :            : {
      47         [ #  # ]:          0 :         struct dst_entry *child = dst_clone(xfrm_dst_child(skb_dst(skb)));
      48                 :            : 
      49         [ #  # ]:          0 :         skb_dst_drop(skb);
      50                 :          0 :         return child;
      51                 :            : }
      52                 :            : 
      53                 :            : /* Add encapsulation header.
      54                 :            :  *
      55                 :            :  * The IP header will be moved forward to make space for the encapsulation
      56                 :            :  * header.
      57                 :            :  */
      58                 :            : static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb)
      59                 :            : {
      60                 :            :         struct iphdr *iph = ip_hdr(skb);
      61                 :            :         int ihl = iph->ihl * 4;
      62                 :            : 
      63                 :            :         skb_set_inner_transport_header(skb, skb_transport_offset(skb));
      64                 :            : 
      65                 :            :         skb_set_network_header(skb, -x->props.header_len);
      66                 :            :         skb->mac_header = skb->network_header +
      67                 :            :                           offsetof(struct iphdr, protocol);
      68                 :            :         skb->transport_header = skb->network_header + ihl;
      69                 :            :         __skb_pull(skb, ihl);
      70                 :            :         memmove(skb_network_header(skb), iph, ihl);
      71                 :            :         return 0;
      72                 :            : }
      73                 :            : 
      74                 :            : /* Add encapsulation header.
      75                 :            :  *
      76                 :            :  * The IP header and mutable extension headers will be moved forward to make
      77                 :            :  * space for the encapsulation header.
      78                 :            :  */
      79                 :          0 : static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb)
      80                 :            : {
      81                 :            : #if IS_ENABLED(CONFIG_IPV6)
      82                 :          0 :         struct ipv6hdr *iph;
      83                 :          0 :         u8 *prevhdr;
      84                 :          0 :         int hdr_len;
      85                 :            : 
      86                 :          0 :         iph = ipv6_hdr(skb);
      87                 :          0 :         skb_set_inner_transport_header(skb, skb_transport_offset(skb));
      88                 :            : 
      89                 :          0 :         hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
      90         [ #  # ]:          0 :         if (hdr_len < 0)
      91                 :            :                 return hdr_len;
      92                 :          0 :         skb_set_mac_header(skb,
      93         [ #  # ]:          0 :                            (prevhdr - x->props.header_len) - skb->data);
      94         [ #  # ]:          0 :         skb_set_network_header(skb, -x->props.header_len);
      95                 :          0 :         skb->transport_header = skb->network_header + hdr_len;
      96         [ #  # ]:          0 :         __skb_pull(skb, hdr_len);
      97                 :          0 :         memmove(ipv6_hdr(skb), iph, hdr_len);
      98                 :          0 :         return 0;
      99                 :            : #else
     100                 :            :         WARN_ON_ONCE(1);
     101                 :            :         return -EAFNOSUPPORT;
     102                 :            : #endif
     103                 :            : }
     104                 :            : 
     105                 :            : /* Add route optimization header space.
     106                 :            :  *
     107                 :            :  * The IP header and mutable extension headers will be moved forward to make
     108                 :            :  * space for the route optimization header.
     109                 :            :  */
     110                 :          0 : static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
     111                 :            : {
     112                 :            : #if IS_ENABLED(CONFIG_IPV6)
     113                 :          0 :         struct ipv6hdr *iph;
     114                 :          0 :         u8 *prevhdr;
     115                 :          0 :         int hdr_len;
     116                 :            : 
     117                 :          0 :         iph = ipv6_hdr(skb);
     118                 :            : 
     119                 :          0 :         hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
     120         [ #  # ]:          0 :         if (hdr_len < 0)
     121                 :            :                 return hdr_len;
     122                 :          0 :         skb_set_mac_header(skb,
     123         [ #  # ]:          0 :                            (prevhdr - x->props.header_len) - skb->data);
     124         [ #  # ]:          0 :         skb_set_network_header(skb, -x->props.header_len);
     125                 :          0 :         skb->transport_header = skb->network_header + hdr_len;
     126         [ #  # ]:          0 :         __skb_pull(skb, hdr_len);
     127                 :          0 :         memmove(ipv6_hdr(skb), iph, hdr_len);
     128                 :            : 
     129                 :          0 :         x->lastused = ktime_get_real_seconds();
     130                 :            : 
     131                 :          0 :         return 0;
     132                 :            : #else
     133                 :            :         WARN_ON_ONCE(1);
     134                 :            :         return -EAFNOSUPPORT;
     135                 :            : #endif
     136                 :            : }
     137                 :            : 
     138                 :            : /* Add encapsulation header.
     139                 :            :  *
     140                 :            :  * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
     141                 :            :  */
     142                 :          0 : static int xfrm4_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb)
     143                 :            : {
     144                 :          0 :         struct ip_beet_phdr *ph;
     145                 :          0 :         struct iphdr *top_iph;
     146                 :          0 :         int hdrlen, optlen;
     147                 :            : 
     148                 :          0 :         hdrlen = 0;
     149                 :          0 :         optlen = XFRM_MODE_SKB_CB(skb)->optlen;
     150         [ #  # ]:          0 :         if (unlikely(optlen))
     151                 :          0 :                 hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
     152                 :            : 
     153                 :          0 :         skb_set_network_header(skb, -x->props.header_len - hdrlen +
     154         [ #  # ]:          0 :                                (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph)));
     155         [ #  # ]:          0 :         if (x->sel.family != AF_INET6)
     156                 :          0 :                 skb->network_header += IPV4_BEET_PHMAXLEN;
     157                 :          0 :         skb->mac_header = skb->network_header +
     158                 :            :                           offsetof(struct iphdr, protocol);
     159                 :          0 :         skb->transport_header = skb->network_header + sizeof(*top_iph);
     160                 :            : 
     161         [ #  # ]:          0 :         xfrm4_beet_make_header(skb);
     162                 :            : 
     163         [ #  # ]:          0 :         ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen);
     164                 :            : 
     165         [ #  # ]:          0 :         top_iph = ip_hdr(skb);
     166                 :            : 
     167         [ #  # ]:          0 :         if (unlikely(optlen)) {
     168                 :          0 :                 if (WARN_ON(optlen < 0))
     169                 :            :                         return -EINVAL;
     170                 :            : 
     171                 :          0 :                 ph->padlen = 4 - (optlen & 4);
     172                 :          0 :                 ph->hdrlen = optlen / 8;
     173                 :          0 :                 ph->nexthdr = top_iph->protocol;
     174         [ #  # ]:          0 :                 if (ph->padlen)
     175                 :          0 :                         memset(ph + 1, IPOPT_NOP, ph->padlen);
     176                 :            : 
     177                 :          0 :                 top_iph->protocol = IPPROTO_BEETPH;
     178                 :          0 :                 top_iph->ihl = sizeof(struct iphdr) / 4;
     179                 :            :         }
     180                 :            : 
     181                 :          0 :         top_iph->saddr = x->props.saddr.a4;
     182                 :          0 :         top_iph->daddr = x->id.daddr.a4;
     183                 :            : 
     184                 :          0 :         return 0;
     185                 :            : }
     186                 :            : 
     187                 :            : /* Add encapsulation header.
     188                 :            :  *
     189                 :            :  * The top IP header will be constructed per RFC 2401.
     190                 :            :  */
     191                 :          0 : static int xfrm4_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb)
     192                 :            : {
     193      [ #  #  # ]:          0 :         struct dst_entry *dst = skb_dst(skb);
     194                 :          0 :         struct iphdr *top_iph;
     195                 :          0 :         int flags;
     196                 :            : 
     197      [ #  #  # ]:          0 :         skb_set_inner_network_header(skb, skb_network_offset(skb));
     198      [ #  #  # ]:          0 :         skb_set_inner_transport_header(skb, skb_transport_offset(skb));
     199                 :            : 
     200      [ #  #  # ]:          0 :         skb_set_network_header(skb, -x->props.header_len);
     201                 :          0 :         skb->mac_header = skb->network_header +
     202                 :            :                           offsetof(struct iphdr, protocol);
     203                 :          0 :         skb->transport_header = skb->network_header + sizeof(*top_iph);
     204      [ #  #  # ]:          0 :         top_iph = ip_hdr(skb);
     205                 :            : 
     206                 :          0 :         top_iph->ihl = 5;
     207                 :          0 :         top_iph->version = 4;
     208                 :            : 
     209      [ #  #  # ]:          0 :         top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family);
     210                 :            : 
     211                 :            :         /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */
     212         [ #  # ]:          0 :         if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
     213                 :          0 :                 top_iph->tos = 0;
     214                 :            :         else
     215                 :          0 :                 top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
     216                 :          0 :         top_iph->tos = INET_ECN_encapsulate(top_iph->tos,
     217         [ #  # ]:          0 :                                             XFRM_MODE_SKB_CB(skb)->tos);
     218                 :            : 
     219                 :          0 :         flags = x->props.flags;
     220         [ #  # ]:          0 :         if (flags & XFRM_STATE_NOECN)
     221                 :          0 :                 IP_ECN_clear(top_iph);
     222                 :            : 
     223         [ #  # ]:          0 :         top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
     224                 :          0 :                 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF));
     225                 :            : 
     226         [ #  # ]:          0 :         top_iph->ttl = ip4_dst_hoplimit(xfrm_dst_child(dst));
     227                 :            : 
     228                 :          0 :         top_iph->saddr = x->props.saddr.a4;
     229                 :          0 :         top_iph->daddr = x->id.daddr.a4;
     230                 :          0 :         ip_select_ident(dev_net(dst->dev), skb, NULL);
     231                 :            : 
     232                 :          0 :         return 0;
     233                 :            : }
     234                 :            : 
     235                 :            : #if IS_ENABLED(CONFIG_IPV6)
     236                 :          0 : static int xfrm6_tunnel_encap_add(struct xfrm_state *x, struct sk_buff *skb)
     237                 :            : {
     238      [ #  #  # ]:          0 :         struct dst_entry *dst = skb_dst(skb);
     239                 :          0 :         struct ipv6hdr *top_iph;
     240                 :          0 :         int dsfield;
     241                 :            : 
     242      [ #  #  # ]:          0 :         skb_set_inner_network_header(skb, skb_network_offset(skb));
     243      [ #  #  # ]:          0 :         skb_set_inner_transport_header(skb, skb_transport_offset(skb));
     244                 :            : 
     245      [ #  #  # ]:          0 :         skb_set_network_header(skb, -x->props.header_len);
     246                 :          0 :         skb->mac_header = skb->network_header +
     247                 :            :                           offsetof(struct ipv6hdr, nexthdr);
     248                 :          0 :         skb->transport_header = skb->network_header + sizeof(*top_iph);
     249      [ #  #  # ]:          0 :         top_iph = ipv6_hdr(skb);
     250                 :            : 
     251                 :          0 :         top_iph->version = 6;
     252                 :            : 
     253                 :          0 :         memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl,
     254                 :            :                sizeof(top_iph->flow_lbl));
     255      [ #  #  # ]:          0 :         top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family);
     256                 :            : 
     257         [ #  # ]:          0 :         if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
     258                 :            :                 dsfield = 0;
     259                 :            :         else
     260                 :          0 :                 dsfield = XFRM_MODE_SKB_CB(skb)->tos;
     261         [ #  # ]:          0 :         dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos);
     262         [ #  # ]:          0 :         if (x->props.flags & XFRM_STATE_NOECN)
     263                 :          0 :                 dsfield &= ~INET_ECN_MASK;
     264         [ #  # ]:          0 :         ipv6_change_dsfield(top_iph, 0, dsfield);
     265         [ #  # ]:          0 :         top_iph->hop_limit = ip6_dst_hoplimit(xfrm_dst_child(dst));
     266                 :          0 :         top_iph->saddr = *(struct in6_addr *)&x->props.saddr;
     267                 :          0 :         top_iph->daddr = *(struct in6_addr *)&x->id.daddr;
     268                 :          0 :         return 0;
     269                 :            : }
     270                 :            : 
     271                 :          0 : static int xfrm6_beet_encap_add(struct xfrm_state *x, struct sk_buff *skb)
     272                 :            : {
     273                 :          0 :         struct ipv6hdr *top_iph;
     274                 :          0 :         struct ip_beet_phdr *ph;
     275                 :          0 :         int optlen, hdr_len;
     276                 :            : 
     277                 :          0 :         hdr_len = 0;
     278                 :          0 :         optlen = XFRM_MODE_SKB_CB(skb)->optlen;
     279         [ #  # ]:          0 :         if (unlikely(optlen))
     280                 :          0 :                 hdr_len += IPV4_BEET_PHMAXLEN - (optlen & 4);
     281                 :            : 
     282         [ #  # ]:          0 :         skb_set_network_header(skb, -x->props.header_len - hdr_len);
     283         [ #  # ]:          0 :         if (x->sel.family != AF_INET6)
     284                 :          0 :                 skb->network_header += IPV4_BEET_PHMAXLEN;
     285                 :          0 :         skb->mac_header = skb->network_header +
     286                 :            :                           offsetof(struct ipv6hdr, nexthdr);
     287                 :          0 :         skb->transport_header = skb->network_header + sizeof(*top_iph);
     288         [ #  # ]:          0 :         ph = __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdr_len);
     289                 :            : 
     290                 :          0 :         xfrm6_beet_make_header(skb);
     291                 :            : 
     292         [ #  # ]:          0 :         top_iph = ipv6_hdr(skb);
     293         [ #  # ]:          0 :         if (unlikely(optlen)) {
     294                 :          0 :                 if (WARN_ON(optlen < 0))
     295                 :            :                         return -EINVAL;
     296                 :            : 
     297                 :          0 :                 ph->padlen = 4 - (optlen & 4);
     298                 :          0 :                 ph->hdrlen = optlen / 8;
     299                 :          0 :                 ph->nexthdr = top_iph->nexthdr;
     300         [ #  # ]:          0 :                 if (ph->padlen)
     301                 :          0 :                         memset(ph + 1, IPOPT_NOP, ph->padlen);
     302                 :            : 
     303                 :          0 :                 top_iph->nexthdr = IPPROTO_BEETPH;
     304                 :            :         }
     305                 :            : 
     306                 :          0 :         top_iph->saddr = *(struct in6_addr *)&x->props.saddr;
     307                 :          0 :         top_iph->daddr = *(struct in6_addr *)&x->id.daddr;
     308                 :          0 :         return 0;
     309                 :            : }
     310                 :            : #endif
     311                 :            : 
     312                 :            : /* Add encapsulation header.
     313                 :            :  *
     314                 :            :  * On exit, the transport header will be set to the start of the
     315                 :            :  * encapsulation header to be filled in by x->type->output and the mac
     316                 :            :  * header will be set to the nextheader (protocol for IPv4) field of the
     317                 :            :  * extension header directly preceding the encapsulation header, or in
     318                 :            :  * its absence, that of the top IP header.
     319                 :            :  * The value of the network header will always point to the top IP header
     320                 :            :  * while skb->data will point to the payload.
     321                 :            :  */
     322                 :          0 : static int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
     323                 :            : {
     324                 :          0 :         int err;
     325                 :            : 
     326                 :          0 :         err = xfrm_inner_extract_output(x, skb);
     327         [ #  # ]:          0 :         if (err)
     328                 :            :                 return err;
     329                 :            : 
     330                 :          0 :         IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
     331                 :          0 :         skb->protocol = htons(ETH_P_IP);
     332                 :            : 
     333      [ #  #  # ]:          0 :         switch (x->outer_mode.encap) {
     334                 :          0 :         case XFRM_MODE_BEET:
     335                 :          0 :                 return xfrm4_beet_encap_add(x, skb);
     336                 :          0 :         case XFRM_MODE_TUNNEL:
     337                 :          0 :                 return xfrm4_tunnel_encap_add(x, skb);
     338                 :            :         }
     339                 :            : 
     340                 :          0 :         WARN_ON_ONCE(1);
     341                 :          0 :         return -EOPNOTSUPP;
     342                 :            : }
     343                 :            : 
     344                 :          0 : static int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
     345                 :            : {
     346                 :            : #if IS_ENABLED(CONFIG_IPV6)
     347                 :          0 :         int err;
     348                 :            : 
     349                 :          0 :         err = xfrm_inner_extract_output(x, skb);
     350         [ #  # ]:          0 :         if (err)
     351                 :            :                 return err;
     352                 :            : 
     353                 :          0 :         skb->ignore_df = 1;
     354                 :          0 :         skb->protocol = htons(ETH_P_IPV6);
     355                 :            : 
     356      [ #  #  # ]:          0 :         switch (x->outer_mode.encap) {
     357                 :          0 :         case XFRM_MODE_BEET:
     358                 :          0 :                 return xfrm6_beet_encap_add(x, skb);
     359                 :          0 :         case XFRM_MODE_TUNNEL:
     360                 :          0 :                 return xfrm6_tunnel_encap_add(x, skb);
     361                 :            :         default:
     362                 :          0 :                 WARN_ON_ONCE(1);
     363                 :          0 :                 return -EOPNOTSUPP;
     364                 :            :         }
     365                 :            : #endif
     366                 :            :         WARN_ON_ONCE(1);
     367                 :            :         return -EAFNOSUPPORT;
     368                 :            : }
     369                 :            : 
     370                 :          0 : static int xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb)
     371                 :            : {
     372   [ #  #  #  # ]:          0 :         switch (x->outer_mode.encap) {
     373                 :          0 :         case XFRM_MODE_BEET:
     374                 :            :         case XFRM_MODE_TUNNEL:
     375         [ #  # ]:          0 :                 if (x->outer_mode.family == AF_INET)
     376                 :          0 :                         return xfrm4_prepare_output(x, skb);
     377         [ #  # ]:          0 :                 if (x->outer_mode.family == AF_INET6)
     378                 :          0 :                         return xfrm6_prepare_output(x, skb);
     379                 :            :                 break;
     380                 :          0 :         case XFRM_MODE_TRANSPORT:
     381         [ #  # ]:          0 :                 if (x->outer_mode.family == AF_INET)
     382                 :          0 :                         return xfrm4_transport_output(x, skb);
     383         [ #  # ]:          0 :                 if (x->outer_mode.family == AF_INET6)
     384                 :          0 :                         return xfrm6_transport_output(x, skb);
     385                 :            :                 break;
     386                 :          0 :         case XFRM_MODE_ROUTEOPTIMIZATION:
     387         [ #  # ]:          0 :                 if (x->outer_mode.family == AF_INET6)
     388                 :          0 :                         return xfrm6_ro_output(x, skb);
     389                 :          0 :                 WARN_ON_ONCE(1);
     390                 :          0 :                 break;
     391                 :            :         default:
     392                 :          0 :                 WARN_ON_ONCE(1);
     393                 :          0 :                 break;
     394                 :            :         }
     395                 :            : 
     396                 :            :         return -EOPNOTSUPP;
     397                 :            : }
     398                 :            : 
     399                 :            : #if IS_ENABLED(CONFIG_NET_PKTGEN)
     400                 :            : int pktgen_xfrm_outer_mode_output(struct xfrm_state *x, struct sk_buff *skb)
     401                 :            : {
     402                 :            :         return xfrm_outer_mode_output(x, skb);
     403                 :            : }
     404                 :            : EXPORT_SYMBOL_GPL(pktgen_xfrm_outer_mode_output);
     405                 :            : #endif
     406                 :            : 
     407                 :          0 : static int xfrm_output_one(struct sk_buff *skb, int err)
     408                 :            : {
     409         [ #  # ]:          0 :         struct dst_entry *dst = skb_dst(skb);
     410                 :          0 :         struct xfrm_state *x = dst->xfrm;
     411         [ #  # ]:          0 :         struct net *net = xs_net(x);
     412                 :            : 
     413         [ #  # ]:          0 :         if (err <= 0)
     414                 :          0 :                 goto resume;
     415                 :            : 
     416                 :          0 :         do {
     417                 :          0 :                 err = xfrm_skb_check_space(skb);
     418         [ #  # ]:          0 :                 if (err) {
     419                 :          0 :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
     420                 :          0 :                         goto error_nolock;
     421                 :            :                 }
     422                 :            : 
     423                 :          0 :                 skb->mark = xfrm_smark_get(skb->mark, x);
     424                 :            : 
     425                 :          0 :                 err = xfrm_outer_mode_output(x, skb);
     426         [ #  # ]:          0 :                 if (err) {
     427                 :          0 :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
     428                 :          0 :                         goto error_nolock;
     429                 :            :                 }
     430                 :            : 
     431                 :          0 :                 spin_lock_bh(&x->lock);
     432                 :            : 
     433         [ #  # ]:          0 :                 if (unlikely(x->km.state != XFRM_STATE_VALID)) {
     434                 :          0 :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEINVALID);
     435                 :          0 :                         err = -EINVAL;
     436                 :          0 :                         goto error;
     437                 :            :                 }
     438                 :            : 
     439                 :          0 :                 err = xfrm_state_check_expire(x);
     440         [ #  # ]:          0 :                 if (err) {
     441                 :          0 :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEEXPIRED);
     442                 :          0 :                         goto error;
     443                 :            :                 }
     444                 :            : 
     445                 :          0 :                 err = x->repl->overflow(x, skb);
     446         [ #  # ]:          0 :                 if (err) {
     447                 :          0 :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATESEQERROR);
     448                 :          0 :                         goto error;
     449                 :            :                 }
     450                 :            : 
     451                 :          0 :                 x->curlft.bytes += skb->len;
     452                 :          0 :                 x->curlft.packets++;
     453                 :            : 
     454                 :          0 :                 spin_unlock_bh(&x->lock);
     455                 :            : 
     456                 :          0 :                 skb_dst_force(skb);
     457         [ #  # ]:          0 :                 if (!skb_dst(skb)) {
     458                 :          0 :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
     459                 :          0 :                         err = -EHOSTUNREACH;
     460                 :          0 :                         goto error_nolock;
     461                 :            :                 }
     462                 :            : 
     463   [ #  #  #  # ]:          0 :                 if (xfrm_offload(skb)) {
     464                 :          0 :                         x->type_offload->encap(x, skb);
     465                 :            :                 } else {
     466                 :            :                         /* Inner headers are invalid now. */
     467                 :          0 :                         skb->encapsulation = 0;
     468                 :            : 
     469                 :          0 :                         err = x->type->output(x, skb);
     470         [ #  # ]:          0 :                         if (err == -EINPROGRESS)
     471                 :          0 :                                 goto out;
     472                 :            :                 }
     473                 :            : 
     474                 :          0 : resume:
     475         [ #  # ]:          0 :                 if (err) {
     476                 :          0 :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
     477                 :          0 :                         goto error_nolock;
     478                 :            :                 }
     479                 :            : 
     480                 :          0 :                 dst = skb_dst_pop(skb);
     481         [ #  # ]:          0 :                 if (!dst) {
     482                 :          0 :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
     483                 :          0 :                         err = -EHOSTUNREACH;
     484                 :          0 :                         goto error_nolock;
     485                 :            :                 }
     486         [ #  # ]:          0 :                 skb_dst_set(skb, dst);
     487                 :          0 :                 x = dst->xfrm;
     488   [ #  #  #  # ]:          0 :         } while (x && !(x->outer_mode.flags & XFRM_MODE_FLAG_TUNNEL));
     489                 :            : 
     490                 :            :         return 0;
     491                 :            : 
     492                 :          0 : error:
     493                 :          0 :         spin_unlock_bh(&x->lock);
     494                 :          0 : error_nolock:
     495                 :          0 :         kfree_skb(skb);
     496                 :            : out:
     497                 :            :         return err;
     498                 :            : }
     499                 :            : 
     500                 :          0 : int xfrm_output_resume(struct sk_buff *skb, int err)
     501                 :            : {
     502                 :          0 :         struct net *net = xs_net(skb_dst(skb)->xfrm);
     503                 :            : 
     504         [ #  # ]:          0 :         while (likely((err = xfrm_output_one(skb, err)) == 0)) {
     505                 :          0 :                 nf_reset_ct(skb);
     506                 :            : 
     507                 :          0 :                 err = skb_dst(skb)->ops->local_out(net, skb->sk, skb);
     508         [ #  # ]:          0 :                 if (unlikely(err != 1))
     509                 :          0 :                         goto out;
     510                 :            : 
     511         [ #  # ]:          0 :                 if (!skb_dst(skb)->xfrm)
     512                 :          0 :                         return dst_output(net, skb->sk, skb);
     513                 :            : 
     514                 :          0 :                 err = nf_hook(skb_dst(skb)->ops->family,
     515                 :            :                               NF_INET_POST_ROUTING, net, skb->sk, skb,
     516                 :            :                               NULL, skb_dst(skb)->dev, xfrm_output2);
     517         [ #  # ]:          0 :                 if (unlikely(err != 1))
     518                 :          0 :                         goto out;
     519                 :            :         }
     520                 :            : 
     521         [ #  # ]:          0 :         if (err == -EINPROGRESS)
     522                 :          0 :                 err = 0;
     523                 :            : 
     524                 :          0 : out:
     525                 :            :         return err;
     526                 :            : }
     527                 :            : EXPORT_SYMBOL_GPL(xfrm_output_resume);
     528                 :            : 
     529                 :          0 : static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
     530                 :            : {
     531                 :          0 :         return xfrm_output_resume(skb, 1);
     532                 :            : }
     533                 :            : 
     534                 :            : static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb)
     535                 :            : {
     536                 :            :         struct sk_buff *segs, *nskb;
     537                 :            : 
     538                 :            :         BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET);
     539                 :            :         BUILD_BUG_ON(sizeof(*IP6CB(skb)) > SKB_SGO_CB_OFFSET);
     540                 :            :         segs = skb_gso_segment(skb, 0);
     541                 :            :         kfree_skb(skb);
     542                 :            :         if (IS_ERR(segs))
     543                 :            :                 return PTR_ERR(segs);
     544                 :            :         if (segs == NULL)
     545                 :            :                 return -EINVAL;
     546                 :            : 
     547                 :            :         skb_list_walk_safe(segs, segs, nskb) {
     548                 :            :                 int err;
     549                 :            : 
     550                 :            :                 skb_mark_not_on_list(segs);
     551                 :            :                 err = xfrm_output2(net, sk, segs);
     552                 :            : 
     553                 :            :                 if (unlikely(err)) {
     554                 :            :                         kfree_skb_list(nskb);
     555                 :            :                         return err;
     556                 :            :                 }
     557                 :            :         }
     558                 :            : 
     559                 :            :         return 0;
     560                 :            : }
     561                 :            : 
     562                 :          0 : int xfrm_output(struct sock *sk, struct sk_buff *skb)
     563                 :            : {
     564         [ #  # ]:          0 :         struct net *net = dev_net(skb_dst(skb)->dev);
     565                 :          0 :         struct xfrm_state *x = skb_dst(skb)->xfrm;
     566                 :          0 :         int err;
     567                 :            : 
     568         [ #  # ]:          0 :         secpath_reset(skb);
     569                 :            : 
     570         [ #  # ]:          0 :         if (xfrm_dev_offload_ok(skb, x)) {
     571                 :            :                 struct sec_path *sp;
     572                 :            : 
     573                 :            :                 sp = secpath_set(skb);
     574                 :            :                 if (!sp) {
     575                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
     576                 :            :                         kfree_skb(skb);
     577                 :            :                         return -ENOMEM;
     578                 :            :                 }
     579                 :            :                 skb->encapsulation = 1;
     580                 :            : 
     581                 :            :                 sp->olen++;
     582                 :            :                 sp->xvec[sp->len++] = x;
     583                 :            :                 xfrm_state_hold(x);
     584                 :            : 
     585                 :            :                 if (skb_is_gso(skb)) {
     586                 :            :                         skb_shinfo(skb)->gso_type |= SKB_GSO_ESP;
     587                 :            : 
     588                 :            :                         return xfrm_output2(net, sk, skb);
     589                 :            :                 }
     590                 :            : 
     591                 :            :                 if (x->xso.dev && x->xso.dev->features & NETIF_F_HW_ESP_TX_CSUM)
     592                 :            :                         goto out;
     593                 :            :         }
     594                 :            : 
     595         [ #  # ]:          0 :         if (skb_is_gso(skb))
     596                 :          0 :                 return xfrm_output_gso(net, sk, skb);
     597                 :            : 
     598         [ #  # ]:          0 :         if (skb->ip_summed == CHECKSUM_PARTIAL) {
     599                 :          0 :                 err = skb_checksum_help(skb);
     600         [ #  # ]:          0 :                 if (err) {
     601                 :          0 :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
     602                 :          0 :                         kfree_skb(skb);
     603                 :          0 :                         return err;
     604                 :            :                 }
     605                 :            :         }
     606                 :            : 
     607                 :          0 : out:
     608                 :          0 :         return xfrm_output2(net, sk, skb);
     609                 :            : }
     610                 :            : EXPORT_SYMBOL_GPL(xfrm_output);
     611                 :            : 
     612                 :          0 : static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
     613                 :            : {
     614                 :          0 :         const struct xfrm_state_afinfo *afinfo;
     615                 :          0 :         const struct xfrm_mode *inner_mode;
     616                 :          0 :         int err = -EAFNOSUPPORT;
     617                 :            : 
     618         [ #  # ]:          0 :         if (x->sel.family == AF_UNSPEC)
     619                 :          0 :                 inner_mode = xfrm_ip2inner_mode(x,
     620      [ #  #  # ]:          0 :                                 xfrm_af2proto(skb_dst(skb)->ops->family));
     621                 :            :         else
     622                 :          0 :                 inner_mode = &x->inner_mode;
     623                 :            : 
     624         [ #  # ]:          0 :         if (inner_mode == NULL)
     625                 :            :                 return -EAFNOSUPPORT;
     626                 :            : 
     627                 :          0 :         rcu_read_lock();
     628                 :          0 :         afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
     629         [ #  # ]:          0 :         if (likely(afinfo))
     630                 :          0 :                 err = afinfo->extract_output(x, skb);
     631                 :          0 :         rcu_read_unlock();
     632                 :            : 
     633                 :          0 :         return err;
     634                 :            : }
     635                 :            : 
     636                 :          0 : void xfrm_local_error(struct sk_buff *skb, int mtu)
     637                 :            : {
     638                 :          0 :         unsigned int proto;
     639                 :          0 :         struct xfrm_state_afinfo *afinfo;
     640                 :            : 
     641         [ #  # ]:          0 :         if (skb->protocol == htons(ETH_P_IP))
     642                 :            :                 proto = AF_INET;
     643         [ #  # ]:          0 :         else if (skb->protocol == htons(ETH_P_IPV6))
     644                 :            :                 proto = AF_INET6;
     645                 :            :         else
     646                 :            :                 return;
     647                 :            : 
     648                 :          0 :         afinfo = xfrm_state_get_afinfo(proto);
     649         [ #  # ]:          0 :         if (afinfo) {
     650                 :          0 :                 afinfo->local_error(skb, mtu);
     651                 :          0 :                 rcu_read_unlock();
     652                 :            :         }
     653                 :            : }
     654                 :            : EXPORT_SYMBOL_GPL(xfrm_local_error);

Generated by: LCOV version 1.14