Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile
[sfrench/cifs-2.6.git] / net / xfrm / xfrm_input.c
1 /*
2  * xfrm_input.c
3  *
4  * Changes:
5  *      YOSHIFUJI Hideaki @USAGI
6  *              Split up af-specific portion
7  *
8  */
9
10 #include <linux/slab.h>
11 #include <linux/module.h>
12 #include <linux/netdevice.h>
13 #include <net/dst.h>
14 #include <net/ip.h>
15 #include <net/xfrm.h>
16
17 static struct kmem_cache *secpath_cachep __read_mostly;
18
19 static DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
20 static struct xfrm_input_afinfo __rcu *xfrm_input_afinfo[NPROTO];
21
22 int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo)
23 {
24         int err = 0;
25
26         if (unlikely(afinfo == NULL))
27                 return -EINVAL;
28         if (unlikely(afinfo->family >= NPROTO))
29                 return -EAFNOSUPPORT;
30         spin_lock_bh(&xfrm_input_afinfo_lock);
31         if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL))
32                 err = -ENOBUFS;
33         else
34                 rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo);
35         spin_unlock_bh(&xfrm_input_afinfo_lock);
36         return err;
37 }
38 EXPORT_SYMBOL(xfrm_input_register_afinfo);
39
40 int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo)
41 {
42         int err = 0;
43
44         if (unlikely(afinfo == NULL))
45                 return -EINVAL;
46         if (unlikely(afinfo->family >= NPROTO))
47                 return -EAFNOSUPPORT;
48         spin_lock_bh(&xfrm_input_afinfo_lock);
49         if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) {
50                 if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo))
51                         err = -EINVAL;
52                 else
53                         RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL);
54         }
55         spin_unlock_bh(&xfrm_input_afinfo_lock);
56         synchronize_rcu();
57         return err;
58 }
59 EXPORT_SYMBOL(xfrm_input_unregister_afinfo);
60
61 static struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family)
62 {
63         struct xfrm_input_afinfo *afinfo;
64
65         if (unlikely(family >= NPROTO))
66                 return NULL;
67         rcu_read_lock();
68         afinfo = rcu_dereference(xfrm_input_afinfo[family]);
69         if (unlikely(!afinfo))
70                 rcu_read_unlock();
71         return afinfo;
72 }
73
74 static void xfrm_input_put_afinfo(struct xfrm_input_afinfo *afinfo)
75 {
76         rcu_read_unlock();
77 }
78
79 static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol,
80                        int err)
81 {
82         int ret;
83         struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family);
84
85         if (!afinfo)
86                 return -EAFNOSUPPORT;
87
88         ret = afinfo->callback(skb, protocol, err);
89         xfrm_input_put_afinfo(afinfo);
90
91         return ret;
92 }
93
94 void __secpath_destroy(struct sec_path *sp)
95 {
96         int i;
97         for (i = 0; i < sp->len; i++)
98                 xfrm_state_put(sp->xvec[i]);
99         kmem_cache_free(secpath_cachep, sp);
100 }
101 EXPORT_SYMBOL(__secpath_destroy);
102
103 struct sec_path *secpath_dup(struct sec_path *src)
104 {
105         struct sec_path *sp;
106
107         sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC);
108         if (!sp)
109                 return NULL;
110
111         sp->len = 0;
112         if (src) {
113                 int i;
114
115                 memcpy(sp, src, sizeof(*sp));
116                 for (i = 0; i < sp->len; i++)
117                         xfrm_state_hold(sp->xvec[i]);
118         }
119         atomic_set(&sp->refcnt, 1);
120         return sp;
121 }
122 EXPORT_SYMBOL(secpath_dup);
123
124 /* Fetch spi and seq from ipsec header */
125
126 int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
127 {
128         int offset, offset_seq;
129         int hlen;
130
131         switch (nexthdr) {
132         case IPPROTO_AH:
133                 hlen = sizeof(struct ip_auth_hdr);
134                 offset = offsetof(struct ip_auth_hdr, spi);
135                 offset_seq = offsetof(struct ip_auth_hdr, seq_no);
136                 break;
137         case IPPROTO_ESP:
138                 hlen = sizeof(struct ip_esp_hdr);
139                 offset = offsetof(struct ip_esp_hdr, spi);
140                 offset_seq = offsetof(struct ip_esp_hdr, seq_no);
141                 break;
142         case IPPROTO_COMP:
143                 if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
144                         return -EINVAL;
145                 *spi = htonl(ntohs(*(__be16 *)(skb_transport_header(skb) + 2)));
146                 *seq = 0;
147                 return 0;
148         default:
149                 return 1;
150         }
151
152         if (!pskb_may_pull(skb, hlen))
153                 return -EINVAL;
154
155         *spi = *(__be32 *)(skb_transport_header(skb) + offset);
156         *seq = *(__be32 *)(skb_transport_header(skb) + offset_seq);
157         return 0;
158 }
159
160 int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
161 {
162         struct xfrm_mode *inner_mode = x->inner_mode;
163         int err;
164
165         err = x->outer_mode->afinfo->extract_input(x, skb);
166         if (err)
167                 return err;
168
169         if (x->sel.family == AF_UNSPEC) {
170                 inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
171                 if (inner_mode == NULL)
172                         return -EAFNOSUPPORT;
173         }
174
175         skb->protocol = inner_mode->afinfo->eth_proto;
176         return inner_mode->input2(x, skb);
177 }
178 EXPORT_SYMBOL(xfrm_prepare_input);
179
180 int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
181 {
182         struct net *net = dev_net(skb->dev);
183         int err;
184         __be32 seq;
185         __be32 seq_hi;
186         struct xfrm_state *x = NULL;
187         xfrm_address_t *daddr;
188         struct xfrm_mode *inner_mode;
189         unsigned int family;
190         int decaps = 0;
191         int async = 0;
192
193         /* A negative encap_type indicates async resumption. */
194         if (encap_type < 0) {
195                 async = 1;
196                 x = xfrm_input_state(skb);
197                 seq = XFRM_SKB_CB(skb)->seq.input.low;
198                 family = x->outer_mode->afinfo->family;
199                 goto resume;
200         }
201
202         daddr = (xfrm_address_t *)(skb_network_header(skb) +
203                                    XFRM_SPI_SKB_CB(skb)->daddroff);
204         family = XFRM_SPI_SKB_CB(skb)->family;
205
206         /* Allocate new secpath or COW existing one. */
207         if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
208                 struct sec_path *sp;
209
210                 sp = secpath_dup(skb->sp);
211                 if (!sp) {
212                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
213                         goto drop;
214                 }
215                 if (skb->sp)
216                         secpath_put(skb->sp);
217                 skb->sp = sp;
218         }
219
220         seq = 0;
221         if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
222                 XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
223                 goto drop;
224         }
225
226         do {
227                 if (skb->sp->len == XFRM_MAX_DEPTH) {
228                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
229                         goto drop;
230                 }
231
232                 x = xfrm_state_lookup(net, skb->mark, daddr, spi, nexthdr, family);
233                 if (x == NULL) {
234                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
235                         xfrm_audit_state_notfound(skb, family, spi, seq);
236                         goto drop;
237                 }
238
239                 skb->sp->xvec[skb->sp->len++] = x;
240
241                 if (xfrm_tunnel_check(skb, x, family)) {
242                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
243                         goto drop;
244                 }
245
246                 spin_lock(&x->lock);
247                 if (unlikely(x->km.state == XFRM_STATE_ACQ)) {
248                         XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
249                         goto drop_unlock;
250                 }
251
252                 if (unlikely(x->km.state != XFRM_STATE_VALID)) {
253                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEINVALID);
254                         goto drop_unlock;
255                 }
256
257                 if ((x->encap ? x->encap->encap_type : 0) != encap_type) {
258                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
259                         goto drop_unlock;
260                 }
261
262                 if (x->repl->check(x, skb, seq)) {
263                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
264                         goto drop_unlock;
265                 }
266
267                 if (xfrm_state_check_expire(x)) {
268                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED);
269                         goto drop_unlock;
270                 }
271
272                 spin_unlock(&x->lock);
273
274                 seq_hi = htonl(xfrm_replay_seqhi(x, seq));
275
276                 XFRM_SKB_CB(skb)->seq.input.low = seq;
277                 XFRM_SKB_CB(skb)->seq.input.hi = seq_hi;
278
279                 skb_dst_force(skb);
280
281                 nexthdr = x->type->input(x, skb);
282
283                 if (nexthdr == -EINPROGRESS)
284                         return 0;
285 resume:
286                 spin_lock(&x->lock);
287                 if (nexthdr <= 0) {
288                         if (nexthdr == -EBADMSG) {
289                                 xfrm_audit_state_icvfail(x, skb,
290                                                          x->type->proto);
291                                 x->stats.integrity_failed++;
292                         }
293                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
294                         goto drop_unlock;
295                 }
296
297                 /* only the first xfrm gets the encap type */
298                 encap_type = 0;
299
300                 if (async && x->repl->recheck(x, skb, seq)) {
301                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
302                         goto drop_unlock;
303                 }
304
305                 x->repl->advance(x, seq);
306
307                 x->curlft.bytes += skb->len;
308                 x->curlft.packets++;
309
310                 spin_unlock(&x->lock);
311
312                 XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
313
314                 inner_mode = x->inner_mode;
315
316                 if (x->sel.family == AF_UNSPEC) {
317                         inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
318                         if (inner_mode == NULL)
319                                 goto drop;
320                 }
321
322                 if (inner_mode->input(x, skb)) {
323                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
324                         goto drop;
325                 }
326
327                 if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
328                         decaps = 1;
329                         break;
330                 }
331
332                 /*
333                  * We need the inner address.  However, we only get here for
334                  * transport mode so the outer address is identical.
335                  */
336                 daddr = &x->id.daddr;
337                 family = x->outer_mode->afinfo->family;
338
339                 err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
340                 if (err < 0) {
341                         XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
342                         goto drop;
343                 }
344         } while (!err);
345
346         err = xfrm_rcv_cb(skb, family, x->type->proto, 0);
347         if (err)
348                 goto drop;
349
350         nf_reset(skb);
351
352         if (decaps) {
353                 skb_dst_drop(skb);
354                 netif_rx(skb);
355                 return 0;
356         } else {
357                 return x->inner_mode->afinfo->transport_finish(skb, async);
358         }
359
360 drop_unlock:
361         spin_unlock(&x->lock);
362 drop:
363         xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
364         kfree_skb(skb);
365         return 0;
366 }
367 EXPORT_SYMBOL(xfrm_input);
368
369 int xfrm_input_resume(struct sk_buff *skb, int nexthdr)
370 {
371         return xfrm_input(skb, nexthdr, 0, -1);
372 }
373 EXPORT_SYMBOL(xfrm_input_resume);
374
375 void __init xfrm_input_init(void)
376 {
377         secpath_cachep = kmem_cache_create("secpath_cache",
378                                            sizeof(struct sec_path),
379                                            0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
380                                            NULL);
381 }