Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.20-rc3 248 lines 4.8 kB view raw
1/* 2 * xfrm6_input.c: based on net/ipv4/xfrm4_input.c 3 * 4 * Authors: 5 * Mitsuru KANDA @USAGI 6 * Kazunori MIYAZAWA @USAGI 7 * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 8 * YOSHIFUJI Hideaki @USAGI 9 * IPv6 support 10 */ 11 12#include <linux/module.h> 13#include <linux/string.h> 14#include <linux/netfilter.h> 15#include <linux/netfilter_ipv6.h> 16#include <net/ipv6.h> 17#include <net/xfrm.h> 18 19int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) 20{ 21 int err; 22 __be32 seq; 23 struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; 24 struct xfrm_state *x; 25 int xfrm_nr = 0; 26 int decaps = 0; 27 int nexthdr; 28 unsigned int nhoff; 29 30 nhoff = IP6CB(skb)->nhoff; 31 nexthdr = skb->nh.raw[nhoff]; 32 33 seq = 0; 34 if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) 35 goto drop; 36 37 do { 38 struct ipv6hdr *iph = skb->nh.ipv6h; 39 40 if (xfrm_nr == XFRM_MAX_DEPTH) 41 goto drop; 42 43 x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_INET6); 44 if (x == NULL) 45 goto drop; 46 spin_lock(&x->lock); 47 if (unlikely(x->km.state != XFRM_STATE_VALID)) 48 goto drop_unlock; 49 50 if (x->props.replay_window && xfrm_replay_check(x, seq)) 51 goto drop_unlock; 52 53 if (xfrm_state_check_expire(x)) 54 goto drop_unlock; 55 56 nexthdr = x->type->input(x, skb); 57 if (nexthdr <= 0) 58 goto drop_unlock; 59 60 skb->nh.raw[nhoff] = nexthdr; 61 62 if (x->props.replay_window) 63 xfrm_replay_advance(x, seq); 64 65 x->curlft.bytes += skb->len; 66 x->curlft.packets++; 67 68 spin_unlock(&x->lock); 69 70 xfrm_vec[xfrm_nr++] = x; 71 72 if (x->mode->input(x, skb)) 73 goto drop; 74 75 if (x->props.mode == XFRM_MODE_TUNNEL) { /* XXX */ 76 decaps = 1; 77 break; 78 } 79 80 if ((err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) < 0) 81 goto drop; 82 } while (!err); 83 84 /* Allocate new secpath or COW existing one. */ 85 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 86 struct sec_path *sp; 87 sp = secpath_dup(skb->sp); 88 if (!sp) 89 goto drop; 90 if (skb->sp) 91 secpath_put(skb->sp); 92 skb->sp = sp; 93 } 94 95 if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) 96 goto drop; 97 98 memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, 99 xfrm_nr * sizeof(xfrm_vec[0])); 100 skb->sp->len += xfrm_nr; 101 skb->ip_summed = CHECKSUM_NONE; 102 103 nf_reset(skb); 104 105 if (decaps) { 106 if (!(skb->dev->flags&IFF_LOOPBACK)) { 107 dst_release(skb->dst); 108 skb->dst = NULL; 109 } 110 netif_rx(skb); 111 return -1; 112 } else { 113#ifdef CONFIG_NETFILTER 114 skb->nh.ipv6h->payload_len = htons(skb->len); 115 __skb_push(skb, skb->data - skb->nh.raw); 116 117 NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL, 118 ip6_rcv_finish); 119 return -1; 120#else 121 return 1; 122#endif 123 } 124 125drop_unlock: 126 spin_unlock(&x->lock); 127 xfrm_state_put(x); 128drop: 129 while (--xfrm_nr >= 0) 130 xfrm_state_put(xfrm_vec[xfrm_nr]); 131 kfree_skb(skb); 132 return -1; 133} 134 135EXPORT_SYMBOL(xfrm6_rcv_spi); 136 137int xfrm6_rcv(struct sk_buff **pskb) 138{ 139 return xfrm6_rcv_spi(*pskb, 0); 140} 141 142int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 143 xfrm_address_t *saddr, u8 proto) 144{ 145 struct xfrm_state *x = NULL; 146 int wildcard = 0; 147 struct in6_addr any; 148 xfrm_address_t *xany; 149 struct xfrm_state *xfrm_vec_one = NULL; 150 int nh = 0; 151 int i = 0; 152 153 ipv6_addr_set(&any, 0, 0, 0, 0); 154 xany = (xfrm_address_t *)&any; 155 156 for (i = 0; i < 3; i++) { 157 xfrm_address_t *dst, *src; 158 switch (i) { 159 case 0: 160 dst = daddr; 161 src = saddr; 162 break; 163 case 1: 164 /* lookup state with wild-card source address */ 165 wildcard = 1; 166 dst = daddr; 167 src = xany; 168 break; 169 case 2: 170 default: 171 /* lookup state with wild-card addresses */ 172 wildcard = 1; /* XXX */ 173 dst = xany; 174 src = xany; 175 break; 176 } 177 178 x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); 179 if (!x) 180 continue; 181 182 spin_lock(&x->lock); 183 184 if (wildcard) { 185 if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { 186 spin_unlock(&x->lock); 187 xfrm_state_put(x); 188 x = NULL; 189 continue; 190 } 191 } 192 193 if (unlikely(x->km.state != XFRM_STATE_VALID)) { 194 spin_unlock(&x->lock); 195 xfrm_state_put(x); 196 x = NULL; 197 continue; 198 } 199 if (xfrm_state_check_expire(x)) { 200 spin_unlock(&x->lock); 201 xfrm_state_put(x); 202 x = NULL; 203 continue; 204 } 205 206 nh = x->type->input(x, skb); 207 if (nh <= 0) { 208 spin_unlock(&x->lock); 209 xfrm_state_put(x); 210 x = NULL; 211 continue; 212 } 213 214 x->curlft.bytes += skb->len; 215 x->curlft.packets++; 216 217 spin_unlock(&x->lock); 218 219 xfrm_vec_one = x; 220 break; 221 } 222 223 if (!xfrm_vec_one) 224 goto drop; 225 226 /* Allocate new secpath or COW existing one. */ 227 if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { 228 struct sec_path *sp; 229 sp = secpath_dup(skb->sp); 230 if (!sp) 231 goto drop; 232 if (skb->sp) 233 secpath_put(skb->sp); 234 skb->sp = sp; 235 } 236 237 if (1 + skb->sp->len > XFRM_MAX_DEPTH) 238 goto drop; 239 240 skb->sp->xvec[skb->sp->len] = xfrm_vec_one; 241 skb->sp->len ++; 242 243 return 1; 244drop: 245 if (xfrm_vec_one) 246 xfrm_state_put(xfrm_vec_one); 247 return -1; 248}