1 // SPDX-License-Identifier: GPL-2.0
3 * xfrm6_state.c: based on xfrm4_state.c
7 * Kazunori MIYAZAWA @USAGI
8 * Kunihiro Ishiguro <kunihiro@ipinfusion.com>
10 * YOSHIFUJI Hideaki @USAGI
11 * Split up af-specific portion
16 #include <linux/pfkeyv2.h>
17 #include <linux/ipsec.h>
18 #include <linux/netfilter_ipv6.h>
19 #include <linux/export.h>
20 #include <net/dsfield.h>
22 #include <net/addrconf.h>
25 __xfrm6_init_tempsel(struct xfrm_selector
*sel
, const struct flowi
*fl
)
27 const struct flowi6
*fl6
= &fl
->u
.ip6
;
29 /* Initialize temporary selector matching only
30 * to current session. */
31 *(struct in6_addr
*)&sel
->daddr
= fl6
->daddr
;
32 *(struct in6_addr
*)&sel
->saddr
= fl6
->saddr
;
33 sel
->dport
= xfrm_flowi_dport(fl
, &fl6
->uli
);
34 sel
->dport_mask
= htons(0xffff);
35 sel
->sport
= xfrm_flowi_sport(fl
, &fl6
->uli
);
36 sel
->sport_mask
= htons(0xffff);
37 sel
->family
= AF_INET6
;
38 sel
->prefixlen_d
= 128;
39 sel
->prefixlen_s
= 128;
40 sel
->proto
= fl6
->flowi6_proto
;
41 sel
->ifindex
= fl6
->flowi6_oif
;
45 xfrm6_init_temprop(struct xfrm_state
*x
, const struct xfrm_tmpl
*tmpl
,
46 const xfrm_address_t
*daddr
, const xfrm_address_t
*saddr
)
49 if (ipv6_addr_any((struct in6_addr
*)&x
->id
.daddr
))
50 memcpy(&x
->id
.daddr
, daddr
, sizeof(x
->sel
.daddr
));
51 memcpy(&x
->props
.saddr
, &tmpl
->saddr
, sizeof(x
->props
.saddr
));
52 if (ipv6_addr_any((struct in6_addr
*)&x
->props
.saddr
))
53 memcpy(&x
->props
.saddr
, saddr
, sizeof(x
->props
.saddr
));
54 x
->props
.mode
= tmpl
->mode
;
55 x
->props
.reqid
= tmpl
->reqid
;
56 x
->props
.family
= AF_INET6
;
59 /* distribution counting sort function for xfrm_state and xfrm_tmpl */
61 __xfrm6_sort(void **dst
, void **src
, int n
, int (*cmp
)(void *p
), int maxclass
)
63 int count
[XFRM_MAX_DEPTH
] = { };
64 int class[XFRM_MAX_DEPTH
];
67 for (i
= 0; i
< n
; i
++) {
69 class[i
] = c
= cmp(src
[i
]);
73 for (i
= 2; i
< maxclass
; i
++)
74 count
[i
] += count
[i
- 1];
76 for (i
= 0; i
< n
; i
++) {
77 dst
[count
[class[i
] - 1]++] = src
[i
];
85 * Rule for xfrm_state:
87 * rule 1: select IPsec transport except AH
88 * rule 2: select MIPv6 RO or inbound trigger
89 * rule 3: select IPsec transport AH
90 * rule 4: select IPsec tunnel
93 static int __xfrm6_state_sort_cmp(void *p
)
95 struct xfrm_state
*v
= p
;
97 switch (v
->props
.mode
) {
98 case XFRM_MODE_TRANSPORT
:
99 if (v
->id
.proto
!= IPPROTO_AH
)
103 #if IS_ENABLED(CONFIG_IPV6_MIP6)
104 case XFRM_MODE_ROUTEOPTIMIZATION
:
105 case XFRM_MODE_IN_TRIGGER
:
108 case XFRM_MODE_TUNNEL
:
116 __xfrm6_state_sort(struct xfrm_state
**dst
, struct xfrm_state
**src
, int n
)
118 return __xfrm6_sort((void **)dst
, (void **)src
, n
,
119 __xfrm6_state_sort_cmp
, 6);
123 * Rule for xfrm_tmpl:
125 * rule 1: select IPsec transport
126 * rule 2: select MIPv6 RO or inbound trigger
127 * rule 3: select IPsec tunnel
130 static int __xfrm6_tmpl_sort_cmp(void *p
)
132 struct xfrm_tmpl
*v
= p
;
134 case XFRM_MODE_TRANSPORT
:
136 #if IS_ENABLED(CONFIG_IPV6_MIP6)
137 case XFRM_MODE_ROUTEOPTIMIZATION
:
138 case XFRM_MODE_IN_TRIGGER
:
141 case XFRM_MODE_TUNNEL
:
149 __xfrm6_tmpl_sort(struct xfrm_tmpl
**dst
, struct xfrm_tmpl
**src
, int n
)
151 return __xfrm6_sort((void **)dst
, (void **)src
, n
,
152 __xfrm6_tmpl_sort_cmp
, 5);
155 int xfrm6_extract_header(struct sk_buff
*skb
)
157 struct ipv6hdr
*iph
= ipv6_hdr(skb
);
159 XFRM_MODE_SKB_CB(skb
)->ihl
= sizeof(*iph
);
160 XFRM_MODE_SKB_CB(skb
)->id
= 0;
161 XFRM_MODE_SKB_CB(skb
)->frag_off
= htons(IP_DF
);
162 XFRM_MODE_SKB_CB(skb
)->tos
= ipv6_get_dsfield(iph
);
163 XFRM_MODE_SKB_CB(skb
)->ttl
= iph
->hop_limit
;
164 XFRM_MODE_SKB_CB(skb
)->optlen
= 0;
165 memcpy(XFRM_MODE_SKB_CB(skb
)->flow_lbl
, iph
->flow_lbl
,
166 sizeof(XFRM_MODE_SKB_CB(skb
)->flow_lbl
));
171 static struct xfrm_state_afinfo xfrm6_state_afinfo
= {
173 .proto
= IPPROTO_IPV6
,
174 .eth_proto
= htons(ETH_P_IPV6
),
175 .owner
= THIS_MODULE
,
176 .init_tempsel
= __xfrm6_init_tempsel
,
177 .init_temprop
= xfrm6_init_temprop
,
178 .tmpl_sort
= __xfrm6_tmpl_sort
,
179 .state_sort
= __xfrm6_state_sort
,
180 .output
= xfrm6_output
,
181 .output_finish
= xfrm6_output_finish
,
182 .extract_input
= xfrm6_extract_input
,
183 .extract_output
= xfrm6_extract_output
,
184 .transport_finish
= xfrm6_transport_finish
,
185 .local_error
= xfrm6_local_error
,
188 int __init
xfrm6_state_init(void)
190 return xfrm_state_register_afinfo(&xfrm6_state_afinfo
);
193 void xfrm6_state_fini(void)
195 xfrm_state_unregister_afinfo(&xfrm6_state_afinfo
);