Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * xfrm4_policy.c
  4 *
  5 * Changes:
  6 *	Kazunori MIYAZAWA @USAGI
  7 * 	YOSHIFUJI Hideaki @USAGI
  8 *		Split up af-specific portion
  9 *
 10 */
 11
 12#include <linux/err.h>
 13#include <linux/kernel.h>
 14#include <linux/inetdevice.h>
 15#include <net/dst.h>
 16#include <net/xfrm.h>
 17#include <net/inet_dscp.h>
 18#include <net/ip.h>
 19#include <net/l3mdev.h>
 20
 21static struct dst_entry *__xfrm4_dst_lookup(struct flowi4 *fl4,
 22					    const struct xfrm_dst_lookup_params *params)
 
 
 
 23{
 24	struct rtable *rt;
 25
 26	memset(fl4, 0, sizeof(*fl4));
 27	fl4->daddr = params->daddr->a4;
 28	fl4->flowi4_tos = inet_dscp_to_dsfield(params->dscp);
 29	fl4->flowi4_l3mdev = l3mdev_master_ifindex_by_index(params->net,
 30							    params->oif);
 31	fl4->flowi4_mark = params->mark;
 32	if (params->saddr)
 33		fl4->saddr = params->saddr->a4;
 34	fl4->flowi4_proto = params->ipproto;
 35	fl4->uli = params->uli;
 36
 37	rt = __ip_route_output_key(params->net, fl4);
 38	if (!IS_ERR(rt))
 39		return &rt->dst;
 40
 41	return ERR_CAST(rt);
 42}
 43
 44static struct dst_entry *xfrm4_dst_lookup(const struct xfrm_dst_lookup_params *params)
 
 
 
 45{
 46	struct flowi4 fl4;
 47
 48	return __xfrm4_dst_lookup(&fl4, params);
 49}
 50
 51static int xfrm4_get_saddr(xfrm_address_t *saddr,
 52			   const struct xfrm_dst_lookup_params *params)
 
 53{
 54	struct dst_entry *dst;
 55	struct flowi4 fl4;
 56
 57	dst = __xfrm4_dst_lookup(&fl4, params);
 58	if (IS_ERR(dst))
 59		return -EHOSTUNREACH;
 60
 61	saddr->a4 = fl4.saddr;
 62	dst_release(dst);
 63	return 0;
 64}
 65
 66static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
 67			  const struct flowi *fl)
 68{
 69	struct rtable *rt = dst_rtable(xdst->route);
 70	const struct flowi4 *fl4 = &fl->u.ip4;
 71
 72	xdst->u.rt.rt_iif = fl4->flowi4_iif;
 73
 74	xdst->u.dst.dev = dev;
 75	netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC);
 76
 77	/* Sheit... I remember I did this right. Apparently,
 78	 * it was magically lost, so this code needs audit */
 79	xdst->u.rt.rt_is_input = rt->rt_is_input;
 80	xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST |
 81					      RTCF_LOCAL);
 82	xdst->u.rt.rt_type = rt->rt_type;
 83	xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway;
 84	xdst->u.rt.rt_gw_family = rt->rt_gw_family;
 85	if (rt->rt_gw_family == AF_INET)
 86		xdst->u.rt.rt_gw4 = rt->rt_gw4;
 87	else if (rt->rt_gw_family == AF_INET6)
 88		xdst->u.rt.rt_gw6 = rt->rt_gw6;
 89	xdst->u.rt.rt_pmtu = rt->rt_pmtu;
 90	xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked;
 91	rt_add_uncached_list(&xdst->u.rt);
 92
 93	return 0;
 94}
 95
 96static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk,
 97			      struct sk_buff *skb, u32 mtu,
 98			      bool confirm_neigh)
 99{
100	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
101	struct dst_entry *path = xdst->route;
102
103	path->ops->update_pmtu(path, sk, skb, mtu, confirm_neigh);
104}
105
106static void xfrm4_redirect(struct dst_entry *dst, struct sock *sk,
107			   struct sk_buff *skb)
108{
109	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
110	struct dst_entry *path = xdst->route;
111
112	path->ops->redirect(path, sk, skb);
113}
114
115static void xfrm4_dst_destroy(struct dst_entry *dst)
116{
117	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
118
119	dst_destroy_metrics_generic(dst);
120	rt_del_uncached_list(&xdst->u.rt);
121	xfrm_dst_destroy(xdst);
122}
123
124static struct dst_ops xfrm4_dst_ops_template = {
125	.family =		AF_INET,
126	.update_pmtu =		xfrm4_update_pmtu,
127	.redirect =		xfrm4_redirect,
128	.cow_metrics =		dst_cow_metrics_generic,
129	.destroy =		xfrm4_dst_destroy,
130	.ifdown =		xfrm_dst_ifdown,
131	.local_out =		__ip_local_out,
132	.gc_thresh =		32768,
133};
134
135static const struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
136	.dst_ops =		&xfrm4_dst_ops_template,
137	.dst_lookup =		xfrm4_dst_lookup,
138	.get_saddr =		xfrm4_get_saddr,
139	.fill_dst =		xfrm4_fill_dst,
140	.blackhole_route =	ipv4_blackhole_route,
141};
142
143#ifdef CONFIG_SYSCTL
144static struct ctl_table xfrm4_policy_table[] = {
145	{
146		.procname       = "xfrm4_gc_thresh",
147		.data           = &init_net.xfrm.xfrm4_dst_ops.gc_thresh,
148		.maxlen         = sizeof(int),
149		.mode           = 0644,
150		.proc_handler   = proc_dointvec,
151	},
 
152};
153
154static __net_init int xfrm4_net_sysctl_init(struct net *net)
155{
156	struct ctl_table *table;
157	struct ctl_table_header *hdr;
158
159	table = xfrm4_policy_table;
160	if (!net_eq(net, &init_net)) {
161		table = kmemdup(table, sizeof(xfrm4_policy_table), GFP_KERNEL);
162		if (!table)
163			goto err_alloc;
164
165		table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
166	}
167
168	hdr = register_net_sysctl_sz(net, "net/ipv4", table,
169				     ARRAY_SIZE(xfrm4_policy_table));
170	if (!hdr)
171		goto err_reg;
172
173	net->ipv4.xfrm4_hdr = hdr;
174	return 0;
175
176err_reg:
177	if (!net_eq(net, &init_net))
178		kfree(table);
179err_alloc:
180	return -ENOMEM;
181}
182
183static __net_exit void xfrm4_net_sysctl_exit(struct net *net)
184{
185	const struct ctl_table *table;
186
187	if (!net->ipv4.xfrm4_hdr)
188		return;
189
190	table = net->ipv4.xfrm4_hdr->ctl_table_arg;
191	unregister_net_sysctl_table(net->ipv4.xfrm4_hdr);
192	if (!net_eq(net, &init_net))
193		kfree(table);
194}
195#else /* CONFIG_SYSCTL */
196static inline int xfrm4_net_sysctl_init(struct net *net)
197{
198	return 0;
199}
200
201static inline void xfrm4_net_sysctl_exit(struct net *net)
202{
203}
204#endif
205
206static int __net_init xfrm4_net_init(struct net *net)
207{
208	int ret;
209
210	memcpy(&net->xfrm.xfrm4_dst_ops, &xfrm4_dst_ops_template,
211	       sizeof(xfrm4_dst_ops_template));
212	ret = dst_entries_init(&net->xfrm.xfrm4_dst_ops);
213	if (ret)
214		return ret;
215
216	ret = xfrm4_net_sysctl_init(net);
217	if (ret)
218		dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
219
220	return ret;
221}
222
223static void __net_exit xfrm4_net_exit(struct net *net)
224{
225	xfrm4_net_sysctl_exit(net);
226	dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
227}
228
229static struct pernet_operations __net_initdata xfrm4_net_ops = {
230	.init	= xfrm4_net_init,
231	.exit	= xfrm4_net_exit,
232};
233
234static void __init xfrm4_policy_init(void)
235{
236	xfrm_policy_register_afinfo(&xfrm4_policy_afinfo, AF_INET);
237}
238
239void __init xfrm4_init(void)
240{
241	xfrm4_state_init();
242	xfrm4_policy_init();
243	xfrm4_protocol_init();
244	register_pernet_subsys(&xfrm4_net_ops);
245}
v6.8
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * xfrm4_policy.c
  4 *
  5 * Changes:
  6 *	Kazunori MIYAZAWA @USAGI
  7 * 	YOSHIFUJI Hideaki @USAGI
  8 *		Split up af-specific portion
  9 *
 10 */
 11
 12#include <linux/err.h>
 13#include <linux/kernel.h>
 14#include <linux/inetdevice.h>
 15#include <net/dst.h>
 16#include <net/xfrm.h>
 
 17#include <net/ip.h>
 18#include <net/l3mdev.h>
 19
 20static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
 21					    int tos, int oif,
 22					    const xfrm_address_t *saddr,
 23					    const xfrm_address_t *daddr,
 24					    u32 mark)
 25{
 26	struct rtable *rt;
 27
 28	memset(fl4, 0, sizeof(*fl4));
 29	fl4->daddr = daddr->a4;
 30	fl4->flowi4_tos = tos;
 31	fl4->flowi4_l3mdev = l3mdev_master_ifindex_by_index(net, oif);
 32	fl4->flowi4_mark = mark;
 33	if (saddr)
 34		fl4->saddr = saddr->a4;
 
 
 
 35
 36	rt = __ip_route_output_key(net, fl4);
 37	if (!IS_ERR(rt))
 38		return &rt->dst;
 39
 40	return ERR_CAST(rt);
 41}
 42
 43static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif,
 44					  const xfrm_address_t *saddr,
 45					  const xfrm_address_t *daddr,
 46					  u32 mark)
 47{
 48	struct flowi4 fl4;
 49
 50	return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr, mark);
 51}
 52
 53static int xfrm4_get_saddr(struct net *net, int oif,
 54			   xfrm_address_t *saddr, xfrm_address_t *daddr,
 55			   u32 mark)
 56{
 57	struct dst_entry *dst;
 58	struct flowi4 fl4;
 59
 60	dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr, mark);
 61	if (IS_ERR(dst))
 62		return -EHOSTUNREACH;
 63
 64	saddr->a4 = fl4.saddr;
 65	dst_release(dst);
 66	return 0;
 67}
 68
 69static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
 70			  const struct flowi *fl)
 71{
 72	struct rtable *rt = (struct rtable *)xdst->route;
 73	const struct flowi4 *fl4 = &fl->u.ip4;
 74
 75	xdst->u.rt.rt_iif = fl4->flowi4_iif;
 76
 77	xdst->u.dst.dev = dev;
 78	netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC);
 79
 80	/* Sheit... I remember I did this right. Apparently,
 81	 * it was magically lost, so this code needs audit */
 82	xdst->u.rt.rt_is_input = rt->rt_is_input;
 83	xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST |
 84					      RTCF_LOCAL);
 85	xdst->u.rt.rt_type = rt->rt_type;
 86	xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway;
 87	xdst->u.rt.rt_gw_family = rt->rt_gw_family;
 88	if (rt->rt_gw_family == AF_INET)
 89		xdst->u.rt.rt_gw4 = rt->rt_gw4;
 90	else if (rt->rt_gw_family == AF_INET6)
 91		xdst->u.rt.rt_gw6 = rt->rt_gw6;
 92	xdst->u.rt.rt_pmtu = rt->rt_pmtu;
 93	xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked;
 94	rt_add_uncached_list(&xdst->u.rt);
 95
 96	return 0;
 97}
 98
 99static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk,
100			      struct sk_buff *skb, u32 mtu,
101			      bool confirm_neigh)
102{
103	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
104	struct dst_entry *path = xdst->route;
105
106	path->ops->update_pmtu(path, sk, skb, mtu, confirm_neigh);
107}
108
109static void xfrm4_redirect(struct dst_entry *dst, struct sock *sk,
110			   struct sk_buff *skb)
111{
112	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
113	struct dst_entry *path = xdst->route;
114
115	path->ops->redirect(path, sk, skb);
116}
117
118static void xfrm4_dst_destroy(struct dst_entry *dst)
119{
120	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
121
122	dst_destroy_metrics_generic(dst);
123	rt_del_uncached_list(&xdst->u.rt);
124	xfrm_dst_destroy(xdst);
125}
126
127static struct dst_ops xfrm4_dst_ops_template = {
128	.family =		AF_INET,
129	.update_pmtu =		xfrm4_update_pmtu,
130	.redirect =		xfrm4_redirect,
131	.cow_metrics =		dst_cow_metrics_generic,
132	.destroy =		xfrm4_dst_destroy,
133	.ifdown =		xfrm_dst_ifdown,
134	.local_out =		__ip_local_out,
135	.gc_thresh =		32768,
136};
137
138static const struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
139	.dst_ops =		&xfrm4_dst_ops_template,
140	.dst_lookup =		xfrm4_dst_lookup,
141	.get_saddr =		xfrm4_get_saddr,
142	.fill_dst =		xfrm4_fill_dst,
143	.blackhole_route =	ipv4_blackhole_route,
144};
145
146#ifdef CONFIG_SYSCTL
147static struct ctl_table xfrm4_policy_table[] = {
148	{
149		.procname       = "xfrm4_gc_thresh",
150		.data           = &init_net.xfrm.xfrm4_dst_ops.gc_thresh,
151		.maxlen         = sizeof(int),
152		.mode           = 0644,
153		.proc_handler   = proc_dointvec,
154	},
155	{ }
156};
157
158static __net_init int xfrm4_net_sysctl_init(struct net *net)
159{
160	struct ctl_table *table;
161	struct ctl_table_header *hdr;
162
163	table = xfrm4_policy_table;
164	if (!net_eq(net, &init_net)) {
165		table = kmemdup(table, sizeof(xfrm4_policy_table), GFP_KERNEL);
166		if (!table)
167			goto err_alloc;
168
169		table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
170	}
171
172	hdr = register_net_sysctl_sz(net, "net/ipv4", table,
173				     ARRAY_SIZE(xfrm4_policy_table));
174	if (!hdr)
175		goto err_reg;
176
177	net->ipv4.xfrm4_hdr = hdr;
178	return 0;
179
180err_reg:
181	if (!net_eq(net, &init_net))
182		kfree(table);
183err_alloc:
184	return -ENOMEM;
185}
186
187static __net_exit void xfrm4_net_sysctl_exit(struct net *net)
188{
189	struct ctl_table *table;
190
191	if (!net->ipv4.xfrm4_hdr)
192		return;
193
194	table = net->ipv4.xfrm4_hdr->ctl_table_arg;
195	unregister_net_sysctl_table(net->ipv4.xfrm4_hdr);
196	if (!net_eq(net, &init_net))
197		kfree(table);
198}
199#else /* CONFIG_SYSCTL */
200static inline int xfrm4_net_sysctl_init(struct net *net)
201{
202	return 0;
203}
204
205static inline void xfrm4_net_sysctl_exit(struct net *net)
206{
207}
208#endif
209
210static int __net_init xfrm4_net_init(struct net *net)
211{
212	int ret;
213
214	memcpy(&net->xfrm.xfrm4_dst_ops, &xfrm4_dst_ops_template,
215	       sizeof(xfrm4_dst_ops_template));
216	ret = dst_entries_init(&net->xfrm.xfrm4_dst_ops);
217	if (ret)
218		return ret;
219
220	ret = xfrm4_net_sysctl_init(net);
221	if (ret)
222		dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
223
224	return ret;
225}
226
227static void __net_exit xfrm4_net_exit(struct net *net)
228{
229	xfrm4_net_sysctl_exit(net);
230	dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
231}
232
233static struct pernet_operations __net_initdata xfrm4_net_ops = {
234	.init	= xfrm4_net_init,
235	.exit	= xfrm4_net_exit,
236};
237
238static void __init xfrm4_policy_init(void)
239{
240	xfrm_policy_register_afinfo(&xfrm4_policy_afinfo, AF_INET);
241}
242
243void __init xfrm4_init(void)
244{
245	xfrm4_state_init();
246	xfrm4_policy_init();
247	xfrm4_protocol_init();
248	register_pernet_subsys(&xfrm4_net_ops);
249}