LCOV - code coverage report
Current view: top level - net/xfrm - xfrm_output.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 76 0.0 %
Date: 2014-04-07 Functions: 0 8 0.0 %
Branches: 0 62 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * xfrm_output.c - Common IPsec encapsulation code.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
       5                 :            :  *
       6                 :            :  * This program is free software; you can redistribute it and/or
       7                 :            :  * modify it under the terms of the GNU General Public License
       8                 :            :  * as published by the Free Software Foundation; either version
       9                 :            :  * 2 of the License, or (at your option) any later version.
      10                 :            :  */
      11                 :            : 
      12                 :            : #include <linux/errno.h>
      13                 :            : #include <linux/module.h>
      14                 :            : #include <linux/netdevice.h>
      15                 :            : #include <linux/netfilter.h>
      16                 :            : #include <linux/skbuff.h>
      17                 :            : #include <linux/slab.h>
      18                 :            : #include <linux/spinlock.h>
      19                 :            : #include <net/dst.h>
      20                 :            : #include <net/xfrm.h>
      21                 :            : 
      22                 :            : static int xfrm_output2(struct sk_buff *skb);
      23                 :            : 
      24                 :          0 : static int xfrm_skb_check_space(struct sk_buff *skb)
      25                 :            : {
      26                 :            :         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                 :          0 : static int xfrm_output_one(struct sk_buff *skb, int err)
      42                 :            : {
      43                 :            :         struct dst_entry *dst = skb_dst(skb);
      44                 :          0 :         struct xfrm_state *x = dst->xfrm;
      45                 :            :         struct net *net = xs_net(x);
      46                 :            : 
      47         [ #  # ]:          0 :         if (err <= 0)
      48                 :            :                 goto resume;
      49                 :            : 
      50                 :            :         do {
      51                 :          0 :                 err = xfrm_skb_check_space(skb);
      52         [ #  # ]:          0 :                 if (err) {
      53                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
      54                 :            :                         goto error_nolock;
      55                 :            :                 }
      56                 :            : 
      57                 :          0 :                 err = x->outer_mode->output(x, skb);
      58         [ #  # ]:          0 :                 if (err) {
      59                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
      60                 :            :                         goto error_nolock;
      61                 :            :                 }
      62                 :            : 
      63                 :            :                 spin_lock_bh(&x->lock);
      64                 :            : 
      65         [ #  # ]:          0 :                 if (unlikely(x->km.state != XFRM_STATE_VALID)) {
      66                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEINVALID);
      67                 :            :                         err = -EINVAL;
      68                 :            :                         goto error;
      69                 :            :                 }
      70                 :            : 
      71                 :          0 :                 err = xfrm_state_check_expire(x);
      72         [ #  # ]:          0 :                 if (err) {
      73                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEEXPIRED);
      74                 :            :                         goto error;
      75                 :            :                 }
      76                 :            : 
      77                 :          0 :                 err = x->repl->overflow(x, skb);
      78         [ #  # ]:          0 :                 if (err) {
      79                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATESEQERROR);
      80                 :            :                         goto error;
      81                 :            :                 }
      82                 :            : 
      83                 :          0 :                 x->curlft.bytes += skb->len;
      84                 :          0 :                 x->curlft.packets++;
      85                 :            : 
      86                 :            :                 spin_unlock_bh(&x->lock);
      87                 :            : 
      88                 :            :                 skb_dst_force(skb);
      89                 :            : 
      90                 :          0 :                 err = x->type->output(x, skb);
      91         [ #  # ]:          0 :                 if (err == -EINPROGRESS)
      92                 :            :                         goto out;
      93                 :            : 
      94                 :            : resume:
      95         [ #  # ]:          0 :                 if (err) {
      96                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
      97                 :            :                         goto error_nolock;
      98                 :            :                 }
      99                 :            : 
     100                 :            :                 dst = skb_dst_pop(skb);
     101         [ #  # ]:          0 :                 if (!dst) {
     102                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
     103                 :            :                         err = -EHOSTUNREACH;
     104                 :            :                         goto error_nolock;
     105                 :            :                 }
     106                 :            :                 skb_dst_set(skb, dst);
     107                 :          0 :                 x = dst->xfrm;
     108 [ #  # ][ #  # ]:          0 :         } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL));
     109                 :            : 
     110                 :            :         return 0;
     111                 :            : 
     112                 :            : error:
     113                 :            :         spin_unlock_bh(&x->lock);
     114                 :            : error_nolock:
     115                 :          0 :         kfree_skb(skb);
     116                 :            : out:
     117                 :          0 :         return err;
     118                 :            : }
     119                 :            : 
     120                 :          0 : int xfrm_output_resume(struct sk_buff *skb, int err)
     121                 :            : {
     122         [ #  # ]:          0 :         while (likely((err = xfrm_output_one(skb, err)) == 0)) {
     123                 :            :                 nf_reset(skb);
     124                 :            : 
     125                 :          0 :                 err = skb_dst(skb)->ops->local_out(skb);
     126         [ #  # ]:          0 :                 if (unlikely(err != 1))
     127                 :            :                         goto out;
     128                 :            : 
     129         [ #  # ]:          0 :                 if (!skb_dst(skb)->xfrm)
     130                 :          0 :                         return dst_output(skb);
     131                 :            : 
     132                 :          0 :                 err = nf_hook(skb_dst(skb)->ops->family,
     133                 :            :                               NF_INET_POST_ROUTING, skb,
     134                 :            :                               NULL, skb_dst(skb)->dev, xfrm_output2);
     135         [ #  # ]:          0 :                 if (unlikely(err != 1))
     136                 :            :                         goto out;
     137                 :            :         }
     138                 :            : 
     139         [ #  # ]:          0 :         if (err == -EINPROGRESS)
     140                 :            :                 err = 0;
     141                 :            : 
     142                 :            : out:
     143                 :          0 :         return err;
     144                 :            : }
     145                 :            : EXPORT_SYMBOL_GPL(xfrm_output_resume);
     146                 :            : 
     147                 :          0 : static int xfrm_output2(struct sk_buff *skb)
     148                 :            : {
     149                 :          0 :         return xfrm_output_resume(skb, 1);
     150                 :            : }
     151                 :            : 
     152                 :          0 : static int xfrm_output_gso(struct sk_buff *skb)
     153                 :            : {
     154                 :            :         struct sk_buff *segs;
     155                 :            : 
     156                 :            :         segs = skb_gso_segment(skb, 0);
     157                 :          0 :         kfree_skb(skb);
     158         [ #  # ]:          0 :         if (IS_ERR(segs))
     159                 :          0 :                 return PTR_ERR(segs);
     160                 :            : 
     161                 :            :         do {
     162                 :          0 :                 struct sk_buff *nskb = segs->next;
     163                 :            :                 int err;
     164                 :            : 
     165                 :          0 :                 segs->next = NULL;
     166                 :            :                 err = xfrm_output2(segs);
     167                 :            : 
     168         [ #  # ]:          0 :                 if (unlikely(err)) {
     169         [ #  # ]:          0 :                         while ((segs = nskb)) {
     170                 :          0 :                                 nskb = segs->next;
     171                 :          0 :                                 segs->next = NULL;
     172                 :          0 :                                 kfree_skb(segs);
     173                 :            :                         }
     174                 :            :                         return err;
     175                 :            :                 }
     176                 :            : 
     177                 :            :                 segs = nskb;
     178         [ #  # ]:          0 :         } while (segs);
     179                 :            : 
     180                 :            :         return 0;
     181                 :            : }
     182                 :            : 
     183                 :          0 : int xfrm_output(struct sk_buff *skb)
     184                 :            : {
     185                 :            :         struct net *net = dev_net(skb_dst(skb)->dev);
     186                 :            :         int err;
     187                 :            : 
     188         [ #  # ]:          0 :         if (skb_is_gso(skb))
     189                 :          0 :                 return xfrm_output_gso(skb);
     190                 :            : 
     191         [ #  # ]:          0 :         if (skb->ip_summed == CHECKSUM_PARTIAL) {
     192                 :          0 :                 err = skb_checksum_help(skb);
     193         [ #  # ]:          0 :                 if (err) {
     194                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
     195                 :          0 :                         kfree_skb(skb);
     196                 :          0 :                         return err;
     197                 :            :                 }
     198                 :            :         }
     199                 :            : 
     200                 :          0 :         return xfrm_output2(skb);
     201                 :            : }
     202                 :            : 
     203                 :          0 : int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
     204                 :            : {
     205                 :            :         struct xfrm_mode *inner_mode;
     206         [ #  # ]:          0 :         if (x->sel.family == AF_UNSPEC)
     207                 :            :                 inner_mode = xfrm_ip2inner_mode(x,
     208                 :          0 :                                 xfrm_af2proto(skb_dst(skb)->ops->family));
     209                 :            :         else
     210                 :          0 :                 inner_mode = x->inner_mode;
     211                 :            : 
     212         [ #  # ]:          0 :         if (inner_mode == NULL)
     213                 :            :                 return -EAFNOSUPPORT;
     214                 :          0 :         return inner_mode->afinfo->extract_output(x, skb);
     215                 :            : }
     216                 :            : 
     217                 :          0 : void xfrm_local_error(struct sk_buff *skb, int mtu)
     218                 :            : {
     219                 :            :         unsigned int proto;
     220                 :            :         struct xfrm_state_afinfo *afinfo;
     221                 :            : 
     222         [ #  # ]:          0 :         if (skb->protocol == htons(ETH_P_IP))
     223                 :            :                 proto = AF_INET;
     224         [ #  # ]:          0 :         else if (skb->protocol == htons(ETH_P_IPV6))
     225                 :            :                 proto = AF_INET6;
     226                 :            :         else
     227                 :            :                 return;
     228                 :            : 
     229                 :          0 :         afinfo = xfrm_state_get_afinfo(proto);
     230         [ #  # ]:          0 :         if (!afinfo)
     231                 :            :                 return;
     232                 :            : 
     233                 :          0 :         afinfo->local_error(skb, mtu);
     234                 :          0 :         xfrm_state_put_afinfo(afinfo);
     235                 :            : }
     236                 :            : 
     237                 :            : EXPORT_SYMBOL_GPL(xfrm_output);
     238                 :            : EXPORT_SYMBOL_GPL(xfrm_inner_extract_output);
     239                 :            : EXPORT_SYMBOL_GPL(xfrm_local_error);

Generated by: LCOV version 1.9