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

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * xfrm_input.c
       3                 :            :  *
       4                 :            :  * Changes:
       5                 :            :  *      YOSHIFUJI Hideaki @USAGI
       6                 :            :  *              Split up af-specific portion
       7                 :            :  *
       8                 :            :  */
       9                 :            : 
      10                 :            : #include <linux/slab.h>
      11                 :            : #include <linux/module.h>
      12                 :            : #include <linux/netdevice.h>
      13                 :            : #include <net/dst.h>
      14                 :            : #include <net/ip.h>
      15                 :            : #include <net/xfrm.h>
      16                 :            : 
      17                 :            : static struct kmem_cache *secpath_cachep __read_mostly;
      18                 :            : 
      19                 :          0 : void __secpath_destroy(struct sec_path *sp)
      20                 :            : {
      21                 :            :         int i;
      22         [ #  # ]:          0 :         for (i = 0; i < sp->len; i++)
      23                 :          0 :                 xfrm_state_put(sp->xvec[i]);
      24                 :          0 :         kmem_cache_free(secpath_cachep, sp);
      25                 :          0 : }
      26                 :            : EXPORT_SYMBOL(__secpath_destroy);
      27                 :            : 
      28                 :          0 : struct sec_path *secpath_dup(struct sec_path *src)
      29                 :            : {
      30                 :            :         struct sec_path *sp;
      31                 :            : 
      32                 :          0 :         sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC);
      33         [ #  # ]:          0 :         if (!sp)
      34                 :            :                 return NULL;
      35                 :            : 
      36                 :          0 :         sp->len = 0;
      37         [ #  # ]:          0 :         if (src) {
      38                 :            :                 int i;
      39                 :            : 
      40                 :          0 :                 memcpy(sp, src, sizeof(*sp));
      41         [ #  # ]:          0 :                 for (i = 0; i < sp->len; i++)
      42                 :          0 :                         xfrm_state_hold(sp->xvec[i]);
      43                 :            :         }
      44                 :          0 :         atomic_set(&sp->refcnt, 1);
      45                 :          0 :         return sp;
      46                 :            : }
      47                 :            : EXPORT_SYMBOL(secpath_dup);
      48                 :            : 
      49                 :            : /* Fetch spi and seq from ipsec header */
      50                 :            : 
      51                 :          0 : int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
      52                 :            : {
      53                 :            :         int offset, offset_seq;
      54                 :            :         int hlen;
      55                 :            : 
      56   [ #  #  #  # ]:          0 :         switch (nexthdr) {
      57                 :            :         case IPPROTO_AH:
      58                 :            :                 hlen = sizeof(struct ip_auth_hdr);
      59                 :            :                 offset = offsetof(struct ip_auth_hdr, spi);
      60                 :            :                 offset_seq = offsetof(struct ip_auth_hdr, seq_no);
      61                 :            :                 break;
      62                 :            :         case IPPROTO_ESP:
      63                 :            :                 hlen = sizeof(struct ip_esp_hdr);
      64                 :            :                 offset = offsetof(struct ip_esp_hdr, spi);
      65                 :            :                 offset_seq = offsetof(struct ip_esp_hdr, seq_no);
      66                 :          0 :                 break;
      67                 :            :         case IPPROTO_COMP:
      68         [ #  # ]:          0 :                 if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
      69                 :            :                         return -EINVAL;
      70                 :          0 :                 *spi = htonl(ntohs(*(__be16*)(skb_transport_header(skb) + 2)));
      71                 :          0 :                 *seq = 0;
      72                 :          0 :                 return 0;
      73                 :            :         default:
      74                 :            :                 return 1;
      75                 :            :         }
      76                 :            : 
      77         [ #  # ]:          0 :         if (!pskb_may_pull(skb, hlen))
      78                 :            :                 return -EINVAL;
      79                 :            : 
      80                 :          0 :         *spi = *(__be32*)(skb_transport_header(skb) + offset);
      81                 :          0 :         *seq = *(__be32*)(skb_transport_header(skb) + offset_seq);
      82                 :          0 :         return 0;
      83                 :            : }
      84                 :            : 
      85                 :          0 : int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
      86                 :            : {
      87                 :          0 :         struct xfrm_mode *inner_mode = x->inner_mode;
      88                 :            :         int err;
      89                 :            : 
      90                 :          0 :         err = x->outer_mode->afinfo->extract_input(x, skb);
      91         [ #  # ]:          0 :         if (err)
      92                 :            :                 return err;
      93                 :            : 
      94         [ #  # ]:          0 :         if (x->sel.family == AF_UNSPEC) {
      95                 :          0 :                 inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
      96         [ #  # ]:          0 :                 if (inner_mode == NULL)
      97                 :            :                         return -EAFNOSUPPORT;
      98                 :            :         }
      99                 :            : 
     100                 :          0 :         skb->protocol = inner_mode->afinfo->eth_proto;
     101                 :          0 :         return inner_mode->input2(x, skb);
     102                 :            : }
     103                 :            : EXPORT_SYMBOL(xfrm_prepare_input);
     104                 :            : 
     105                 :          0 : int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
     106                 :            : {
     107                 :            :         struct net *net = dev_net(skb->dev);
     108                 :            :         int err;
     109                 :            :         __be32 seq;
     110                 :            :         __be32 seq_hi;
     111                 :            :         struct xfrm_state *x;
     112                 :            :         xfrm_address_t *daddr;
     113                 :            :         struct xfrm_mode *inner_mode;
     114                 :            :         unsigned int family;
     115                 :            :         int decaps = 0;
     116                 :            :         int async = 0;
     117                 :            : 
     118                 :            :         /* A negative encap_type indicates async resumption. */
     119         [ #  # ]:          0 :         if (encap_type < 0) {
     120                 :            :                 async = 1;
     121                 :            :                 x = xfrm_input_state(skb);
     122                 :          0 :                 seq = XFRM_SKB_CB(skb)->seq.input.low;
     123                 :          0 :                 goto resume;
     124                 :            :         }
     125                 :            : 
     126                 :            :         /* Allocate new secpath or COW existing one. */
     127 [ #  # ][ #  # ]:          0 :         if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
     128                 :            :                 struct sec_path *sp;
     129                 :            : 
     130                 :          0 :                 sp = secpath_dup(skb->sp);
     131         [ #  # ]:          0 :                 if (!sp) {
     132                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
     133                 :            :                         goto drop;
     134                 :            :                 }
     135         [ #  # ]:          0 :                 if (skb->sp)
     136                 :            :                         secpath_put(skb->sp);
     137                 :          0 :                 skb->sp = sp;
     138                 :            :         }
     139                 :            : 
     140                 :          0 :         daddr = (xfrm_address_t *)(skb_network_header(skb) +
     141                 :            :                                    XFRM_SPI_SKB_CB(skb)->daddroff);
     142                 :          0 :         family = XFRM_SPI_SKB_CB(skb)->family;
     143                 :            : 
     144                 :          0 :         seq = 0;
     145 [ #  # ][ #  # ]:          0 :         if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
     146                 :            :                 XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
     147                 :            :                 goto drop;
     148                 :            :         }
     149                 :            : 
     150                 :            :         do {
     151         [ #  # ]:          0 :                 if (skb->sp->len == XFRM_MAX_DEPTH) {
     152                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
     153                 :            :                         goto drop;
     154                 :            :                 }
     155                 :            : 
     156                 :          0 :                 x = xfrm_state_lookup(net, skb->mark, daddr, spi, nexthdr, family);
     157         [ #  # ]:          0 :                 if (x == NULL) {
     158                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
     159                 :          0 :                         xfrm_audit_state_notfound(skb, family, spi, seq);
     160                 :          0 :                         goto drop;
     161                 :            :                 }
     162                 :            : 
     163                 :          0 :                 skb->sp->xvec[skb->sp->len++] = x;
     164                 :            : 
     165                 :            :                 spin_lock(&x->lock);
     166         [ #  # ]:          0 :                 if (unlikely(x->km.state == XFRM_STATE_ACQ)) {
     167                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
     168                 :            :                         goto drop_unlock;
     169                 :            :                 }
     170                 :            : 
     171         [ #  # ]:          0 :                 if (unlikely(x->km.state != XFRM_STATE_VALID)) {
     172                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEINVALID);
     173                 :            :                         goto drop_unlock;
     174                 :            :                 }
     175                 :            : 
     176 [ #  # ][ #  # ]:          0 :                 if ((x->encap ? x->encap->encap_type : 0) != encap_type) {
     177                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
     178                 :            :                         goto drop_unlock;
     179                 :            :                 }
     180                 :            : 
     181         [ #  # ]:          0 :                 if (x->repl->check(x, skb, seq)) {
     182                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
     183                 :            :                         goto drop_unlock;
     184                 :            :                 }
     185                 :            : 
     186         [ #  # ]:          0 :                 if (xfrm_state_check_expire(x)) {
     187                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED);
     188                 :            :                         goto drop_unlock;
     189                 :            :                 }
     190                 :            : 
     191                 :            :                 spin_unlock(&x->lock);
     192                 :            : 
     193                 :          0 :                 seq_hi = htonl(xfrm_replay_seqhi(x, seq));
     194                 :            : 
     195                 :          0 :                 XFRM_SKB_CB(skb)->seq.input.low = seq;
     196                 :          0 :                 XFRM_SKB_CB(skb)->seq.input.hi = seq_hi;
     197                 :            : 
     198                 :            :                 skb_dst_force(skb);
     199                 :            : 
     200                 :          0 :                 nexthdr = x->type->input(x, skb);
     201                 :            : 
     202         [ #  # ]:          0 :                 if (nexthdr == -EINPROGRESS)
     203                 :            :                         return 0;
     204                 :            : 
     205                 :            : resume:
     206                 :            :                 spin_lock(&x->lock);
     207         [ #  # ]:          0 :                 if (nexthdr <= 0) {
     208         [ #  # ]:          0 :                         if (nexthdr == -EBADMSG) {
     209                 :          0 :                                 xfrm_audit_state_icvfail(x, skb,
     210                 :          0 :                                                          x->type->proto);
     211                 :          0 :                                 x->stats.integrity_failed++;
     212                 :            :                         }
     213                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
     214                 :            :                         goto drop_unlock;
     215                 :            :                 }
     216                 :            : 
     217                 :            :                 /* only the first xfrm gets the encap type */
     218                 :            :                 encap_type = 0;
     219                 :            : 
     220 [ #  # ][ #  # ]:          0 :                 if (async && x->repl->recheck(x, skb, seq)) {
     221                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
     222                 :            :                         goto drop_unlock;
     223                 :            :                 }
     224                 :            : 
     225                 :          0 :                 x->repl->advance(x, seq);
     226                 :            : 
     227                 :          0 :                 x->curlft.bytes += skb->len;
     228                 :          0 :                 x->curlft.packets++;
     229                 :            : 
     230                 :            :                 spin_unlock(&x->lock);
     231                 :            : 
     232                 :          0 :                 XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
     233                 :            : 
     234                 :          0 :                 inner_mode = x->inner_mode;
     235                 :            : 
     236         [ #  # ]:          0 :                 if (x->sel.family == AF_UNSPEC) {
     237                 :          0 :                         inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
     238         [ #  # ]:          0 :                         if (inner_mode == NULL)
     239                 :            :                                 goto drop;
     240                 :            :                 }
     241                 :            : 
     242         [ #  # ]:          0 :                 if (inner_mode->input(x, skb)) {
     243                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
     244                 :            :                         goto drop;
     245                 :            :                 }
     246                 :            : 
     247         [ #  # ]:          0 :                 if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
     248                 :            :                         decaps = 1;
     249                 :            :                         break;
     250                 :            :                 }
     251                 :            : 
     252                 :            :                 /*
     253                 :            :                  * We need the inner address.  However, we only get here for
     254                 :            :                  * transport mode so the outer address is identical.
     255                 :            :                  */
     256                 :          0 :                 daddr = &x->id.daddr;
     257                 :          0 :                 family = x->outer_mode->afinfo->family;
     258                 :            : 
     259                 :          0 :                 err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
     260         [ #  # ]:          0 :                 if (err < 0) {
     261                 :            :                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
     262                 :            :                         goto drop;
     263                 :            :                 }
     264         [ #  # ]:          0 :         } while (!err);
     265                 :            : 
     266                 :            :         nf_reset(skb);
     267                 :            : 
     268         [ #  # ]:          0 :         if (decaps) {
     269                 :            :                 skb_dst_drop(skb);
     270                 :          0 :                 netif_rx(skb);
     271                 :          0 :                 return 0;
     272                 :            :         } else {
     273                 :          0 :                 return x->inner_mode->afinfo->transport_finish(skb, async);
     274                 :            :         }
     275                 :            : 
     276                 :            : drop_unlock:
     277                 :            :         spin_unlock(&x->lock);
     278                 :            : drop:
     279                 :          0 :         kfree_skb(skb);
     280                 :          0 :         return 0;
     281                 :            : }
     282                 :            : EXPORT_SYMBOL(xfrm_input);
     283                 :            : 
     284                 :          0 : int xfrm_input_resume(struct sk_buff *skb, int nexthdr)
     285                 :            : {
     286                 :          0 :         return xfrm_input(skb, nexthdr, 0, -1);
     287                 :            : }
     288                 :            : EXPORT_SYMBOL(xfrm_input_resume);
     289                 :            : 
     290                 :          0 : void __init xfrm_input_init(void)
     291                 :            : {
     292                 :          0 :         secpath_cachep = kmem_cache_create("secpath_cache",
     293                 :            :                                            sizeof(struct sec_path),
     294                 :            :                                            0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
     295                 :            :                                            NULL);
     296                 :          0 : }

Generated by: LCOV version 1.9