]> Git Repo - J-linux.git/blob - net/ipv4/xfrm4_policy.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / net / ipv4 / xfrm4_policy.c
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
21 static 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
44 static 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
51 static 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
66 static 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
96 static 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
106 static 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
115 static 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
124 static 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
135 static 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
144 static 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
154 static __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
176 err_reg:
177         if (!net_eq(net, &init_net))
178                 kfree(table);
179 err_alloc:
180         return -ENOMEM;
181 }
182
183 static __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 */
196 static inline int xfrm4_net_sysctl_init(struct net *net)
197 {
198         return 0;
199 }
200
201 static inline void xfrm4_net_sysctl_exit(struct net *net)
202 {
203 }
204 #endif
205
206 static 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
223 static 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
229 static struct pernet_operations __net_initdata xfrm4_net_ops = {
230         .init   = xfrm4_net_init,
231         .exit   = xfrm4_net_exit,
232 };
233
234 static void __init xfrm4_policy_init(void)
235 {
236         xfrm_policy_register_afinfo(&xfrm4_policy_afinfo, AF_INET);
237 }
238
239 void __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 }
This page took 0.037919 seconds and 4 git commands to generate.