Merge branch 'pandora-27-omap1' into rev2
[pandora-kernel.git] / net / ipv4 / xfrm4_input.c
index 2fa1082..390dcb1 100644 (file)
 #include <net/ip.h>
 #include <net/xfrm.h>
 
-static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
+int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-       switch (nexthdr) {
-       case IPPROTO_IPIP:
-       case IPPROTO_IPV6:
-               *spi = ip_hdr(skb)->saddr;
-               *seq = 0;
-               return 0;
-       }
-
-       return xfrm_parse_spi(skb, nexthdr, spi, seq);
+       return xfrm4_extract_header(skb);
 }
 
-#ifdef CONFIG_NETFILTER
 static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
 {
        if (skb->dst == NULL) {
@@ -44,120 +35,33 @@ drop:
        kfree_skb(skb);
        return NET_RX_DROP;
 }
-#endif
 
-static int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
+int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
+                   int encap_type)
 {
-       __be32 spi, seq;
-       struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
-       struct xfrm_state *x;
-       int xfrm_nr = 0;
-       int decaps = 0;
-       int err = xfrm4_parse_spi(skb, ip_hdr(skb)->protocol, &spi, &seq);
-
-       if (err != 0)
-               goto drop;
-
-       do {
-               const struct iphdr *iph = ip_hdr(skb);
-
-               if (xfrm_nr == XFRM_MAX_DEPTH)
-                       goto drop;
-
-               x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi,
-                               iph->protocol != IPPROTO_IPV6 ? iph->protocol : IPPROTO_IPIP, AF_INET);
-               if (x == NULL)
-                       goto drop;
-
-               spin_lock(&x->lock);
-               if (unlikely(x->km.state != XFRM_STATE_VALID))
-                       goto drop_unlock;
-
-               if ((x->encap ? x->encap->encap_type : 0) != encap_type)
-                       goto drop_unlock;
-
-               if (x->props.replay_window && xfrm_replay_check(x, seq))
-                       goto drop_unlock;
-
-               if (xfrm_state_check_expire(x))
-                       goto drop_unlock;
-
-               if (x->type->input(x, skb))
-                       goto drop_unlock;
-
-               /* only the first xfrm gets the encap type */
-               encap_type = 0;
-
-               if (x->props.replay_window)
-                       xfrm_replay_advance(x, seq);
-
-               x->curlft.bytes += skb->len;
-               x->curlft.packets++;
-
-               spin_unlock(&x->lock);
-
-               xfrm_vec[xfrm_nr++] = x;
-
-               if (x->mode->input(x, skb))
-                       goto drop;
-
-               if (x->props.mode == XFRM_MODE_TUNNEL) {
-                       decaps = 1;
-                       break;
-               }
-
-               err = xfrm_parse_spi(skb, ip_hdr(skb)->protocol, &spi, &seq);
-               if (err < 0)
-                       goto drop;
-       } while (!err);
-
-       /* Allocate new secpath or COW existing one. */
-
-       if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
-               struct sec_path *sp;
-               sp = secpath_dup(skb->sp);
-               if (!sp)
-                       goto drop;
-               if (skb->sp)
-                       secpath_put(skb->sp);
-               skb->sp = sp;
-       }
-       if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
-               goto drop;
-
-       memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
-              xfrm_nr * sizeof(xfrm_vec[0]));
-       skb->sp->len += xfrm_nr;
+       XFRM_SPI_SKB_CB(skb)->family = AF_INET;
+       XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
+       return xfrm_input(skb, nexthdr, spi, encap_type);
+}
+EXPORT_SYMBOL(xfrm4_rcv_encap);
 
-       nf_reset(skb);
+int xfrm4_transport_finish(struct sk_buff *skb, int async)
+{
+       struct iphdr *iph = ip_hdr(skb);
 
-       if (decaps) {
-               dst_release(skb->dst);
-               skb->dst = NULL;
-               netif_rx(skb);
-               return 0;
-       } else {
-#ifdef CONFIG_NETFILTER
-               __skb_push(skb, skb->data - skb_network_header(skb));
-               ip_hdr(skb)->tot_len = htons(skb->len);
-               ip_send_check(ip_hdr(skb));
+       iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
 
-               NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
-                       xfrm4_rcv_encap_finish);
-               return 0;
-#else
-               return -ip_hdr(skb)->protocol;
+#ifndef CONFIG_NETFILTER
+       if (!async)
+               return -iph->protocol;
 #endif
-       }
 
-drop_unlock:
-       spin_unlock(&x->lock);
-       xfrm_state_put(x);
-drop:
-       while (--xfrm_nr >= 0)
-               xfrm_state_put(xfrm_vec[xfrm_nr]);
+       __skb_push(skb, skb->data - skb_network_header(skb));
+       iph->tot_len = htons(skb->len);
+       ip_send_check(iph);
 
-       kfree_skb(skb);
+       NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
+               xfrm4_rcv_encap_finish);
        return 0;
 }
 
@@ -247,11 +151,8 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
        __skb_pull(skb, len);
        skb_reset_transport_header(skb);
 
-       /* modify the protocol (it's ESP!) */
-       iph->protocol = IPPROTO_ESP;
-
        /* process ESP */
-       ret = xfrm4_rcv_encap(skb, encap_type);
+       ret = xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type);
        return ret;
 
 drop:
@@ -261,7 +162,7 @@ drop:
 
 int xfrm4_rcv(struct sk_buff *skb)
 {
-       return xfrm4_rcv_encap(skb, 0);
+       return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0);
 }
 
 EXPORT_SYMBOL(xfrm4_rcv);