1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * xfrm6_policy.c: based on xfrm4_policy.c 4 * 5 * Authors: 6 * Mitsuru KANDA @USAGI 7 * Kazunori MIYAZAWA @USAGI 8 * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 9 * IPv6 support 10 * YOSHIFUJI Hideaki 11 * Split up af-specific portion 12 * 13 */ 14 15 #include <linux/err.h> 16 #include <linux/kernel.h> 17 #include <linux/netdevice.h> 18 #include <net/addrconf.h> 19 #include <net/dst.h> 20 #include <net/xfrm.h> 21 #include <net/ip.h> 22 #include <net/ipv6.h> 23 #include <net/ip6_route.h> 24 #include <net/l3mdev.h> 25 26 static struct dst_entry *xfrm6_dst_lookup(const struct xfrm_dst_lookup_params *params) 27 { 28 struct flowi6 fl6; 29 struct dst_entry *dst; 30 int err; 31 32 memset(&fl6, 0, sizeof(fl6)); 33 fl6.flowi6_l3mdev = l3mdev_master_ifindex_by_index(params->net, 34 params->oif); 35 fl6.flowi6_mark = params->mark; 36 memcpy(&fl6.daddr, params->daddr, sizeof(fl6.daddr)); 37 if (params->saddr) 38 memcpy(&fl6.saddr, params->saddr, sizeof(fl6.saddr)); 39 40 fl6.flowi4_proto = params->ipproto; 41 fl6.uli = params->uli; 42 43 dst = ip6_route_output(params->net, NULL, &fl6); 44 45 err = dst->error; 46 if (dst->error) { 47 dst_release(dst); 48 dst = ERR_PTR(err); 49 } 50 51 return dst; 52 } 53 54 static int xfrm6_get_saddr(xfrm_address_t *saddr, 55 const struct xfrm_dst_lookup_params *params) 56 { 57 struct dst_entry *dst; 58 struct net_device *dev; 59 struct inet6_dev *idev; 60 int err; 61 62 dst = xfrm6_dst_lookup(params); 63 if (IS_ERR(dst)) 64 return -EHOSTUNREACH; 65 66 idev = ip6_dst_idev(dst); 67 if (!idev) { 68 dst_release(dst); 69 return -EHOSTUNREACH; 70 } 71 dev = idev->dev; 72 err = ipv6_dev_get_saddr(dev_net(dev), dev, ¶ms->daddr->in6, 0, 73 &saddr->in6); 74 dst_release(dst); 75 if (err) 76 return -EHOSTUNREACH; 77 return 0; 78 } 79 80 static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, 81 const struct flowi *fl) 82 { 83 struct rt6_info *rt = dst_rt6_info(xdst->route); 84 85 xdst->u.dst.dev = dev; 86 netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC); 87 88 xdst->u.rt6.rt6i_idev = in6_dev_get(dev); 89 if (!xdst->u.rt6.rt6i_idev) { 90 netdev_put(dev, &xdst->u.dst.dev_tracker); 91 return -ENODEV; 92 } 93 94 /* Sheit... I remember I did this right. Apparently, 95 * it was magically lost, so this code needs audit */ 96 xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | 97 RTF_LOCAL); 98 xdst->route_cookie = rt6_get_cookie(rt); 99 xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway; 100 xdst->u.rt6.rt6i_dst = rt->rt6i_dst; 101 xdst->u.rt6.rt6i_src = rt->rt6i_src; 102 rt6_uncached_list_add(&xdst->u.rt6); 103 104 return 0; 105 } 106 107 static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, 108 struct sk_buff *skb, u32 mtu, 109 bool confirm_neigh) 110 { 111 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 112 struct dst_entry *path = xdst->route; 113 114 path->ops->update_pmtu(path, sk, skb, mtu, confirm_neigh); 115 } 116 117 static void xfrm6_redirect(struct dst_entry *dst, struct sock *sk, 118 struct sk_buff *skb) 119 { 120 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 121 struct dst_entry *path = xdst->route; 122 123 path->ops->redirect(path, sk, skb); 124 } 125 126 static void xfrm6_dst_destroy(struct dst_entry *dst) 127 { 128 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 129 130 dst_destroy_metrics_generic(dst); 131 rt6_uncached_list_del(&xdst->u.rt6); 132 if (likely(xdst->u.rt6.rt6i_idev)) 133 in6_dev_put(xdst->u.rt6.rt6i_idev); 134 xfrm_dst_destroy(xdst); 135 } 136 137 static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev) 138 { 139 struct xfrm_dst *xdst; 140 141 xdst = (struct xfrm_dst *)dst; 142 if (xdst->u.rt6.rt6i_idev->dev == dev) { 143 struct inet6_dev *loopback_idev = 144 in6_dev_get(dev_net(dev)->loopback_dev); 145 146 do { 147 in6_dev_put(xdst->u.rt6.rt6i_idev); 148 xdst->u.rt6.rt6i_idev = loopback_idev; 149 in6_dev_hold(loopback_idev); 150 xdst = (struct xfrm_dst *)xfrm_dst_child(&xdst->u.dst); 151 } while (xdst->u.dst.xfrm); 152 153 __in6_dev_put(loopback_idev); 154 } 155 156 xfrm_dst_ifdown(dst, dev); 157 } 158 159 static struct dst_ops xfrm6_dst_ops_template = { 160 .family = AF_INET6, 161 .update_pmtu = xfrm6_update_pmtu, 162 .redirect = xfrm6_redirect, 163 .cow_metrics = dst_cow_metrics_generic, 164 .destroy = xfrm6_dst_destroy, 165 .ifdown = xfrm6_dst_ifdown, 166 .local_out = __ip6_local_out, 167 .gc_thresh = 32768, 168 }; 169 170 static const struct xfrm_policy_afinfo xfrm6_policy_afinfo = { 171 .dst_ops = &xfrm6_dst_ops_template, 172 .dst_lookup = xfrm6_dst_lookup, 173 .get_saddr = xfrm6_get_saddr, 174 .fill_dst = xfrm6_fill_dst, 175 .blackhole_route = ip6_blackhole_route, 176 }; 177 178 static int __init xfrm6_policy_init(void) 179 { 180 return xfrm_policy_register_afinfo(&xfrm6_policy_afinfo, AF_INET6); 181 } 182 183 static void xfrm6_policy_fini(void) 184 { 185 xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo); 186 } 187 188 #ifdef CONFIG_SYSCTL 189 static struct ctl_table xfrm6_policy_table[] = { 190 { 191 .procname = "xfrm6_gc_thresh", 192 .data = &init_net.xfrm.xfrm6_dst_ops.gc_thresh, 193 .maxlen = sizeof(int), 194 .mode = 0644, 195 .proc_handler = proc_dointvec, 196 }, 197 }; 198 199 static int __net_init xfrm6_net_sysctl_init(struct net *net) 200 { 201 struct ctl_table *table; 202 struct ctl_table_header *hdr; 203 204 table = xfrm6_policy_table; 205 if (!net_eq(net, &init_net)) { 206 table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL); 207 if (!table) 208 goto err_alloc; 209 210 table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh; 211 } 212 213 hdr = register_net_sysctl_sz(net, "net/ipv6", table, 214 ARRAY_SIZE(xfrm6_policy_table)); 215 if (!hdr) 216 goto err_reg; 217 218 net->ipv6.sysctl.xfrm6_hdr = hdr; 219 return 0; 220 221 err_reg: 222 if (!net_eq(net, &init_net)) 223 kfree(table); 224 err_alloc: 225 return -ENOMEM; 226 } 227 228 static void __net_exit xfrm6_net_sysctl_exit(struct net *net) 229 { 230 const struct ctl_table *table; 231 232 if (!net->ipv6.sysctl.xfrm6_hdr) 233 return; 234 235 table = net->ipv6.sysctl.xfrm6_hdr->ctl_table_arg; 236 unregister_net_sysctl_table(net->ipv6.sysctl.xfrm6_hdr); 237 if (!net_eq(net, &init_net)) 238 kfree(table); 239 } 240 #else /* CONFIG_SYSCTL */ 241 static inline int xfrm6_net_sysctl_init(struct net *net) 242 { 243 return 0; 244 } 245 246 static inline void xfrm6_net_sysctl_exit(struct net *net) 247 { 248 } 249 #endif 250 251 static int __net_init xfrm6_net_init(struct net *net) 252 { 253 int ret; 254 255 memcpy(&net->xfrm.xfrm6_dst_ops, &xfrm6_dst_ops_template, 256 sizeof(xfrm6_dst_ops_template)); 257 ret = dst_entries_init(&net->xfrm.xfrm6_dst_ops); 258 if (ret) 259 return ret; 260 261 ret = xfrm6_net_sysctl_init(net); 262 if (ret) 263 dst_entries_destroy(&net->xfrm.xfrm6_dst_ops); 264 265 return ret; 266 } 267 268 static void __net_exit xfrm6_net_exit(struct net *net) 269 { 270 xfrm6_net_sysctl_exit(net); 271 dst_entries_destroy(&net->xfrm.xfrm6_dst_ops); 272 } 273 274 static struct pernet_operations xfrm6_net_ops = { 275 .init = xfrm6_net_init, 276 .exit = xfrm6_net_exit, 277 }; 278 279 int __init xfrm6_init(void) 280 { 281 int ret; 282 283 ret = xfrm6_policy_init(); 284 if (ret) 285 goto out; 286 ret = xfrm6_state_init(); 287 if (ret) 288 goto out_policy; 289 290 ret = xfrm6_protocol_init(); 291 if (ret) 292 goto out_state; 293 294 ret = register_pernet_subsys(&xfrm6_net_ops); 295 if (ret) 296 goto out_protocol; 297 298 ret = xfrm_nat_keepalive_init(AF_INET6); 299 if (ret) 300 goto out_nat_keepalive; 301 out: 302 return ret; 303 out_nat_keepalive: 304 unregister_pernet_subsys(&xfrm6_net_ops); 305 out_protocol: 306 xfrm6_protocol_fini(); 307 out_state: 308 xfrm6_state_fini(); 309 out_policy: 310 xfrm6_policy_fini(); 311 goto out; 312 } 313 314 void xfrm6_fini(void) 315 { 316 xfrm_nat_keepalive_fini(AF_INET6); 317 unregister_pernet_subsys(&xfrm6_net_ops); 318 xfrm6_protocol_fini(); 319 xfrm6_policy_fini(); 320 xfrm6_state_fini(); 321 } 322