blob: 6269584e610e4367aae46f3e451eda10a632e3fe [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * xfrm6_state.c: based on xfrm4_state.c
3 *
4 * Authors:
5 * Mitsuru KANDA @USAGI
6 * Kazunori MIYAZAWA @USAGI
7 * Kunihiro Ishiguro <kunihiro@ipinfusion.com>
8 * IPv6 support
9 * YOSHIFUJI Hideaki @USAGI
10 * Split up af-specific portion
11 *
12 */
13
14#include <net/xfrm.h>
15#include <linux/pfkeyv2.h>
16#include <linux/ipsec.h>
17#include <net/ipv6.h>
Patrick McHardyee51b1b2006-01-13 14:34:36 -080018#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
20static struct xfrm_state_afinfo xfrm6_state_afinfo;
21
22static void
23__xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
24 struct xfrm_tmpl *tmpl,
25 xfrm_address_t *daddr, xfrm_address_t *saddr)
26{
27 /* Initialize temporary selector matching only
28 * to current session. */
29 ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
30 ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
31 x->sel.dport = xfrm_flowi_dport(fl);
32 x->sel.dport_mask = ~0;
33 x->sel.sport = xfrm_flowi_sport(fl);
34 x->sel.sport_mask = ~0;
35 x->sel.prefixlen_d = 128;
36 x->sel.prefixlen_s = 128;
37 x->sel.proto = fl->proto;
38 x->sel.ifindex = fl->oif;
39 x->id = tmpl->id;
40 if (ipv6_addr_any((struct in6_addr*)&x->id.daddr))
41 memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
42 memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
43 if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
44 memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
Masahide NAKAMURA7e49e6d2006-09-22 15:05:15 -070045 if (tmpl->mode == XFRM_MODE_TUNNEL && ipv6_addr_any((struct in6_addr*)&x->props.saddr)) {
Patrick McHardyee51b1b2006-01-13 14:34:36 -080046 struct rt6_info *rt;
47 struct flowi fl_tunnel = {
48 .nl_u = {
49 .ip6_u = {
50 .daddr = *(struct in6_addr *)daddr,
51 }
52 }
53 };
54 if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
55 &fl_tunnel, AF_INET6)) {
56 ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr,
57 (struct in6_addr *)&x->props.saddr);
58 dst_release(&rt->u.dst);
59 }
60 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 x->props.mode = tmpl->mode;
62 x->props.reqid = tmpl->reqid;
63 x->props.family = AF_INET6;
64}
65
66static struct xfrm_state *
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -070067__xfrm6_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr,
68 u8 proto)
69{
70 struct xfrm_state *x = NULL;
71 unsigned h;
72
73 h = __xfrm6_src_hash(saddr);
74 list_for_each_entry(x, xfrm6_state_afinfo.state_bysrc+h, bysrc) {
75 if (x->props.family == AF_INET6 &&
76 ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
77 ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6) &&
78 proto == x->id.proto) {
79 xfrm_state_hold(x);
80 return x;
81 }
82 }
83 return NULL;
84}
85
86static struct xfrm_state *
Linus Torvalds1da177e2005-04-16 15:20:36 -070087__xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto)
88{
89 unsigned h = __xfrm6_spi_hash(daddr, spi, proto);
90 struct xfrm_state *x;
91
92 list_for_each_entry(x, xfrm6_state_afinfo.state_byspi+h, byspi) {
93 if (x->props.family == AF_INET6 &&
94 spi == x->id.spi &&
95 ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
96 proto == x->id.proto) {
97 xfrm_state_hold(x);
98 return x;
99 }
100 }
101 return NULL;
102}
103
104static struct xfrm_state *
105__xfrm6_find_acq(u8 mode, u32 reqid, u8 proto,
106 xfrm_address_t *daddr, xfrm_address_t *saddr,
107 int create)
108{
109 struct xfrm_state *x, *x0;
110 unsigned h = __xfrm6_dst_hash(daddr);
111
112 x0 = NULL;
113
114 list_for_each_entry(x, xfrm6_state_afinfo.state_bydst+h, bydst) {
115 if (x->props.family == AF_INET6 &&
116 ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
117 mode == x->props.mode &&
118 proto == x->id.proto &&
119 ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)x->props.saddr.a6) &&
120 reqid == x->props.reqid &&
121 x->km.state == XFRM_STATE_ACQ &&
122 !x->id.spi) {
123 x0 = x;
124 break;
125 }
126 }
127 if (!x0 && create && (x0 = xfrm_state_alloc()) != NULL) {
128 ipv6_addr_copy((struct in6_addr *)x0->sel.daddr.a6,
129 (struct in6_addr *)daddr);
130 ipv6_addr_copy((struct in6_addr *)x0->sel.saddr.a6,
131 (struct in6_addr *)saddr);
132 x0->sel.prefixlen_d = 128;
133 x0->sel.prefixlen_s = 128;
134 ipv6_addr_copy((struct in6_addr *)x0->props.saddr.a6,
135 (struct in6_addr *)saddr);
136 x0->km.state = XFRM_STATE_ACQ;
137 ipv6_addr_copy((struct in6_addr *)x0->id.daddr.a6,
138 (struct in6_addr *)daddr);
139 x0->id.proto = proto;
140 x0->props.family = AF_INET6;
141 x0->props.mode = mode;
142 x0->props.reqid = reqid;
143 x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
144 xfrm_state_hold(x0);
145 x0->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
146 add_timer(&x0->timer);
147 xfrm_state_hold(x0);
148 list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h);
Masahide NAKAMURA6c44e6b2006-08-23 17:53:57 -0700149 h = __xfrm6_src_hash(saddr);
150 xfrm_state_hold(x0);
151 list_add_tail(&x0->bysrc, xfrm6_state_afinfo.state_bysrc+h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 wake_up(&km_waitq);
153 }
154 if (x0)
155 xfrm_state_hold(x0);
156 return x0;
157}
158
Masahide NAKAMURA58c949d2006-08-23 22:51:02 -0700159static int
160__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
161{
162 int i;
163 int j = 0;
164
165 /* Rule 1: select IPsec transport except AH */
166 for (i = 0; i < n; i++) {
167 if (src[i]->props.mode == XFRM_MODE_TRANSPORT &&
168 src[i]->id.proto != IPPROTO_AH) {
169 dst[j++] = src[i];
170 src[i] = NULL;
171 }
172 }
173 if (j == n)
174 goto end;
175
Masahide NAKAMURA64d9fdd2006-08-23 22:54:07 -0700176 /* Rule 2: select MIPv6 RO or inbound trigger */
177#ifdef CONFIG_IPV6_MIP6
178 for (i = 0; i < n; i++) {
179 if (src[i] &&
180 (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION ||
181 src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) {
182 dst[j++] = src[i];
183 src[i] = NULL;
184 }
185 }
186 if (j == n)
187 goto end;
188#endif
Masahide NAKAMURA58c949d2006-08-23 22:51:02 -0700189
190 /* Rule 3: select IPsec transport AH */
191 for (i = 0; i < n; i++) {
192 if (src[i] &&
193 src[i]->props.mode == XFRM_MODE_TRANSPORT &&
194 src[i]->id.proto == IPPROTO_AH) {
195 dst[j++] = src[i];
196 src[i] = NULL;
197 }
198 }
199 if (j == n)
200 goto end;
201
202 /* Rule 4: select IPsec tunnel */
203 for (i = 0; i < n; i++) {
204 if (src[i] &&
205 src[i]->props.mode == XFRM_MODE_TUNNEL) {
206 dst[j++] = src[i];
207 src[i] = NULL;
208 }
209 }
210 if (likely(j == n))
211 goto end;
212
213 /* Final rule */
214 for (i = 0; i < n; i++) {
215 if (src[i]) {
216 dst[j++] = src[i];
217 src[i] = NULL;
218 }
219 }
220
221 end:
222 return 0;
223}
224
225static int
226__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
227{
228 int i;
229 int j = 0;
230
231 /* Rule 1: select IPsec transport */
232 for (i = 0; i < n; i++) {
233 if (src[i]->mode == XFRM_MODE_TRANSPORT) {
234 dst[j++] = src[i];
235 src[i] = NULL;
236 }
237 }
238 if (j == n)
239 goto end;
240
Masahide NAKAMURA64d9fdd2006-08-23 22:54:07 -0700241 /* Rule 2: select MIPv6 RO or inbound trigger */
242#ifdef CONFIG_IPV6_MIP6
243 for (i = 0; i < n; i++) {
244 if (src[i] &&
245 (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION ||
246 src[i]->mode == XFRM_MODE_IN_TRIGGER)) {
247 dst[j++] = src[i];
248 src[i] = NULL;
249 }
250 }
251 if (j == n)
252 goto end;
253#endif
Masahide NAKAMURA58c949d2006-08-23 22:51:02 -0700254
255 /* Rule 3: select IPsec tunnel */
256 for (i = 0; i < n; i++) {
257 if (src[i] &&
258 src[i]->mode == XFRM_MODE_TUNNEL) {
259 dst[j++] = src[i];
260 src[i] = NULL;
261 }
262 }
263 if (likely(j == n))
264 goto end;
265
266 /* Final rule */
267 for (i = 0; i < n; i++) {
268 if (src[i]) {
269 dst[j++] = src[i];
270 src[i] = NULL;
271 }
272 }
273
274 end:
275 return 0;
276}
277
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278static struct xfrm_state_afinfo xfrm6_state_afinfo = {
279 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 .init_tempsel = __xfrm6_init_tempsel,
281 .state_lookup = __xfrm6_state_lookup,
Masahide NAKAMURAeb2971b2006-08-23 17:56:04 -0700282 .state_lookup_byaddr = __xfrm6_state_lookup_byaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 .find_acq = __xfrm6_find_acq,
Masahide NAKAMURA58c949d2006-08-23 22:51:02 -0700284 .tmpl_sort = __xfrm6_tmpl_sort,
285 .state_sort = __xfrm6_state_sort,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286};
287
288void __init xfrm6_state_init(void)
289{
290 xfrm_state_register_afinfo(&xfrm6_state_afinfo);
291}
292
293void xfrm6_state_fini(void)
294{
295 xfrm_state_unregister_afinfo(&xfrm6_state_afinfo);
296}
297