2 * xfrm6_state.c: based on xfrm4_state.c
6 * Kazunori MIYAZAWA @USAGI
7 * Kunihiro Ishiguro <kunihiro@ipinfusion.com>
9 * YOSHIFUJI Hideaki @USAGI
10 * Split up af-specific portion
15 #include <linux/pfkeyv2.h>
16 #include <linux/ipsec.h>
18 #include <net/addrconf.h>
20 static struct xfrm_state_afinfo xfrm6_state_afinfo
;
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
)
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
;
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
));
45 if (tmpl
->mode
== XFRM_MODE_TUNNEL
&& ipv6_addr_any((struct in6_addr
*)&x
->props
.saddr
)) {
47 struct flowi fl_tunnel
= {
50 .daddr
= *(struct in6_addr
*)daddr
,
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
);
61 x
->props
.mode
= tmpl
->mode
;
62 x
->props
.reqid
= tmpl
->reqid
;
63 x
->props
.family
= AF_INET6
;
66 static struct xfrm_state
*
67 __xfrm6_state_lookup_byaddr(xfrm_address_t
*daddr
, xfrm_address_t
*saddr
,
70 struct xfrm_state
*x
= NULL
;
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
) {
86 static struct xfrm_state
*
87 __xfrm6_state_lookup(xfrm_address_t
*daddr
, u32 spi
, u8 proto
)
89 unsigned h
= __xfrm6_spi_hash(daddr
, spi
, proto
);
92 list_for_each_entry(x
, xfrm6_state_afinfo
.state_byspi
+h
, byspi
) {
93 if (x
->props
.family
== AF_INET6
&&
95 ipv6_addr_equal((struct in6_addr
*)daddr
, (struct in6_addr
*)x
->id
.daddr
.a6
) &&
96 proto
== x
->id
.proto
) {
104 static struct xfrm_state
*
105 __xfrm6_find_acq(u8 mode
, u32 reqid
, u8 proto
,
106 xfrm_address_t
*daddr
, xfrm_address_t
*saddr
,
109 struct xfrm_state
*x
, *x0
;
110 unsigned h
= __xfrm6_dst_hash(daddr
);
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
&&
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
;
145 x0
->timer
.expires
= jiffies
+ XFRM_ACQ_EXPIRES
*HZ
;
146 add_timer(&x0
->timer
);
148 list_add_tail(&x0
->bydst
, xfrm6_state_afinfo
.state_bydst
+h
);
149 h
= __xfrm6_src_hash(saddr
);
151 list_add_tail(&x0
->bysrc
, xfrm6_state_afinfo
.state_bysrc
+h
);
160 __xfrm6_state_sort(struct xfrm_state
**dst
, struct xfrm_state
**src
, int n
)
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
) {
176 /* Rule 2: select MIPv6 RO or inbound trigger */
177 #ifdef CONFIG_IPV6_MIP6
178 for (i
= 0; i
< n
; i
++) {
180 (src
[i
]->props
.mode
== XFRM_MODE_ROUTEOPTIMIZATION
||
181 src
[i
]->props
.mode
== XFRM_MODE_IN_TRIGGER
)) {
190 /* Rule 3: select IPsec transport AH */
191 for (i
= 0; i
< n
; i
++) {
193 src
[i
]->props
.mode
== XFRM_MODE_TRANSPORT
&&
194 src
[i
]->id
.proto
== IPPROTO_AH
) {
202 /* Rule 4: select IPsec tunnel */
203 for (i
= 0; i
< n
; i
++) {
205 src
[i
]->props
.mode
== XFRM_MODE_TUNNEL
) {
214 for (i
= 0; i
< n
; i
++) {
226 __xfrm6_tmpl_sort(struct xfrm_tmpl
**dst
, struct xfrm_tmpl
**src
, int n
)
231 /* Rule 1: select IPsec transport */
232 for (i
= 0; i
< n
; i
++) {
233 if (src
[i
]->mode
== XFRM_MODE_TRANSPORT
) {
241 /* Rule 2: select MIPv6 RO or inbound trigger */
242 #ifdef CONFIG_IPV6_MIP6
243 for (i
= 0; i
< n
; i
++) {
245 (src
[i
]->mode
== XFRM_MODE_ROUTEOPTIMIZATION
||
246 src
[i
]->mode
== XFRM_MODE_IN_TRIGGER
)) {
255 /* Rule 3: select IPsec tunnel */
256 for (i
= 0; i
< n
; i
++) {
258 src
[i
]->mode
== XFRM_MODE_TUNNEL
) {
267 for (i
= 0; i
< n
; i
++) {
278 static struct xfrm_state_afinfo xfrm6_state_afinfo
= {
280 .init_tempsel
= __xfrm6_init_tempsel
,
281 .state_lookup
= __xfrm6_state_lookup
,
282 .state_lookup_byaddr
= __xfrm6_state_lookup_byaddr
,
283 .find_acq
= __xfrm6_find_acq
,
284 .tmpl_sort
= __xfrm6_tmpl_sort
,
285 .state_sort
= __xfrm6_state_sort
,
288 void __init
xfrm6_state_init(void)
290 xfrm_state_register_afinfo(&xfrm6_state_afinfo
);
293 void xfrm6_state_fini(void)
295 xfrm_state_unregister_afinfo(&xfrm6_state_afinfo
);