Blame view

net/ipv6/xfrm6_policy.c 6.74 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   * xfrm6_policy.c: based on xfrm4_policy.c
   *
   * Authors:
   *	Mitsuru KANDA @USAGI
67ba4152e   Ian Morris   ipv6: White-space...
7
8
9
10
11
   *	Kazunori MIYAZAWA @USAGI
   *	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
   *		IPv6 support
   *	YOSHIFUJI Hideaki
   *		Split up af-specific portion
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
12
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
   */
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
14
15
  #include <linux/err.h>
  #include <linux/kernel.h>
aabc9761b   Herbert Xu   [IPSEC]: Store id...
16
17
  #include <linux/netdevice.h>
  #include <net/addrconf.h>
45ff5a3f9   Herbert Xu   [IPSEC]: Set dst-...
18
  #include <net/dst.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
  #include <net/xfrm.h>
  #include <net/ip.h>
  #include <net/ipv6.h>
  #include <net/ip6_route.h>
385add906   David Ahern   net: Replace vrf_...
23
  #include <net/l3mdev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24

42a7b32b7   David Ahern   xfrm: Add oif to ...
25
  static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif,
5e6b930f2   David S. Miller   xfrm: Const'ify a...
26
  					  const xfrm_address_t *saddr,
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
27
28
  					  const xfrm_address_t *daddr,
  					  u32 mark)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  {
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
30
  	struct flowi6 fl6;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
31
32
  	struct dst_entry *dst;
  	int err;
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
33
  	memset(&fl6, 0, sizeof(fl6));
11d7a0bb9   David Ahern   xfrm: Only add l3...
34
  	fl6.flowi6_oif = l3mdev_master_ifindex_by_index(net, oif);
4148987a5   David Ahern   net: Fix vti use ...
35
  	fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF;
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
36
  	fl6.flowi6_mark = mark;
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
37
  	memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr));
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
38
  	if (saddr)
7e1dc7b6f   David S. Miller   net: Use flowi4 a...
39
  		memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr));
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
40

4c9483b2f   David S. Miller   ipv6: Convert to ...
41
  	dst = ip6_route_output(net, NULL, &fl6);
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
42
43
44
  
  	err = dst->error;
  	if (dst->error) {
4251320fa   Ville Nuorvala   [IPV6]: Make sure...
45
  		dst_release(dst);
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
46
47
48
49
  		dst = ERR_PTR(err);
  	}
  
  	return dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  }
42a7b32b7   David Ahern   xfrm: Add oif to ...
51
  static int xfrm6_get_saddr(struct net *net, int oif,
077fbac40   Lorenzo Colitti   net: xfrm: suppor...
52
53
  			   xfrm_address_t *saddr, xfrm_address_t *daddr,
  			   u32 mark)
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
54
  {
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
55
  	struct dst_entry *dst;
191cd5825   Brian Haley   netns: Add networ...
56
  	struct net_device *dev;
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
57

077fbac40   Lorenzo Colitti   net: xfrm: suppor...
58
  	dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr, mark);
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
59
60
  	if (IS_ERR(dst))
  		return -EHOSTUNREACH;
191cd5825   Brian Haley   netns: Add networ...
61
  	dev = ip6_dst_idev(dst)->dev;
15e318bdc   Jiri Benc   xfrm: simplify xf...
62
  	ipv6_dev_get_saddr(dev_net(dev), dev, &daddr->in6, 0, &saddr->in6);
66cdb3ca2   Herbert Xu   [IPSEC]: Move flo...
63
64
  	dst_release(dst);
  	return 0;
a1e59abf8   Patrick McHardy   [XFRM]: Fix wildc...
65
  }
87c1e12b5   Herbert Xu   ipsec: Fix bogus ...
66
  static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
0c7b3eefb   David S. Miller   xfrm: Mark flowi ...
67
  			  const struct flowi *fl)
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
68
  {
67ba4152e   Ian Morris   ipv6: White-space...
69
  	struct rt6_info *rt = (struct rt6_info *)xdst->route;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
71
72
  	xdst->u.dst.dev = dev;
  	dev_hold(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73

bc8e4b954   Nicolas Dichtel   xfrm6: ensure to ...
74
  	xdst->u.rt6.rt6i_idev = in6_dev_get(dev);
84c4a9dfb   Cong Wang   xfrm6: release de...
75
76
  	if (!xdst->u.rt6.rt6i_idev) {
  		dev_put(dev);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
77
  		return -ENODEV;
84c4a9dfb   Cong Wang   xfrm6: release de...
78
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79

25ee3286d   Herbert Xu   [IPSEC]: Merge co...
80
81
82
83
  	/* Sheit... I remember I did this right. Apparently,
  	 * it was magically lost, so this code needs audit */
  	xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
  						   RTF_LOCAL);
b197df4f0   Martin KaFai Lau   ipv6: Add rt6_get...
84
  	xdst->route_cookie = rt6_get_cookie(rt);
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
85
86
87
  	xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
  	xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
  	xdst->u.rt6.rt6i_src = rt->rt6i_src;
510c321b5   Xin Long   xfrm: reuse uncac...
88
89
90
  	INIT_LIST_HEAD(&xdst->u.rt6.rt6i_uncached);
  	rt6_uncached_list_add(&xdst->u.rt6);
  	atomic_inc(&dev_net(dev)->ipv6.rt6_stats->fib_rt_uncache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  }
6700c2709   David S. Miller   net: Pass optiona...
94
  static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk,
bd085ef67   Hangbin Liu   net: add bool con...
95
96
  			      struct sk_buff *skb, u32 mtu,
  			      bool confirm_neigh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
  {
  	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
  	struct dst_entry *path = xdst->route;
bd085ef67   Hangbin Liu   net: add bool con...
100
  	path->ops->update_pmtu(path, sk, skb, mtu, confirm_neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  }
6700c2709   David S. Miller   net: Pass optiona...
102
103
  static void xfrm6_redirect(struct dst_entry *dst, struct sock *sk,
  			   struct sk_buff *skb)
ec18d9a26   David S. Miller   ipv6: Add redirec...
104
105
106
  {
  	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
  	struct dst_entry *path = xdst->route;
6700c2709   David S. Miller   net: Pass optiona...
107
  	path->ops->redirect(path, sk, skb);
ec18d9a26   David S. Miller   ipv6: Add redirec...
108
  }
aabc9761b   Herbert Xu   [IPSEC]: Store id...
109
110
111
112
113
114
  static void xfrm6_dst_destroy(struct dst_entry *dst)
  {
  	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
  
  	if (likely(xdst->u.rt6.rt6i_idev))
  		in6_dev_put(xdst->u.rt6.rt6i_idev);
62fa8a846   David S. Miller   net: Implement re...
115
  	dst_destroy_metrics_generic(dst);
510c321b5   Xin Long   xfrm: reuse uncac...
116
117
  	if (xdst->u.rt6.rt6i_uncached_list)
  		rt6_uncached_list_del(&xdst->u.rt6);
aabc9761b   Herbert Xu   [IPSEC]: Store id...
118
119
120
121
122
123
124
125
126
127
128
129
130
  	xfrm_dst_destroy(xdst);
  }
  
  static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
  			     int unregister)
  {
  	struct xfrm_dst *xdst;
  
  	if (!unregister)
  		return;
  
  	xdst = (struct xfrm_dst *)dst;
  	if (xdst->u.rt6.rt6i_idev->dev == dev) {
5a3e55d68   Denis V. Lunev   [NET]: Multiple n...
131
  		struct inet6_dev *loopback_idev =
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
132
  			in6_dev_get(dev_net(dev)->loopback_dev);
aabc9761b   Herbert Xu   [IPSEC]: Store id...
133
134
135
136
137
  
  		do {
  			in6_dev_put(xdst->u.rt6.rt6i_idev);
  			xdst->u.rt6.rt6i_idev = loopback_idev;
  			in6_dev_hold(loopback_idev);
b92cf4aab   David Miller   net: Create and u...
138
  			xdst = (struct xfrm_dst *)xfrm_dst_child(&xdst->u.dst);
aabc9761b   Herbert Xu   [IPSEC]: Store id...
139
140
141
142
143
144
145
  		} while (xdst->u.dst.xfrm);
  
  		__in6_dev_put(loopback_idev);
  	}
  
  	xfrm_dst_ifdown(dst, dev);
  }
a8a572a6b   Dan Streetman   xfrm: dst_entries...
146
  static struct dst_ops xfrm6_dst_ops_template = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  	.family =		AF_INET6,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  	.update_pmtu =		xfrm6_update_pmtu,
ec18d9a26   David S. Miller   ipv6: Add redirec...
149
  	.redirect =		xfrm6_redirect,
62fa8a846   David S. Miller   net: Implement re...
150
  	.cow_metrics =		dst_cow_metrics_generic,
aabc9761b   Herbert Xu   [IPSEC]: Store id...
151
152
  	.destroy =		xfrm6_dst_destroy,
  	.ifdown =		xfrm6_dst_ifdown,
862b82c6f   Herbert Xu   [IPSEC]: Merge mo...
153
  	.local_out =		__ip6_local_out,
3c2a89ddc   Florian Westphal   net: xfrm: revert...
154
  	.gc_thresh =		32768,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  };
37b103830   Florian Westphal   xfrm: policy: mak...
156
  static const struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
a8a572a6b   Dan Streetman   xfrm: dst_entries...
157
  	.dst_ops =		&xfrm6_dst_ops_template,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	.dst_lookup =		xfrm6_dst_lookup,
67ba4152e   Ian Morris   ipv6: White-space...
159
  	.get_saddr =		xfrm6_get_saddr,
25ee3286d   Herbert Xu   [IPSEC]: Merge co...
160
  	.fill_dst =		xfrm6_fill_dst,
2774c131b   David S. Miller   xfrm: Handle blac...
161
  	.blackhole_route =	ip6_blackhole_route,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  };
0013cabab   Daniel Lezcano   [IPV6]: Make xfrm...
163
  static int __init xfrm6_policy_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  {
a2817d8b2   Florian Westphal   xfrm: policy: rem...
165
  	return xfrm_policy_register_afinfo(&xfrm6_policy_afinfo, AF_INET6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
169
170
171
  }
  
  static void xfrm6_policy_fini(void)
  {
  	xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo);
  }
db71789c0   David S. Miller   xfrm6: Fix xfrm6_...
172
  #ifdef CONFIG_SYSCTL
a44a4a006   Neil Horman   xfrm: export xfrm...
173
174
  static struct ctl_table xfrm6_policy_table[] = {
  	{
a44a4a006   Neil Horman   xfrm: export xfrm...
175
  		.procname       = "xfrm6_gc_thresh",
67ba4152e   Ian Morris   ipv6: White-space...
176
177
178
  		.data		= &init_net.xfrm.xfrm6_dst_ops.gc_thresh,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
a44a4a006   Neil Horman   xfrm: export xfrm...
179
180
181
182
  		.proc_handler   = proc_dointvec,
  	},
  	{ }
  };
a8a572a6b   Dan Streetman   xfrm: dst_entries...
183
  static int __net_init xfrm6_net_sysctl_init(struct net *net)
8d068875c   Michal Kubecek   xfrm: make gc_thr...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  {
  	struct ctl_table *table;
  	struct ctl_table_header *hdr;
  
  	table = xfrm6_policy_table;
  	if (!net_eq(net, &init_net)) {
  		table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL);
  		if (!table)
  			goto err_alloc;
  
  		table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh;
  	}
  
  	hdr = register_net_sysctl(net, "net/ipv6", table);
  	if (!hdr)
  		goto err_reg;
  
  	net->ipv6.sysctl.xfrm6_hdr = hdr;
  	return 0;
  
  err_reg:
  	if (!net_eq(net, &init_net))
  		kfree(table);
  err_alloc:
  	return -ENOMEM;
  }
a8a572a6b   Dan Streetman   xfrm: dst_entries...
210
  static void __net_exit xfrm6_net_sysctl_exit(struct net *net)
8d068875c   Michal Kubecek   xfrm: make gc_thr...
211
212
  {
  	struct ctl_table *table;
63159f29b   Ian Morris   ipv6: coding styl...
213
  	if (!net->ipv6.sysctl.xfrm6_hdr)
8d068875c   Michal Kubecek   xfrm: make gc_thr...
214
215
216
217
218
219
220
  		return;
  
  	table = net->ipv6.sysctl.xfrm6_hdr->ctl_table_arg;
  	unregister_net_sysctl_table(net->ipv6.sysctl.xfrm6_hdr);
  	if (!net_eq(net, &init_net))
  		kfree(table);
  }
a8a572a6b   Dan Streetman   xfrm: dst_entries...
221
  #else /* CONFIG_SYSCTL */
318d3cc04   Arnd Bergmann   net: xfrm: fix ol...
222
  static inline int xfrm6_net_sysctl_init(struct net *net)
a8a572a6b   Dan Streetman   xfrm: dst_entries...
223
224
225
  {
  	return 0;
  }
318d3cc04   Arnd Bergmann   net: xfrm: fix ol...
226
  static inline void xfrm6_net_sysctl_exit(struct net *net)
a8a572a6b   Dan Streetman   xfrm: dst_entries...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  {
  }
  #endif
  
  static int __net_init xfrm6_net_init(struct net *net)
  {
  	int ret;
  
  	memcpy(&net->xfrm.xfrm6_dst_ops, &xfrm6_dst_ops_template,
  	       sizeof(xfrm6_dst_ops_template));
  	ret = dst_entries_init(&net->xfrm.xfrm6_dst_ops);
  	if (ret)
  		return ret;
  
  	ret = xfrm6_net_sysctl_init(net);
  	if (ret)
  		dst_entries_destroy(&net->xfrm.xfrm6_dst_ops);
  
  	return ret;
  }
  
  static void __net_exit xfrm6_net_exit(struct net *net)
  {
  	xfrm6_net_sysctl_exit(net);
  	dst_entries_destroy(&net->xfrm.xfrm6_dst_ops);
  }
8d068875c   Michal Kubecek   xfrm: make gc_thr...
253
254
255
256
257
  
  static struct pernet_operations xfrm6_net_ops = {
  	.init	= xfrm6_net_init,
  	.exit	= xfrm6_net_exit,
  };
a44a4a006   Neil Horman   xfrm: export xfrm...
258

0013cabab   Daniel Lezcano   [IPV6]: Make xfrm...
259
  int __init xfrm6_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
  {
0013cabab   Daniel Lezcano   [IPV6]: Make xfrm...
261
  	int ret;
c38132865   Steffen Klassert   xfrm: Use a stati...
262

d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
263
  	ret = xfrm6_policy_init();
a8a572a6b   Dan Streetman   xfrm: dst_entries...
264
  	if (ret)
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
265
  		goto out;
d7c7544c3   Alexey Dobriyan   netns xfrm: deal ...
266
267
268
  	ret = xfrm6_state_init();
  	if (ret)
  		goto out_policy;
7e14ea152   Steffen Klassert   xfrm6: Add IPsec ...
269
270
271
  	ret = xfrm6_protocol_init();
  	if (ret)
  		goto out_state;
8d068875c   Michal Kubecek   xfrm: make gc_thr...
272
  	register_pernet_subsys(&xfrm6_net_ops);
0013cabab   Daniel Lezcano   [IPV6]: Make xfrm...
273
274
  out:
  	return ret;
7e14ea152   Steffen Klassert   xfrm6: Add IPsec ...
275
276
  out_state:
  	xfrm6_state_fini();
0013cabab   Daniel Lezcano   [IPV6]: Make xfrm...
277
278
279
  out_policy:
  	xfrm6_policy_fini();
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
  }
  
  void xfrm6_fini(void)
  {
8d068875c   Michal Kubecek   xfrm: make gc_thr...
284
  	unregister_pernet_subsys(&xfrm6_net_ops);
7e14ea152   Steffen Klassert   xfrm6: Add IPsec ...
285
  	xfrm6_protocol_fini();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
  	xfrm6_policy_fini();
  	xfrm6_state_fini();
  }