xref: /openbmc/linux/net/ipv6/xfrm6_state.c (revision a1e58bbd)
1 /*
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 <linux/netfilter_ipv6.h>
18 #include <net/dsfield.h>
19 #include <net/ipv6.h>
20 #include <net/addrconf.h>
21 
22 static struct xfrm_state_afinfo xfrm6_state_afinfo;
23 
24 static void
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)
28 {
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;
41 	x->id = tmpl->id;
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;
50 }
51 
52 static int
53 __xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
54 {
55 	int i;
56 	int j = 0;
57 
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) {
62 			dst[j++] = src[i];
63 			src[i] = NULL;
64 		}
65 	}
66 	if (j == n)
67 		goto end;
68 
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++) {
72 		if (src[i] &&
73 		    (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION ||
74 		     src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) {
75 			dst[j++] = src[i];
76 			src[i] = NULL;
77 		}
78 	}
79 	if (j == n)
80 		goto end;
81 #endif
82 
83 	/* Rule 3: select IPsec transport AH */
84 	for (i = 0; i < n; i++) {
85 		if (src[i] &&
86 		    src[i]->props.mode == XFRM_MODE_TRANSPORT &&
87 		    src[i]->id.proto == IPPROTO_AH) {
88 			dst[j++] = src[i];
89 			src[i] = NULL;
90 		}
91 	}
92 	if (j == n)
93 		goto end;
94 
95 	/* Rule 4: select IPsec tunnel */
96 	for (i = 0; i < n; i++) {
97 		if (src[i] &&
98 		    (src[i]->props.mode == XFRM_MODE_TUNNEL ||
99 		     src[i]->props.mode == XFRM_MODE_BEET)) {
100 			dst[j++] = src[i];
101 			src[i] = NULL;
102 		}
103 	}
104 	if (likely(j == n))
105 		goto end;
106 
107 	/* Final rule */
108 	for (i = 0; i < n; i++) {
109 		if (src[i]) {
110 			dst[j++] = src[i];
111 			src[i] = NULL;
112 		}
113 	}
114 
115  end:
116 	return 0;
117 }
118 
119 static int
120 __xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
121 {
122 	int i;
123 	int j = 0;
124 
125 	/* Rule 1: select IPsec transport */
126 	for (i = 0; i < n; i++) {
127 		if (src[i]->mode == XFRM_MODE_TRANSPORT) {
128 			dst[j++] = src[i];
129 			src[i] = NULL;
130 		}
131 	}
132 	if (j == n)
133 		goto end;
134 
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++) {
138 		if (src[i] &&
139 		    (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION ||
140 		     src[i]->mode == XFRM_MODE_IN_TRIGGER)) {
141 			dst[j++] = src[i];
142 			src[i] = NULL;
143 		}
144 	}
145 	if (j == n)
146 		goto end;
147 #endif
148 
149 	/* Rule 3: select IPsec tunnel */
150 	for (i = 0; i < n; i++) {
151 		if (src[i] &&
152 		    (src[i]->mode == XFRM_MODE_TUNNEL ||
153 		     src[i]->mode == XFRM_MODE_BEET)) {
154 			dst[j++] = src[i];
155 			src[i] = NULL;
156 		}
157 	}
158 	if (likely(j == n))
159 		goto end;
160 
161 	/* Final rule */
162 	for (i = 0; i < n; i++) {
163 		if (src[i]) {
164 			dst[j++] = src[i];
165 			src[i] = NULL;
166 		}
167 	}
168 
169  end:
170 	return 0;
171 }
172 
173 int xfrm6_extract_header(struct sk_buff *skb)
174 {
175 	struct ipv6hdr *iph = ipv6_hdr(skb);
176 
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));
185 
186 	return 0;
187 }
188 
189 static struct xfrm_state_afinfo xfrm6_state_afinfo = {
190 	.family			= AF_INET6,
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,
201 };
202 
203 int __init xfrm6_state_init(void)
204 {
205 	return xfrm_state_register_afinfo(&xfrm6_state_afinfo);
206 }
207 
208 void xfrm6_state_fini(void)
209 {
210 	xfrm_state_unregister_afinfo(&xfrm6_state_afinfo);
211 }
212 
213