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>
17 #include <linux/netfilter_ipv6.h>
18 #include <net/dsfield.h>
20 #include <net/addrconf.h>
22 static struct xfrm_state_afinfo xfrm6_state_afinfo
;
25 __xfrm6_init_tempsel(struct xfrm_state
*x
, struct flowi
*fl
,
26 struct xfrm_tmpl
*tmpl
,
27 xfrm_address_t
*daddr
, xfrm_address_t
*saddr
)
29 /* Initialize temporary selector matching only
30 * to current session. */
31 ipv6_addr_copy((struct in6_addr
*)&x
->sel
.daddr
, &fl
->fl6_dst
);
32 ipv6_addr_copy((struct in6_addr
*)&x
->sel
.saddr
, &fl
->fl6_src
);
33 x
->sel
.dport
= xfrm_flowi_dport(fl
);
34 x
->sel
.dport_mask
= htons(0xffff);
35 x
->sel
.sport
= xfrm_flowi_sport(fl
);
36 x
->sel
.sport_mask
= htons(0xffff);
37 x
->sel
.prefixlen_d
= 128;
38 x
->sel
.prefixlen_s
= 128;
39 x
->sel
.proto
= fl
->proto
;
40 x
->sel
.ifindex
= fl
->oif
;
42 if (ipv6_addr_any((struct in6_addr
*)&x
->id
.daddr
))
43 memcpy(&x
->id
.daddr
, daddr
, sizeof(x
->sel
.daddr
));
44 memcpy(&x
->props
.saddr
, &tmpl
->saddr
, sizeof(x
->props
.saddr
));
45 if (ipv6_addr_any((struct in6_addr
*)&x
->props
.saddr
))
46 memcpy(&x
->props
.saddr
, saddr
, sizeof(x
->props
.saddr
));
47 x
->props
.mode
= tmpl
->mode
;
48 x
->props
.reqid
= tmpl
->reqid
;
49 x
->props
.family
= AF_INET6
;
53 __xfrm6_state_sort(struct xfrm_state
**dst
, struct xfrm_state
**src
, int n
)
58 /* Rule 1: select IPsec transport except AH */
59 for (i
= 0; i
< n
; i
++) {
60 if (src
[i
]->props
.mode
== XFRM_MODE_TRANSPORT
&&
61 src
[i
]->id
.proto
!= IPPROTO_AH
) {
69 /* Rule 2: select MIPv6 RO or inbound trigger */
70 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
71 for (i
= 0; i
< n
; i
++) {
73 (src
[i
]->props
.mode
== XFRM_MODE_ROUTEOPTIMIZATION
||
74 src
[i
]->props
.mode
== XFRM_MODE_IN_TRIGGER
)) {
83 /* Rule 3: select IPsec transport AH */
84 for (i
= 0; i
< n
; i
++) {
86 src
[i
]->props
.mode
== XFRM_MODE_TRANSPORT
&&
87 src
[i
]->id
.proto
== IPPROTO_AH
) {
95 /* Rule 4: select IPsec tunnel */
96 for (i
= 0; i
< n
; i
++) {
98 (src
[i
]->props
.mode
== XFRM_MODE_TUNNEL
||
99 src
[i
]->props
.mode
== XFRM_MODE_BEET
)) {
108 for (i
= 0; i
< n
; i
++) {
120 __xfrm6_tmpl_sort(struct xfrm_tmpl
**dst
, struct xfrm_tmpl
**src
, int n
)
125 /* Rule 1: select IPsec transport */
126 for (i
= 0; i
< n
; i
++) {
127 if (src
[i
]->mode
== XFRM_MODE_TRANSPORT
) {
135 /* Rule 2: select MIPv6 RO or inbound trigger */
136 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
137 for (i
= 0; i
< n
; i
++) {
139 (src
[i
]->mode
== XFRM_MODE_ROUTEOPTIMIZATION
||
140 src
[i
]->mode
== XFRM_MODE_IN_TRIGGER
)) {
149 /* Rule 3: select IPsec tunnel */
150 for (i
= 0; i
< n
; i
++) {
152 (src
[i
]->mode
== XFRM_MODE_TUNNEL
||
153 src
[i
]->mode
== XFRM_MODE_BEET
)) {
162 for (i
= 0; i
< n
; i
++) {
173 int xfrm6_extract_header(struct sk_buff
*skb
)
175 struct ipv6hdr
*iph
= ipv6_hdr(skb
);
177 XFRM_MODE_SKB_CB(skb
)->ihl
= sizeof(*iph
);
178 XFRM_MODE_SKB_CB(skb
)->id
= 0;
179 XFRM_MODE_SKB_CB(skb
)->frag_off
= htons(IP_DF
);
180 XFRM_MODE_SKB_CB(skb
)->tos
= ipv6_get_dsfield(iph
);
181 XFRM_MODE_SKB_CB(skb
)->ttl
= iph
->hop_limit
;
182 XFRM_MODE_SKB_CB(skb
)->optlen
= 0;
183 memcpy(XFRM_MODE_SKB_CB(skb
)->flow_lbl
, iph
->flow_lbl
,
184 sizeof(XFRM_MODE_SKB_CB(skb
)->flow_lbl
));
189 static struct xfrm_state_afinfo xfrm6_state_afinfo
= {
191 .proto
= IPPROTO_IPV6
,
192 .eth_proto
= htons(ETH_P_IPV6
),
193 .owner
= THIS_MODULE
,
194 .init_tempsel
= __xfrm6_init_tempsel
,
195 .tmpl_sort
= __xfrm6_tmpl_sort
,
196 .state_sort
= __xfrm6_state_sort
,
197 .output
= xfrm6_output
,
198 .extract_input
= xfrm6_extract_input
,
199 .extract_output
= xfrm6_extract_output
,
200 .transport_finish
= xfrm6_transport_finish
,
203 int __init
xfrm6_state_init(void)
205 return xfrm_state_register_afinfo(&xfrm6_state_afinfo
);
208 void xfrm6_state_fini(void)
210 xfrm_state_unregister_afinfo(&xfrm6_state_afinfo
);