Linux Audio

Check our new training course

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