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 xdst->u.dst.dev = NULL; 92 return -ENODEV; 93 } 94 95 /* Sheit... I remember I did this right. Apparently, 96 * it was magically lost, so this code needs audit */ 97 xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | 98 RTF_LOCAL); 99 xdst->route_cookie = rt6_get_cookie(rt); 100 xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway; 101 xdst->u.rt6.rt6i_dst = rt->rt6i_dst; 102 xdst->u.rt6.rt6i_src = rt->rt6i_src; 103 rt6_uncached_list_add(&xdst->u.rt6); 104 105 return 0; 106 } 107 108 static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, 109 struct sk_buff *skb, u32 mtu, 110 bool confirm_neigh) 111 { 112 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 113 struct dst_entry *path = xdst->route; 114 115 path->ops->update_pmtu(path, sk, skb, mtu, confirm_neigh); 116 } 117 118 static void xfrm6_redirect(struct dst_entry *dst, struct sock *sk, 119 struct sk_buff *skb) 120 { 121 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 122 struct dst_entry *path = xdst->route; 123 124 path->ops->redirect(path, sk, skb); 125 } 126 127 static void xfrm6_dst_destroy(struct dst_entry *dst) 128 { 129 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 130 131 dst_destroy_metrics_generic(dst); 132 rt6_uncached_list_del(&xdst->u.rt6); 133 if (likely(xdst->u.rt6.rt6i_idev)) 134 in6_dev_put(xdst->u.rt6.rt6i_idev); 135 xfrm_dst_destroy(xdst); 136 } 137 138 static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev) 139 { 140 struct xfrm_dst *xdst; 141 142 xdst = (struct xfrm_dst *)dst; 143 if (xdst->u.rt6.rt6i_idev->dev == dev) { 144 struct inet6_dev *loopback_idev = 145 in6_dev_get(dev_net(dev)->loopback_dev); 146 147 do { 148 in6_dev_put(xdst->u.rt6.rt6i_idev); 149 xdst->u.rt6.rt6i_idev = loopback_idev; 150 in6_dev_hold(loopback_idev); 151 xdst = (struct xfrm_dst *)xfrm_dst_child(&xdst->u.dst); 152 } while (xdst->u.dst.xfrm); 153 154 __in6_dev_put(loopback_idev); 155 } 156 157 xfrm_dst_ifdown(dst, dev); 158 } 159 160 static struct dst_ops xfrm6_dst_ops_template = { 161 .family = AF_INET6, 162 .update_pmtu = xfrm6_update_pmtu, 163 .redirect = xfrm6_redirect, 164 .cow_metrics = dst_cow_metrics_generic, 165 .destroy = xfrm6_dst_destroy, 166 .ifdown = xfrm6_dst_ifdown, 167 .local_out = __ip6_local_out, 168 .gc_thresh = 32768, 169 }; 170 171 static const struct xfrm_policy_afinfo xfrm6_policy_afinfo = { 172 .dst_ops = &xfrm6_dst_ops_template, 173 .dst_lookup = xfrm6_dst_lookup, 174 .get_saddr = xfrm6_get_saddr, 175 .fill_dst = xfrm6_fill_dst, 176 .blackhole_route = ip6_blackhole_route, 177 }; 178 179 static int __init xfrm6_policy_init(void) 180 { 181 return xfrm_policy_register_afinfo(&xfrm6_policy_afinfo, AF_INET6); 182 } 183 184 static void xfrm6_policy_fini(void) 185 { 186 xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo); 187 } 188 189 #ifdef CONFIG_SYSCTL 190 static const struct ctl_table xfrm6_policy_table[] = { 191 { 192 .procname = "xfrm6_gc_thresh", 193 .data = &init_net.xfrm.xfrm6_dst_ops.gc_thresh, 194 .maxlen = sizeof(int), 195 .mode = 0644, 196 .proc_handler = proc_dointvec, 197 }, 198 }; 199 200 static const struct ctl_table *xfrm6_policy_table_dup(struct net *net) 201 { 202 struct ctl_table *table; 203 204 table = kmemdup(xfrm6_policy_table, sizeof(xfrm6_policy_table), 205 GFP_KERNEL); 206 if (!table) 207 return NULL; 208 209 table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh; 210 211 return table; 212 } 213 214 static int __net_init xfrm6_net_sysctl_init(struct net *net) 215 { 216 const struct ctl_table *table; 217 struct ctl_table_header *hdr; 218 219 table = xfrm6_policy_table; 220 if (!net_eq(net, &init_net)) { 221 table = xfrm6_policy_table_dup(net); 222 if (!table) 223 goto err_alloc; 224 } 225 226 hdr = register_net_sysctl_sz(net, "net/ipv6", table, 227 ARRAY_SIZE(xfrm6_policy_table)); 228 if (!hdr) 229 goto err_reg; 230 231 net->ipv6.sysctl.xfrm6_hdr = hdr; 232 return 0; 233 234 err_reg: 235 if (!net_eq(net, &init_net)) 236 kfree(table); 237 err_alloc: 238 return -ENOMEM; 239 } 240 241 static void __net_exit xfrm6_net_sysctl_exit(struct net *net) 242 { 243 const struct ctl_table *table; 244 245 if (!net->ipv6.sysctl.xfrm6_hdr) 246 return; 247 248 table = net->ipv6.sysctl.xfrm6_hdr->ctl_table_arg; 249 unregister_net_sysctl_table(net->ipv6.sysctl.xfrm6_hdr); 250 if (!net_eq(net, &init_net)) 251 kfree(table); 252 } 253 #else /* CONFIG_SYSCTL */ 254 static inline int xfrm6_net_sysctl_init(struct net *net) 255 { 256 return 0; 257 } 258 259 static inline void xfrm6_net_sysctl_exit(struct net *net) 260 { 261 } 262 #endif 263 264 static int __net_init xfrm6_net_init(struct net *net) 265 { 266 int ret; 267 268 memcpy(&net->xfrm.xfrm6_dst_ops, &xfrm6_dst_ops_template, 269 sizeof(xfrm6_dst_ops_template)); 270 ret = dst_entries_init(&net->xfrm.xfrm6_dst_ops); 271 if (ret) 272 return ret; 273 274 ret = xfrm6_net_sysctl_init(net); 275 if (ret) 276 dst_entries_destroy(&net->xfrm.xfrm6_dst_ops); 277 278 return ret; 279 } 280 281 static void __net_exit xfrm6_net_exit(struct net *net) 282 { 283 xfrm6_net_sysctl_exit(net); 284 dst_entries_destroy(&net->xfrm.xfrm6_dst_ops); 285 } 286 287 static struct pernet_operations xfrm6_net_ops = { 288 .init = xfrm6_net_init, 289 .exit = xfrm6_net_exit, 290 }; 291 292 int __init xfrm6_init(void) 293 { 294 int ret; 295 296 ret = xfrm6_policy_init(); 297 if (ret) 298 goto out; 299 ret = xfrm6_state_init(); 300 if (ret) 301 goto out_policy; 302 303 ret = xfrm6_protocol_init(); 304 if (ret) 305 goto out_state; 306 307 ret = register_pernet_subsys(&xfrm6_net_ops); 308 if (ret) 309 goto out_protocol; 310 311 ret = xfrm_nat_keepalive_init(AF_INET6); 312 if (ret) 313 goto out_nat_keepalive; 314 out: 315 return ret; 316 out_nat_keepalive: 317 unregister_pernet_subsys(&xfrm6_net_ops); 318 out_protocol: 319 xfrm6_protocol_fini(); 320 out_state: 321 xfrm6_state_fini(); 322 out_policy: 323 xfrm6_policy_fini(); 324 goto out; 325 } 326 327 void xfrm6_fini(void) 328 { 329 xfrm_nat_keepalive_fini(AF_INET6); 330 unregister_pernet_subsys(&xfrm6_net_ops); 331 xfrm6_protocol_fini(); 332 xfrm6_policy_fini(); 333 xfrm6_state_fini(); 334 } 335