diff options
Diffstat (limited to 'net/ipv4/xfrm4_mode_beet.c')
-rw-r--r-- | net/ipv4/xfrm4_mode_beet.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c new file mode 100644 index 000000000000..89cf59ea7bbe --- /dev/null +++ b/net/ipv4/xfrm4_mode_beet.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4. | ||
3 | * | ||
4 | * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com> | ||
5 | * Miika Komu <miika@iki.fi> | ||
6 | * Herbert Xu <herbert@gondor.apana.org.au> | ||
7 | * Abhinav Pathak <abhinav.pathak@hiit.fi> | ||
8 | * Jeff Ahrenholz <ahrenholz@gmail.com> | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/stringify.h> | ||
16 | #include <net/dst.h> | ||
17 | #include <net/ip.h> | ||
18 | #include <net/xfrm.h> | ||
19 | |||
20 | /* Add encapsulation header. | ||
21 | * | ||
22 | * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | ||
23 | * The following fields in it shall be filled in by x->type->output: | ||
24 | * tot_len | ||
25 | * check | ||
26 | * | ||
27 | * On exit, skb->h will be set to the start of the payload to be processed | ||
28 | * by x->type->output and skb->nh will be set to the top IP header. | ||
29 | */ | ||
30 | static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) | ||
31 | { | ||
32 | struct iphdr *iph, *top_iph = NULL; | ||
33 | int hdrlen, optlen; | ||
34 | |||
35 | iph = skb->nh.iph; | ||
36 | skb->h.ipiph = iph; | ||
37 | |||
38 | hdrlen = 0; | ||
39 | optlen = iph->ihl * 4 - sizeof(*iph); | ||
40 | if (unlikely(optlen)) | ||
41 | hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); | ||
42 | |||
43 | skb->nh.raw = skb_push(skb, x->props.header_len + hdrlen); | ||
44 | top_iph = skb->nh.iph; | ||
45 | hdrlen = iph->ihl * 4 - optlen; | ||
46 | skb->h.raw += hdrlen; | ||
47 | |||
48 | memmove(top_iph, iph, hdrlen); | ||
49 | if (unlikely(optlen)) { | ||
50 | struct ip_beet_phdr *ph; | ||
51 | |||
52 | BUG_ON(optlen < 0); | ||
53 | |||
54 | ph = (struct ip_beet_phdr *)skb->h.raw; | ||
55 | ph->padlen = 4 - (optlen & 4); | ||
56 | ph->hdrlen = (optlen + ph->padlen + sizeof(*ph)) / 8; | ||
57 | ph->nexthdr = top_iph->protocol; | ||
58 | |||
59 | top_iph->protocol = IPPROTO_BEETPH; | ||
60 | top_iph->ihl = sizeof(struct iphdr) / 4; | ||
61 | } | ||
62 | |||
63 | top_iph->saddr = x->props.saddr.a4; | ||
64 | top_iph->daddr = x->id.daddr.a4; | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb) | ||
70 | { | ||
71 | struct iphdr *iph = skb->nh.iph; | ||
72 | int phlen = 0; | ||
73 | int optlen = 0; | ||
74 | __u8 ph_nexthdr = 0, protocol = 0; | ||
75 | int err = -EINVAL; | ||
76 | |||
77 | protocol = iph->protocol; | ||
78 | |||
79 | if (unlikely(iph->protocol == IPPROTO_BEETPH)) { | ||
80 | struct ip_beet_phdr *ph = (struct ip_beet_phdr*)(iph + 1); | ||
81 | |||
82 | if (!pskb_may_pull(skb, sizeof(*ph))) | ||
83 | goto out; | ||
84 | |||
85 | phlen = ph->hdrlen * 8; | ||
86 | optlen = phlen - ph->padlen - sizeof(*ph); | ||
87 | if (optlen < 0 || optlen & 3 || optlen > 250) | ||
88 | goto out; | ||
89 | |||
90 | if (!pskb_may_pull(skb, phlen)) | ||
91 | goto out; | ||
92 | |||
93 | ph_nexthdr = ph->nexthdr; | ||
94 | } | ||
95 | |||
96 | skb_push(skb, sizeof(*iph) - phlen + optlen); | ||
97 | memmove(skb->data, skb->nh.raw, sizeof(*iph)); | ||
98 | skb->nh.raw = skb->data; | ||
99 | |||
100 | iph = skb->nh.iph; | ||
101 | iph->ihl = (sizeof(*iph) + optlen) / 4; | ||
102 | iph->tot_len = htons(skb->len); | ||
103 | iph->daddr = x->sel.daddr.a4; | ||
104 | iph->saddr = x->sel.saddr.a4; | ||
105 | if (ph_nexthdr) | ||
106 | iph->protocol = ph_nexthdr; | ||
107 | else | ||
108 | iph->protocol = protocol; | ||
109 | iph->check = 0; | ||
110 | iph->check = ip_fast_csum(skb->nh.raw, iph->ihl); | ||
111 | err = 0; | ||
112 | out: | ||
113 | return err; | ||
114 | } | ||
115 | |||
116 | static struct xfrm_mode xfrm4_beet_mode = { | ||
117 | .input = xfrm4_beet_input, | ||
118 | .output = xfrm4_beet_output, | ||
119 | .owner = THIS_MODULE, | ||
120 | .encap = XFRM_MODE_BEET, | ||
121 | }; | ||
122 | |||
123 | static int __init xfrm4_beet_init(void) | ||
124 | { | ||
125 | return xfrm_register_mode(&xfrm4_beet_mode, AF_INET); | ||
126 | } | ||
127 | |||
128 | static void __exit xfrm4_beet_exit(void) | ||
129 | { | ||
130 | int err; | ||
131 | |||
132 | err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET); | ||
133 | BUG_ON(err); | ||
134 | } | ||
135 | |||
136 | module_init(xfrm4_beet_init); | ||
137 | module_exit(xfrm4_beet_exit); | ||
138 | MODULE_LICENSE("GPL"); | ||
139 | MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET); | ||