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 <linux/module.h> 13#include <linux/string.h> 14#include <linux/netfilter.h> 15#include <linux/netfilter_ipv4.h> 16#include <net/ip.h> 17#include <net/xfrm.h> 18 19int xfrm4_rcv(struct sk_buff *skb) 20{ 21 return xfrm4_rcv_encap(skb, 0); 22} 23 24EXPORT_SYMBOL(xfrm4_rcv); 25 26static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) 27{ 28 switch (nexthdr) { 29 case IPPROTO_IPIP: 30 case IPPROTO_IPV6: 31 *spi = ip_hdr(skb)->saddr; 32 *seq = 0; 33 return 0; 34 } 35 36 return xfrm_parse_spi(skb, nexthdr, spi, seq); 37} 38 39#ifdef CONFIG_NETFILTER 40static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb) 41{ 42 if (skb->dst == NULL) { 43 const struct iphdr *iph = ip_hdr(skb); 44 45 if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, 46 skb->dev)) 47 goto drop; 48 } 49 return dst_input(skb); 50drop: 51 kfree_skb(skb); 52 return NET_RX_DROP; 53} 54#endif 55 56int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) 57{ 58 __be32 spi, seq; 59 struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; 60 struct xfrm_state *x; 61 int xfrm_nr = 0; 62 int decaps = 0; 63 int err = xfrm4_parse_spi(skb, ip_hdr(skb)->protocol, &spi, &seq); 64 65 if (err != 0) 66 goto drop; 67 68 do { 69 const struct iphdr *iph = ip_hdr(skb); 70 71 if (xfrm_nr == XFRM_MAX_DEPTH) 72 goto drop; 73 74 x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, 75 iph->protocol != IPPROTO_IPV6 ? iph->protocol : IPPROTO_IPIP, AF_INET); 76 if (x == NULL) 77 goto drop; 78 79 spin_lock(&x->lock); 80 if (unlikely(x->km.state != XFRM_STATE_VALID)) 81 goto drop_unlock; 82 83 if ((x->encap ? x->encap->encap_type : 0) != encap_type) 84 goto drop_unlock; 85 86 if (x->props.replay_window && xfrm_replay_check(x, seq)) 87 goto drop_unlock; 88 89 if (xfrm_state_check_expire(x)) 90 goto drop_unlock; 91 92 if (x->type->input(x, skb)) 93 goto drop_unlock; 94 95 /* only the first xfrm gets the encap type */ 96 encap_type = 0; 97 98 if (x->props.replay_window) 99 xfrm_replay_advance(x, seq); 100 101 x->curlft.bytes += skb->len; 102 x->curlft.packets++; 103 104 spin_unlock(&x->lock); 105 106 xfrm_vec[xfrm_nr++] = x; 107 108 if (x->mode->input(x, skb)) 109 goto drop; 110 111 if (x->props.mode == XFRM_MODE_TUNNEL) { 112 decaps = 1; 113 break; 114 } 115 116 err = xfrm_parse_spi(skb, ip_hdr(skb)->protocol, &spi, &seq); 117 if (err < 0) 118 goto drop; 119 } while (!err); 120 121 /* Allocate new secpath or COW existing one. */ 122 123 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 124 struct sec_path *sp; 125 sp = secpath_dup(skb->sp); 126 if (!sp) 127 goto drop; 128 if (skb->sp) 129 secpath_put(skb->sp); 130 skb->sp = sp; 131 } 132 if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) 133 goto drop; 134 135 memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, 136 xfrm_nr * sizeof(xfrm_vec[0])); 137 skb->sp->len += xfrm_nr; 138 139 nf_reset(skb); 140 141 if (decaps) { 142 dst_release(skb->dst); 143 skb->dst = NULL; 144 netif_rx(skb); 145 return 0; 146 } else { 147#ifdef CONFIG_NETFILTER 148 __skb_push(skb, skb->data - skb_network_header(skb)); 149 ip_hdr(skb)->tot_len = htons(skb->len); 150 ip_send_check(ip_hdr(skb)); 151 152 NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, 153 xfrm4_rcv_encap_finish); 154 return 0; 155#else 156 return -ip_hdr(skb)->protocol; 157#endif 158 } 159 160drop_unlock: 161 spin_unlock(&x->lock); 162 xfrm_state_put(x); 163drop: 164 while (--xfrm_nr >= 0) 165 xfrm_state_put(xfrm_vec[xfrm_nr]); 166 167 kfree_skb(skb); 168 return 0; 169} 170