Merge with Linux 2.5.48.
[linux-2.6/linux-mips.git] / net / ipv4 / ah.c
bloba1c6d137c4d9d36f76e208618c3c4c54a485425d
1 #include <linux/config.h>
2 #include <linux/module.h>
3 #include <net/ip.h>
4 #include <net/xfrm.h>
5 #include <linux/crypto.h>
6 #include <linux/pfkeyv2.h>
7 #include <net/icmp.h>
8 #include <asm/scatterlist.h>
10 struct ah_data
12 u8 *key;
13 int key_len;
14 u8 *work_digest;
15 int digest_len;
17 void (*digest)(struct ah_data*,
18 struct sk_buff *skb,
19 u8 *digest);
21 struct crypto_tfm *tfm;
25 /* Clear mutable options and find final destination to substitute
26 * into IP header for digest calculation. Options are already checked
27 * for validity, so paranoia is not required. */
29 int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr)
31 unsigned char * optptr = (unsigned char*)(iph+1);
32 int l = iph->ihl*4 - 20;
33 int optlen;
35 while (l > 0) {
36 switch (*optptr) {
37 case IPOPT_END:
38 return 0;
39 case IPOPT_NOOP:
40 l--;
41 optptr++;
42 continue;
44 optlen = optptr[1];
45 if (optlen<2 || optlen>l)
46 return -EINVAL;
47 switch (*optptr) {
48 case IPOPT_SEC:
49 case 0x85: /* Some "Extended Security" crap. */
50 case 0x86: /* Another "Commercial Security" crap. */
51 case IPOPT_RA:
52 case 0x80|21: /* RFC1770 */
53 break;
54 case IPOPT_LSRR:
55 case IPOPT_SSRR:
56 if (optlen < 6)
57 return -EINVAL;
58 memcpy(daddr, optptr+optlen-4, 4);
59 /* Fall through */
60 default:
61 memset(optptr+2, 0, optlen-2);
63 l -= optlen;
64 optptr += optlen;
66 return 0;
69 void skb_ah_walk(const struct sk_buff *skb, struct crypto_tfm *tfm)
71 int offset = 0;
72 int len = skb->len;
73 int start = skb->len - skb->data_len;
74 int i, copy = start - offset;
75 struct scatterlist sg;
77 /* Checksum header. */
78 if (copy > 0) {
79 if (copy > len)
80 copy = len;
82 sg.page = virt_to_page(skb->data + offset);
83 sg.offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
84 sg.length = copy;
86 crypto_hmac_update(tfm, &sg, 1);
88 if ((len -= copy) == 0)
89 return;
90 offset += copy;
93 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
94 int end;
96 BUG_TRAP(start <= offset + len);
98 end = start + skb_shinfo(skb)->frags[i].size;
99 if ((copy = end - offset) > 0) {
100 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
102 if (copy > len)
103 copy = len;
105 sg.page = frag->page;
106 sg.offset = frag->page_offset + offset-start;
107 sg.length = copy;
109 crypto_hmac_update(tfm, &sg, 1);
111 if (!(len -= copy))
112 return;
113 offset += copy;
115 start = end;
118 if (skb_shinfo(skb)->frag_list) {
119 struct sk_buff *list = skb_shinfo(skb)->frag_list;
121 for (; list; list = list->next) {
122 int end;
124 BUG_TRAP(start <= offset + len);
126 end = start + list->len;
127 if ((copy = end - offset) > 0) {
128 if (copy > len)
129 copy = len;
130 skb_ah_walk(list, tfm);
131 if ((len -= copy) == 0)
132 return;
133 offset += copy;
135 start = end;
138 if (len)
139 BUG();
142 static void
143 ah_hmac_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data)
145 struct crypto_tfm *tfm = ahp->tfm;
147 memset(auth_data, 0, ahp->digest_len);
148 crypto_hmac_init(tfm, ahp->key, &ahp->key_len);
149 skb_ah_walk(skb, tfm);
150 crypto_hmac_final(tfm, ahp->key, &ahp->key_len, ahp->work_digest);
151 memcpy(auth_data, ahp->work_digest, ahp->digest_len);
154 int ah_output(struct sk_buff *skb)
156 int err;
157 struct dst_entry *dst = skb->dst;
158 struct xfrm_state *x = dst->xfrm;
159 struct iphdr *iph, *top_iph;
160 struct ip_auth_hdr *ah;
161 struct ah_data *ahp;
162 union {
163 struct iphdr iph;
164 char buf[60];
165 } tmp_iph;
167 if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL)
168 return -EINVAL;
170 spin_lock_bh(&x->lock);
171 if ((err = xfrm_state_check_expire(x)) != 0)
172 goto error;
173 if ((err = xfrm_state_check_space(x, skb)) != 0)
174 goto error;
176 iph = skb->nh.iph;
177 if (x->props.mode) {
178 top_iph = (struct iphdr*)skb_push(skb, x->props.header_len);
179 top_iph->ihl = 5;
180 top_iph->version = 4;
181 top_iph->tos = 0;
182 top_iph->tot_len = htons(skb->len);
183 top_iph->frag_off = 0;
184 if (!(iph->frag_off&htons(IP_DF)))
185 __ip_select_ident(top_iph, dst, 0);
186 top_iph->ttl = 0;
187 top_iph->protocol = IPPROTO_AH;
188 top_iph->check = 0;
189 top_iph->saddr = x->props.saddr.xfrm4_addr;
190 top_iph->daddr = x->id.daddr.xfrm4_addr;
191 ah = (struct ip_auth_hdr*)(top_iph+1);
192 ah->nexthdr = IPPROTO_IPIP;
193 } else {
194 memcpy(&tmp_iph, skb->data, iph->ihl*4);
195 top_iph = (struct iphdr*)skb_push(skb, x->props.header_len);
196 memcpy(top_iph, &tmp_iph, iph->ihl*4);
197 iph = &tmp_iph.iph;
198 top_iph->tos = 0;
199 top_iph->tot_len = htons(skb->len);
200 top_iph->frag_off = 0;
201 top_iph->ttl = 0;
202 top_iph->protocol = IPPROTO_AH;
203 top_iph->check = 0;
204 if (top_iph->ihl != 5) {
205 err = ip_clear_mutable_options(top_iph, &top_iph->daddr);
206 if (err)
207 goto error;
209 ah = (struct ip_auth_hdr*)((char*)top_iph+iph->ihl*4);
210 ah->nexthdr = iph->protocol;
212 ahp = x->data;
213 ah->hdrlen = (((ahp->digest_len + 12 + 7)&~7)>>2)-2;
214 ah->reserved = 0;
215 ah->spi = x->id.spi;
216 ah->seq_no = htonl(++x->replay.oseq);
217 ahp->digest(ahp, skb, ah->auth_data);
218 top_iph->tos = iph->tos;
219 top_iph->ttl = iph->ttl;
220 if (x->props.mode) {
221 top_iph->frag_off = iph->frag_off&~htons(IP_MF|IP_OFFSET);
222 memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
223 } else {
224 top_iph->frag_off = iph->frag_off;
225 top_iph->daddr = iph->daddr;
226 if (iph->ihl != 5)
227 memcpy(top_iph+1, iph+1, iph->ihl*5 - 20);
229 ip_send_check(top_iph);
231 skb->nh.raw = skb->data;
233 x->curlft.bytes += skb->len;
234 x->curlft.packets++;
235 spin_unlock_bh(&x->lock);
236 if ((skb->dst = dst_pop(dst)) == NULL)
237 goto error;
238 return NET_XMIT_BYPASS;
240 error:
241 spin_unlock_bh(&x->lock);
242 kfree_skb(skb);
243 return err;
246 int ah_input(struct xfrm_state *x, struct sk_buff *skb)
248 struct iphdr *iph;
249 struct ip_auth_hdr *ah;
250 struct ah_data *ahp;
251 char work_buf[60];
253 if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
254 goto out;
256 ah = (struct ip_auth_hdr*)skb->data;
258 ahp = x->data;
260 if (((ah->hdrlen+2)<<2) != ((ahp->digest_len + 12 + 7)&~7))
261 goto out;
263 if (!pskb_may_pull(skb, (ah->hdrlen+2)<<2))
264 goto out;
266 /* We are going to _remove_ AH header to keep sockets happy,
267 * so... Later this can change. */
268 if (skb_cloned(skb) &&
269 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
270 goto out;
272 ah = (struct ip_auth_hdr*)skb->data;
273 iph = skb->nh.iph;
275 memcpy(work_buf, iph, iph->ihl*4);
277 iph->ttl = 0;
278 iph->tos = 0;
279 iph->frag_off = 0;
280 iph->check = 0;
281 if (iph->ihl != 5) {
282 u32 dummy;
283 if (ip_clear_mutable_options(iph, &dummy))
284 goto out;
287 u8 auth_data[ahp->digest_len];
288 memcpy(auth_data, ah->auth_data, ahp->digest_len);
289 skb_push(skb, skb->data - skb->nh.raw);
290 ahp->digest(ahp, skb, ah->auth_data);
291 if (memcmp(ah->auth_data, auth_data, ahp->digest_len)) {
292 x->stats.integrity_failed++;
293 goto out;
296 ((struct iphdr*)work_buf)->protocol = ah->nexthdr;
297 skb->nh.raw = skb_pull(skb, (ah->hdrlen+2)<<2);
298 memcpy(skb->nh.raw, work_buf, iph->ihl*4);
299 skb->nh.iph->tot_len = htons(skb->len);
300 skb_pull(skb, skb->nh.iph->ihl*4);
301 skb->h.raw = skb->data;
303 return 0;
305 out:
306 return -EINVAL;
309 void ah4_err(struct sk_buff *skb, u32 info)
311 struct iphdr *iph = (struct iphdr*)skb->data;
312 struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2));
313 struct xfrm_state *x;
315 if (skb->h.icmph->type != ICMP_DEST_UNREACH ||
316 skb->h.icmph->code != ICMP_FRAG_NEEDED)
317 return;
319 x = xfrm_state_lookup(iph->daddr, ah->spi, IPPROTO_AH);
320 if (!x)
321 return;
322 printk(KERN_DEBUG "pmtu discvovery on SA AH/%08x/%08x\n",
323 ntohl(ah->spi), ntohl(iph->daddr));
324 xfrm_state_put(x);
327 int ah_init_state(struct xfrm_state *x, void *args)
329 struct ah_data *ahp = NULL;
331 if (x->aalg == NULL || x->aalg->alg_key_len == 0 ||
332 x->aalg->alg_key_len > 512)
333 goto error;
335 ahp = kmalloc(sizeof(*ahp), GFP_KERNEL);
336 if (ahp == NULL)
337 return -ENOMEM;
339 memset(ahp, 0, sizeof(*ahp));
341 ahp->key = x->aalg->alg_key;
342 ahp->key_len = (x->aalg->alg_key_len+7)/8;
343 ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
344 if (!ahp->tfm)
345 goto error;
346 ahp->digest = ah_hmac_digest;
347 ahp->digest_len = 12;
348 ahp->work_digest = kmalloc(crypto_tfm_alg_digestsize(ahp->tfm),
349 GFP_KERNEL);
350 if (!ahp->work_digest)
351 goto error;
352 x->props.header_len = (12 + ahp->digest_len + 7)&~7;
353 if (x->props.mode)
354 x->props.header_len += 20;
355 x->data = ahp;
357 return 0;
359 error:
360 if (ahp) {
361 if (ahp->work_digest)
362 kfree(ahp->work_digest);
363 if (ahp->tfm)
364 crypto_free_tfm(ahp->tfm);
365 kfree(ahp);
367 return -EINVAL;
370 void ah_destroy(struct xfrm_state *x)
372 struct ah_data *ahp = x->data;
374 if (ahp->work_digest) {
375 kfree(ahp->work_digest);
376 ahp->work_digest = NULL;
378 if (ahp->tfm) {
379 crypto_free_tfm(ahp->tfm);
380 ahp->tfm = NULL;
385 static struct xfrm_type ah_type =
387 .description = "AH4",
388 .proto = IPPROTO_AH,
389 .init_state = ah_init_state,
390 .destructor = ah_destroy,
391 .input = ah_input,
392 .output = ah_output
395 static struct inet_protocol ah4_protocol = {
396 .handler = xfrm4_rcv,
397 .err_handler = ah4_err,
398 .no_policy = 1,
401 int __init ah4_init(void)
403 SET_MODULE_OWNER(&ah_type);
404 if (xfrm_register_type(&ah_type) < 0) {
405 printk(KERN_INFO "ip ah init: can't add xfrm type\n");
406 return -EAGAIN;
408 if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) {
409 printk(KERN_INFO "ip ah init: can't add protocol\n");
410 xfrm_unregister_type(&ah_type);
411 return -EAGAIN;
413 return 0;
416 static void __exit ah4_fini(void)
418 if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0)
419 printk(KERN_INFO "ip ah close: can't remove protocol\n");
420 if (xfrm_unregister_type(&ah_type) < 0)
421 printk(KERN_INFO "ip ah close: can't remove xfrm type\n");
424 module_init(ah4_init);
425 module_exit(ah4_fini);
426 MODULE_LICENSE("GPL");