Blame view
net/xfrm/xfrm_input.c
6.22 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 |
/* * xfrm_input.c * * Changes: * YOSHIFUJI Hideaki @USAGI * Split up af-specific portion |
a716c1197 [NET] XFRM: Fix w... |
7 |
* |
1da177e4c Linux-2.6.12-rc2 |
8 9 10 11 |
*/ #include <linux/slab.h> #include <linux/module.h> |
716062fd4 [IPSEC]: Merge mo... |
12 13 |
#include <linux/netdevice.h> #include <net/dst.h> |
1da177e4c Linux-2.6.12-rc2 |
14 15 |
#include <net/ip.h> #include <net/xfrm.h> |
e18b890bb [PATCH] slab: rem... |
16 |
static struct kmem_cache *secpath_cachep __read_mostly; |
1da177e4c Linux-2.6.12-rc2 |
17 18 19 20 21 |
void __secpath_destroy(struct sec_path *sp) { int i; for (i = 0; i < sp->len; i++) |
dbe5b4aaa [IPSEC]: Kill unu... |
22 |
xfrm_state_put(sp->xvec[i]); |
1da177e4c Linux-2.6.12-rc2 |
23 24 25 26 27 28 29 |
kmem_cache_free(secpath_cachep, sp); } EXPORT_SYMBOL(__secpath_destroy); struct sec_path *secpath_dup(struct sec_path *src) { struct sec_path *sp; |
54e6ecb23 [PATCH] slab: rem... |
30 |
sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC); |
1da177e4c Linux-2.6.12-rc2 |
31 32 33 34 35 36 37 38 39 |
if (!sp) return NULL; sp->len = 0; if (src) { int i; memcpy(sp, src, sizeof(*sp)); for (i = 0; i < sp->len; i++) |
dbe5b4aaa [IPSEC]: Kill unu... |
40 |
xfrm_state_hold(sp->xvec[i]); |
1da177e4c Linux-2.6.12-rc2 |
41 42 43 44 45 46 47 |
} atomic_set(&sp->refcnt, 1); return sp; } EXPORT_SYMBOL(secpath_dup); /* Fetch spi and seq from ipsec header */ |
6067b2bab [XFRM]: xfrm_pars... |
48 |
int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) |
1da177e4c Linux-2.6.12-rc2 |
49 50 |
{ int offset, offset_seq; |
440725000 [IPSEC]: Fix leng... |
51 |
int hlen; |
1da177e4c Linux-2.6.12-rc2 |
52 53 54 |
switch (nexthdr) { case IPPROTO_AH: |
440725000 [IPSEC]: Fix leng... |
55 |
hlen = sizeof(struct ip_auth_hdr); |
1da177e4c Linux-2.6.12-rc2 |
56 57 58 59 |
offset = offsetof(struct ip_auth_hdr, spi); offset_seq = offsetof(struct ip_auth_hdr, seq_no); break; case IPPROTO_ESP: |
440725000 [IPSEC]: Fix leng... |
60 |
hlen = sizeof(struct ip_esp_hdr); |
1da177e4c Linux-2.6.12-rc2 |
61 62 63 64 65 66 |
offset = offsetof(struct ip_esp_hdr, spi); offset_seq = offsetof(struct ip_esp_hdr, seq_no); break; case IPPROTO_COMP: if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr))) return -EINVAL; |
9c70220b7 [SK_BUFF]: Introd... |
67 |
*spi = htonl(ntohs(*(__be16*)(skb_transport_header(skb) + 2))); |
1da177e4c Linux-2.6.12-rc2 |
68 69 70 71 72 |
*seq = 0; return 0; default: return 1; } |
440725000 [IPSEC]: Fix leng... |
73 |
if (!pskb_may_pull(skb, hlen)) |
1da177e4c Linux-2.6.12-rc2 |
74 |
return -EINVAL; |
9c70220b7 [SK_BUFF]: Introd... |
75 76 |
*spi = *(__be32*)(skb_transport_header(skb) + offset); *seq = *(__be32*)(skb_transport_header(skb) + offset_seq); |
1da177e4c Linux-2.6.12-rc2 |
77 78 |
return 0; } |
1da177e4c Linux-2.6.12-rc2 |
79 |
|
227620e29 [IPSEC]: Separate... |
80 81 |
int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) { |
df9dcb458 [IPSEC]: Fix inte... |
82 |
struct xfrm_mode *inner_mode = x->inner_mode; |
227620e29 [IPSEC]: Separate... |
83 84 85 86 87 |
int err; err = x->outer_mode->afinfo->extract_input(x, skb); if (err) return err; |
df9dcb458 [IPSEC]: Fix inte... |
88 89 90 91 92 93 94 95 |
if (x->sel.family == AF_UNSPEC) { inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); if (inner_mode == NULL) return -EAFNOSUPPORT; } skb->protocol = inner_mode->afinfo->eth_proto; return inner_mode->input2(x, skb); |
227620e29 [IPSEC]: Separate... |
96 97 |
} EXPORT_SYMBOL(xfrm_prepare_input); |
716062fd4 [IPSEC]: Merge mo... |
98 99 |
int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) { |
bd235e3cf netns xfrm: xfrm_... |
100 |
struct net *net = dev_net(skb->dev); |
716062fd4 [IPSEC]: Merge mo... |
101 102 |
int err; __be32 seq; |
2cd084678 xfrm: Add support... |
103 |
__be32 seq_hi; |
716062fd4 [IPSEC]: Merge mo... |
104 |
struct xfrm_state *x; |
1bf06cd2e [IPSEC]: Add asyn... |
105 |
xfrm_address_t *daddr; |
df9dcb458 [IPSEC]: Fix inte... |
106 |
struct xfrm_mode *inner_mode; |
2fcb45b6b [IPSEC]: Use the ... |
107 |
unsigned int family; |
716062fd4 [IPSEC]: Merge mo... |
108 |
int decaps = 0; |
1bf06cd2e [IPSEC]: Add asyn... |
109 110 111 112 113 |
int async = 0; /* A negative encap_type indicates async resumption. */ if (encap_type < 0) { async = 1; |
005011211 [IPSEC]: Add xfrm... |
114 |
x = xfrm_input_state(skb); |
1ce3644ad xfrm: Use separat... |
115 |
seq = XFRM_SKB_CB(skb)->seq.input.low; |
1bf06cd2e [IPSEC]: Add asyn... |
116 117 |
goto resume; } |
716062fd4 [IPSEC]: Merge mo... |
118 |
|
b2aa5e9d4 [IPSEC]: Store xf... |
119 120 121 122 123 |
/* 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); |
0aa647746 [XFRM]: Support t... |
124 |
if (!sp) { |
59c9940ed netns xfrm: per-n... |
125 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); |
b2aa5e9d4 [IPSEC]: Store xf... |
126 |
goto drop; |
0aa647746 [XFRM]: Support t... |
127 |
} |
b2aa5e9d4 [IPSEC]: Store xf... |
128 129 130 131 |
if (skb->sp) secpath_put(skb->sp); skb->sp = sp; } |
1bf06cd2e [IPSEC]: Add asyn... |
132 133 |
daddr = (xfrm_address_t *)(skb_network_header(skb) + XFRM_SPI_SKB_CB(skb)->daddroff); |
2fcb45b6b [IPSEC]: Use the ... |
134 |
family = XFRM_SPI_SKB_CB(skb)->family; |
1bf06cd2e [IPSEC]: Add asyn... |
135 |
|
716062fd4 [IPSEC]: Merge mo... |
136 |
seq = 0; |
0aa647746 [XFRM]: Support t... |
137 |
if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) { |
59c9940ed netns xfrm: per-n... |
138 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); |
716062fd4 [IPSEC]: Merge mo... |
139 |
goto drop; |
0aa647746 [XFRM]: Support t... |
140 |
} |
716062fd4 [IPSEC]: Merge mo... |
141 142 |
do { |
0aa647746 [XFRM]: Support t... |
143 |
if (skb->sp->len == XFRM_MAX_DEPTH) { |
59c9940ed netns xfrm: per-n... |
144 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); |
716062fd4 [IPSEC]: Merge mo... |
145 |
goto drop; |
0aa647746 [XFRM]: Support t... |
146 |
} |
716062fd4 [IPSEC]: Merge mo... |
147 |
|
bd55775c8 xfrm: SA lookups ... |
148 |
x = xfrm_state_lookup(net, skb->mark, daddr, spi, nexthdr, family); |
0aa647746 [XFRM]: Support t... |
149 |
if (x == NULL) { |
59c9940ed netns xfrm: per-n... |
150 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); |
afeb14b49 [XFRM]: RFC4303 c... |
151 |
xfrm_audit_state_notfound(skb, family, spi, seq); |
716062fd4 [IPSEC]: Merge mo... |
152 |
goto drop; |
0aa647746 [XFRM]: Support t... |
153 |
} |
716062fd4 [IPSEC]: Merge mo... |
154 |
|
b2aa5e9d4 [IPSEC]: Store xf... |
155 |
skb->sp->xvec[skb->sp->len++] = x; |
716062fd4 [IPSEC]: Merge mo... |
156 |
spin_lock(&x->lock); |
0aa647746 [XFRM]: Support t... |
157 |
if (unlikely(x->km.state != XFRM_STATE_VALID)) { |
59c9940ed netns xfrm: per-n... |
158 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEINVALID); |
716062fd4 [IPSEC]: Merge mo... |
159 |
goto drop_unlock; |
0aa647746 [XFRM]: Support t... |
160 |
} |
716062fd4 [IPSEC]: Merge mo... |
161 |
|
3de77cf23 Revert "xfrm: Acc... |
162 163 164 165 |
if ((x->encap ? x->encap->encap_type : 0) != encap_type) { XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); goto drop_unlock; } |
36ae0148d xfrm: Move the te... |
166 |
if (x->repl->check(x, skb, seq)) { |
59c9940ed netns xfrm: per-n... |
167 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR); |
716062fd4 [IPSEC]: Merge mo... |
168 |
goto drop_unlock; |
0aa647746 [XFRM]: Support t... |
169 |
} |
716062fd4 [IPSEC]: Merge mo... |
170 |
|
0aa647746 [XFRM]: Support t... |
171 |
if (xfrm_state_check_expire(x)) { |
59c9940ed netns xfrm: per-n... |
172 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED); |
716062fd4 [IPSEC]: Merge mo... |
173 |
goto drop_unlock; |
0aa647746 [XFRM]: Support t... |
174 |
} |
716062fd4 [IPSEC]: Merge mo... |
175 |
|
0ebea8ef3 [IPSEC]: Move sta... |
176 |
spin_unlock(&x->lock); |
2cd084678 xfrm: Add support... |
177 |
seq_hi = htonl(xfrm_replay_seqhi(x, seq)); |
1ce3644ad xfrm: Use separat... |
178 |
XFRM_SKB_CB(skb)->seq.input.low = seq; |
2cd084678 xfrm: Add support... |
179 |
XFRM_SKB_CB(skb)->seq.input.hi = seq_hi; |
1bf06cd2e [IPSEC]: Add asyn... |
180 |
|
3bc07321c xfrm: Force a dst... |
181 |
skb_dst_force(skb); |
716062fd4 [IPSEC]: Merge mo... |
182 |
nexthdr = x->type->input(x, skb); |
0ebea8ef3 [IPSEC]: Move sta... |
183 |
|
1bf06cd2e [IPSEC]: Add asyn... |
184 185 186 187 |
if (nexthdr == -EINPROGRESS) return 0; resume: |
0ebea8ef3 [IPSEC]: Move sta... |
188 |
spin_lock(&x->lock); |
668dc8af3 [IPSEC]: Move int... |
189 |
if (nexthdr <= 0) { |
9dd3245a2 [IPSEC]: Move all... |
190 191 192 |
if (nexthdr == -EBADMSG) { xfrm_audit_state_icvfail(x, skb, x->type->proto); |
668dc8af3 [IPSEC]: Move int... |
193 |
x->stats.integrity_failed++; |
9dd3245a2 [IPSEC]: Move all... |
194 |
} |
59c9940ed netns xfrm: per-n... |
195 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR); |
716062fd4 [IPSEC]: Merge mo... |
196 |
goto drop_unlock; |
668dc8af3 [IPSEC]: Move int... |
197 |
} |
716062fd4 [IPSEC]: Merge mo... |
198 |
|
716062fd4 [IPSEC]: Merge mo... |
199 200 |
/* only the first xfrm gets the encap type */ encap_type = 0; |
bcf66bf54 xfrm: Perform a r... |
201 202 203 204 |
if (async && x->repl->check(x, skb, seq)) { XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR); goto drop_unlock; } |
9fdc4883d xfrm: Move IPsec ... |
205 |
x->repl->advance(x, seq); |
716062fd4 [IPSEC]: Merge mo... |
206 207 208 209 210 |
x->curlft.bytes += skb->len; x->curlft.packets++; spin_unlock(&x->lock); |
60d5fcfb1 [IPSEC]: Remove n... |
211 |
XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; |
df9dcb458 [IPSEC]: Fix inte... |
212 213 214 215 216 217 218 219 220 |
inner_mode = x->inner_mode; if (x->sel.family == AF_UNSPEC) { inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); if (inner_mode == NULL) goto drop; } if (inner_mode->input(x, skb)) { |
59c9940ed netns xfrm: per-n... |
221 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); |
716062fd4 [IPSEC]: Merge mo... |
222 |
goto drop; |
0aa647746 [XFRM]: Support t... |
223 |
} |
716062fd4 [IPSEC]: Merge mo... |
224 225 226 227 228 |
if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { decaps = 1; break; } |
1bf06cd2e [IPSEC]: Add asyn... |
229 230 231 232 233 |
/* * We need the inner address. However, we only get here for * transport mode so the outer address is identical. */ daddr = &x->id.daddr; |
2fcb45b6b [IPSEC]: Use the ... |
234 |
family = x->outer_mode->afinfo->family; |
1bf06cd2e [IPSEC]: Add asyn... |
235 |
|
716062fd4 [IPSEC]: Merge mo... |
236 |
err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); |
0aa647746 [XFRM]: Support t... |
237 |
if (err < 0) { |
59c9940ed netns xfrm: per-n... |
238 |
XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); |
716062fd4 [IPSEC]: Merge mo... |
239 |
goto drop; |
0aa647746 [XFRM]: Support t... |
240 |
} |
716062fd4 [IPSEC]: Merge mo... |
241 |
} while (!err); |
716062fd4 [IPSEC]: Merge mo... |
242 243 244 |
nf_reset(skb); if (decaps) { |
adf30907d net: skb->dst acc... |
245 |
skb_dst_drop(skb); |
716062fd4 [IPSEC]: Merge mo... |
246 247 248 |
netif_rx(skb); return 0; } else { |
1bf06cd2e [IPSEC]: Add asyn... |
249 |
return x->inner_mode->afinfo->transport_finish(skb, async); |
716062fd4 [IPSEC]: Merge mo... |
250 251 252 253 |
} drop_unlock: spin_unlock(&x->lock); |
716062fd4 [IPSEC]: Merge mo... |
254 |
drop: |
716062fd4 [IPSEC]: Merge mo... |
255 256 257 258 |
kfree_skb(skb); return 0; } EXPORT_SYMBOL(xfrm_input); |
1bf06cd2e [IPSEC]: Add asyn... |
259 260 261 262 263 |
int xfrm_input_resume(struct sk_buff *skb, int nexthdr) { return xfrm_input(skb, nexthdr, 0, -1); } EXPORT_SYMBOL(xfrm_input_resume); |
1da177e4c Linux-2.6.12-rc2 |
264 265 266 267 |
void __init xfrm_input_init(void) { secpath_cachep = kmem_cache_create("secpath_cache", sizeof(struct sec_path), |
e5d679f33 [NET]: Use SLAB_P... |
268 |
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
20c2df83d mm: Remove slab d... |
269 |
NULL); |
1da177e4c Linux-2.6.12-rc2 |
270 |
} |