blob: d88cd92c864e6d9cad400a4288e0beb88bfaa002 [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
Masahide NAKAMURA58c949d2006-08-23 22:51:02 -070066static int
67__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
68{
69 int i;
70 int j = 0;
71
72 /* Rule 1: select IPsec transport except AH */
73 for (i = 0; i < n; i++) {
74 if (src[i]->props.mode == XFRM_MODE_TRANSPORT &&
75 src[i]->id.proto != IPPROTO_AH) {
76 dst[j++] = src[i];
77 src[i] = NULL;
78 }
79 }
80 if (j == n)
81 goto end;
82
Masahide NAKAMURA64d9fdd2006-08-23 22:54:07 -070083 /* Rule 2: select MIPv6 RO or inbound trigger */
84#ifdef CONFIG_IPV6_MIP6
85 for (i = 0; i < n; i++) {
86 if (src[i] &&
87 (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION ||
88 src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) {
89 dst[j++] = src[i];
90 src[i] = NULL;
91 }
92 }
93 if (j == n)
94 goto end;
95#endif
Masahide NAKAMURA58c949d2006-08-23 22:51:02 -070096
97 /* Rule 3: select IPsec transport AH */
98 for (i = 0; i < n; i++) {
99 if (src[i] &&
100 src[i]->props.mode == XFRM_MODE_TRANSPORT &&
101 src[i]->id.proto == IPPROTO_AH) {
102 dst[j++] = src[i];
103 src[i] = NULL;
104 }
105 }
106 if (j == n)
107 goto end;
108
109 /* Rule 4: select IPsec tunnel */
110 for (i = 0; i < n; i++) {
111 if (src[i] &&
112 src[i]->props.mode == XFRM_MODE_TUNNEL) {
113 dst[j++] = src[i];
114 src[i] = NULL;
115 }
116 }
117 if (likely(j == n))
118 goto end;
119
120 /* Final rule */
121 for (i = 0; i < n; i++) {
122 if (src[i]) {
123 dst[j++] = src[i];
124 src[i] = NULL;
125 }
126 }
127
128 end:
129 return 0;
130}
131
132static int
133__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
134{
135 int i;
136 int j = 0;
137
138 /* Rule 1: select IPsec transport */
139 for (i = 0; i < n; i++) {
140 if (src[i]->mode == XFRM_MODE_TRANSPORT) {
141 dst[j++] = src[i];
142 src[i] = NULL;
143 }
144 }
145 if (j == n)
146 goto end;
147
Masahide NAKAMURA64d9fdd2006-08-23 22:54:07 -0700148 /* Rule 2: select MIPv6 RO or inbound trigger */
149#ifdef CONFIG_IPV6_MIP6
150 for (i = 0; i < n; i++) {
151 if (src[i] &&
152 (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION ||
153 src[i]->mode == XFRM_MODE_IN_TRIGGER)) {
154 dst[j++] = src[i];
155 src[i] = NULL;
156 }
157 }
158 if (j == n)
159 goto end;
160#endif
Masahide NAKAMURA58c949d2006-08-23 22:51:02 -0700161
162 /* Rule 3: select IPsec tunnel */
163 for (i = 0; i < n; i++) {
164 if (src[i] &&
165 src[i]->mode == XFRM_MODE_TUNNEL) {
166 dst[j++] = src[i];
167 src[i] = NULL;
168 }
169 }
170 if (likely(j == n))
171 goto end;
172
173 /* Final rule */
174 for (i = 0; i < n; i++) {
175 if (src[i]) {
176 dst[j++] = src[i];
177 src[i] = NULL;
178 }
179 }
180
181 end:
182 return 0;
183}
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static struct xfrm_state_afinfo xfrm6_state_afinfo = {
186 .family = AF_INET6,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 .init_tempsel = __xfrm6_init_tempsel,
Masahide NAKAMURA58c949d2006-08-23 22:51:02 -0700188 .tmpl_sort = __xfrm6_tmpl_sort,
189 .state_sort = __xfrm6_state_sort,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190};
191
192void __init xfrm6_state_init(void)
193{
194 xfrm_state_register_afinfo(&xfrm6_state_afinfo);
195}
196
197void xfrm6_state_fini(void)
198{
199 xfrm_state_unregister_afinfo(&xfrm6_state_afinfo);
200}
201