| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * IP multicast routing support for mrouted 3.6/3.8 |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * (c) 1995 Alan Cox, <alan@lxorguk.ukuu.org.uk> |
|---|
| 5 | 6 | * Linux Consultancy and Custom Driver Development |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or |
|---|
| 8 | | - * modify it under the terms of the GNU General Public License |
|---|
| 9 | | - * as published by the Free Software Foundation; either version |
|---|
| 10 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 11 | 7 | * |
|---|
| 12 | 8 | * Fixes: |
|---|
| 13 | 9 | * Michael Chastain : Incorrect size of copying. |
|---|
| .. | .. |
|---|
| 23 | 19 | * Carlos Picoto : PIMv1 Support |
|---|
| 24 | 20 | * Pavlin Ivanov Radoslavov: PIMv2 Registers must checksum only PIM header |
|---|
| 25 | 21 | * Relax this requirement to work with older peers. |
|---|
| 26 | | - * |
|---|
| 27 | 22 | */ |
|---|
| 28 | 23 | |
|---|
| 29 | 24 | #include <linux/uaccess.h> |
|---|
| .. | .. |
|---|
| 66 | 61 | #include <net/netlink.h> |
|---|
| 67 | 62 | #include <net/fib_rules.h> |
|---|
| 68 | 63 | #include <linux/netconf.h> |
|---|
| 69 | | -#include <net/nexthop.h> |
|---|
| 70 | | -#include <net/switchdev.h> |
|---|
| 64 | +#include <net/rtnh.h> |
|---|
| 71 | 65 | |
|---|
| 72 | 66 | #include <linux/nospec.h> |
|---|
| 73 | 67 | |
|---|
| .. | .. |
|---|
| 111 | 105 | static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc, |
|---|
| 112 | 106 | int cmd); |
|---|
| 113 | 107 | static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt); |
|---|
| 114 | | -static void mroute_clean_tables(struct mr_table *mrt, bool all); |
|---|
| 108 | +static void mroute_clean_tables(struct mr_table *mrt, int flags); |
|---|
| 115 | 109 | static void ipmr_expire_process(struct timer_list *t); |
|---|
| 116 | 110 | |
|---|
| 117 | 111 | #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES |
|---|
| 118 | | -#define ipmr_for_each_table(mrt, net) \ |
|---|
| 119 | | - list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list) |
|---|
| 112 | +#define ipmr_for_each_table(mrt, net) \ |
|---|
| 113 | + list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list, \ |
|---|
| 114 | + lockdep_rtnl_is_held() || \ |
|---|
| 115 | + list_empty(&net->ipv4.mr_tables)) |
|---|
| 120 | 116 | |
|---|
| 121 | 117 | static struct mr_table *ipmr_mr_table_iter(struct net *net, |
|---|
| 122 | 118 | struct mr_table *mrt) |
|---|
| .. | .. |
|---|
| 286 | 282 | rtnl_unlock(); |
|---|
| 287 | 283 | } |
|---|
| 288 | 284 | |
|---|
| 289 | | -static int ipmr_rules_dump(struct net *net, struct notifier_block *nb) |
|---|
| 285 | +static int ipmr_rules_dump(struct net *net, struct notifier_block *nb, |
|---|
| 286 | + struct netlink_ext_ack *extack) |
|---|
| 290 | 287 | { |
|---|
| 291 | | - return fib_rules_dump(net, nb, RTNL_FAMILY_IPMR); |
|---|
| 288 | + return fib_rules_dump(net, nb, RTNL_FAMILY_IPMR, extack); |
|---|
| 292 | 289 | } |
|---|
| 293 | 290 | |
|---|
| 294 | 291 | static unsigned int ipmr_rules_seq_read(struct net *net) |
|---|
| .. | .. |
|---|
| 344 | 341 | rtnl_unlock(); |
|---|
| 345 | 342 | } |
|---|
| 346 | 343 | |
|---|
| 347 | | -static int ipmr_rules_dump(struct net *net, struct notifier_block *nb) |
|---|
| 344 | +static int ipmr_rules_dump(struct net *net, struct notifier_block *nb, |
|---|
| 345 | + struct netlink_ext_ack *extack) |
|---|
| 348 | 346 | { |
|---|
| 349 | 347 | return 0; |
|---|
| 350 | 348 | } |
|---|
| .. | .. |
|---|
| 376 | 374 | .key_offset = offsetof(struct mfc_cache, cmparg), |
|---|
| 377 | 375 | .key_len = sizeof(struct mfc_cache_cmp_arg), |
|---|
| 378 | 376 | .nelem_hint = 3, |
|---|
| 379 | | - .locks_mul = 1, |
|---|
| 380 | 377 | .obj_cmpfn = ipmr_hash_cmp, |
|---|
| 381 | 378 | .automatic_shrinking = true, |
|---|
| 382 | 379 | }; |
|---|
| .. | .. |
|---|
| 418 | 415 | static void ipmr_free_table(struct mr_table *mrt) |
|---|
| 419 | 416 | { |
|---|
| 420 | 417 | del_timer_sync(&mrt->ipmr_expire_timer); |
|---|
| 421 | | - mroute_clean_tables(mrt, true); |
|---|
| 418 | + mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC | |
|---|
| 419 | + MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC); |
|---|
| 422 | 420 | rhltable_destroy(&mrt->mfc_hash); |
|---|
| 423 | 421 | kfree(mrt); |
|---|
| 424 | 422 | } |
|---|
| 425 | 423 | |
|---|
| 426 | 424 | /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ |
|---|
| 427 | | - |
|---|
| 428 | | -static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) |
|---|
| 429 | | -{ |
|---|
| 430 | | - struct net *net = dev_net(dev); |
|---|
| 431 | | - |
|---|
| 432 | | - dev_close(dev); |
|---|
| 433 | | - |
|---|
| 434 | | - dev = __dev_get_by_name(net, "tunl0"); |
|---|
| 435 | | - if (dev) { |
|---|
| 436 | | - const struct net_device_ops *ops = dev->netdev_ops; |
|---|
| 437 | | - struct ifreq ifr; |
|---|
| 438 | | - struct ip_tunnel_parm p; |
|---|
| 439 | | - |
|---|
| 440 | | - memset(&p, 0, sizeof(p)); |
|---|
| 441 | | - p.iph.daddr = v->vifc_rmt_addr.s_addr; |
|---|
| 442 | | - p.iph.saddr = v->vifc_lcl_addr.s_addr; |
|---|
| 443 | | - p.iph.version = 4; |
|---|
| 444 | | - p.iph.ihl = 5; |
|---|
| 445 | | - p.iph.protocol = IPPROTO_IPIP; |
|---|
| 446 | | - sprintf(p.name, "dvmrp%d", v->vifc_vifi); |
|---|
| 447 | | - ifr.ifr_ifru.ifru_data = (__force void __user *)&p; |
|---|
| 448 | | - |
|---|
| 449 | | - if (ops->ndo_do_ioctl) { |
|---|
| 450 | | - mm_segment_t oldfs = get_fs(); |
|---|
| 451 | | - |
|---|
| 452 | | - set_fs(KERNEL_DS); |
|---|
| 453 | | - ops->ndo_do_ioctl(dev, &ifr, SIOCDELTUNNEL); |
|---|
| 454 | | - set_fs(oldfs); |
|---|
| 455 | | - } |
|---|
| 456 | | - } |
|---|
| 457 | | -} |
|---|
| 458 | 425 | |
|---|
| 459 | 426 | /* Initialize ipmr pimreg/tunnel in_device */ |
|---|
| 460 | 427 | static bool ipmr_init_vif_indev(const struct net_device *dev) |
|---|
| .. | .. |
|---|
| 475 | 442 | |
|---|
| 476 | 443 | static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) |
|---|
| 477 | 444 | { |
|---|
| 478 | | - struct net_device *dev; |
|---|
| 445 | + struct net_device *tunnel_dev, *new_dev; |
|---|
| 446 | + struct ip_tunnel_parm p = { }; |
|---|
| 447 | + int err; |
|---|
| 479 | 448 | |
|---|
| 480 | | - dev = __dev_get_by_name(net, "tunl0"); |
|---|
| 449 | + tunnel_dev = __dev_get_by_name(net, "tunl0"); |
|---|
| 450 | + if (!tunnel_dev) |
|---|
| 451 | + goto out; |
|---|
| 481 | 452 | |
|---|
| 482 | | - if (dev) { |
|---|
| 483 | | - const struct net_device_ops *ops = dev->netdev_ops; |
|---|
| 484 | | - int err; |
|---|
| 485 | | - struct ifreq ifr; |
|---|
| 486 | | - struct ip_tunnel_parm p; |
|---|
| 453 | + p.iph.daddr = v->vifc_rmt_addr.s_addr; |
|---|
| 454 | + p.iph.saddr = v->vifc_lcl_addr.s_addr; |
|---|
| 455 | + p.iph.version = 4; |
|---|
| 456 | + p.iph.ihl = 5; |
|---|
| 457 | + p.iph.protocol = IPPROTO_IPIP; |
|---|
| 458 | + sprintf(p.name, "dvmrp%d", v->vifc_vifi); |
|---|
| 487 | 459 | |
|---|
| 488 | | - memset(&p, 0, sizeof(p)); |
|---|
| 489 | | - p.iph.daddr = v->vifc_rmt_addr.s_addr; |
|---|
| 490 | | - p.iph.saddr = v->vifc_lcl_addr.s_addr; |
|---|
| 491 | | - p.iph.version = 4; |
|---|
| 492 | | - p.iph.ihl = 5; |
|---|
| 493 | | - p.iph.protocol = IPPROTO_IPIP; |
|---|
| 494 | | - sprintf(p.name, "dvmrp%d", v->vifc_vifi); |
|---|
| 495 | | - ifr.ifr_ifru.ifru_data = (__force void __user *)&p; |
|---|
| 460 | + if (!tunnel_dev->netdev_ops->ndo_tunnel_ctl) |
|---|
| 461 | + goto out; |
|---|
| 462 | + err = tunnel_dev->netdev_ops->ndo_tunnel_ctl(tunnel_dev, &p, |
|---|
| 463 | + SIOCADDTUNNEL); |
|---|
| 464 | + if (err) |
|---|
| 465 | + goto out; |
|---|
| 496 | 466 | |
|---|
| 497 | | - if (ops->ndo_do_ioctl) { |
|---|
| 498 | | - mm_segment_t oldfs = get_fs(); |
|---|
| 467 | + new_dev = __dev_get_by_name(net, p.name); |
|---|
| 468 | + if (!new_dev) |
|---|
| 469 | + goto out; |
|---|
| 499 | 470 | |
|---|
| 500 | | - set_fs(KERNEL_DS); |
|---|
| 501 | | - err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL); |
|---|
| 502 | | - set_fs(oldfs); |
|---|
| 503 | | - } else { |
|---|
| 504 | | - err = -EOPNOTSUPP; |
|---|
| 505 | | - } |
|---|
| 506 | | - dev = NULL; |
|---|
| 507 | | - |
|---|
| 508 | | - if (err == 0 && |
|---|
| 509 | | - (dev = __dev_get_by_name(net, p.name)) != NULL) { |
|---|
| 510 | | - dev->flags |= IFF_MULTICAST; |
|---|
| 511 | | - if (!ipmr_init_vif_indev(dev)) |
|---|
| 512 | | - goto failure; |
|---|
| 513 | | - if (dev_open(dev)) |
|---|
| 514 | | - goto failure; |
|---|
| 515 | | - dev_hold(dev); |
|---|
| 516 | | - } |
|---|
| 471 | + new_dev->flags |= IFF_MULTICAST; |
|---|
| 472 | + if (!ipmr_init_vif_indev(new_dev)) |
|---|
| 473 | + goto out_unregister; |
|---|
| 474 | + if (dev_open(new_dev, NULL)) |
|---|
| 475 | + goto out_unregister; |
|---|
| 476 | + dev_hold(new_dev); |
|---|
| 477 | + err = dev_set_allmulti(new_dev, 1); |
|---|
| 478 | + if (err) { |
|---|
| 479 | + dev_close(new_dev); |
|---|
| 480 | + tunnel_dev->netdev_ops->ndo_tunnel_ctl(tunnel_dev, &p, |
|---|
| 481 | + SIOCDELTUNNEL); |
|---|
| 482 | + dev_put(new_dev); |
|---|
| 483 | + new_dev = ERR_PTR(err); |
|---|
| 517 | 484 | } |
|---|
| 518 | | - return dev; |
|---|
| 485 | + return new_dev; |
|---|
| 519 | 486 | |
|---|
| 520 | | -failure: |
|---|
| 521 | | - unregister_netdevice(dev); |
|---|
| 522 | | - return NULL; |
|---|
| 487 | +out_unregister: |
|---|
| 488 | + unregister_netdevice(new_dev); |
|---|
| 489 | +out: |
|---|
| 490 | + return ERR_PTR(-ENOBUFS); |
|---|
| 523 | 491 | } |
|---|
| 524 | 492 | |
|---|
| 525 | 493 | #if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2) |
|---|
| .. | .. |
|---|
| 593 | 561 | |
|---|
| 594 | 562 | if (!ipmr_init_vif_indev(dev)) |
|---|
| 595 | 563 | goto failure; |
|---|
| 596 | | - if (dev_open(dev)) |
|---|
| 564 | + if (dev_open(dev, NULL)) |
|---|
| 597 | 565 | goto failure; |
|---|
| 598 | 566 | |
|---|
| 599 | 567 | dev_hold(dev); |
|---|
| .. | .. |
|---|
| 670 | 638 | |
|---|
| 671 | 639 | /** |
|---|
| 672 | 640 | * vif_delete - Delete a VIF entry |
|---|
| 641 | + * @mrt: Table to delete from |
|---|
| 642 | + * @vifi: VIF identifier to delete |
|---|
| 673 | 643 | * @notify: Set to 1, if the caller is a notifier_call |
|---|
| 644 | + * @head: if unregistering the VIF, place it on this queue |
|---|
| 674 | 645 | */ |
|---|
| 675 | 646 | static int vif_delete(struct mr_table *mrt, int vifi, int notify, |
|---|
| 676 | 647 | struct list_head *head) |
|---|
| .. | .. |
|---|
| 839 | 810 | static int vif_add(struct net *net, struct mr_table *mrt, |
|---|
| 840 | 811 | struct vifctl *vifc, int mrtsock) |
|---|
| 841 | 812 | { |
|---|
| 813 | + struct netdev_phys_item_id ppid = { }; |
|---|
| 842 | 814 | int vifi = vifc->vifc_vifi; |
|---|
| 843 | | - struct switchdev_attr attr = { |
|---|
| 844 | | - .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, |
|---|
| 845 | | - }; |
|---|
| 846 | 815 | struct vif_device *v = &mrt->vif_table[vifi]; |
|---|
| 847 | 816 | struct net_device *dev; |
|---|
| 848 | 817 | struct in_device *in_dev; |
|---|
| .. | .. |
|---|
| 873 | 842 | break; |
|---|
| 874 | 843 | case VIFF_TUNNEL: |
|---|
| 875 | 844 | dev = ipmr_new_tunnel(net, vifc); |
|---|
| 876 | | - if (!dev) |
|---|
| 877 | | - return -ENOBUFS; |
|---|
| 878 | | - err = dev_set_allmulti(dev, 1); |
|---|
| 879 | | - if (err) { |
|---|
| 880 | | - ipmr_del_tunnel(dev, vifc); |
|---|
| 881 | | - dev_put(dev); |
|---|
| 882 | | - return err; |
|---|
| 883 | | - } |
|---|
| 845 | + if (IS_ERR(dev)) |
|---|
| 846 | + return PTR_ERR(dev); |
|---|
| 884 | 847 | break; |
|---|
| 885 | 848 | case VIFF_USE_IFINDEX: |
|---|
| 886 | 849 | case 0: |
|---|
| .. | .. |
|---|
| 921 | 884 | vifc->vifc_flags | (!mrtsock ? VIFF_STATIC : 0), |
|---|
| 922 | 885 | (VIFF_TUNNEL | VIFF_REGISTER)); |
|---|
| 923 | 886 | |
|---|
| 924 | | - attr.orig_dev = dev; |
|---|
| 925 | | - if (!switchdev_port_attr_get(dev, &attr)) { |
|---|
| 926 | | - memcpy(v->dev_parent_id.id, attr.u.ppid.id, attr.u.ppid.id_len); |
|---|
| 927 | | - v->dev_parent_id.id_len = attr.u.ppid.id_len; |
|---|
| 887 | + err = dev_get_port_parent_id(dev, &ppid, true); |
|---|
| 888 | + if (err == 0) { |
|---|
| 889 | + memcpy(v->dev_parent_id.id, ppid.id, ppid.id_len); |
|---|
| 890 | + v->dev_parent_id.id_len = ppid.id_len; |
|---|
| 928 | 891 | } else { |
|---|
| 929 | 892 | v->dev_parent_id.id_len = 0; |
|---|
| 930 | 893 | } |
|---|
| .. | .. |
|---|
| 1077 | 1040 | memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr)); |
|---|
| 1078 | 1041 | msg->im_msgtype = assert; |
|---|
| 1079 | 1042 | msg->im_mbz = 0; |
|---|
| 1080 | | - if (assert == IGMPMSG_WRVIFWHOLE) |
|---|
| 1043 | + if (assert == IGMPMSG_WRVIFWHOLE) { |
|---|
| 1081 | 1044 | msg->im_vif = vifi; |
|---|
| 1082 | | - else |
|---|
| 1045 | + msg->im_vif_hi = vifi >> 8; |
|---|
| 1046 | + } else { |
|---|
| 1083 | 1047 | msg->im_vif = mrt->mroute_reg_vif_num; |
|---|
| 1048 | + msg->im_vif_hi = mrt->mroute_reg_vif_num >> 8; |
|---|
| 1049 | + } |
|---|
| 1084 | 1050 | ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2; |
|---|
| 1085 | 1051 | ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) + |
|---|
| 1086 | 1052 | sizeof(struct iphdr)); |
|---|
| .. | .. |
|---|
| 1093 | 1059 | ip_hdr(skb)->protocol = 0; |
|---|
| 1094 | 1060 | msg = (struct igmpmsg *)skb_network_header(skb); |
|---|
| 1095 | 1061 | msg->im_vif = vifi; |
|---|
| 1062 | + msg->im_vif_hi = vifi >> 8; |
|---|
| 1096 | 1063 | skb_dst_set(skb, dst_clone(skb_dst(pkt))); |
|---|
| 1097 | 1064 | /* Add our header */ |
|---|
| 1098 | 1065 | igmp = skb_put(skb, sizeof(struct igmphdr)); |
|---|
| .. | .. |
|---|
| 1144 | 1111 | |
|---|
| 1145 | 1112 | if (!found) { |
|---|
| 1146 | 1113 | /* Create a new entry if allowable */ |
|---|
| 1147 | | - if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 || |
|---|
| 1148 | | - (c = ipmr_cache_alloc_unres()) == NULL) { |
|---|
| 1114 | + c = ipmr_cache_alloc_unres(); |
|---|
| 1115 | + if (!c) { |
|---|
| 1149 | 1116 | spin_unlock_bh(&mfc_unres_lock); |
|---|
| 1150 | 1117 | |
|---|
| 1151 | 1118 | kfree_skb(skb); |
|---|
| .. | .. |
|---|
| 1301 | 1268 | } |
|---|
| 1302 | 1269 | |
|---|
| 1303 | 1270 | /* Close the multicast socket, and clear the vif tables etc */ |
|---|
| 1304 | | -static void mroute_clean_tables(struct mr_table *mrt, bool all) |
|---|
| 1271 | +static void mroute_clean_tables(struct mr_table *mrt, int flags) |
|---|
| 1305 | 1272 | { |
|---|
| 1306 | 1273 | struct net *net = read_pnet(&mrt->net); |
|---|
| 1307 | 1274 | struct mr_mfc *c, *tmp; |
|---|
| .. | .. |
|---|
| 1310 | 1277 | int i; |
|---|
| 1311 | 1278 | |
|---|
| 1312 | 1279 | /* Shut down all active vif entries */ |
|---|
| 1313 | | - for (i = 0; i < mrt->maxvif; i++) { |
|---|
| 1314 | | - if (!all && (mrt->vif_table[i].flags & VIFF_STATIC)) |
|---|
| 1315 | | - continue; |
|---|
| 1316 | | - vif_delete(mrt, i, 0, &list); |
|---|
| 1280 | + if (flags & (MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC)) { |
|---|
| 1281 | + for (i = 0; i < mrt->maxvif; i++) { |
|---|
| 1282 | + if (((mrt->vif_table[i].flags & VIFF_STATIC) && |
|---|
| 1283 | + !(flags & MRT_FLUSH_VIFS_STATIC)) || |
|---|
| 1284 | + (!(mrt->vif_table[i].flags & VIFF_STATIC) && !(flags & MRT_FLUSH_VIFS))) |
|---|
| 1285 | + continue; |
|---|
| 1286 | + vif_delete(mrt, i, 0, &list); |
|---|
| 1287 | + } |
|---|
| 1288 | + unregister_netdevice_many(&list); |
|---|
| 1317 | 1289 | } |
|---|
| 1318 | | - unregister_netdevice_many(&list); |
|---|
| 1319 | 1290 | |
|---|
| 1320 | 1291 | /* Wipe the cache */ |
|---|
| 1321 | | - list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) { |
|---|
| 1322 | | - if (!all && (c->mfc_flags & MFC_STATIC)) |
|---|
| 1323 | | - continue; |
|---|
| 1324 | | - rhltable_remove(&mrt->mfc_hash, &c->mnode, ipmr_rht_params); |
|---|
| 1325 | | - list_del_rcu(&c->list); |
|---|
| 1326 | | - cache = (struct mfc_cache *)c; |
|---|
| 1327 | | - call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, cache, |
|---|
| 1328 | | - mrt->id); |
|---|
| 1329 | | - mroute_netlink_event(mrt, cache, RTM_DELROUTE); |
|---|
| 1330 | | - mr_cache_put(c); |
|---|
| 1292 | + if (flags & (MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC)) { |
|---|
| 1293 | + list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) { |
|---|
| 1294 | + if (((c->mfc_flags & MFC_STATIC) && !(flags & MRT_FLUSH_MFC_STATIC)) || |
|---|
| 1295 | + (!(c->mfc_flags & MFC_STATIC) && !(flags & MRT_FLUSH_MFC))) |
|---|
| 1296 | + continue; |
|---|
| 1297 | + rhltable_remove(&mrt->mfc_hash, &c->mnode, ipmr_rht_params); |
|---|
| 1298 | + list_del_rcu(&c->list); |
|---|
| 1299 | + cache = (struct mfc_cache *)c; |
|---|
| 1300 | + call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, cache, |
|---|
| 1301 | + mrt->id); |
|---|
| 1302 | + mroute_netlink_event(mrt, cache, RTM_DELROUTE); |
|---|
| 1303 | + mr_cache_put(c); |
|---|
| 1304 | + } |
|---|
| 1331 | 1305 | } |
|---|
| 1332 | 1306 | |
|---|
| 1333 | | - if (atomic_read(&mrt->cache_resolve_queue_len) != 0) { |
|---|
| 1334 | | - spin_lock_bh(&mfc_unres_lock); |
|---|
| 1335 | | - list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { |
|---|
| 1336 | | - list_del(&c->list); |
|---|
| 1337 | | - cache = (struct mfc_cache *)c; |
|---|
| 1338 | | - mroute_netlink_event(mrt, cache, RTM_DELROUTE); |
|---|
| 1339 | | - ipmr_destroy_unres(mrt, cache); |
|---|
| 1307 | + if (flags & MRT_FLUSH_MFC) { |
|---|
| 1308 | + if (atomic_read(&mrt->cache_resolve_queue_len) != 0) { |
|---|
| 1309 | + spin_lock_bh(&mfc_unres_lock); |
|---|
| 1310 | + list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { |
|---|
| 1311 | + list_del(&c->list); |
|---|
| 1312 | + cache = (struct mfc_cache *)c; |
|---|
| 1313 | + mroute_netlink_event(mrt, cache, RTM_DELROUTE); |
|---|
| 1314 | + ipmr_destroy_unres(mrt, cache); |
|---|
| 1315 | + } |
|---|
| 1316 | + spin_unlock_bh(&mfc_unres_lock); |
|---|
| 1340 | 1317 | } |
|---|
| 1341 | | - spin_unlock_bh(&mfc_unres_lock); |
|---|
| 1342 | 1318 | } |
|---|
| 1343 | 1319 | } |
|---|
| 1344 | 1320 | |
|---|
| .. | .. |
|---|
| 1359 | 1335 | NETCONFA_IFINDEX_ALL, |
|---|
| 1360 | 1336 | net->ipv4.devconf_all); |
|---|
| 1361 | 1337 | RCU_INIT_POINTER(mrt->mroute_sk, NULL); |
|---|
| 1362 | | - mroute_clean_tables(mrt, false); |
|---|
| 1338 | + mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_MFC); |
|---|
| 1363 | 1339 | } |
|---|
| 1364 | 1340 | } |
|---|
| 1365 | 1341 | rtnl_unlock(); |
|---|
| .. | .. |
|---|
| 1371 | 1347 | * MOSPF/PIM router set up we can clean this up. |
|---|
| 1372 | 1348 | */ |
|---|
| 1373 | 1349 | |
|---|
| 1374 | | -int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, |
|---|
| 1350 | +int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval, |
|---|
| 1375 | 1351 | unsigned int optlen) |
|---|
| 1376 | 1352 | { |
|---|
| 1377 | 1353 | struct net *net = sock_net(sk); |
|---|
| .. | .. |
|---|
| 1443 | 1419 | ret = -EINVAL; |
|---|
| 1444 | 1420 | break; |
|---|
| 1445 | 1421 | } |
|---|
| 1446 | | - if (copy_from_user(&vif, optval, sizeof(vif))) { |
|---|
| 1422 | + if (copy_from_sockptr(&vif, optval, sizeof(vif))) { |
|---|
| 1447 | 1423 | ret = -EFAULT; |
|---|
| 1448 | 1424 | break; |
|---|
| 1449 | 1425 | } |
|---|
| .. | .. |
|---|
| 1464 | 1440 | case MRT_ADD_MFC: |
|---|
| 1465 | 1441 | case MRT_DEL_MFC: |
|---|
| 1466 | 1442 | parent = -1; |
|---|
| 1467 | | - /* fall through */ |
|---|
| 1443 | + fallthrough; |
|---|
| 1468 | 1444 | case MRT_ADD_MFC_PROXY: |
|---|
| 1469 | 1445 | case MRT_DEL_MFC_PROXY: |
|---|
| 1470 | 1446 | if (optlen != sizeof(mfc)) { |
|---|
| 1471 | 1447 | ret = -EINVAL; |
|---|
| 1472 | 1448 | break; |
|---|
| 1473 | 1449 | } |
|---|
| 1474 | | - if (copy_from_user(&mfc, optval, sizeof(mfc))) { |
|---|
| 1450 | + if (copy_from_sockptr(&mfc, optval, sizeof(mfc))) { |
|---|
| 1475 | 1451 | ret = -EFAULT; |
|---|
| 1476 | 1452 | break; |
|---|
| 1477 | 1453 | } |
|---|
| .. | .. |
|---|
| 1484 | 1460 | sk == rtnl_dereference(mrt->mroute_sk), |
|---|
| 1485 | 1461 | parent); |
|---|
| 1486 | 1462 | break; |
|---|
| 1463 | + case MRT_FLUSH: |
|---|
| 1464 | + if (optlen != sizeof(val)) { |
|---|
| 1465 | + ret = -EINVAL; |
|---|
| 1466 | + break; |
|---|
| 1467 | + } |
|---|
| 1468 | + if (copy_from_sockptr(&val, optval, sizeof(val))) { |
|---|
| 1469 | + ret = -EFAULT; |
|---|
| 1470 | + break; |
|---|
| 1471 | + } |
|---|
| 1472 | + mroute_clean_tables(mrt, val); |
|---|
| 1473 | + break; |
|---|
| 1487 | 1474 | /* Control PIM assert. */ |
|---|
| 1488 | 1475 | case MRT_ASSERT: |
|---|
| 1489 | 1476 | if (optlen != sizeof(val)) { |
|---|
| 1490 | 1477 | ret = -EINVAL; |
|---|
| 1491 | 1478 | break; |
|---|
| 1492 | 1479 | } |
|---|
| 1493 | | - if (get_user(val, (int __user *)optval)) { |
|---|
| 1480 | + if (copy_from_sockptr(&val, optval, sizeof(val))) { |
|---|
| 1494 | 1481 | ret = -EFAULT; |
|---|
| 1495 | 1482 | break; |
|---|
| 1496 | 1483 | } |
|---|
| .. | .. |
|---|
| 1505 | 1492 | ret = -EINVAL; |
|---|
| 1506 | 1493 | break; |
|---|
| 1507 | 1494 | } |
|---|
| 1508 | | - if (get_user(val, (int __user *)optval)) { |
|---|
| 1495 | + if (copy_from_sockptr(&val, optval, sizeof(val))) { |
|---|
| 1509 | 1496 | ret = -EFAULT; |
|---|
| 1510 | 1497 | break; |
|---|
| 1511 | 1498 | } |
|---|
| .. | .. |
|---|
| 1527 | 1514 | ret = -EINVAL; |
|---|
| 1528 | 1515 | break; |
|---|
| 1529 | 1516 | } |
|---|
| 1530 | | - if (get_user(uval, (u32 __user *)optval)) { |
|---|
| 1517 | + if (copy_from_sockptr(&uval, optval, sizeof(uval))) { |
|---|
| 1531 | 1518 | ret = -EFAULT; |
|---|
| 1532 | 1519 | break; |
|---|
| 1533 | 1520 | } |
|---|
| .. | .. |
|---|
| 1784 | 1771 | ip_send_check(iph); |
|---|
| 1785 | 1772 | |
|---|
| 1786 | 1773 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
|---|
| 1787 | | - nf_reset(skb); |
|---|
| 1774 | + nf_reset_ct(skb); |
|---|
| 1788 | 1775 | } |
|---|
| 1789 | 1776 | |
|---|
| 1790 | 1777 | static inline int ipmr_forward_finish(struct net *net, struct sock *sk, |
|---|
| .. | .. |
|---|
| 1808 | 1795 | struct vif_device *out_vif = &mrt->vif_table[out_vifi]; |
|---|
| 1809 | 1796 | struct vif_device *in_vif = &mrt->vif_table[in_vifi]; |
|---|
| 1810 | 1797 | |
|---|
| 1811 | | - if (!skb->offload_mr_fwd_mark) |
|---|
| 1798 | + if (!skb->offload_l3_fwd_mark) |
|---|
| 1812 | 1799 | return false; |
|---|
| 1813 | 1800 | if (!out_vif->dev_parent_id.id_len || !in_vif->dev_parent_id.id_len) |
|---|
| 1814 | 1801 | return false; |
|---|
| .. | .. |
|---|
| 1826 | 1813 | /* Processing handlers for ipmr_forward */ |
|---|
| 1827 | 1814 | |
|---|
| 1828 | 1815 | static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, |
|---|
| 1829 | | - int in_vifi, struct sk_buff *skb, |
|---|
| 1830 | | - struct mfc_cache *c, int vifi) |
|---|
| 1816 | + int in_vifi, struct sk_buff *skb, int vifi) |
|---|
| 1831 | 1817 | { |
|---|
| 1832 | 1818 | const struct iphdr *iph = ip_hdr(skb); |
|---|
| 1833 | 1819 | struct vif_device *vif = &mrt->vif_table[vifi]; |
|---|
| .. | .. |
|---|
| 2033 | 2019 | |
|---|
| 2034 | 2020 | if (skb2) |
|---|
| 2035 | 2021 | ipmr_queue_xmit(net, mrt, true_vifi, |
|---|
| 2036 | | - skb2, c, psend); |
|---|
| 2022 | + skb2, psend); |
|---|
| 2037 | 2023 | } |
|---|
| 2038 | 2024 | psend = ct; |
|---|
| 2039 | 2025 | } |
|---|
| .. | .. |
|---|
| 2045 | 2031 | |
|---|
| 2046 | 2032 | if (skb2) |
|---|
| 2047 | 2033 | ipmr_queue_xmit(net, mrt, true_vifi, skb2, |
|---|
| 2048 | | - c, psend); |
|---|
| 2034 | + psend); |
|---|
| 2049 | 2035 | } else { |
|---|
| 2050 | | - ipmr_queue_xmit(net, mrt, true_vifi, skb, c, psend); |
|---|
| 2036 | + ipmr_queue_xmit(net, mrt, true_vifi, skb, psend); |
|---|
| 2051 | 2037 | return; |
|---|
| 2052 | 2038 | } |
|---|
| 2053 | 2039 | } |
|---|
| .. | .. |
|---|
| 2131 | 2117 | |
|---|
| 2132 | 2118 | mroute_sk = rcu_dereference(mrt->mroute_sk); |
|---|
| 2133 | 2119 | if (mroute_sk) { |
|---|
| 2134 | | - nf_reset(skb); |
|---|
| 2120 | + nf_reset_ct(skb); |
|---|
| 2135 | 2121 | raw_rcv(mroute_sk, skb); |
|---|
| 2136 | 2122 | return 0; |
|---|
| 2137 | 2123 | } |
|---|
| .. | .. |
|---|
| 2416 | 2402 | + nla_total_size(4) /* IPMRA_CREPORT_VIF_ID */ |
|---|
| 2417 | 2403 | + nla_total_size(4) /* IPMRA_CREPORT_SRC_ADDR */ |
|---|
| 2418 | 2404 | + nla_total_size(4) /* IPMRA_CREPORT_DST_ADDR */ |
|---|
| 2405 | + + nla_total_size(4) /* IPMRA_CREPORT_TABLE */ |
|---|
| 2419 | 2406 | /* IPMRA_CREPORT_PKT */ |
|---|
| 2420 | 2407 | + nla_total_size(payloadlen) |
|---|
| 2421 | 2408 | ; |
|---|
| .. | .. |
|---|
| 2447 | 2434 | rtgenm = nlmsg_data(nlh); |
|---|
| 2448 | 2435 | rtgenm->rtgen_family = RTNL_FAMILY_IPMR; |
|---|
| 2449 | 2436 | if (nla_put_u8(skb, IPMRA_CREPORT_MSGTYPE, msg->im_msgtype) || |
|---|
| 2450 | | - nla_put_u32(skb, IPMRA_CREPORT_VIF_ID, msg->im_vif) || |
|---|
| 2437 | + nla_put_u32(skb, IPMRA_CREPORT_VIF_ID, msg->im_vif | (msg->im_vif_hi << 8)) || |
|---|
| 2451 | 2438 | nla_put_in_addr(skb, IPMRA_CREPORT_SRC_ADDR, |
|---|
| 2452 | 2439 | msg->im_src.s_addr) || |
|---|
| 2453 | 2440 | nla_put_in_addr(skb, IPMRA_CREPORT_DST_ADDR, |
|---|
| 2454 | | - msg->im_dst.s_addr)) |
|---|
| 2441 | + msg->im_dst.s_addr) || |
|---|
| 2442 | + nla_put_u32(skb, IPMRA_CREPORT_TABLE, mrt->id)) |
|---|
| 2455 | 2443 | goto nla_put_failure; |
|---|
| 2456 | 2444 | |
|---|
| 2457 | 2445 | nla = nla_reserve(skb, IPMRA_CREPORT_PKT, payloadlen); |
|---|
| .. | .. |
|---|
| 2471 | 2459 | rtnl_set_sk_err(net, RTNLGRP_IPV4_MROUTE_R, -ENOBUFS); |
|---|
| 2472 | 2460 | } |
|---|
| 2473 | 2461 | |
|---|
| 2462 | +static int ipmr_rtm_valid_getroute_req(struct sk_buff *skb, |
|---|
| 2463 | + const struct nlmsghdr *nlh, |
|---|
| 2464 | + struct nlattr **tb, |
|---|
| 2465 | + struct netlink_ext_ack *extack) |
|---|
| 2466 | +{ |
|---|
| 2467 | + struct rtmsg *rtm; |
|---|
| 2468 | + int i, err; |
|---|
| 2469 | + |
|---|
| 2470 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) { |
|---|
| 2471 | + NL_SET_ERR_MSG(extack, "ipv4: Invalid header for multicast route get request"); |
|---|
| 2472 | + return -EINVAL; |
|---|
| 2473 | + } |
|---|
| 2474 | + |
|---|
| 2475 | + if (!netlink_strict_get_check(skb)) |
|---|
| 2476 | + return nlmsg_parse_deprecated(nlh, sizeof(*rtm), tb, RTA_MAX, |
|---|
| 2477 | + rtm_ipv4_policy, extack); |
|---|
| 2478 | + |
|---|
| 2479 | + rtm = nlmsg_data(nlh); |
|---|
| 2480 | + if ((rtm->rtm_src_len && rtm->rtm_src_len != 32) || |
|---|
| 2481 | + (rtm->rtm_dst_len && rtm->rtm_dst_len != 32) || |
|---|
| 2482 | + rtm->rtm_tos || rtm->rtm_table || rtm->rtm_protocol || |
|---|
| 2483 | + rtm->rtm_scope || rtm->rtm_type || rtm->rtm_flags) { |
|---|
| 2484 | + NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for multicast route get request"); |
|---|
| 2485 | + return -EINVAL; |
|---|
| 2486 | + } |
|---|
| 2487 | + |
|---|
| 2488 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(*rtm), tb, RTA_MAX, |
|---|
| 2489 | + rtm_ipv4_policy, extack); |
|---|
| 2490 | + if (err) |
|---|
| 2491 | + return err; |
|---|
| 2492 | + |
|---|
| 2493 | + if ((tb[RTA_SRC] && !rtm->rtm_src_len) || |
|---|
| 2494 | + (tb[RTA_DST] && !rtm->rtm_dst_len)) { |
|---|
| 2495 | + NL_SET_ERR_MSG(extack, "ipv4: rtm_src_len and rtm_dst_len must be 32 for IPv4"); |
|---|
| 2496 | + return -EINVAL; |
|---|
| 2497 | + } |
|---|
| 2498 | + |
|---|
| 2499 | + for (i = 0; i <= RTA_MAX; i++) { |
|---|
| 2500 | + if (!tb[i]) |
|---|
| 2501 | + continue; |
|---|
| 2502 | + |
|---|
| 2503 | + switch (i) { |
|---|
| 2504 | + case RTA_SRC: |
|---|
| 2505 | + case RTA_DST: |
|---|
| 2506 | + case RTA_TABLE: |
|---|
| 2507 | + break; |
|---|
| 2508 | + default: |
|---|
| 2509 | + NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in multicast route get request"); |
|---|
| 2510 | + return -EINVAL; |
|---|
| 2511 | + } |
|---|
| 2512 | + } |
|---|
| 2513 | + |
|---|
| 2514 | + return 0; |
|---|
| 2515 | +} |
|---|
| 2516 | + |
|---|
| 2474 | 2517 | static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, |
|---|
| 2475 | 2518 | struct netlink_ext_ack *extack) |
|---|
| 2476 | 2519 | { |
|---|
| .. | .. |
|---|
| 2479 | 2522 | struct sk_buff *skb = NULL; |
|---|
| 2480 | 2523 | struct mfc_cache *cache; |
|---|
| 2481 | 2524 | struct mr_table *mrt; |
|---|
| 2482 | | - struct rtmsg *rtm; |
|---|
| 2483 | 2525 | __be32 src, grp; |
|---|
| 2484 | 2526 | u32 tableid; |
|---|
| 2485 | 2527 | int err; |
|---|
| 2486 | 2528 | |
|---|
| 2487 | | - err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, |
|---|
| 2488 | | - rtm_ipv4_policy, extack); |
|---|
| 2529 | + err = ipmr_rtm_valid_getroute_req(in_skb, nlh, tb, extack); |
|---|
| 2489 | 2530 | if (err < 0) |
|---|
| 2490 | 2531 | goto errout; |
|---|
| 2491 | | - |
|---|
| 2492 | | - rtm = nlmsg_data(nlh); |
|---|
| 2493 | 2532 | |
|---|
| 2494 | 2533 | src = tb[RTA_SRC] ? nla_get_in_addr(tb[RTA_SRC]) : 0; |
|---|
| 2495 | 2534 | grp = tb[RTA_DST] ? nla_get_in_addr(tb[RTA_DST]) : 0; |
|---|
| .. | .. |
|---|
| 2534 | 2573 | |
|---|
| 2535 | 2574 | static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) |
|---|
| 2536 | 2575 | { |
|---|
| 2576 | + struct fib_dump_filter filter = {}; |
|---|
| 2577 | + int err; |
|---|
| 2578 | + |
|---|
| 2579 | + if (cb->strict_check) { |
|---|
| 2580 | + err = ip_valid_fib_dump_req(sock_net(skb->sk), cb->nlh, |
|---|
| 2581 | + &filter, cb); |
|---|
| 2582 | + if (err < 0) |
|---|
| 2583 | + return err; |
|---|
| 2584 | + } |
|---|
| 2585 | + |
|---|
| 2586 | + if (filter.table_id) { |
|---|
| 2587 | + struct mr_table *mrt; |
|---|
| 2588 | + |
|---|
| 2589 | + mrt = ipmr_get_table(sock_net(skb->sk), filter.table_id); |
|---|
| 2590 | + if (!mrt) { |
|---|
| 2591 | + if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IPMR) |
|---|
| 2592 | + return skb->len; |
|---|
| 2593 | + |
|---|
| 2594 | + NL_SET_ERR_MSG(cb->extack, "ipv4: MR table does not exist"); |
|---|
| 2595 | + return -ENOENT; |
|---|
| 2596 | + } |
|---|
| 2597 | + err = mr_table_dump(mrt, skb, cb, _ipmr_fill_mroute, |
|---|
| 2598 | + &mfc_unres_lock, &filter); |
|---|
| 2599 | + return skb->len ? : err; |
|---|
| 2600 | + } |
|---|
| 2601 | + |
|---|
| 2537 | 2602 | return mr_rtm_dumproute(skb, cb, ipmr_mr_table_iter, |
|---|
| 2538 | | - _ipmr_fill_mroute, &mfc_unres_lock); |
|---|
| 2603 | + _ipmr_fill_mroute, &mfc_unres_lock, &filter); |
|---|
| 2539 | 2604 | } |
|---|
| 2540 | 2605 | |
|---|
| 2541 | 2606 | static const struct nla_policy rtm_ipmr_policy[RTA_MAX + 1] = { |
|---|
| .. | .. |
|---|
| 2584 | 2649 | struct rtmsg *rtm; |
|---|
| 2585 | 2650 | int ret, rem; |
|---|
| 2586 | 2651 | |
|---|
| 2587 | | - ret = nlmsg_validate(nlh, sizeof(*rtm), RTA_MAX, rtm_ipmr_policy, |
|---|
| 2588 | | - extack); |
|---|
| 2652 | + ret = nlmsg_validate_deprecated(nlh, sizeof(*rtm), RTA_MAX, |
|---|
| 2653 | + rtm_ipmr_policy, extack); |
|---|
| 2589 | 2654 | if (ret < 0) |
|---|
| 2590 | 2655 | goto out; |
|---|
| 2591 | 2656 | rtm = nlmsg_data(nlh); |
|---|
| .. | .. |
|---|
| 2693 | 2758 | return true; |
|---|
| 2694 | 2759 | |
|---|
| 2695 | 2760 | vif = &mrt->vif_table[vifid]; |
|---|
| 2696 | | - vif_nest = nla_nest_start(skb, IPMRA_VIF); |
|---|
| 2761 | + vif_nest = nla_nest_start_noflag(skb, IPMRA_VIF); |
|---|
| 2697 | 2762 | if (!vif_nest) |
|---|
| 2698 | 2763 | return false; |
|---|
| 2699 | 2764 | if (nla_put_u32(skb, IPMRA_VIFA_IFINDEX, vif->dev->ifindex) || |
|---|
| .. | .. |
|---|
| 2717 | 2782 | return true; |
|---|
| 2718 | 2783 | } |
|---|
| 2719 | 2784 | |
|---|
| 2785 | +static int ipmr_valid_dumplink(const struct nlmsghdr *nlh, |
|---|
| 2786 | + struct netlink_ext_ack *extack) |
|---|
| 2787 | +{ |
|---|
| 2788 | + struct ifinfomsg *ifm; |
|---|
| 2789 | + |
|---|
| 2790 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
|---|
| 2791 | + NL_SET_ERR_MSG(extack, "ipv4: Invalid header for ipmr link dump"); |
|---|
| 2792 | + return -EINVAL; |
|---|
| 2793 | + } |
|---|
| 2794 | + |
|---|
| 2795 | + if (nlmsg_attrlen(nlh, sizeof(*ifm))) { |
|---|
| 2796 | + NL_SET_ERR_MSG(extack, "Invalid data after header in ipmr link dump"); |
|---|
| 2797 | + return -EINVAL; |
|---|
| 2798 | + } |
|---|
| 2799 | + |
|---|
| 2800 | + ifm = nlmsg_data(nlh); |
|---|
| 2801 | + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || |
|---|
| 2802 | + ifm->ifi_change || ifm->ifi_index) { |
|---|
| 2803 | + NL_SET_ERR_MSG(extack, "Invalid values in header for ipmr link dump request"); |
|---|
| 2804 | + return -EINVAL; |
|---|
| 2805 | + } |
|---|
| 2806 | + |
|---|
| 2807 | + return 0; |
|---|
| 2808 | +} |
|---|
| 2809 | + |
|---|
| 2720 | 2810 | static int ipmr_rtm_dumplink(struct sk_buff *skb, struct netlink_callback *cb) |
|---|
| 2721 | 2811 | { |
|---|
| 2722 | 2812 | struct net *net = sock_net(skb->sk); |
|---|
| .. | .. |
|---|
| 2724 | 2814 | unsigned int t = 0, s_t; |
|---|
| 2725 | 2815 | unsigned int e = 0, s_e; |
|---|
| 2726 | 2816 | struct mr_table *mrt; |
|---|
| 2817 | + |
|---|
| 2818 | + if (cb->strict_check) { |
|---|
| 2819 | + int err = ipmr_valid_dumplink(cb->nlh, cb->extack); |
|---|
| 2820 | + |
|---|
| 2821 | + if (err < 0) |
|---|
| 2822 | + return err; |
|---|
| 2823 | + } |
|---|
| 2727 | 2824 | |
|---|
| 2728 | 2825 | s_t = cb->args[0]; |
|---|
| 2729 | 2826 | s_e = cb->args[1]; |
|---|
| .. | .. |
|---|
| 2745 | 2842 | memset(hdr, 0, sizeof(*hdr)); |
|---|
| 2746 | 2843 | hdr->ifi_family = RTNL_FAMILY_IPMR; |
|---|
| 2747 | 2844 | |
|---|
| 2748 | | - af = nla_nest_start(skb, IFLA_AF_SPEC); |
|---|
| 2845 | + af = nla_nest_start_noflag(skb, IFLA_AF_SPEC); |
|---|
| 2749 | 2846 | if (!af) { |
|---|
| 2750 | 2847 | nlmsg_cancel(skb, nlh); |
|---|
| 2751 | 2848 | goto out; |
|---|
| .. | .. |
|---|
| 2756 | 2853 | goto out; |
|---|
| 2757 | 2854 | } |
|---|
| 2758 | 2855 | |
|---|
| 2759 | | - vifs = nla_nest_start(skb, IPMRA_TABLE_VIFS); |
|---|
| 2856 | + vifs = nla_nest_start_noflag(skb, IPMRA_TABLE_VIFS); |
|---|
| 2760 | 2857 | if (!vifs) { |
|---|
| 2761 | 2858 | nla_nest_end(skb, af); |
|---|
| 2762 | 2859 | nlmsg_end(skb, nlh); |
|---|
| .. | .. |
|---|
| 2923 | 3020 | return net->ipv4.ipmr_seq + ipmr_rules_seq_read(net); |
|---|
| 2924 | 3021 | } |
|---|
| 2925 | 3022 | |
|---|
| 2926 | | -static int ipmr_dump(struct net *net, struct notifier_block *nb) |
|---|
| 3023 | +static int ipmr_dump(struct net *net, struct notifier_block *nb, |
|---|
| 3024 | + struct netlink_ext_ack *extack) |
|---|
| 2927 | 3025 | { |
|---|
| 2928 | 3026 | return mr_dump(net, nb, RTNL_FAMILY_IPMR, ipmr_rules_dump, |
|---|
| 2929 | | - ipmr_mr_table_iter, &mrt_lock); |
|---|
| 3027 | + ipmr_mr_table_iter, &mrt_lock, extack); |
|---|
| 2930 | 3028 | } |
|---|
| 2931 | 3029 | |
|---|
| 2932 | 3030 | static const struct fib_notifier_ops ipmr_notifier_ops_template = { |
|---|