linux-bk/net/ipv4/xfrm4_input.c
<<
>>
Prefs
   1/*
   2 * xfrm4_input.c
   3 *
   4 * Changes:
   5 *      YOSHIFUJI Hideaki @USAGI
   6 *              Split up af-specific portion
   7 *      Derek Atkins <derek@ihtfp.com>
   8 *              Add Encapsulation support
   9 *      
  10 */
  11
  12#include <net/inet_ecn.h>
  13#include <net/ip.h>
  14#include <net/xfrm.h>
  15
  16int xfrm4_rcv(struct sk_buff *skb)
  17{
  18        return xfrm4_rcv_encap(skb, 0);
  19}
  20
  21static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk_buff *skb)
  22{
  23        struct iphdr *inner_iph = skb->nh.iph;
  24
  25        if (INET_ECN_is_ce(outer_iph->tos) &&
  26            INET_ECN_is_not_ce(inner_iph->tos))
  27                IP_ECN_set_ce(inner_iph);
  28}
  29
  30static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
  31{
  32        switch (nexthdr) {
  33        case IPPROTO_IPIP:
  34                if (!pskb_may_pull(skb, sizeof(struct iphdr)))
  35                        return -EINVAL;
  36                *spi = skb->nh.iph->saddr;
  37                *seq = 0;
  38                return 0;
  39        }
  40
  41        return xfrm_parse_spi(skb, nexthdr, spi, seq);
  42}
  43
  44int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
  45{
  46        int err;
  47        u32 spi, seq;
  48        struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
  49        struct xfrm_state *x;
  50        int xfrm_nr = 0;
  51        int decaps = 0;
  52
  53        if ((err = xfrm4_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) != 0)
  54                goto drop;
  55
  56        do {
  57                struct iphdr *iph = skb->nh.iph;
  58
  59                if (xfrm_nr == XFRM_MAX_DEPTH)
  60                        goto drop;
  61
  62                x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, iph->protocol, AF_INET);
  63                if (x == NULL)
  64                        goto drop;
  65
  66                spin_lock(&x->lock);
  67                if (unlikely(x->km.state != XFRM_STATE_VALID))
  68                        goto drop_unlock;
  69
  70                if (x->props.replay_window && xfrm_replay_check(x, seq))
  71                        goto drop_unlock;
  72
  73                if (xfrm_state_check_expire(x))
  74                        goto drop_unlock;
  75
  76                xfrm_vec[xfrm_nr].decap.decap_type = encap_type;
  77                if (x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb))
  78                        goto drop_unlock;
  79
  80                /* only the first xfrm gets the encap type */
  81                encap_type = 0;
  82
  83                if (x->props.replay_window)
  84                        xfrm_replay_advance(x, seq);
  85
  86                x->curlft.bytes += skb->len;
  87                x->curlft.packets++;
  88
  89                spin_unlock(&x->lock);
  90
  91                xfrm_vec[xfrm_nr++].xvec = x;
  92
  93                iph = skb->nh.iph;
  94
  95                if (x->props.mode) {
  96                        if (iph->protocol != IPPROTO_IPIP)
  97                                goto drop;
  98                        skb->nh.raw = skb->data;
  99                        if (!(x->props.flags & XFRM_STATE_NOECN))
 100                                ipip_ecn_decapsulate(iph, skb);
 101                        iph = skb->nh.iph;
 102                        memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
 103                        decaps = 1;
 104                        break;
 105                }
 106
 107                if ((err = xfrm_parse_spi(skb, skb->nh.iph->protocol, &spi, &seq)) < 0)
 108                        goto drop;
 109        } while (!err);
 110
 111        /* Allocate new secpath or COW existing one. */
 112
 113        if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
 114                struct sec_path *sp;
 115                sp = secpath_dup(skb->sp);
 116                if (!sp)
 117                        goto drop;
 118                if (skb->sp)
 119                        secpath_put(skb->sp);
 120                skb->sp = sp;
 121        }
 122        if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
 123                goto drop;
 124
 125        memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state));
 126        skb->sp->len += xfrm_nr;
 127
 128        if (decaps) {
 129                if (!(skb->dev->flags&IFF_LOOPBACK)) {
 130                        dst_release(skb->dst);
 131                        skb->dst = NULL;
 132                }
 133                netif_rx(skb);
 134                return 0;
 135        } else {
 136                return -skb->nh.iph->protocol;
 137        }
 138
 139drop_unlock:
 140        spin_unlock(&x->lock);
 141        xfrm_state_put(x);
 142drop:
 143        while (--xfrm_nr >= 0)
 144                xfrm_state_put(xfrm_vec[xfrm_nr].xvec);
 145
 146        kfree_skb(skb);
 147        return 0;
 148}
 149
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.