1/*
2 * xfrm6_policy.c: based on xfrm4_policy.c
3 *
4 * Authors:
5 *	Mitsuru KANDA @USAGI
6 *	Kazunori MIYAZAWA @USAGI
7 *	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
8 *		IPv6 support
9 *	YOSHIFUJI Hideaki
10 *		Split up af-specific portion
11 *
12 */
13
14#include <linux/err.h>
15#include <linux/kernel.h>
16#include <linux/netdevice.h>
17#include <net/addrconf.h>
18#include <net/dst.h>
19#include <net/xfrm.h>
20#include <net/ip.h>
21#include <net/ipv6.h>
22#include <net/ip6_route.h>
23#if IS_ENABLED(CONFIG_IPV6_MIP6)
24#include <net/mip6.h>
25#endif
26
27static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
28
29static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos,
30					  const xfrm_address_t *saddr,
31					  const xfrm_address_t *daddr)
32{
33	struct flowi6 fl6;
34	struct dst_entry *dst;
35	int err;
36
37	memset(&fl6, 0, sizeof(fl6));
38	memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr));
39	if (saddr)
40		memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr));
41
42	dst = ip6_route_output(net, NULL, &fl6);
43
44	err = dst->error;
45	if (dst->error) {
46		dst_release(dst);
47		dst = ERR_PTR(err);
48	}
49
50	return dst;
51}
52
53static int xfrm6_get_saddr(struct net *net,
54			   xfrm_address_t *saddr, xfrm_address_t *daddr)
55{
56	struct dst_entry *dst;
57	struct net_device *dev;
58
59	dst = xfrm6_dst_lookup(net, 0, NULL, daddr);
60	if (IS_ERR(dst))
61		return -EHOSTUNREACH;
62
63	dev = ip6_dst_idev(dst)->dev;
64	ipv6_dev_get_saddr(dev_net(dev), dev, &daddr->in6, 0, &saddr->in6);
65	dst_release(dst);
66	return 0;
67}
68
69static int xfrm6_get_tos(const struct flowi *fl)
70{
71	return 0;
72}
73
74static void xfrm6_init_dst(struct net *net, struct xfrm_dst *xdst)
75{
76	struct rt6_info *rt = (struct rt6_info *)xdst;
77
78	rt6_init_peer(rt, net->ipv6.peers);
79}
80
81static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst,
82			   int nfheader_len)
83{
84	if (dst->ops->family == AF_INET6) {
85		struct rt6_info *rt = (struct rt6_info *)dst;
86		if (rt->rt6i_node)
87			path->path_cookie = rt->rt6i_node->fn_sernum;
88	}
89
90	path->u.rt6.rt6i_nfheader_len = nfheader_len;
91
92	return 0;
93}
94
95static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
96			  const struct flowi *fl)
97{
98	struct rt6_info *rt = (struct rt6_info *)xdst->route;
99
100	xdst->u.dst.dev = dev;
101	dev_hold(dev);
102
103	xdst->u.rt6.rt6i_idev = in6_dev_get(dev);
104	if (!xdst->u.rt6.rt6i_idev) {
105		dev_put(dev);
106		return -ENODEV;
107	}
108
109	rt6_transfer_peer(&xdst->u.rt6, rt);
110
111	/* Sheit... I remember I did this right. Apparently,
112	 * it was magically lost, so this code needs audit */
113	xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
114						   RTF_LOCAL);
115	xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
116	xdst->u.rt6.rt6i_node = rt->rt6i_node;
117	if (rt->rt6i_node)
118		xdst->route_cookie = rt->rt6i_node->fn_sernum;
119	xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
120	xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
121	xdst->u.rt6.rt6i_src = rt->rt6i_src;
122
123	return 0;
124}
125
126static inline void
127_decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
128{
129	struct flowi6 *fl6 = &fl->u.ip6;
130	int onlyproto = 0;
131	const struct ipv6hdr *hdr = ipv6_hdr(skb);
132	u16 offset = sizeof(*hdr);
133	struct ipv6_opt_hdr *exthdr;
134	const unsigned char *nh = skb_network_header(skb);
135	u16 nhoff = IP6CB(skb)->nhoff;
136	int oif = 0;
137	u8 nexthdr;
138
139	if (!nhoff)
140		nhoff = offsetof(struct ipv6hdr, nexthdr);
141
142	nexthdr = nh[nhoff];
143
144	if (skb_dst(skb))
145		oif = skb_dst(skb)->dev->ifindex;
146
147	memset(fl6, 0, sizeof(struct flowi6));
148	fl6->flowi6_mark = skb->mark;
149	fl6->flowi6_oif = reverse ? skb->skb_iif : oif;
150
151	fl6->daddr = reverse ? hdr->saddr : hdr->daddr;
152	fl6->saddr = reverse ? hdr->daddr : hdr->saddr;
153
154	while (nh + offset + 1 < skb->data ||
155	       pskb_may_pull(skb, nh + offset + 1 - skb->data)) {
156		nh = skb_network_header(skb);
157		exthdr = (struct ipv6_opt_hdr *)(nh + offset);
158
159		switch (nexthdr) {
160		case NEXTHDR_FRAGMENT:
161			onlyproto = 1;
162		case NEXTHDR_ROUTING:
163		case NEXTHDR_HOP:
164		case NEXTHDR_DEST:
165			offset += ipv6_optlen(exthdr);
166			nexthdr = exthdr->nexthdr;
167			exthdr = (struct ipv6_opt_hdr *)(nh + offset);
168			break;
169
170		case IPPROTO_UDP:
171		case IPPROTO_UDPLITE:
172		case IPPROTO_TCP:
173		case IPPROTO_SCTP:
174		case IPPROTO_DCCP:
175			if (!onlyproto && (nh + offset + 4 < skb->data ||
176			     pskb_may_pull(skb, nh + offset + 4 - skb->data))) {
177				__be16 *ports;
178
179				nh = skb_network_header(skb);
180				ports = (__be16 *)(nh + offset);
181				fl6->fl6_sport = ports[!!reverse];
182				fl6->fl6_dport = ports[!reverse];
183			}
184			fl6->flowi6_proto = nexthdr;
185			return;
186
187		case IPPROTO_ICMPV6:
188			if (!onlyproto && pskb_may_pull(skb, nh + offset + 2 - skb->data)) {
189				u8 *icmp;
190
191				nh = skb_network_header(skb);
192				icmp = (u8 *)(nh + offset);
193				fl6->fl6_icmp_type = icmp[0];
194				fl6->fl6_icmp_code = icmp[1];
195			}
196			fl6->flowi6_proto = nexthdr;
197			return;
198
199#if IS_ENABLED(CONFIG_IPV6_MIP6)
200		case IPPROTO_MH:
201			offset += ipv6_optlen(exthdr);
202			if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
203				struct ip6_mh *mh;
204
205				nh = skb_network_header(skb);
206				mh = (struct ip6_mh *)(nh + offset);
207				fl6->fl6_mh_type = mh->ip6mh_type;
208			}
209			fl6->flowi6_proto = nexthdr;
210			return;
211#endif
212
213		/* XXX Why are there these headers? */
214		case IPPROTO_AH:
215		case IPPROTO_ESP:
216		case IPPROTO_COMP:
217		default:
218			fl6->fl6_ipsec_spi = 0;
219			fl6->flowi6_proto = nexthdr;
220			return;
221		}
222	}
223}
224
225static inline int xfrm6_garbage_collect(struct dst_ops *ops)
226{
227	struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops);
228
229	xfrm6_policy_afinfo.garbage_collect(net);
230	return dst_entries_get_fast(ops) > ops->gc_thresh * 2;
231}
232
233static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk,
234			      struct sk_buff *skb, u32 mtu)
235{
236	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
237	struct dst_entry *path = xdst->route;
238
239	path->ops->update_pmtu(path, sk, skb, mtu);
240}
241
242static void xfrm6_redirect(struct dst_entry *dst, struct sock *sk,
243			   struct sk_buff *skb)
244{
245	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
246	struct dst_entry *path = xdst->route;
247
248	path->ops->redirect(path, sk, skb);
249}
250
251static void xfrm6_dst_destroy(struct dst_entry *dst)
252{
253	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
254
255	if (likely(xdst->u.rt6.rt6i_idev))
256		in6_dev_put(xdst->u.rt6.rt6i_idev);
257	dst_destroy_metrics_generic(dst);
258	if (rt6_has_peer(&xdst->u.rt6)) {
259		struct inet_peer *peer = rt6_peer_ptr(&xdst->u.rt6);
260		inet_putpeer(peer);
261	}
262	xfrm_dst_destroy(xdst);
263}
264
265static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
266			     int unregister)
267{
268	struct xfrm_dst *xdst;
269
270	if (!unregister)
271		return;
272
273	xdst = (struct xfrm_dst *)dst;
274	if (xdst->u.rt6.rt6i_idev->dev == dev) {
275		struct inet6_dev *loopback_idev =
276			in6_dev_get(dev_net(dev)->loopback_dev);
277		BUG_ON(!loopback_idev);
278
279		do {
280			in6_dev_put(xdst->u.rt6.rt6i_idev);
281			xdst->u.rt6.rt6i_idev = loopback_idev;
282			in6_dev_hold(loopback_idev);
283			xdst = (struct xfrm_dst *)xdst->u.dst.child;
284		} while (xdst->u.dst.xfrm);
285
286		__in6_dev_put(loopback_idev);
287	}
288
289	xfrm_dst_ifdown(dst, dev);
290}
291
292static struct dst_ops xfrm6_dst_ops_template = {
293	.family =		AF_INET6,
294	.gc =			xfrm6_garbage_collect,
295	.update_pmtu =		xfrm6_update_pmtu,
296	.redirect =		xfrm6_redirect,
297	.cow_metrics =		dst_cow_metrics_generic,
298	.destroy =		xfrm6_dst_destroy,
299	.ifdown =		xfrm6_dst_ifdown,
300	.local_out =		__ip6_local_out,
301	.gc_thresh =		32768,
302};
303
304static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
305	.family =		AF_INET6,
306	.dst_ops =		&xfrm6_dst_ops_template,
307	.dst_lookup =		xfrm6_dst_lookup,
308	.get_saddr =		xfrm6_get_saddr,
309	.decode_session =	_decode_session6,
310	.get_tos =		xfrm6_get_tos,
311	.init_dst =		xfrm6_init_dst,
312	.init_path =		xfrm6_init_path,
313	.fill_dst =		xfrm6_fill_dst,
314	.blackhole_route =	ip6_blackhole_route,
315};
316
317static int __init xfrm6_policy_init(void)
318{
319	return xfrm_policy_register_afinfo(&xfrm6_policy_afinfo);
320}
321
322static void xfrm6_policy_fini(void)
323{
324	xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo);
325}
326
327#ifdef CONFIG_SYSCTL
328static struct ctl_table xfrm6_policy_table[] = {
329	{
330		.procname       = "xfrm6_gc_thresh",
331		.data		= &init_net.xfrm.xfrm6_dst_ops.gc_thresh,
332		.maxlen		= sizeof(int),
333		.mode		= 0644,
334		.proc_handler   = proc_dointvec,
335	},
336	{ }
337};
338
339static int __net_init xfrm6_net_sysctl_init(struct net *net)
340{
341	struct ctl_table *table;
342	struct ctl_table_header *hdr;
343
344	table = xfrm6_policy_table;
345	if (!net_eq(net, &init_net)) {
346		table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL);
347		if (!table)
348			goto err_alloc;
349
350		table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh;
351	}
352
353	hdr = register_net_sysctl(net, "net/ipv6", table);
354	if (!hdr)
355		goto err_reg;
356
357	net->ipv6.sysctl.xfrm6_hdr = hdr;
358	return 0;
359
360err_reg:
361	if (!net_eq(net, &init_net))
362		kfree(table);
363err_alloc:
364	return -ENOMEM;
365}
366
367static void __net_exit xfrm6_net_sysctl_exit(struct net *net)
368{
369	struct ctl_table *table;
370
371	if (!net->ipv6.sysctl.xfrm6_hdr)
372		return;
373
374	table = net->ipv6.sysctl.xfrm6_hdr->ctl_table_arg;
375	unregister_net_sysctl_table(net->ipv6.sysctl.xfrm6_hdr);
376	if (!net_eq(net, &init_net))
377		kfree(table);
378}
379#else /* CONFIG_SYSCTL */
380static int inline xfrm6_net_sysctl_init(struct net *net)
381{
382	return 0;
383}
384
385static void inline xfrm6_net_sysctl_exit(struct net *net)
386{
387}
388#endif
389
390static int __net_init xfrm6_net_init(struct net *net)
391{
392	int ret;
393
394	memcpy(&net->xfrm.xfrm6_dst_ops, &xfrm6_dst_ops_template,
395	       sizeof(xfrm6_dst_ops_template));
396	ret = dst_entries_init(&net->xfrm.xfrm6_dst_ops);
397	if (ret)
398		return ret;
399
400	ret = xfrm6_net_sysctl_init(net);
401	if (ret)
402		dst_entries_destroy(&net->xfrm.xfrm6_dst_ops);
403
404	return ret;
405}
406
407static void __net_exit xfrm6_net_exit(struct net *net)
408{
409	xfrm6_net_sysctl_exit(net);
410	dst_entries_destroy(&net->xfrm.xfrm6_dst_ops);
411}
412
413static struct pernet_operations xfrm6_net_ops = {
414	.init	= xfrm6_net_init,
415	.exit	= xfrm6_net_exit,
416};
417
418int __init xfrm6_init(void)
419{
420	int ret;
421
422	ret = xfrm6_policy_init();
423	if (ret)
424		goto out;
425	ret = xfrm6_state_init();
426	if (ret)
427		goto out_policy;
428
429	ret = xfrm6_protocol_init();
430	if (ret)
431		goto out_state;
432
433	register_pernet_subsys(&xfrm6_net_ops);
434out:
435	return ret;
436out_state:
437	xfrm6_state_fini();
438out_policy:
439	xfrm6_policy_fini();
440	goto out;
441}
442
443void xfrm6_fini(void)
444{
445	unregister_pernet_subsys(&xfrm6_net_ops);
446	xfrm6_protocol_fini();
447	xfrm6_policy_fini();
448	xfrm6_state_fini();
449}
450