.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * INET An implementation of the TCP/IP protocol suite for the LINUX |
---|
3 | 4 | * operating system. INET is implemented using the BSD Socket |
---|
.. | .. |
---|
6 | 7 | * Routing netlink socket interface: protocol independent part. |
---|
7 | 8 | * |
---|
8 | 9 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can redistribute it and/or |
---|
11 | | - * modify it under the terms of the GNU General Public License |
---|
12 | | - * as published by the Free Software Foundation; either version |
---|
13 | | - * 2 of the License, or (at your option) any later version. |
---|
14 | 10 | * |
---|
15 | 11 | * Fixes: |
---|
16 | 12 | * Vitaly E. Lavrov RTA_OK arithmetics was wrong. |
---|
.. | .. |
---|
46 | 42 | |
---|
47 | 43 | #include <linux/inet.h> |
---|
48 | 44 | #include <linux/netdevice.h> |
---|
49 | | -#include <net/switchdev.h> |
---|
50 | 45 | #include <net/ip.h> |
---|
51 | 46 | #include <net/protocol.h> |
---|
52 | 47 | #include <net/arp.h> |
---|
.. | .. |
---|
59 | 54 | #include <net/rtnetlink.h> |
---|
60 | 55 | #include <net/net_namespace.h> |
---|
61 | 56 | |
---|
62 | | -#define RTNL_MAX_TYPE 48 |
---|
| 57 | +#define RTNL_MAX_TYPE 50 |
---|
63 | 58 | #define RTNL_SLAVE_MAX_TYPE 36 |
---|
64 | 59 | |
---|
65 | 60 | struct rtnl_link { |
---|
.. | .. |
---|
635 | 630 | if (nla_put_string(skb, IFLA_INFO_SLAVE_KIND, ops->kind) < 0) |
---|
636 | 631 | return -EMSGSIZE; |
---|
637 | 632 | if (ops->fill_slave_info) { |
---|
638 | | - slave_data = nla_nest_start(skb, IFLA_INFO_SLAVE_DATA); |
---|
| 633 | + slave_data = nla_nest_start_noflag(skb, IFLA_INFO_SLAVE_DATA); |
---|
639 | 634 | if (!slave_data) |
---|
640 | 635 | return -EMSGSIZE; |
---|
641 | 636 | err = ops->fill_slave_info(skb, master_dev, dev); |
---|
.. | .. |
---|
667 | 662 | return err; |
---|
668 | 663 | } |
---|
669 | 664 | if (ops->fill_info) { |
---|
670 | | - data = nla_nest_start(skb, IFLA_INFO_DATA); |
---|
| 665 | + data = nla_nest_start_noflag(skb, IFLA_INFO_DATA); |
---|
671 | 666 | if (data == NULL) |
---|
672 | 667 | return -EMSGSIZE; |
---|
673 | 668 | err = ops->fill_info(skb, dev); |
---|
.. | .. |
---|
687 | 682 | struct nlattr *linkinfo; |
---|
688 | 683 | int err = -EMSGSIZE; |
---|
689 | 684 | |
---|
690 | | - linkinfo = nla_nest_start(skb, IFLA_LINKINFO); |
---|
| 685 | + linkinfo = nla_nest_start_noflag(skb, IFLA_LINKINFO); |
---|
691 | 686 | if (linkinfo == NULL) |
---|
692 | 687 | goto out; |
---|
693 | 688 | |
---|
.. | .. |
---|
756 | 751 | struct nlattr *mx; |
---|
757 | 752 | int i, valid = 0; |
---|
758 | 753 | |
---|
759 | | - mx = nla_nest_start(skb, RTA_METRICS); |
---|
| 754 | + /* nothing is dumped for dst_default_metrics, so just skip the loop */ |
---|
| 755 | + if (metrics == dst_default_metrics.metrics) |
---|
| 756 | + return 0; |
---|
| 757 | + |
---|
| 758 | + mx = nla_nest_start_noflag(skb, RTA_METRICS); |
---|
760 | 759 | if (mx == NULL) |
---|
761 | 760 | return -ENOBUFS; |
---|
762 | 761 | |
---|
.. | .. |
---|
830 | 829 | switch (transition) { |
---|
831 | 830 | case IF_OPER_UP: |
---|
832 | 831 | if ((operstate == IF_OPER_DORMANT || |
---|
| 832 | + operstate == IF_OPER_TESTING || |
---|
833 | 833 | operstate == IF_OPER_UNKNOWN) && |
---|
834 | | - !netif_dormant(dev)) |
---|
| 834 | + !netif_dormant(dev) && !netif_testing(dev)) |
---|
835 | 835 | operstate = IF_OPER_UP; |
---|
| 836 | + break; |
---|
| 837 | + |
---|
| 838 | + case IF_OPER_TESTING: |
---|
| 839 | + if (operstate == IF_OPER_UP || |
---|
| 840 | + operstate == IF_OPER_UNKNOWN) |
---|
| 841 | + operstate = IF_OPER_TESTING; |
---|
836 | 842 | break; |
---|
837 | 843 | |
---|
838 | 844 | case IF_OPER_DORMANT: |
---|
.. | .. |
---|
913 | 919 | size += num_vfs * |
---|
914 | 920 | (nla_total_size(0) + |
---|
915 | 921 | nla_total_size(sizeof(struct ifla_vf_mac)) + |
---|
| 922 | + nla_total_size(sizeof(struct ifla_vf_broadcast)) + |
---|
916 | 923 | nla_total_size(sizeof(struct ifla_vf_vlan)) + |
---|
917 | 924 | nla_total_size(0) + /* nest IFLA_VF_VLAN_LIST */ |
---|
918 | 925 | nla_total_size(MAX_VLAN_LIST_LEN * |
---|
.. | .. |
---|
980 | 987 | return xdp_size; |
---|
981 | 988 | } |
---|
982 | 989 | |
---|
| 990 | +static size_t rtnl_prop_list_size(const struct net_device *dev) |
---|
| 991 | +{ |
---|
| 992 | + struct netdev_name_node *name_node; |
---|
| 993 | + size_t size; |
---|
| 994 | + |
---|
| 995 | + if (list_empty(&dev->name_node->list)) |
---|
| 996 | + return 0; |
---|
| 997 | + size = nla_total_size(0); |
---|
| 998 | + list_for_each_entry(name_node, &dev->name_node->list, list) |
---|
| 999 | + size += nla_total_size(ALTIFNAMSIZ); |
---|
| 1000 | + return size; |
---|
| 1001 | +} |
---|
| 1002 | + |
---|
| 1003 | +static size_t rtnl_proto_down_size(const struct net_device *dev) |
---|
| 1004 | +{ |
---|
| 1005 | + size_t size = nla_total_size(1); |
---|
| 1006 | + |
---|
| 1007 | + if (dev->proto_down_reason) |
---|
| 1008 | + size += nla_total_size(0) + nla_total_size(4); |
---|
| 1009 | + |
---|
| 1010 | + return size; |
---|
| 1011 | +} |
---|
| 1012 | + |
---|
983 | 1013 | static noinline size_t if_nlmsg_size(const struct net_device *dev, |
---|
984 | 1014 | u32 ext_filter_mask) |
---|
985 | 1015 | { |
---|
.. | .. |
---|
1021 | 1051 | + nla_total_size(4) /* IFLA_EVENT */ |
---|
1022 | 1052 | + nla_total_size(4) /* IFLA_NEW_NETNSID */ |
---|
1023 | 1053 | + nla_total_size(4) /* IFLA_NEW_IFINDEX */ |
---|
1024 | | - + nla_total_size(1) /* IFLA_PROTO_DOWN */ |
---|
1025 | | - + nla_total_size(4) /* IFLA_IF_NETNSID */ |
---|
| 1054 | + + rtnl_proto_down_size(dev) /* proto down */ |
---|
| 1055 | + + nla_total_size(4) /* IFLA_TARGET_NETNSID */ |
---|
1026 | 1056 | + nla_total_size(4) /* IFLA_CARRIER_UP_COUNT */ |
---|
1027 | 1057 | + nla_total_size(4) /* IFLA_CARRIER_DOWN_COUNT */ |
---|
1028 | 1058 | + nla_total_size(4) /* IFLA_MIN_MTU */ |
---|
1029 | 1059 | + nla_total_size(4) /* IFLA_MAX_MTU */ |
---|
| 1060 | + + rtnl_prop_list_size(dev) |
---|
| 1061 | + + nla_total_size(MAX_ADDR_LEN) /* IFLA_PERM_ADDRESS */ |
---|
1030 | 1062 | + 0; |
---|
1031 | 1063 | } |
---|
1032 | 1064 | |
---|
.. | .. |
---|
1037 | 1069 | int vf; |
---|
1038 | 1070 | int err; |
---|
1039 | 1071 | |
---|
1040 | | - vf_ports = nla_nest_start(skb, IFLA_VF_PORTS); |
---|
| 1072 | + vf_ports = nla_nest_start_noflag(skb, IFLA_VF_PORTS); |
---|
1041 | 1073 | if (!vf_ports) |
---|
1042 | 1074 | return -EMSGSIZE; |
---|
1043 | 1075 | |
---|
1044 | 1076 | for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++) { |
---|
1045 | | - vf_port = nla_nest_start(skb, IFLA_VF_PORT); |
---|
| 1077 | + vf_port = nla_nest_start_noflag(skb, IFLA_VF_PORT); |
---|
1046 | 1078 | if (!vf_port) |
---|
1047 | 1079 | goto nla_put_failure; |
---|
1048 | 1080 | if (nla_put_u32(skb, IFLA_PORT_VF, vf)) |
---|
.. | .. |
---|
1071 | 1103 | struct nlattr *port_self; |
---|
1072 | 1104 | int err; |
---|
1073 | 1105 | |
---|
1074 | | - port_self = nla_nest_start(skb, IFLA_PORT_SELF); |
---|
| 1106 | + port_self = nla_nest_start_noflag(skb, IFLA_PORT_SELF); |
---|
1075 | 1107 | if (!port_self) |
---|
1076 | 1108 | return -EMSGSIZE; |
---|
1077 | 1109 | |
---|
.. | .. |
---|
1146 | 1178 | |
---|
1147 | 1179 | static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev) |
---|
1148 | 1180 | { |
---|
| 1181 | + struct netdev_phys_item_id ppid = { }; |
---|
1149 | 1182 | int err; |
---|
1150 | | - struct switchdev_attr attr = { |
---|
1151 | | - .orig_dev = dev, |
---|
1152 | | - .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, |
---|
1153 | | - .flags = SWITCHDEV_F_NO_RECURSE, |
---|
1154 | | - }; |
---|
1155 | 1183 | |
---|
1156 | | - err = switchdev_port_attr_get(dev, &attr); |
---|
| 1184 | + err = dev_get_port_parent_id(dev, &ppid, false); |
---|
1157 | 1185 | if (err) { |
---|
1158 | 1186 | if (err == -EOPNOTSUPP) |
---|
1159 | 1187 | return 0; |
---|
1160 | 1188 | return err; |
---|
1161 | 1189 | } |
---|
1162 | 1190 | |
---|
1163 | | - if (nla_put(skb, IFLA_PHYS_SWITCH_ID, attr.u.ppid.id_len, |
---|
1164 | | - attr.u.ppid.id)) |
---|
| 1191 | + if (nla_put(skb, IFLA_PHYS_SWITCH_ID, ppid.id_len, ppid.id)) |
---|
1165 | 1192 | return -EMSGSIZE; |
---|
1166 | 1193 | |
---|
1167 | 1194 | return 0; |
---|
.. | .. |
---|
1207 | 1234 | struct ifla_vf_vlan vf_vlan; |
---|
1208 | 1235 | struct ifla_vf_rate vf_rate; |
---|
1209 | 1236 | struct ifla_vf_mac vf_mac; |
---|
| 1237 | + struct ifla_vf_broadcast vf_broadcast; |
---|
1210 | 1238 | struct ifla_vf_info ivi; |
---|
| 1239 | + struct ifla_vf_guid node_guid; |
---|
| 1240 | + struct ifla_vf_guid port_guid; |
---|
1211 | 1241 | |
---|
1212 | 1242 | memset(&ivi, 0, sizeof(ivi)); |
---|
1213 | 1243 | |
---|
.. | .. |
---|
1229 | 1259 | return 0; |
---|
1230 | 1260 | |
---|
1231 | 1261 | memset(&vf_vlan_info, 0, sizeof(vf_vlan_info)); |
---|
| 1262 | + memset(&node_guid, 0, sizeof(node_guid)); |
---|
| 1263 | + memset(&port_guid, 0, sizeof(port_guid)); |
---|
1232 | 1264 | |
---|
1233 | 1265 | vf_mac.vf = |
---|
1234 | 1266 | vf_vlan.vf = |
---|
.. | .. |
---|
1238 | 1270 | vf_spoofchk.vf = |
---|
1239 | 1271 | vf_linkstate.vf = |
---|
1240 | 1272 | vf_rss_query_en.vf = |
---|
1241 | | - vf_trust.vf = ivi.vf; |
---|
| 1273 | + vf_trust.vf = |
---|
| 1274 | + node_guid.vf = |
---|
| 1275 | + port_guid.vf = ivi.vf; |
---|
1242 | 1276 | |
---|
1243 | 1277 | memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac)); |
---|
| 1278 | + memcpy(vf_broadcast.broadcast, dev->broadcast, dev->addr_len); |
---|
1244 | 1279 | vf_vlan.vlan = ivi.vlan; |
---|
1245 | 1280 | vf_vlan.qos = ivi.qos; |
---|
1246 | 1281 | vf_vlan_info.vlan = ivi.vlan; |
---|
.. | .. |
---|
1253 | 1288 | vf_linkstate.link_state = ivi.linkstate; |
---|
1254 | 1289 | vf_rss_query_en.setting = ivi.rss_query_en; |
---|
1255 | 1290 | vf_trust.setting = ivi.trusted; |
---|
1256 | | - vf = nla_nest_start(skb, IFLA_VF_INFO); |
---|
| 1291 | + vf = nla_nest_start_noflag(skb, IFLA_VF_INFO); |
---|
1257 | 1292 | if (!vf) |
---|
1258 | 1293 | goto nla_put_vfinfo_failure; |
---|
1259 | 1294 | if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) || |
---|
| 1295 | + nla_put(skb, IFLA_VF_BROADCAST, sizeof(vf_broadcast), &vf_broadcast) || |
---|
1260 | 1296 | nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) || |
---|
1261 | 1297 | nla_put(skb, IFLA_VF_RATE, sizeof(vf_rate), |
---|
1262 | 1298 | &vf_rate) || |
---|
.. | .. |
---|
1272 | 1308 | nla_put(skb, IFLA_VF_TRUST, |
---|
1273 | 1309 | sizeof(vf_trust), &vf_trust)) |
---|
1274 | 1310 | goto nla_put_vf_failure; |
---|
1275 | | - vfvlanlist = nla_nest_start(skb, IFLA_VF_VLAN_LIST); |
---|
| 1311 | + |
---|
| 1312 | + if (dev->netdev_ops->ndo_get_vf_guid && |
---|
| 1313 | + !dev->netdev_ops->ndo_get_vf_guid(dev, vfs_num, &node_guid, |
---|
| 1314 | + &port_guid)) { |
---|
| 1315 | + if (nla_put(skb, IFLA_VF_IB_NODE_GUID, sizeof(node_guid), |
---|
| 1316 | + &node_guid) || |
---|
| 1317 | + nla_put(skb, IFLA_VF_IB_PORT_GUID, sizeof(port_guid), |
---|
| 1318 | + &port_guid)) |
---|
| 1319 | + goto nla_put_vf_failure; |
---|
| 1320 | + } |
---|
| 1321 | + vfvlanlist = nla_nest_start_noflag(skb, IFLA_VF_VLAN_LIST); |
---|
1276 | 1322 | if (!vfvlanlist) |
---|
1277 | 1323 | goto nla_put_vf_failure; |
---|
1278 | 1324 | if (nla_put(skb, IFLA_VF_VLAN_INFO, sizeof(vf_vlan_info), |
---|
.. | .. |
---|
1285 | 1331 | if (dev->netdev_ops->ndo_get_vf_stats) |
---|
1286 | 1332 | dev->netdev_ops->ndo_get_vf_stats(dev, vfs_num, |
---|
1287 | 1333 | &vf_stats); |
---|
1288 | | - vfstats = nla_nest_start(skb, IFLA_VF_STATS); |
---|
| 1334 | + vfstats = nla_nest_start_noflag(skb, IFLA_VF_STATS); |
---|
1289 | 1335 | if (!vfstats) |
---|
1290 | 1336 | goto nla_put_vf_failure; |
---|
1291 | 1337 | if (nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_PACKETS, |
---|
.. | .. |
---|
1335 | 1381 | if (!dev->netdev_ops->ndo_get_vf_config) |
---|
1336 | 1382 | return 0; |
---|
1337 | 1383 | |
---|
1338 | | - vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); |
---|
| 1384 | + vfinfo = nla_nest_start_noflag(skb, IFLA_VFINFO_LIST); |
---|
1339 | 1385 | if (!vfinfo) |
---|
1340 | 1386 | return -EMSGSIZE; |
---|
1341 | 1387 | |
---|
.. | .. |
---|
1380 | 1426 | |
---|
1381 | 1427 | static u32 rtnl_xdp_prog_drv(struct net_device *dev) |
---|
1382 | 1428 | { |
---|
1383 | | - return __dev_xdp_query(dev, dev->netdev_ops->ndo_bpf, XDP_QUERY_PROG); |
---|
| 1429 | + return dev_xdp_prog_id(dev, XDP_MODE_DRV); |
---|
1384 | 1430 | } |
---|
1385 | 1431 | |
---|
1386 | 1432 | static u32 rtnl_xdp_prog_hw(struct net_device *dev) |
---|
1387 | 1433 | { |
---|
1388 | | - return __dev_xdp_query(dev, dev->netdev_ops->ndo_bpf, |
---|
1389 | | - XDP_QUERY_PROG_HW); |
---|
| 1434 | + return dev_xdp_prog_id(dev, XDP_MODE_HW); |
---|
1390 | 1435 | } |
---|
1391 | 1436 | |
---|
1392 | 1437 | static int rtnl_xdp_report_one(struct sk_buff *skb, struct net_device *dev, |
---|
.. | .. |
---|
1420 | 1465 | int err; |
---|
1421 | 1466 | u8 mode; |
---|
1422 | 1467 | |
---|
1423 | | - xdp = nla_nest_start(skb, IFLA_XDP); |
---|
| 1468 | + xdp = nla_nest_start_noflag(skb, IFLA_XDP); |
---|
1424 | 1469 | if (!xdp) |
---|
1425 | 1470 | return -EMSGSIZE; |
---|
1426 | 1471 | |
---|
.. | .. |
---|
1552 | 1597 | const struct rtnl_af_ops *af_ops; |
---|
1553 | 1598 | struct nlattr *af_spec; |
---|
1554 | 1599 | |
---|
1555 | | - af_spec = nla_nest_start(skb, IFLA_AF_SPEC); |
---|
| 1600 | + af_spec = nla_nest_start_noflag(skb, IFLA_AF_SPEC); |
---|
1556 | 1601 | if (!af_spec) |
---|
1557 | 1602 | return -EMSGSIZE; |
---|
1558 | 1603 | |
---|
.. | .. |
---|
1563 | 1608 | if (!af_ops->fill_link_af) |
---|
1564 | 1609 | continue; |
---|
1565 | 1610 | |
---|
1566 | | - af = nla_nest_start(skb, af_ops->family); |
---|
| 1611 | + af = nla_nest_start_noflag(skb, af_ops->family); |
---|
1567 | 1612 | if (!af) |
---|
1568 | 1613 | return -EMSGSIZE; |
---|
1569 | 1614 | |
---|
.. | .. |
---|
1586 | 1631 | return 0; |
---|
1587 | 1632 | } |
---|
1588 | 1633 | |
---|
| 1634 | +static int rtnl_fill_alt_ifnames(struct sk_buff *skb, |
---|
| 1635 | + const struct net_device *dev) |
---|
| 1636 | +{ |
---|
| 1637 | + struct netdev_name_node *name_node; |
---|
| 1638 | + int count = 0; |
---|
| 1639 | + |
---|
| 1640 | + list_for_each_entry(name_node, &dev->name_node->list, list) { |
---|
| 1641 | + if (nla_put_string(skb, IFLA_ALT_IFNAME, name_node->name)) |
---|
| 1642 | + return -EMSGSIZE; |
---|
| 1643 | + count++; |
---|
| 1644 | + } |
---|
| 1645 | + return count; |
---|
| 1646 | +} |
---|
| 1647 | + |
---|
| 1648 | +static int rtnl_fill_prop_list(struct sk_buff *skb, |
---|
| 1649 | + const struct net_device *dev) |
---|
| 1650 | +{ |
---|
| 1651 | + struct nlattr *prop_list; |
---|
| 1652 | + int ret; |
---|
| 1653 | + |
---|
| 1654 | + prop_list = nla_nest_start(skb, IFLA_PROP_LIST); |
---|
| 1655 | + if (!prop_list) |
---|
| 1656 | + return -EMSGSIZE; |
---|
| 1657 | + |
---|
| 1658 | + ret = rtnl_fill_alt_ifnames(skb, dev); |
---|
| 1659 | + if (ret <= 0) |
---|
| 1660 | + goto nest_cancel; |
---|
| 1661 | + |
---|
| 1662 | + nla_nest_end(skb, prop_list); |
---|
| 1663 | + return 0; |
---|
| 1664 | + |
---|
| 1665 | +nest_cancel: |
---|
| 1666 | + nla_nest_cancel(skb, prop_list); |
---|
| 1667 | + return ret; |
---|
| 1668 | +} |
---|
| 1669 | + |
---|
| 1670 | +static int rtnl_fill_proto_down(struct sk_buff *skb, |
---|
| 1671 | + const struct net_device *dev) |
---|
| 1672 | +{ |
---|
| 1673 | + struct nlattr *pr; |
---|
| 1674 | + u32 preason; |
---|
| 1675 | + |
---|
| 1676 | + if (nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down)) |
---|
| 1677 | + goto nla_put_failure; |
---|
| 1678 | + |
---|
| 1679 | + preason = dev->proto_down_reason; |
---|
| 1680 | + if (!preason) |
---|
| 1681 | + return 0; |
---|
| 1682 | + |
---|
| 1683 | + pr = nla_nest_start(skb, IFLA_PROTO_DOWN_REASON); |
---|
| 1684 | + if (!pr) |
---|
| 1685 | + return -EMSGSIZE; |
---|
| 1686 | + |
---|
| 1687 | + if (nla_put_u32(skb, IFLA_PROTO_DOWN_REASON_VALUE, preason)) { |
---|
| 1688 | + nla_nest_cancel(skb, pr); |
---|
| 1689 | + goto nla_put_failure; |
---|
| 1690 | + } |
---|
| 1691 | + |
---|
| 1692 | + nla_nest_end(skb, pr); |
---|
| 1693 | + return 0; |
---|
| 1694 | + |
---|
| 1695 | +nla_put_failure: |
---|
| 1696 | + return -EMSGSIZE; |
---|
| 1697 | +} |
---|
| 1698 | + |
---|
1589 | 1699 | static int rtnl_fill_ifinfo(struct sk_buff *skb, |
---|
1590 | 1700 | struct net_device *dev, struct net *src_net, |
---|
1591 | 1701 | int type, u32 pid, u32 seq, u32 change, |
---|
.. | .. |
---|
1595 | 1705 | { |
---|
1596 | 1706 | struct ifinfomsg *ifm; |
---|
1597 | 1707 | struct nlmsghdr *nlh; |
---|
| 1708 | + struct Qdisc *qdisc; |
---|
1598 | 1709 | |
---|
1599 | 1710 | ASSERT_RTNL(); |
---|
1600 | 1711 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); |
---|
.. | .. |
---|
1609 | 1720 | ifm->ifi_flags = dev_get_flags(dev); |
---|
1610 | 1721 | ifm->ifi_change = change; |
---|
1611 | 1722 | |
---|
1612 | | - if (tgt_netnsid >= 0 && nla_put_s32(skb, IFLA_IF_NETNSID, tgt_netnsid)) |
---|
| 1723 | + if (tgt_netnsid >= 0 && nla_put_s32(skb, IFLA_TARGET_NETNSID, tgt_netnsid)) |
---|
1613 | 1724 | goto nla_put_failure; |
---|
1614 | 1725 | |
---|
| 1726 | + qdisc = rtnl_dereference(dev->qdisc); |
---|
1615 | 1727 | if (nla_put_string(skb, IFLA_IFNAME, dev->name) || |
---|
1616 | 1728 | nla_put_u32(skb, IFLA_TXQLEN, dev->tx_queue_len) || |
---|
1617 | 1729 | nla_put_u8(skb, IFLA_OPERSTATE, |
---|
.. | .. |
---|
1630 | 1742 | #endif |
---|
1631 | 1743 | put_master_ifindex(skb, dev) || |
---|
1632 | 1744 | nla_put_u8(skb, IFLA_CARRIER, netif_carrier_ok(dev)) || |
---|
1633 | | - (dev->qdisc && |
---|
1634 | | - nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) || |
---|
| 1745 | + (qdisc && |
---|
| 1746 | + nla_put_string(skb, IFLA_QDISC, qdisc->ops->id)) || |
---|
1635 | 1747 | nla_put_ifalias(skb, dev) || |
---|
1636 | 1748 | nla_put_u32(skb, IFLA_CARRIER_CHANGES, |
---|
1637 | 1749 | atomic_read(&dev->carrier_up_count) + |
---|
1638 | 1750 | atomic_read(&dev->carrier_down_count)) || |
---|
1639 | | - nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down) || |
---|
1640 | 1751 | nla_put_u32(skb, IFLA_CARRIER_UP_COUNT, |
---|
1641 | 1752 | atomic_read(&dev->carrier_up_count)) || |
---|
1642 | 1753 | nla_put_u32(skb, IFLA_CARRIER_DOWN_COUNT, |
---|
1643 | 1754 | atomic_read(&dev->carrier_down_count))) |
---|
| 1755 | + goto nla_put_failure; |
---|
| 1756 | + |
---|
| 1757 | + if (rtnl_fill_proto_down(skb, dev)) |
---|
1644 | 1758 | goto nla_put_failure; |
---|
1645 | 1759 | |
---|
1646 | 1760 | if (event != IFLA_EVENT_NONE) { |
---|
.. | .. |
---|
1693 | 1807 | nla_put_s32(skb, IFLA_NEW_IFINDEX, new_ifindex) < 0) |
---|
1694 | 1808 | goto nla_put_failure; |
---|
1695 | 1809 | |
---|
| 1810 | + if (memchr_inv(dev->perm_addr, '\0', dev->addr_len) && |
---|
| 1811 | + nla_put(skb, IFLA_PERM_ADDRESS, dev->addr_len, dev->perm_addr)) |
---|
| 1812 | + goto nla_put_failure; |
---|
1696 | 1813 | |
---|
1697 | 1814 | rcu_read_lock(); |
---|
1698 | 1815 | if (rtnl_fill_link_af(skb, dev, ext_filter_mask)) |
---|
1699 | 1816 | goto nla_put_failure_rcu; |
---|
1700 | 1817 | rcu_read_unlock(); |
---|
| 1818 | + |
---|
| 1819 | + if (rtnl_fill_prop_list(skb, dev)) |
---|
| 1820 | + goto nla_put_failure; |
---|
1701 | 1821 | |
---|
1702 | 1822 | nlmsg_end(skb, nlh); |
---|
1703 | 1823 | return 0; |
---|
.. | .. |
---|
1747 | 1867 | [IFLA_XDP] = { .type = NLA_NESTED }, |
---|
1748 | 1868 | [IFLA_EVENT] = { .type = NLA_U32 }, |
---|
1749 | 1869 | [IFLA_GROUP] = { .type = NLA_U32 }, |
---|
1750 | | - [IFLA_IF_NETNSID] = { .type = NLA_S32 }, |
---|
| 1870 | + [IFLA_TARGET_NETNSID] = { .type = NLA_S32 }, |
---|
1751 | 1871 | [IFLA_CARRIER_UP_COUNT] = { .type = NLA_U32 }, |
---|
1752 | 1872 | [IFLA_CARRIER_DOWN_COUNT] = { .type = NLA_U32 }, |
---|
1753 | 1873 | [IFLA_MIN_MTU] = { .type = NLA_U32 }, |
---|
1754 | 1874 | [IFLA_MAX_MTU] = { .type = NLA_U32 }, |
---|
| 1875 | + [IFLA_PROP_LIST] = { .type = NLA_NESTED }, |
---|
| 1876 | + [IFLA_ALT_IFNAME] = { .type = NLA_STRING, |
---|
| 1877 | + .len = ALTIFNAMSIZ - 1 }, |
---|
| 1878 | + [IFLA_PERM_ADDRESS] = { .type = NLA_REJECT }, |
---|
| 1879 | + [IFLA_PROTO_DOWN_REASON] = { .type = NLA_NESTED }, |
---|
1755 | 1880 | }; |
---|
1756 | 1881 | |
---|
1757 | 1882 | static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { |
---|
.. | .. |
---|
1763 | 1888 | |
---|
1764 | 1889 | static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { |
---|
1765 | 1890 | [IFLA_VF_MAC] = { .len = sizeof(struct ifla_vf_mac) }, |
---|
| 1891 | + [IFLA_VF_BROADCAST] = { .type = NLA_REJECT }, |
---|
1766 | 1892 | [IFLA_VF_VLAN] = { .len = sizeof(struct ifla_vf_vlan) }, |
---|
1767 | 1893 | [IFLA_VF_VLAN_LIST] = { .type = NLA_NESTED }, |
---|
1768 | 1894 | [IFLA_VF_TX_RATE] = { .len = sizeof(struct ifla_vf_tx_rate) }, |
---|
.. | .. |
---|
1796 | 1922 | }; |
---|
1797 | 1923 | |
---|
1798 | 1924 | static const struct nla_policy ifla_xdp_policy[IFLA_XDP_MAX + 1] = { |
---|
| 1925 | + [IFLA_XDP_UNSPEC] = { .strict_start_type = IFLA_XDP_EXPECTED_FD }, |
---|
1799 | 1926 | [IFLA_XDP_FD] = { .type = NLA_S32 }, |
---|
| 1927 | + [IFLA_XDP_EXPECTED_FD] = { .type = NLA_S32 }, |
---|
1800 | 1928 | [IFLA_XDP_ATTACHED] = { .type = NLA_U8 }, |
---|
1801 | 1929 | [IFLA_XDP_FLAGS] = { .type = NLA_U32 }, |
---|
1802 | 1930 | [IFLA_XDP_PROG_ID] = { .type = NLA_U32 }, |
---|
.. | .. |
---|
1807 | 1935 | const struct rtnl_link_ops *ops = NULL; |
---|
1808 | 1936 | struct nlattr *linfo[IFLA_INFO_MAX + 1]; |
---|
1809 | 1937 | |
---|
1810 | | - if (nla_parse_nested(linfo, IFLA_INFO_MAX, nla, |
---|
1811 | | - ifla_info_policy, NULL) < 0) |
---|
| 1938 | + if (nla_parse_nested_deprecated(linfo, IFLA_INFO_MAX, nla, ifla_info_policy, NULL) < 0) |
---|
1812 | 1939 | return NULL; |
---|
1813 | 1940 | |
---|
1814 | 1941 | if (linfo[IFLA_INFO_KIND]) { |
---|
.. | .. |
---|
1855 | 1982 | return false; |
---|
1856 | 1983 | } |
---|
1857 | 1984 | |
---|
1858 | | -static struct net *get_target_net(struct sock *sk, int netnsid) |
---|
| 1985 | +/** |
---|
| 1986 | + * rtnl_get_net_ns_capable - Get netns if sufficiently privileged. |
---|
| 1987 | + * @sk: netlink socket |
---|
| 1988 | + * @netnsid: network namespace identifier |
---|
| 1989 | + * |
---|
| 1990 | + * Returns the network namespace identified by netnsid on success or an error |
---|
| 1991 | + * pointer on failure. |
---|
| 1992 | + */ |
---|
| 1993 | +struct net *rtnl_get_net_ns_capable(struct sock *sk, int netnsid) |
---|
1859 | 1994 | { |
---|
1860 | 1995 | struct net *net; |
---|
1861 | 1996 | |
---|
.. | .. |
---|
1872 | 2007 | } |
---|
1873 | 2008 | return net; |
---|
1874 | 2009 | } |
---|
| 2010 | +EXPORT_SYMBOL_GPL(rtnl_get_net_ns_capable); |
---|
| 2011 | + |
---|
| 2012 | +static int rtnl_valid_dump_ifinfo_req(const struct nlmsghdr *nlh, |
---|
| 2013 | + bool strict_check, struct nlattr **tb, |
---|
| 2014 | + struct netlink_ext_ack *extack) |
---|
| 2015 | +{ |
---|
| 2016 | + int hdrlen; |
---|
| 2017 | + |
---|
| 2018 | + if (strict_check) { |
---|
| 2019 | + struct ifinfomsg *ifm; |
---|
| 2020 | + |
---|
| 2021 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
---|
| 2022 | + NL_SET_ERR_MSG(extack, "Invalid header for link dump"); |
---|
| 2023 | + return -EINVAL; |
---|
| 2024 | + } |
---|
| 2025 | + |
---|
| 2026 | + ifm = nlmsg_data(nlh); |
---|
| 2027 | + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || |
---|
| 2028 | + ifm->ifi_change) { |
---|
| 2029 | + NL_SET_ERR_MSG(extack, "Invalid values in header for link dump request"); |
---|
| 2030 | + return -EINVAL; |
---|
| 2031 | + } |
---|
| 2032 | + if (ifm->ifi_index) { |
---|
| 2033 | + NL_SET_ERR_MSG(extack, "Filter by device index not supported for link dumps"); |
---|
| 2034 | + return -EINVAL; |
---|
| 2035 | + } |
---|
| 2036 | + |
---|
| 2037 | + return nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, |
---|
| 2038 | + IFLA_MAX, ifla_policy, |
---|
| 2039 | + extack); |
---|
| 2040 | + } |
---|
| 2041 | + |
---|
| 2042 | + /* A hack to preserve kernel<->userspace interface. |
---|
| 2043 | + * The correct header is ifinfomsg. It is consistent with rtnl_getlink. |
---|
| 2044 | + * However, before Linux v3.9 the code here assumed rtgenmsg and that's |
---|
| 2045 | + * what iproute2 < v3.9.0 used. |
---|
| 2046 | + * We can detect the old iproute2. Even including the IFLA_EXT_MASK |
---|
| 2047 | + * attribute, its netlink message is shorter than struct ifinfomsg. |
---|
| 2048 | + */ |
---|
| 2049 | + hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ? |
---|
| 2050 | + sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); |
---|
| 2051 | + |
---|
| 2052 | + return nlmsg_parse_deprecated(nlh, hdrlen, tb, IFLA_MAX, ifla_policy, |
---|
| 2053 | + extack); |
---|
| 2054 | +} |
---|
1875 | 2055 | |
---|
1876 | 2056 | static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) |
---|
1877 | 2057 | { |
---|
| 2058 | + struct netlink_ext_ack *extack = cb->extack; |
---|
| 2059 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
1878 | 2060 | struct net *net = sock_net(skb->sk); |
---|
1879 | 2061 | struct net *tgt_net = net; |
---|
1880 | 2062 | int h, s_h; |
---|
.. | .. |
---|
1887 | 2069 | unsigned int flags = NLM_F_MULTI; |
---|
1888 | 2070 | int master_idx = 0; |
---|
1889 | 2071 | int netnsid = -1; |
---|
1890 | | - int err; |
---|
1891 | | - int hdrlen; |
---|
| 2072 | + int err, i; |
---|
1892 | 2073 | |
---|
1893 | 2074 | s_h = cb->args[0]; |
---|
1894 | 2075 | s_idx = cb->args[1]; |
---|
1895 | 2076 | |
---|
1896 | | - /* A hack to preserve kernel<->userspace interface. |
---|
1897 | | - * The correct header is ifinfomsg. It is consistent with rtnl_getlink. |
---|
1898 | | - * However, before Linux v3.9 the code here assumed rtgenmsg and that's |
---|
1899 | | - * what iproute2 < v3.9.0 used. |
---|
1900 | | - * We can detect the old iproute2. Even including the IFLA_EXT_MASK |
---|
1901 | | - * attribute, its netlink message is shorter than struct ifinfomsg. |
---|
1902 | | - */ |
---|
1903 | | - hdrlen = nlmsg_len(cb->nlh) < sizeof(struct ifinfomsg) ? |
---|
1904 | | - sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); |
---|
| 2077 | + err = rtnl_valid_dump_ifinfo_req(nlh, cb->strict_check, tb, extack); |
---|
| 2078 | + if (err < 0) { |
---|
| 2079 | + if (cb->strict_check) |
---|
| 2080 | + return err; |
---|
1905 | 2081 | |
---|
1906 | | - if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX, |
---|
1907 | | - ifla_policy, NULL) >= 0) { |
---|
1908 | | - if (tb[IFLA_IF_NETNSID]) { |
---|
1909 | | - netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]); |
---|
1910 | | - tgt_net = get_target_net(skb->sk, netnsid); |
---|
1911 | | - if (IS_ERR(tgt_net)) |
---|
1912 | | - return PTR_ERR(tgt_net); |
---|
1913 | | - } |
---|
1914 | | - |
---|
1915 | | - if (tb[IFLA_EXT_MASK]) |
---|
1916 | | - ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); |
---|
1917 | | - |
---|
1918 | | - if (tb[IFLA_MASTER]) |
---|
1919 | | - master_idx = nla_get_u32(tb[IFLA_MASTER]); |
---|
1920 | | - |
---|
1921 | | - if (tb[IFLA_LINKINFO]) |
---|
1922 | | - kind_ops = linkinfo_to_kind_ops(tb[IFLA_LINKINFO]); |
---|
1923 | | - |
---|
1924 | | - if (master_idx || kind_ops) |
---|
1925 | | - flags |= NLM_F_DUMP_FILTERED; |
---|
| 2082 | + goto walk_entries; |
---|
1926 | 2083 | } |
---|
1927 | 2084 | |
---|
| 2085 | + for (i = 0; i <= IFLA_MAX; ++i) { |
---|
| 2086 | + if (!tb[i]) |
---|
| 2087 | + continue; |
---|
| 2088 | + |
---|
| 2089 | + /* new attributes should only be added with strict checking */ |
---|
| 2090 | + switch (i) { |
---|
| 2091 | + case IFLA_TARGET_NETNSID: |
---|
| 2092 | + netnsid = nla_get_s32(tb[i]); |
---|
| 2093 | + tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid); |
---|
| 2094 | + if (IS_ERR(tgt_net)) { |
---|
| 2095 | + NL_SET_ERR_MSG(extack, "Invalid target network namespace id"); |
---|
| 2096 | + return PTR_ERR(tgt_net); |
---|
| 2097 | + } |
---|
| 2098 | + break; |
---|
| 2099 | + case IFLA_EXT_MASK: |
---|
| 2100 | + ext_filter_mask = nla_get_u32(tb[i]); |
---|
| 2101 | + break; |
---|
| 2102 | + case IFLA_MASTER: |
---|
| 2103 | + master_idx = nla_get_u32(tb[i]); |
---|
| 2104 | + break; |
---|
| 2105 | + case IFLA_LINKINFO: |
---|
| 2106 | + kind_ops = linkinfo_to_kind_ops(tb[i]); |
---|
| 2107 | + break; |
---|
| 2108 | + default: |
---|
| 2109 | + if (cb->strict_check) { |
---|
| 2110 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in link dump request"); |
---|
| 2111 | + return -EINVAL; |
---|
| 2112 | + } |
---|
| 2113 | + } |
---|
| 2114 | + } |
---|
| 2115 | + |
---|
| 2116 | + if (master_idx || kind_ops) |
---|
| 2117 | + flags |= NLM_F_DUMP_FILTERED; |
---|
| 2118 | + |
---|
| 2119 | +walk_entries: |
---|
1928 | 2120 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
---|
1929 | 2121 | idx = 0; |
---|
1930 | 2122 | head = &tgt_net->dev_index_head[h]; |
---|
.. | .. |
---|
1936 | 2128 | err = rtnl_fill_ifinfo(skb, dev, net, |
---|
1937 | 2129 | RTM_NEWLINK, |
---|
1938 | 2130 | NETLINK_CB(cb->skb).portid, |
---|
1939 | | - cb->nlh->nlmsg_seq, 0, |
---|
1940 | | - flags, |
---|
| 2131 | + nlh->nlmsg_seq, 0, flags, |
---|
1941 | 2132 | ext_filter_mask, 0, NULL, 0, |
---|
1942 | 2133 | netnsid, GFP_KERNEL); |
---|
1943 | 2134 | |
---|
.. | .. |
---|
1967 | 2158 | int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len, |
---|
1968 | 2159 | struct netlink_ext_ack *exterr) |
---|
1969 | 2160 | { |
---|
1970 | | - return nla_parse(tb, IFLA_MAX, head, len, ifla_policy, exterr); |
---|
| 2161 | + return nla_parse_deprecated(tb, IFLA_MAX, head, len, ifla_policy, |
---|
| 2162 | + exterr); |
---|
1971 | 2163 | } |
---|
1972 | 2164 | EXPORT_SYMBOL(rtnl_nla_parse_ifla); |
---|
1973 | 2165 | |
---|
.. | .. |
---|
1992 | 2184 | * |
---|
1993 | 2185 | * 1. IFLA_NET_NS_PID |
---|
1994 | 2186 | * 2. IFLA_NET_NS_FD |
---|
1995 | | - * 3. IFLA_IF_NETNSID |
---|
| 2187 | + * 3. IFLA_TARGET_NETNSID |
---|
1996 | 2188 | */ |
---|
1997 | 2189 | static struct net *rtnl_link_get_net_by_nlattr(struct net *src_net, |
---|
1998 | 2190 | struct nlattr *tb[]) |
---|
.. | .. |
---|
2002 | 2194 | if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) |
---|
2003 | 2195 | return rtnl_link_get_net(src_net, tb); |
---|
2004 | 2196 | |
---|
2005 | | - if (!tb[IFLA_IF_NETNSID]) |
---|
| 2197 | + if (!tb[IFLA_TARGET_NETNSID]) |
---|
2006 | 2198 | return get_net(src_net); |
---|
2007 | 2199 | |
---|
2008 | | - net = get_net_ns_by_id(src_net, nla_get_u32(tb[IFLA_IF_NETNSID])); |
---|
| 2200 | + net = get_net_ns_by_id(src_net, nla_get_u32(tb[IFLA_TARGET_NETNSID])); |
---|
2009 | 2201 | if (!net) |
---|
2010 | 2202 | return ERR_PTR(-EINVAL); |
---|
2011 | 2203 | |
---|
.. | .. |
---|
2046 | 2238 | return -EOPNOTSUPP; |
---|
2047 | 2239 | } |
---|
2048 | 2240 | |
---|
2049 | | - if (tb[IFLA_IF_NETNSID] && (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD])) |
---|
| 2241 | + if (tb[IFLA_TARGET_NETNSID] && (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD])) |
---|
2050 | 2242 | goto invalid_attr; |
---|
2051 | 2243 | |
---|
2052 | | - if (tb[IFLA_NET_NS_PID] && (tb[IFLA_IF_NETNSID] || tb[IFLA_NET_NS_FD])) |
---|
| 2244 | + if (tb[IFLA_NET_NS_PID] && (tb[IFLA_TARGET_NETNSID] || tb[IFLA_NET_NS_FD])) |
---|
2053 | 2245 | goto invalid_attr; |
---|
2054 | 2246 | |
---|
2055 | | - if (tb[IFLA_NET_NS_FD] && (tb[IFLA_IF_NETNSID] || tb[IFLA_NET_NS_PID])) |
---|
| 2247 | + if (tb[IFLA_NET_NS_FD] && (tb[IFLA_TARGET_NETNSID] || tb[IFLA_NET_NS_PID])) |
---|
2056 | 2248 | goto invalid_attr; |
---|
2057 | 2249 | |
---|
2058 | 2250 | return 0; |
---|
.. | .. |
---|
2334 | 2526 | return 0; |
---|
2335 | 2527 | } |
---|
2336 | 2528 | |
---|
| 2529 | +static const struct nla_policy ifla_proto_down_reason_policy[IFLA_PROTO_DOWN_REASON_VALUE + 1] = { |
---|
| 2530 | + [IFLA_PROTO_DOWN_REASON_MASK] = { .type = NLA_U32 }, |
---|
| 2531 | + [IFLA_PROTO_DOWN_REASON_VALUE] = { .type = NLA_U32 }, |
---|
| 2532 | +}; |
---|
| 2533 | + |
---|
| 2534 | +static int do_set_proto_down(struct net_device *dev, |
---|
| 2535 | + struct nlattr *nl_proto_down, |
---|
| 2536 | + struct nlattr *nl_proto_down_reason, |
---|
| 2537 | + struct netlink_ext_ack *extack) |
---|
| 2538 | +{ |
---|
| 2539 | + struct nlattr *pdreason[IFLA_PROTO_DOWN_REASON_MAX + 1]; |
---|
| 2540 | + const struct net_device_ops *ops = dev->netdev_ops; |
---|
| 2541 | + unsigned long mask = 0; |
---|
| 2542 | + u32 value; |
---|
| 2543 | + bool proto_down; |
---|
| 2544 | + int err; |
---|
| 2545 | + |
---|
| 2546 | + if (!ops->ndo_change_proto_down) { |
---|
| 2547 | + NL_SET_ERR_MSG(extack, "Protodown not supported by device"); |
---|
| 2548 | + return -EOPNOTSUPP; |
---|
| 2549 | + } |
---|
| 2550 | + |
---|
| 2551 | + if (nl_proto_down_reason) { |
---|
| 2552 | + err = nla_parse_nested_deprecated(pdreason, |
---|
| 2553 | + IFLA_PROTO_DOWN_REASON_MAX, |
---|
| 2554 | + nl_proto_down_reason, |
---|
| 2555 | + ifla_proto_down_reason_policy, |
---|
| 2556 | + NULL); |
---|
| 2557 | + if (err < 0) |
---|
| 2558 | + return err; |
---|
| 2559 | + |
---|
| 2560 | + if (!pdreason[IFLA_PROTO_DOWN_REASON_VALUE]) { |
---|
| 2561 | + NL_SET_ERR_MSG(extack, "Invalid protodown reason value"); |
---|
| 2562 | + return -EINVAL; |
---|
| 2563 | + } |
---|
| 2564 | + |
---|
| 2565 | + value = nla_get_u32(pdreason[IFLA_PROTO_DOWN_REASON_VALUE]); |
---|
| 2566 | + |
---|
| 2567 | + if (pdreason[IFLA_PROTO_DOWN_REASON_MASK]) |
---|
| 2568 | + mask = nla_get_u32(pdreason[IFLA_PROTO_DOWN_REASON_MASK]); |
---|
| 2569 | + |
---|
| 2570 | + dev_change_proto_down_reason(dev, mask, value); |
---|
| 2571 | + } |
---|
| 2572 | + |
---|
| 2573 | + if (nl_proto_down) { |
---|
| 2574 | + proto_down = nla_get_u8(nl_proto_down); |
---|
| 2575 | + |
---|
| 2576 | + /* Dont turn off protodown if there are active reasons */ |
---|
| 2577 | + if (!proto_down && dev->proto_down_reason) { |
---|
| 2578 | + NL_SET_ERR_MSG(extack, "Cannot clear protodown, active reasons"); |
---|
| 2579 | + return -EBUSY; |
---|
| 2580 | + } |
---|
| 2581 | + err = dev_change_proto_down(dev, |
---|
| 2582 | + proto_down); |
---|
| 2583 | + if (err) |
---|
| 2584 | + return err; |
---|
| 2585 | + } |
---|
| 2586 | + |
---|
| 2587 | + return 0; |
---|
| 2588 | +} |
---|
| 2589 | + |
---|
2337 | 2590 | #define DO_SETLINK_MODIFIED 0x01 |
---|
2338 | 2591 | /* notify flag means notify + modified. */ |
---|
2339 | 2592 | #define DO_SETLINK_NOTIFY 0x03 |
---|
.. | .. |
---|
2349 | 2602 | if (err < 0) |
---|
2350 | 2603 | return err; |
---|
2351 | 2604 | |
---|
2352 | | - if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_IF_NETNSID]) { |
---|
| 2605 | + if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_TARGET_NETNSID]) { |
---|
| 2606 | + const char *pat = ifname && ifname[0] ? ifname : NULL; |
---|
2353 | 2607 | struct net *net = rtnl_link_get_net_capable(skb, dev_net(dev), |
---|
2354 | 2608 | tb, CAP_NET_ADMIN); |
---|
2355 | 2609 | if (IS_ERR(net)) { |
---|
.. | .. |
---|
2357 | 2611 | goto errout; |
---|
2358 | 2612 | } |
---|
2359 | 2613 | |
---|
2360 | | - err = dev_change_net_namespace(dev, net, ifname); |
---|
| 2614 | + err = dev_change_net_namespace(dev, net, pat); |
---|
2361 | 2615 | put_net(net); |
---|
2362 | 2616 | if (err) |
---|
2363 | 2617 | goto errout; |
---|
.. | .. |
---|
2407 | 2661 | sa->sa_family = dev->type; |
---|
2408 | 2662 | memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]), |
---|
2409 | 2663 | dev->addr_len); |
---|
2410 | | - err = dev_set_mac_address(dev, sa); |
---|
| 2664 | + err = dev_set_mac_address_user(dev, sa, extack); |
---|
2411 | 2665 | kfree(sa); |
---|
2412 | 2666 | if (err) |
---|
2413 | 2667 | goto errout; |
---|
.. | .. |
---|
2452 | 2706 | } |
---|
2453 | 2707 | |
---|
2454 | 2708 | if (ifm->ifi_flags || ifm->ifi_change) { |
---|
2455 | | - err = dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm)); |
---|
| 2709 | + err = dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm), |
---|
| 2710 | + extack); |
---|
2456 | 2711 | if (err < 0) |
---|
2457 | 2712 | goto errout; |
---|
2458 | 2713 | } |
---|
.. | .. |
---|
2532 | 2787 | err = -EINVAL; |
---|
2533 | 2788 | goto errout; |
---|
2534 | 2789 | } |
---|
2535 | | - err = nla_parse_nested(vfinfo, IFLA_VF_MAX, attr, |
---|
2536 | | - ifla_vf_policy, NULL); |
---|
| 2790 | + err = nla_parse_nested_deprecated(vfinfo, IFLA_VF_MAX, |
---|
| 2791 | + attr, |
---|
| 2792 | + ifla_vf_policy, |
---|
| 2793 | + NULL); |
---|
2537 | 2794 | if (err < 0) |
---|
2538 | 2795 | goto errout; |
---|
2539 | 2796 | err = do_setvfinfo(dev, vfinfo); |
---|
.. | .. |
---|
2560 | 2817 | err = -EINVAL; |
---|
2561 | 2818 | goto errout; |
---|
2562 | 2819 | } |
---|
2563 | | - err = nla_parse_nested(port, IFLA_PORT_MAX, attr, |
---|
2564 | | - ifla_port_policy, NULL); |
---|
| 2820 | + err = nla_parse_nested_deprecated(port, IFLA_PORT_MAX, |
---|
| 2821 | + attr, |
---|
| 2822 | + ifla_port_policy, |
---|
| 2823 | + NULL); |
---|
2565 | 2824 | if (err < 0) |
---|
2566 | 2825 | goto errout; |
---|
2567 | 2826 | if (!port[IFLA_PORT_VF]) { |
---|
.. | .. |
---|
2580 | 2839 | if (tb[IFLA_PORT_SELF]) { |
---|
2581 | 2840 | struct nlattr *port[IFLA_PORT_MAX+1]; |
---|
2582 | 2841 | |
---|
2583 | | - err = nla_parse_nested(port, IFLA_PORT_MAX, |
---|
2584 | | - tb[IFLA_PORT_SELF], ifla_port_policy, |
---|
2585 | | - NULL); |
---|
| 2842 | + err = nla_parse_nested_deprecated(port, IFLA_PORT_MAX, |
---|
| 2843 | + tb[IFLA_PORT_SELF], |
---|
| 2844 | + ifla_port_policy, NULL); |
---|
2586 | 2845 | if (err < 0) |
---|
2587 | 2846 | goto errout; |
---|
2588 | 2847 | |
---|
.. | .. |
---|
2617 | 2876 | } |
---|
2618 | 2877 | err = 0; |
---|
2619 | 2878 | |
---|
2620 | | - if (tb[IFLA_PROTO_DOWN]) { |
---|
2621 | | - err = dev_change_proto_down(dev, |
---|
2622 | | - nla_get_u8(tb[IFLA_PROTO_DOWN])); |
---|
| 2879 | + if (tb[IFLA_PROTO_DOWN] || tb[IFLA_PROTO_DOWN_REASON]) { |
---|
| 2880 | + err = do_set_proto_down(dev, tb[IFLA_PROTO_DOWN], |
---|
| 2881 | + tb[IFLA_PROTO_DOWN_REASON], extack); |
---|
2623 | 2882 | if (err) |
---|
2624 | 2883 | goto errout; |
---|
2625 | 2884 | status |= DO_SETLINK_NOTIFY; |
---|
.. | .. |
---|
2629 | 2888 | struct nlattr *xdp[IFLA_XDP_MAX + 1]; |
---|
2630 | 2889 | u32 xdp_flags = 0; |
---|
2631 | 2890 | |
---|
2632 | | - err = nla_parse_nested(xdp, IFLA_XDP_MAX, tb[IFLA_XDP], |
---|
2633 | | - ifla_xdp_policy, NULL); |
---|
| 2891 | + err = nla_parse_nested_deprecated(xdp, IFLA_XDP_MAX, |
---|
| 2892 | + tb[IFLA_XDP], |
---|
| 2893 | + ifla_xdp_policy, NULL); |
---|
2634 | 2894 | if (err < 0) |
---|
2635 | 2895 | goto errout; |
---|
2636 | 2896 | |
---|
.. | .. |
---|
2652 | 2912 | } |
---|
2653 | 2913 | |
---|
2654 | 2914 | if (xdp[IFLA_XDP_FD]) { |
---|
| 2915 | + int expected_fd = -1; |
---|
| 2916 | + |
---|
| 2917 | + if (xdp_flags & XDP_FLAGS_REPLACE) { |
---|
| 2918 | + if (!xdp[IFLA_XDP_EXPECTED_FD]) { |
---|
| 2919 | + err = -EINVAL; |
---|
| 2920 | + goto errout; |
---|
| 2921 | + } |
---|
| 2922 | + expected_fd = |
---|
| 2923 | + nla_get_s32(xdp[IFLA_XDP_EXPECTED_FD]); |
---|
| 2924 | + } |
---|
| 2925 | + |
---|
2655 | 2926 | err = dev_change_xdp_fd(dev, extack, |
---|
2656 | 2927 | nla_get_s32(xdp[IFLA_XDP_FD]), |
---|
| 2928 | + expected_fd, |
---|
2657 | 2929 | xdp_flags); |
---|
2658 | 2930 | if (err) |
---|
2659 | 2931 | goto errout; |
---|
.. | .. |
---|
2674 | 2946 | return err; |
---|
2675 | 2947 | } |
---|
2676 | 2948 | |
---|
| 2949 | +static struct net_device *rtnl_dev_get(struct net *net, |
---|
| 2950 | + struct nlattr *ifname_attr, |
---|
| 2951 | + struct nlattr *altifname_attr, |
---|
| 2952 | + char *ifname) |
---|
| 2953 | +{ |
---|
| 2954 | + char buffer[ALTIFNAMSIZ]; |
---|
| 2955 | + |
---|
| 2956 | + if (!ifname) { |
---|
| 2957 | + ifname = buffer; |
---|
| 2958 | + if (ifname_attr) |
---|
| 2959 | + nla_strlcpy(ifname, ifname_attr, IFNAMSIZ); |
---|
| 2960 | + else if (altifname_attr) |
---|
| 2961 | + nla_strlcpy(ifname, altifname_attr, ALTIFNAMSIZ); |
---|
| 2962 | + else |
---|
| 2963 | + return NULL; |
---|
| 2964 | + } |
---|
| 2965 | + |
---|
| 2966 | + return __dev_get_by_name(net, ifname); |
---|
| 2967 | +} |
---|
| 2968 | + |
---|
2677 | 2969 | static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
2678 | 2970 | struct netlink_ext_ack *extack) |
---|
2679 | 2971 | { |
---|
.. | .. |
---|
2684 | 2976 | struct nlattr *tb[IFLA_MAX+1]; |
---|
2685 | 2977 | char ifname[IFNAMSIZ]; |
---|
2686 | 2978 | |
---|
2687 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, |
---|
2688 | | - extack); |
---|
| 2979 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFLA_MAX, |
---|
| 2980 | + ifla_policy, extack); |
---|
2689 | 2981 | if (err < 0) |
---|
2690 | 2982 | goto errout; |
---|
2691 | 2983 | |
---|
.. | .. |
---|
2702 | 2994 | ifm = nlmsg_data(nlh); |
---|
2703 | 2995 | if (ifm->ifi_index > 0) |
---|
2704 | 2996 | dev = __dev_get_by_index(net, ifm->ifi_index); |
---|
2705 | | - else if (tb[IFLA_IFNAME]) |
---|
2706 | | - dev = __dev_get_by_name(net, ifname); |
---|
| 2997 | + else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) |
---|
| 2998 | + dev = rtnl_dev_get(net, NULL, tb[IFLA_ALT_IFNAME], ifname); |
---|
2707 | 2999 | else |
---|
2708 | 3000 | goto errout; |
---|
2709 | 3001 | |
---|
.. | .. |
---|
2776 | 3068 | struct net *tgt_net = net; |
---|
2777 | 3069 | struct net_device *dev = NULL; |
---|
2778 | 3070 | struct ifinfomsg *ifm; |
---|
2779 | | - char ifname[IFNAMSIZ]; |
---|
2780 | 3071 | struct nlattr *tb[IFLA_MAX+1]; |
---|
2781 | 3072 | int err; |
---|
2782 | 3073 | int netnsid = -1; |
---|
2783 | 3074 | |
---|
2784 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack); |
---|
| 3075 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFLA_MAX, |
---|
| 3076 | + ifla_policy, extack); |
---|
2785 | 3077 | if (err < 0) |
---|
2786 | 3078 | return err; |
---|
2787 | 3079 | |
---|
.. | .. |
---|
2789 | 3081 | if (err < 0) |
---|
2790 | 3082 | return err; |
---|
2791 | 3083 | |
---|
2792 | | - if (tb[IFLA_IFNAME]) |
---|
2793 | | - nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); |
---|
2794 | | - |
---|
2795 | | - if (tb[IFLA_IF_NETNSID]) { |
---|
2796 | | - netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]); |
---|
2797 | | - tgt_net = get_target_net(NETLINK_CB(skb).sk, netnsid); |
---|
| 3084 | + if (tb[IFLA_TARGET_NETNSID]) { |
---|
| 3085 | + netnsid = nla_get_s32(tb[IFLA_TARGET_NETNSID]); |
---|
| 3086 | + tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, netnsid); |
---|
2798 | 3087 | if (IS_ERR(tgt_net)) |
---|
2799 | 3088 | return PTR_ERR(tgt_net); |
---|
2800 | 3089 | } |
---|
.. | .. |
---|
2803 | 3092 | ifm = nlmsg_data(nlh); |
---|
2804 | 3093 | if (ifm->ifi_index > 0) |
---|
2805 | 3094 | dev = __dev_get_by_index(tgt_net, ifm->ifi_index); |
---|
2806 | | - else if (tb[IFLA_IFNAME]) |
---|
2807 | | - dev = __dev_get_by_name(tgt_net, ifname); |
---|
| 3095 | + else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) |
---|
| 3096 | + dev = rtnl_dev_get(net, tb[IFLA_IFNAME], |
---|
| 3097 | + tb[IFLA_ALT_IFNAME], NULL); |
---|
2808 | 3098 | else if (tb[IFLA_GROUP]) |
---|
2809 | 3099 | err = rtnl_group_dellink(tgt_net, nla_get_u32(tb[IFLA_GROUP])); |
---|
2810 | 3100 | else |
---|
.. | .. |
---|
2833 | 3123 | |
---|
2834 | 3124 | old_flags = dev->flags; |
---|
2835 | 3125 | if (ifm && (ifm->ifi_flags || ifm->ifi_change)) { |
---|
2836 | | - err = __dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm)); |
---|
| 3126 | + err = __dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm), |
---|
| 3127 | + NULL); |
---|
2837 | 3128 | if (err < 0) |
---|
2838 | 3129 | return err; |
---|
2839 | 3130 | } |
---|
.. | .. |
---|
2848 | 3139 | } |
---|
2849 | 3140 | EXPORT_SYMBOL(rtnl_configure_link); |
---|
2850 | 3141 | |
---|
2851 | | -struct net_device *rtnl_create_link(struct net *net, |
---|
2852 | | - const char *ifname, unsigned char name_assign_type, |
---|
2853 | | - const struct rtnl_link_ops *ops, struct nlattr *tb[]) |
---|
| 3142 | +struct net_device *rtnl_create_link(struct net *net, const char *ifname, |
---|
| 3143 | + unsigned char name_assign_type, |
---|
| 3144 | + const struct rtnl_link_ops *ops, |
---|
| 3145 | + struct nlattr *tb[], |
---|
| 3146 | + struct netlink_ext_ack *extack) |
---|
2854 | 3147 | { |
---|
2855 | 3148 | struct net_device *dev; |
---|
2856 | 3149 | unsigned int num_tx_queues = 1; |
---|
.. | .. |
---|
2866 | 3159 | else if (ops->get_num_rx_queues) |
---|
2867 | 3160 | num_rx_queues = ops->get_num_rx_queues(); |
---|
2868 | 3161 | |
---|
2869 | | - if (num_tx_queues < 1 || num_tx_queues > 4096) |
---|
| 3162 | + if (num_tx_queues < 1 || num_tx_queues > 4096) { |
---|
| 3163 | + NL_SET_ERR_MSG(extack, "Invalid number of transmit queues"); |
---|
2870 | 3164 | return ERR_PTR(-EINVAL); |
---|
| 3165 | + } |
---|
2871 | 3166 | |
---|
2872 | | - if (num_rx_queues < 1 || num_rx_queues > 4096) |
---|
| 3167 | + if (num_rx_queues < 1 || num_rx_queues > 4096) { |
---|
| 3168 | + NL_SET_ERR_MSG(extack, "Invalid number of receive queues"); |
---|
2873 | 3169 | return ERR_PTR(-EINVAL); |
---|
| 3170 | + } |
---|
2874 | 3171 | |
---|
2875 | 3172 | dev = alloc_netdev_mqs(ops->priv_size, ifname, name_assign_type, |
---|
2876 | 3173 | ops->setup, num_tx_queues, num_rx_queues); |
---|
.. | .. |
---|
2885 | 3182 | u32 mtu = nla_get_u32(tb[IFLA_MTU]); |
---|
2886 | 3183 | int err; |
---|
2887 | 3184 | |
---|
2888 | | - err = dev_validate_mtu(dev, mtu, NULL); |
---|
| 3185 | + err = dev_validate_mtu(dev, mtu, extack); |
---|
2889 | 3186 | if (err) { |
---|
2890 | 3187 | free_netdev(dev); |
---|
2891 | 3188 | return ERR_PTR(err); |
---|
.. | .. |
---|
2937 | 3234 | return 0; |
---|
2938 | 3235 | } |
---|
2939 | 3236 | |
---|
2940 | | -static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
2941 | | - struct netlink_ext_ack *extack) |
---|
| 3237 | +static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 3238 | + struct nlattr **attr, struct netlink_ext_ack *extack) |
---|
2942 | 3239 | { |
---|
| 3240 | + struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1]; |
---|
| 3241 | + unsigned char name_assign_type = NET_NAME_USER; |
---|
| 3242 | + struct nlattr *linkinfo[IFLA_INFO_MAX + 1]; |
---|
| 3243 | + const struct rtnl_link_ops *m_ops; |
---|
| 3244 | + struct net_device *master_dev; |
---|
2943 | 3245 | struct net *net = sock_net(skb->sk); |
---|
2944 | 3246 | const struct rtnl_link_ops *ops; |
---|
2945 | | - const struct rtnl_link_ops *m_ops; |
---|
2946 | | - struct net_device *dev; |
---|
2947 | | - struct net_device *master_dev; |
---|
2948 | | - struct ifinfomsg *ifm; |
---|
| 3247 | + struct nlattr *tb[IFLA_MAX + 1]; |
---|
| 3248 | + struct net *dest_net, *link_net; |
---|
| 3249 | + struct nlattr **slave_data; |
---|
2949 | 3250 | char kind[MODULE_NAME_LEN]; |
---|
| 3251 | + struct net_device *dev; |
---|
| 3252 | + struct ifinfomsg *ifm; |
---|
2950 | 3253 | char ifname[IFNAMSIZ]; |
---|
2951 | | - struct nlattr *tb[IFLA_MAX+1]; |
---|
2952 | | - struct nlattr *linkinfo[IFLA_INFO_MAX+1]; |
---|
2953 | | - unsigned char name_assign_type = NET_NAME_USER; |
---|
| 3254 | + struct nlattr **data; |
---|
2954 | 3255 | int err; |
---|
2955 | 3256 | |
---|
2956 | 3257 | #ifdef CONFIG_MODULES |
---|
2957 | 3258 | replay: |
---|
2958 | 3259 | #endif |
---|
2959 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack); |
---|
| 3260 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFLA_MAX, |
---|
| 3261 | + ifla_policy, extack); |
---|
2960 | 3262 | if (err < 0) |
---|
2961 | 3263 | return err; |
---|
2962 | 3264 | |
---|
.. | .. |
---|
2972 | 3274 | ifm = nlmsg_data(nlh); |
---|
2973 | 3275 | if (ifm->ifi_index > 0) |
---|
2974 | 3276 | dev = __dev_get_by_index(net, ifm->ifi_index); |
---|
2975 | | - else { |
---|
2976 | | - if (ifname[0]) |
---|
2977 | | - dev = __dev_get_by_name(net, ifname); |
---|
2978 | | - else |
---|
2979 | | - dev = NULL; |
---|
2980 | | - } |
---|
| 3277 | + else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) |
---|
| 3278 | + dev = rtnl_dev_get(net, NULL, tb[IFLA_ALT_IFNAME], ifname); |
---|
| 3279 | + else |
---|
| 3280 | + dev = NULL; |
---|
2981 | 3281 | |
---|
2982 | 3282 | master_dev = NULL; |
---|
2983 | 3283 | m_ops = NULL; |
---|
.. | .. |
---|
2992 | 3292 | return err; |
---|
2993 | 3293 | |
---|
2994 | 3294 | if (tb[IFLA_LINKINFO]) { |
---|
2995 | | - err = nla_parse_nested(linkinfo, IFLA_INFO_MAX, |
---|
2996 | | - tb[IFLA_LINKINFO], ifla_info_policy, |
---|
2997 | | - NULL); |
---|
| 3295 | + err = nla_parse_nested_deprecated(linkinfo, IFLA_INFO_MAX, |
---|
| 3296 | + tb[IFLA_LINKINFO], |
---|
| 3297 | + ifla_info_policy, NULL); |
---|
2998 | 3298 | if (err < 0) |
---|
2999 | 3299 | return err; |
---|
3000 | 3300 | } else |
---|
.. | .. |
---|
3008 | 3308 | ops = NULL; |
---|
3009 | 3309 | } |
---|
3010 | 3310 | |
---|
3011 | | - if (1) { |
---|
3012 | | - struct nlattr *attr[RTNL_MAX_TYPE + 1]; |
---|
3013 | | - struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1]; |
---|
3014 | | - struct nlattr **data = NULL; |
---|
3015 | | - struct nlattr **slave_data = NULL; |
---|
3016 | | - struct net *dest_net, *link_net = NULL; |
---|
| 3311 | + data = NULL; |
---|
| 3312 | + if (ops) { |
---|
| 3313 | + if (ops->maxtype > RTNL_MAX_TYPE) |
---|
| 3314 | + return -EINVAL; |
---|
3017 | 3315 | |
---|
3018 | | - if (ops) { |
---|
3019 | | - if (ops->maxtype > RTNL_MAX_TYPE) |
---|
3020 | | - return -EINVAL; |
---|
3021 | | - |
---|
3022 | | - if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { |
---|
3023 | | - err = nla_parse_nested(attr, ops->maxtype, |
---|
3024 | | - linkinfo[IFLA_INFO_DATA], |
---|
3025 | | - ops->policy, NULL); |
---|
3026 | | - if (err < 0) |
---|
3027 | | - return err; |
---|
3028 | | - data = attr; |
---|
3029 | | - } |
---|
3030 | | - if (ops->validate) { |
---|
3031 | | - err = ops->validate(tb, data, extack); |
---|
3032 | | - if (err < 0) |
---|
3033 | | - return err; |
---|
3034 | | - } |
---|
| 3316 | + if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { |
---|
| 3317 | + err = nla_parse_nested_deprecated(attr, ops->maxtype, |
---|
| 3318 | + linkinfo[IFLA_INFO_DATA], |
---|
| 3319 | + ops->policy, extack); |
---|
| 3320 | + if (err < 0) |
---|
| 3321 | + return err; |
---|
| 3322 | + data = attr; |
---|
3035 | 3323 | } |
---|
3036 | | - |
---|
3037 | | - if (m_ops) { |
---|
3038 | | - if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE) |
---|
3039 | | - return -EINVAL; |
---|
3040 | | - |
---|
3041 | | - if (m_ops->slave_maxtype && |
---|
3042 | | - linkinfo[IFLA_INFO_SLAVE_DATA]) { |
---|
3043 | | - err = nla_parse_nested(slave_attr, |
---|
3044 | | - m_ops->slave_maxtype, |
---|
3045 | | - linkinfo[IFLA_INFO_SLAVE_DATA], |
---|
3046 | | - m_ops->slave_policy, |
---|
3047 | | - NULL); |
---|
3048 | | - if (err < 0) |
---|
3049 | | - return err; |
---|
3050 | | - slave_data = slave_attr; |
---|
3051 | | - } |
---|
| 3324 | + if (ops->validate) { |
---|
| 3325 | + err = ops->validate(tb, data, extack); |
---|
| 3326 | + if (err < 0) |
---|
| 3327 | + return err; |
---|
3052 | 3328 | } |
---|
| 3329 | + } |
---|
3053 | 3330 | |
---|
3054 | | - if (dev) { |
---|
3055 | | - int status = 0; |
---|
| 3331 | + slave_data = NULL; |
---|
| 3332 | + if (m_ops) { |
---|
| 3333 | + if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE) |
---|
| 3334 | + return -EINVAL; |
---|
3056 | 3335 | |
---|
3057 | | - if (nlh->nlmsg_flags & NLM_F_EXCL) |
---|
3058 | | - return -EEXIST; |
---|
3059 | | - if (nlh->nlmsg_flags & NLM_F_REPLACE) |
---|
| 3336 | + if (m_ops->slave_maxtype && |
---|
| 3337 | + linkinfo[IFLA_INFO_SLAVE_DATA]) { |
---|
| 3338 | + err = nla_parse_nested_deprecated(slave_attr, |
---|
| 3339 | + m_ops->slave_maxtype, |
---|
| 3340 | + linkinfo[IFLA_INFO_SLAVE_DATA], |
---|
| 3341 | + m_ops->slave_policy, |
---|
| 3342 | + extack); |
---|
| 3343 | + if (err < 0) |
---|
| 3344 | + return err; |
---|
| 3345 | + slave_data = slave_attr; |
---|
| 3346 | + } |
---|
| 3347 | + } |
---|
| 3348 | + |
---|
| 3349 | + if (dev) { |
---|
| 3350 | + int status = 0; |
---|
| 3351 | + |
---|
| 3352 | + if (nlh->nlmsg_flags & NLM_F_EXCL) |
---|
| 3353 | + return -EEXIST; |
---|
| 3354 | + if (nlh->nlmsg_flags & NLM_F_REPLACE) |
---|
| 3355 | + return -EOPNOTSUPP; |
---|
| 3356 | + |
---|
| 3357 | + if (linkinfo[IFLA_INFO_DATA]) { |
---|
| 3358 | + if (!ops || ops != dev->rtnl_link_ops || |
---|
| 3359 | + !ops->changelink) |
---|
3060 | 3360 | return -EOPNOTSUPP; |
---|
3061 | 3361 | |
---|
3062 | | - if (linkinfo[IFLA_INFO_DATA]) { |
---|
3063 | | - if (!ops || ops != dev->rtnl_link_ops || |
---|
3064 | | - !ops->changelink) |
---|
3065 | | - return -EOPNOTSUPP; |
---|
3066 | | - |
---|
3067 | | - err = ops->changelink(dev, tb, data, extack); |
---|
3068 | | - if (err < 0) |
---|
3069 | | - return err; |
---|
3070 | | - status |= DO_SETLINK_NOTIFY; |
---|
3071 | | - } |
---|
3072 | | - |
---|
3073 | | - if (linkinfo[IFLA_INFO_SLAVE_DATA]) { |
---|
3074 | | - if (!m_ops || !m_ops->slave_changelink) |
---|
3075 | | - return -EOPNOTSUPP; |
---|
3076 | | - |
---|
3077 | | - err = m_ops->slave_changelink(master_dev, dev, |
---|
3078 | | - tb, slave_data, |
---|
3079 | | - extack); |
---|
3080 | | - if (err < 0) |
---|
3081 | | - return err; |
---|
3082 | | - status |= DO_SETLINK_NOTIFY; |
---|
3083 | | - } |
---|
3084 | | - |
---|
3085 | | - return do_setlink(skb, dev, ifm, extack, tb, ifname, |
---|
3086 | | - status); |
---|
| 3362 | + err = ops->changelink(dev, tb, data, extack); |
---|
| 3363 | + if (err < 0) |
---|
| 3364 | + return err; |
---|
| 3365 | + status |= DO_SETLINK_NOTIFY; |
---|
3087 | 3366 | } |
---|
3088 | 3367 | |
---|
3089 | | - if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { |
---|
3090 | | - if (ifm->ifi_index == 0 && tb[IFLA_GROUP]) |
---|
3091 | | - return rtnl_group_changelink(skb, net, |
---|
| 3368 | + if (linkinfo[IFLA_INFO_SLAVE_DATA]) { |
---|
| 3369 | + if (!m_ops || !m_ops->slave_changelink) |
---|
| 3370 | + return -EOPNOTSUPP; |
---|
| 3371 | + |
---|
| 3372 | + err = m_ops->slave_changelink(master_dev, dev, tb, |
---|
| 3373 | + slave_data, extack); |
---|
| 3374 | + if (err < 0) |
---|
| 3375 | + return err; |
---|
| 3376 | + status |= DO_SETLINK_NOTIFY; |
---|
| 3377 | + } |
---|
| 3378 | + |
---|
| 3379 | + return do_setlink(skb, dev, ifm, extack, tb, ifname, status); |
---|
| 3380 | + } |
---|
| 3381 | + |
---|
| 3382 | + if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { |
---|
| 3383 | + if (ifm->ifi_index == 0 && tb[IFLA_GROUP]) |
---|
| 3384 | + return rtnl_group_changelink(skb, net, |
---|
3092 | 3385 | nla_get_u32(tb[IFLA_GROUP]), |
---|
3093 | 3386 | ifm, extack, tb); |
---|
3094 | | - return -ENODEV; |
---|
3095 | | - } |
---|
| 3387 | + return -ENODEV; |
---|
| 3388 | + } |
---|
3096 | 3389 | |
---|
3097 | | - if (tb[IFLA_MAP] || tb[IFLA_PROTINFO]) |
---|
3098 | | - return -EOPNOTSUPP; |
---|
| 3390 | + if (tb[IFLA_MAP] || tb[IFLA_PROTINFO]) |
---|
| 3391 | + return -EOPNOTSUPP; |
---|
3099 | 3392 | |
---|
3100 | | - if (!ops) { |
---|
| 3393 | + if (!ops) { |
---|
3101 | 3394 | #ifdef CONFIG_MODULES |
---|
3102 | | - if (kind[0]) { |
---|
3103 | | - __rtnl_unlock(); |
---|
3104 | | - request_module("rtnl-link-%s", kind); |
---|
3105 | | - rtnl_lock(); |
---|
3106 | | - ops = rtnl_link_ops_get(kind); |
---|
3107 | | - if (ops) |
---|
3108 | | - goto replay; |
---|
3109 | | - } |
---|
| 3395 | + if (kind[0]) { |
---|
| 3396 | + __rtnl_unlock(); |
---|
| 3397 | + request_module("rtnl-link-%s", kind); |
---|
| 3398 | + rtnl_lock(); |
---|
| 3399 | + ops = rtnl_link_ops_get(kind); |
---|
| 3400 | + if (ops) |
---|
| 3401 | + goto replay; |
---|
| 3402 | + } |
---|
3110 | 3403 | #endif |
---|
3111 | | - return -EOPNOTSUPP; |
---|
3112 | | - } |
---|
| 3404 | + NL_SET_ERR_MSG(extack, "Unknown device type"); |
---|
| 3405 | + return -EOPNOTSUPP; |
---|
| 3406 | + } |
---|
3113 | 3407 | |
---|
3114 | | - if (!ops->setup) |
---|
3115 | | - return -EOPNOTSUPP; |
---|
| 3408 | + if (!ops->setup) |
---|
| 3409 | + return -EOPNOTSUPP; |
---|
3116 | 3410 | |
---|
3117 | | - if (!ifname[0]) { |
---|
3118 | | - snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); |
---|
3119 | | - name_assign_type = NET_NAME_ENUM; |
---|
3120 | | - } |
---|
| 3411 | + if (!ifname[0]) { |
---|
| 3412 | + snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); |
---|
| 3413 | + name_assign_type = NET_NAME_ENUM; |
---|
| 3414 | + } |
---|
3121 | 3415 | |
---|
3122 | | - dest_net = rtnl_link_get_net_capable(skb, net, tb, CAP_NET_ADMIN); |
---|
3123 | | - if (IS_ERR(dest_net)) |
---|
3124 | | - return PTR_ERR(dest_net); |
---|
| 3416 | + dest_net = rtnl_link_get_net_capable(skb, net, tb, CAP_NET_ADMIN); |
---|
| 3417 | + if (IS_ERR(dest_net)) |
---|
| 3418 | + return PTR_ERR(dest_net); |
---|
3125 | 3419 | |
---|
3126 | | - if (tb[IFLA_LINK_NETNSID]) { |
---|
3127 | | - int id = nla_get_s32(tb[IFLA_LINK_NETNSID]); |
---|
| 3420 | + if (tb[IFLA_LINK_NETNSID]) { |
---|
| 3421 | + int id = nla_get_s32(tb[IFLA_LINK_NETNSID]); |
---|
3128 | 3422 | |
---|
3129 | | - link_net = get_net_ns_by_id(dest_net, id); |
---|
3130 | | - if (!link_net) { |
---|
3131 | | - err = -EINVAL; |
---|
3132 | | - goto out; |
---|
3133 | | - } |
---|
3134 | | - err = -EPERM; |
---|
3135 | | - if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN)) |
---|
3136 | | - goto out; |
---|
3137 | | - } |
---|
3138 | | - |
---|
3139 | | - dev = rtnl_create_link(link_net ? : dest_net, ifname, |
---|
3140 | | - name_assign_type, ops, tb); |
---|
3141 | | - if (IS_ERR(dev)) { |
---|
3142 | | - err = PTR_ERR(dev); |
---|
| 3423 | + link_net = get_net_ns_by_id(dest_net, id); |
---|
| 3424 | + if (!link_net) { |
---|
| 3425 | + NL_SET_ERR_MSG(extack, "Unknown network namespace id"); |
---|
| 3426 | + err = -EINVAL; |
---|
3143 | 3427 | goto out; |
---|
3144 | 3428 | } |
---|
| 3429 | + err = -EPERM; |
---|
| 3430 | + if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN)) |
---|
| 3431 | + goto out; |
---|
| 3432 | + } else { |
---|
| 3433 | + link_net = NULL; |
---|
| 3434 | + } |
---|
3145 | 3435 | |
---|
3146 | | - dev->ifindex = ifm->ifi_index; |
---|
3147 | | - |
---|
3148 | | - if (ops->newlink) { |
---|
3149 | | - err = ops->newlink(link_net ? : net, dev, tb, data, |
---|
3150 | | - extack); |
---|
3151 | | - /* Drivers should call free_netdev() in ->destructor |
---|
3152 | | - * and unregister it on failure after registration |
---|
3153 | | - * so that device could be finally freed in rtnl_unlock. |
---|
3154 | | - */ |
---|
3155 | | - if (err < 0) { |
---|
3156 | | - /* If device is not registered at all, free it now */ |
---|
3157 | | - if (dev->reg_state == NETREG_UNINITIALIZED || |
---|
3158 | | - dev->reg_state == NETREG_UNREGISTERED) |
---|
3159 | | - free_netdev(dev); |
---|
3160 | | - goto out; |
---|
3161 | | - } |
---|
3162 | | - } else { |
---|
3163 | | - err = register_netdevice(dev); |
---|
3164 | | - if (err < 0) { |
---|
3165 | | - free_netdev(dev); |
---|
3166 | | - goto out; |
---|
3167 | | - } |
---|
3168 | | - } |
---|
3169 | | - err = rtnl_configure_link(dev, ifm); |
---|
3170 | | - if (err < 0) |
---|
3171 | | - goto out_unregister; |
---|
3172 | | - if (link_net) { |
---|
3173 | | - err = dev_change_net_namespace(dev, dest_net, ifname); |
---|
3174 | | - if (err < 0) |
---|
3175 | | - goto out_unregister; |
---|
3176 | | - } |
---|
3177 | | - if (tb[IFLA_MASTER]) { |
---|
3178 | | - err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]), |
---|
3179 | | - extack); |
---|
3180 | | - if (err) |
---|
3181 | | - goto out_unregister; |
---|
3182 | | - } |
---|
3183 | | -out: |
---|
3184 | | - if (link_net) |
---|
3185 | | - put_net(link_net); |
---|
3186 | | - put_net(dest_net); |
---|
3187 | | - return err; |
---|
3188 | | -out_unregister: |
---|
3189 | | - if (ops->newlink) { |
---|
3190 | | - LIST_HEAD(list_kill); |
---|
3191 | | - |
---|
3192 | | - ops->dellink(dev, &list_kill); |
---|
3193 | | - unregister_netdevice_many(&list_kill); |
---|
3194 | | - } else { |
---|
3195 | | - unregister_netdevice(dev); |
---|
3196 | | - } |
---|
| 3436 | + dev = rtnl_create_link(link_net ? : dest_net, ifname, |
---|
| 3437 | + name_assign_type, ops, tb, extack); |
---|
| 3438 | + if (IS_ERR(dev)) { |
---|
| 3439 | + err = PTR_ERR(dev); |
---|
3197 | 3440 | goto out; |
---|
3198 | 3441 | } |
---|
| 3442 | + |
---|
| 3443 | + dev->ifindex = ifm->ifi_index; |
---|
| 3444 | + |
---|
| 3445 | + if (ops->newlink) |
---|
| 3446 | + err = ops->newlink(link_net ? : net, dev, tb, data, extack); |
---|
| 3447 | + else |
---|
| 3448 | + err = register_netdevice(dev); |
---|
| 3449 | + if (err < 0) { |
---|
| 3450 | + free_netdev(dev); |
---|
| 3451 | + goto out; |
---|
| 3452 | + } |
---|
| 3453 | + |
---|
| 3454 | + err = rtnl_configure_link(dev, ifm); |
---|
| 3455 | + if (err < 0) |
---|
| 3456 | + goto out_unregister; |
---|
| 3457 | + if (link_net) { |
---|
| 3458 | + err = dev_change_net_namespace(dev, dest_net, ifname); |
---|
| 3459 | + if (err < 0) |
---|
| 3460 | + goto out_unregister; |
---|
| 3461 | + } |
---|
| 3462 | + if (tb[IFLA_MASTER]) { |
---|
| 3463 | + err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]), extack); |
---|
| 3464 | + if (err) |
---|
| 3465 | + goto out_unregister; |
---|
| 3466 | + } |
---|
| 3467 | +out: |
---|
| 3468 | + if (link_net) |
---|
| 3469 | + put_net(link_net); |
---|
| 3470 | + put_net(dest_net); |
---|
| 3471 | + return err; |
---|
| 3472 | +out_unregister: |
---|
| 3473 | + if (ops->newlink) { |
---|
| 3474 | + LIST_HEAD(list_kill); |
---|
| 3475 | + |
---|
| 3476 | + ops->dellink(dev, &list_kill); |
---|
| 3477 | + unregister_netdevice_many(&list_kill); |
---|
| 3478 | + } else { |
---|
| 3479 | + unregister_netdevice(dev); |
---|
| 3480 | + } |
---|
| 3481 | + goto out; |
---|
| 3482 | +} |
---|
| 3483 | + |
---|
| 3484 | +static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 3485 | + struct netlink_ext_ack *extack) |
---|
| 3486 | +{ |
---|
| 3487 | + struct nlattr **attr; |
---|
| 3488 | + int ret; |
---|
| 3489 | + |
---|
| 3490 | + attr = kmalloc_array(RTNL_MAX_TYPE + 1, sizeof(*attr), GFP_KERNEL); |
---|
| 3491 | + if (!attr) |
---|
| 3492 | + return -ENOMEM; |
---|
| 3493 | + |
---|
| 3494 | + ret = __rtnl_newlink(skb, nlh, attr, extack); |
---|
| 3495 | + kfree(attr); |
---|
| 3496 | + return ret; |
---|
| 3497 | +} |
---|
| 3498 | + |
---|
| 3499 | +static int rtnl_valid_getlink_req(struct sk_buff *skb, |
---|
| 3500 | + const struct nlmsghdr *nlh, |
---|
| 3501 | + struct nlattr **tb, |
---|
| 3502 | + struct netlink_ext_ack *extack) |
---|
| 3503 | +{ |
---|
| 3504 | + struct ifinfomsg *ifm; |
---|
| 3505 | + int i, err; |
---|
| 3506 | + |
---|
| 3507 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
---|
| 3508 | + NL_SET_ERR_MSG(extack, "Invalid header for get link"); |
---|
| 3509 | + return -EINVAL; |
---|
| 3510 | + } |
---|
| 3511 | + |
---|
| 3512 | + if (!netlink_strict_get_check(skb)) |
---|
| 3513 | + return nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFLA_MAX, |
---|
| 3514 | + ifla_policy, extack); |
---|
| 3515 | + |
---|
| 3516 | + ifm = nlmsg_data(nlh); |
---|
| 3517 | + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || |
---|
| 3518 | + ifm->ifi_change) { |
---|
| 3519 | + NL_SET_ERR_MSG(extack, "Invalid values in header for get link request"); |
---|
| 3520 | + return -EINVAL; |
---|
| 3521 | + } |
---|
| 3522 | + |
---|
| 3523 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, IFLA_MAX, |
---|
| 3524 | + ifla_policy, extack); |
---|
| 3525 | + if (err) |
---|
| 3526 | + return err; |
---|
| 3527 | + |
---|
| 3528 | + for (i = 0; i <= IFLA_MAX; i++) { |
---|
| 3529 | + if (!tb[i]) |
---|
| 3530 | + continue; |
---|
| 3531 | + |
---|
| 3532 | + switch (i) { |
---|
| 3533 | + case IFLA_IFNAME: |
---|
| 3534 | + case IFLA_ALT_IFNAME: |
---|
| 3535 | + case IFLA_EXT_MASK: |
---|
| 3536 | + case IFLA_TARGET_NETNSID: |
---|
| 3537 | + break; |
---|
| 3538 | + default: |
---|
| 3539 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in get link request"); |
---|
| 3540 | + return -EINVAL; |
---|
| 3541 | + } |
---|
| 3542 | + } |
---|
| 3543 | + |
---|
| 3544 | + return 0; |
---|
3199 | 3545 | } |
---|
3200 | 3546 | |
---|
3201 | 3547 | static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
.. | .. |
---|
3204 | 3550 | struct net *net = sock_net(skb->sk); |
---|
3205 | 3551 | struct net *tgt_net = net; |
---|
3206 | 3552 | struct ifinfomsg *ifm; |
---|
3207 | | - char ifname[IFNAMSIZ]; |
---|
3208 | 3553 | struct nlattr *tb[IFLA_MAX+1]; |
---|
3209 | 3554 | struct net_device *dev = NULL; |
---|
3210 | 3555 | struct sk_buff *nskb; |
---|
.. | .. |
---|
3212 | 3557 | int err; |
---|
3213 | 3558 | u32 ext_filter_mask = 0; |
---|
3214 | 3559 | |
---|
3215 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack); |
---|
| 3560 | + err = rtnl_valid_getlink_req(skb, nlh, tb, extack); |
---|
3216 | 3561 | if (err < 0) |
---|
3217 | 3562 | return err; |
---|
3218 | 3563 | |
---|
.. | .. |
---|
3220 | 3565 | if (err < 0) |
---|
3221 | 3566 | return err; |
---|
3222 | 3567 | |
---|
3223 | | - if (tb[IFLA_IF_NETNSID]) { |
---|
3224 | | - netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]); |
---|
3225 | | - tgt_net = get_target_net(NETLINK_CB(skb).sk, netnsid); |
---|
| 3568 | + if (tb[IFLA_TARGET_NETNSID]) { |
---|
| 3569 | + netnsid = nla_get_s32(tb[IFLA_TARGET_NETNSID]); |
---|
| 3570 | + tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, netnsid); |
---|
3226 | 3571 | if (IS_ERR(tgt_net)) |
---|
3227 | 3572 | return PTR_ERR(tgt_net); |
---|
3228 | 3573 | } |
---|
3229 | | - |
---|
3230 | | - if (tb[IFLA_IFNAME]) |
---|
3231 | | - nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); |
---|
3232 | 3574 | |
---|
3233 | 3575 | if (tb[IFLA_EXT_MASK]) |
---|
3234 | 3576 | ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); |
---|
.. | .. |
---|
3237 | 3579 | ifm = nlmsg_data(nlh); |
---|
3238 | 3580 | if (ifm->ifi_index > 0) |
---|
3239 | 3581 | dev = __dev_get_by_index(tgt_net, ifm->ifi_index); |
---|
3240 | | - else if (tb[IFLA_IFNAME]) |
---|
3241 | | - dev = __dev_get_by_name(tgt_net, ifname); |
---|
| 3582 | + else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) |
---|
| 3583 | + dev = rtnl_dev_get(tgt_net, tb[IFLA_IFNAME], |
---|
| 3584 | + tb[IFLA_ALT_IFNAME], NULL); |
---|
3242 | 3585 | else |
---|
3243 | 3586 | goto out; |
---|
3244 | 3587 | |
---|
.. | .. |
---|
3268 | 3611 | return err; |
---|
3269 | 3612 | } |
---|
3270 | 3613 | |
---|
3271 | | -static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh) |
---|
| 3614 | +static int rtnl_alt_ifname(int cmd, struct net_device *dev, struct nlattr *attr, |
---|
| 3615 | + bool *changed, struct netlink_ext_ack *extack) |
---|
| 3616 | +{ |
---|
| 3617 | + char *alt_ifname; |
---|
| 3618 | + size_t size; |
---|
| 3619 | + int err; |
---|
| 3620 | + |
---|
| 3621 | + err = nla_validate(attr, attr->nla_len, IFLA_MAX, ifla_policy, extack); |
---|
| 3622 | + if (err) |
---|
| 3623 | + return err; |
---|
| 3624 | + |
---|
| 3625 | + if (cmd == RTM_NEWLINKPROP) { |
---|
| 3626 | + size = rtnl_prop_list_size(dev); |
---|
| 3627 | + size += nla_total_size(ALTIFNAMSIZ); |
---|
| 3628 | + if (size >= U16_MAX) { |
---|
| 3629 | + NL_SET_ERR_MSG(extack, |
---|
| 3630 | + "effective property list too long"); |
---|
| 3631 | + return -EINVAL; |
---|
| 3632 | + } |
---|
| 3633 | + } |
---|
| 3634 | + |
---|
| 3635 | + alt_ifname = nla_strdup(attr, GFP_KERNEL_ACCOUNT); |
---|
| 3636 | + if (!alt_ifname) |
---|
| 3637 | + return -ENOMEM; |
---|
| 3638 | + |
---|
| 3639 | + if (cmd == RTM_NEWLINKPROP) { |
---|
| 3640 | + err = netdev_name_node_alt_create(dev, alt_ifname); |
---|
| 3641 | + if (!err) |
---|
| 3642 | + alt_ifname = NULL; |
---|
| 3643 | + } else if (cmd == RTM_DELLINKPROP) { |
---|
| 3644 | + err = netdev_name_node_alt_destroy(dev, alt_ifname); |
---|
| 3645 | + } else { |
---|
| 3646 | + WARN_ON_ONCE(1); |
---|
| 3647 | + err = -EINVAL; |
---|
| 3648 | + } |
---|
| 3649 | + |
---|
| 3650 | + kfree(alt_ifname); |
---|
| 3651 | + if (!err) |
---|
| 3652 | + *changed = true; |
---|
| 3653 | + return err; |
---|
| 3654 | +} |
---|
| 3655 | + |
---|
| 3656 | +static int rtnl_linkprop(int cmd, struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 3657 | + struct netlink_ext_ack *extack) |
---|
3272 | 3658 | { |
---|
3273 | 3659 | struct net *net = sock_net(skb->sk); |
---|
| 3660 | + struct nlattr *tb[IFLA_MAX + 1]; |
---|
3274 | 3661 | struct net_device *dev; |
---|
| 3662 | + struct ifinfomsg *ifm; |
---|
| 3663 | + bool changed = false; |
---|
| 3664 | + struct nlattr *attr; |
---|
| 3665 | + int err, rem; |
---|
| 3666 | + |
---|
| 3667 | + err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack); |
---|
| 3668 | + if (err) |
---|
| 3669 | + return err; |
---|
| 3670 | + |
---|
| 3671 | + err = rtnl_ensure_unique_netns(tb, extack, true); |
---|
| 3672 | + if (err) |
---|
| 3673 | + return err; |
---|
| 3674 | + |
---|
| 3675 | + ifm = nlmsg_data(nlh); |
---|
| 3676 | + if (ifm->ifi_index > 0) |
---|
| 3677 | + dev = __dev_get_by_index(net, ifm->ifi_index); |
---|
| 3678 | + else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) |
---|
| 3679 | + dev = rtnl_dev_get(net, tb[IFLA_IFNAME], |
---|
| 3680 | + tb[IFLA_ALT_IFNAME], NULL); |
---|
| 3681 | + else |
---|
| 3682 | + return -EINVAL; |
---|
| 3683 | + |
---|
| 3684 | + if (!dev) |
---|
| 3685 | + return -ENODEV; |
---|
| 3686 | + |
---|
| 3687 | + if (!tb[IFLA_PROP_LIST]) |
---|
| 3688 | + return 0; |
---|
| 3689 | + |
---|
| 3690 | + nla_for_each_nested(attr, tb[IFLA_PROP_LIST], rem) { |
---|
| 3691 | + switch (nla_type(attr)) { |
---|
| 3692 | + case IFLA_ALT_IFNAME: |
---|
| 3693 | + err = rtnl_alt_ifname(cmd, dev, attr, &changed, extack); |
---|
| 3694 | + if (err) |
---|
| 3695 | + return err; |
---|
| 3696 | + break; |
---|
| 3697 | + } |
---|
| 3698 | + } |
---|
| 3699 | + |
---|
| 3700 | + if (changed) |
---|
| 3701 | + netdev_state_change(dev); |
---|
| 3702 | + return 0; |
---|
| 3703 | +} |
---|
| 3704 | + |
---|
| 3705 | +static int rtnl_newlinkprop(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 3706 | + struct netlink_ext_ack *extack) |
---|
| 3707 | +{ |
---|
| 3708 | + return rtnl_linkprop(RTM_NEWLINKPROP, skb, nlh, extack); |
---|
| 3709 | +} |
---|
| 3710 | + |
---|
| 3711 | +static int rtnl_dellinkprop(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 3712 | + struct netlink_ext_ack *extack) |
---|
| 3713 | +{ |
---|
| 3714 | + return rtnl_linkprop(RTM_DELLINKPROP, skb, nlh, extack); |
---|
| 3715 | +} |
---|
| 3716 | + |
---|
| 3717 | +static u32 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh) |
---|
| 3718 | +{ |
---|
| 3719 | + struct net *net = sock_net(skb->sk); |
---|
| 3720 | + size_t min_ifinfo_dump_size = 0; |
---|
3275 | 3721 | struct nlattr *tb[IFLA_MAX+1]; |
---|
3276 | 3722 | u32 ext_filter_mask = 0; |
---|
3277 | | - u16 min_ifinfo_dump_size = 0; |
---|
| 3723 | + struct net_device *dev; |
---|
3278 | 3724 | int hdrlen; |
---|
3279 | 3725 | |
---|
3280 | 3726 | /* Same kernel<->userspace interface hack as in rtnl_dump_ifinfo. */ |
---|
3281 | 3727 | hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ? |
---|
3282 | 3728 | sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); |
---|
3283 | 3729 | |
---|
3284 | | - if (nlmsg_parse(nlh, hdrlen, tb, IFLA_MAX, ifla_policy, NULL) >= 0) { |
---|
| 3730 | + if (nlmsg_parse_deprecated(nlh, hdrlen, tb, IFLA_MAX, ifla_policy, NULL) >= 0) { |
---|
3285 | 3731 | if (tb[IFLA_EXT_MASK]) |
---|
3286 | 3732 | ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); |
---|
3287 | 3733 | } |
---|
.. | .. |
---|
3294 | 3740 | */ |
---|
3295 | 3741 | rcu_read_lock(); |
---|
3296 | 3742 | for_each_netdev_rcu(net, dev) { |
---|
3297 | | - min_ifinfo_dump_size = max_t(u16, min_ifinfo_dump_size, |
---|
3298 | | - if_nlmsg_size(dev, |
---|
3299 | | - ext_filter_mask)); |
---|
| 3743 | + min_ifinfo_dump_size = max(min_ifinfo_dump_size, |
---|
| 3744 | + if_nlmsg_size(dev, ext_filter_mask)); |
---|
3300 | 3745 | } |
---|
3301 | 3746 | rcu_read_unlock(); |
---|
3302 | 3747 | |
---|
.. | .. |
---|
3308 | 3753 | int idx; |
---|
3309 | 3754 | int s_idx = cb->family; |
---|
3310 | 3755 | int type = cb->nlh->nlmsg_type - RTM_BASE; |
---|
| 3756 | + int ret = 0; |
---|
3311 | 3757 | |
---|
3312 | 3758 | if (s_idx == 0) |
---|
3313 | 3759 | s_idx = 1; |
---|
.. | .. |
---|
3340 | 3786 | cb->prev_seq = 0; |
---|
3341 | 3787 | cb->seq = 0; |
---|
3342 | 3788 | } |
---|
3343 | | - if (dumpit(skb, cb)) |
---|
| 3789 | + ret = dumpit(skb, cb); |
---|
| 3790 | + if (ret) |
---|
3344 | 3791 | break; |
---|
3345 | 3792 | } |
---|
3346 | 3793 | cb->family = idx; |
---|
3347 | 3794 | |
---|
3348 | | - return skb->len; |
---|
| 3795 | + return skb->len ? : ret; |
---|
3349 | 3796 | } |
---|
3350 | 3797 | |
---|
3351 | 3798 | struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev, |
---|
.. | .. |
---|
3482 | 3929 | rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); |
---|
3483 | 3930 | } |
---|
3484 | 3931 | |
---|
3485 | | -/** |
---|
| 3932 | +/* |
---|
3486 | 3933 | * ndo_dflt_fdb_add - default netdevice operation to add an FDB entry |
---|
3487 | 3934 | */ |
---|
3488 | 3935 | int ndo_dflt_fdb_add(struct ndmsg *ndm, |
---|
.. | .. |
---|
3552 | 3999 | u16 vid; |
---|
3553 | 4000 | int err; |
---|
3554 | 4001 | |
---|
3555 | | - err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, extack); |
---|
3556 | | - if (err < 0) |
---|
3557 | | - return err; |
---|
3558 | | - |
---|
3559 | | - ndm = nlmsg_data(nlh); |
---|
3560 | | - if (ndm->ndm_ifindex == 0) { |
---|
3561 | | - NL_SET_ERR_MSG(extack, "invalid ifindex"); |
---|
3562 | | - return -EINVAL; |
---|
3563 | | - } |
---|
3564 | | - |
---|
3565 | | - dev = __dev_get_by_index(net, ndm->ndm_ifindex); |
---|
3566 | | - if (dev == NULL) { |
---|
3567 | | - NL_SET_ERR_MSG(extack, "unknown ifindex"); |
---|
3568 | | - return -ENODEV; |
---|
3569 | | - } |
---|
3570 | | - |
---|
3571 | | - if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) { |
---|
3572 | | - NL_SET_ERR_MSG(extack, "invalid address"); |
---|
3573 | | - return -EINVAL; |
---|
3574 | | - } |
---|
3575 | | - |
---|
3576 | | - if (dev->type != ARPHRD_ETHER) { |
---|
3577 | | - NL_SET_ERR_MSG(extack, "FDB delete only supported for Ethernet devices"); |
---|
3578 | | - return -EINVAL; |
---|
3579 | | - } |
---|
3580 | | - |
---|
3581 | | - addr = nla_data(tb[NDA_LLADDR]); |
---|
3582 | | - |
---|
3583 | | - err = fdb_vid_parse(tb[NDA_VLAN], &vid, extack); |
---|
3584 | | - if (err) |
---|
3585 | | - return err; |
---|
3586 | | - |
---|
3587 | | - err = -EOPNOTSUPP; |
---|
3588 | | - |
---|
3589 | | - /* Support fdb on master device the net/bridge default case */ |
---|
3590 | | - if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && |
---|
3591 | | - (dev->priv_flags & IFF_BRIDGE_PORT)) { |
---|
3592 | | - struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
---|
3593 | | - const struct net_device_ops *ops = br_dev->netdev_ops; |
---|
3594 | | - |
---|
3595 | | - err = ops->ndo_fdb_add(ndm, tb, dev, addr, vid, |
---|
3596 | | - nlh->nlmsg_flags); |
---|
3597 | | - if (err) |
---|
3598 | | - goto out; |
---|
3599 | | - else |
---|
3600 | | - ndm->ndm_flags &= ~NTF_MASTER; |
---|
3601 | | - } |
---|
3602 | | - |
---|
3603 | | - /* Embedded bridge, macvlan, and any other device support */ |
---|
3604 | | - if ((ndm->ndm_flags & NTF_SELF)) { |
---|
3605 | | - if (dev->netdev_ops->ndo_fdb_add) |
---|
3606 | | - err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr, |
---|
3607 | | - vid, |
---|
3608 | | - nlh->nlmsg_flags); |
---|
3609 | | - else |
---|
3610 | | - err = ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, |
---|
3611 | | - nlh->nlmsg_flags); |
---|
3612 | | - |
---|
3613 | | - if (!err) { |
---|
3614 | | - rtnl_fdb_notify(dev, addr, vid, RTM_NEWNEIGH, |
---|
3615 | | - ndm->ndm_state); |
---|
3616 | | - ndm->ndm_flags &= ~NTF_SELF; |
---|
3617 | | - } |
---|
3618 | | - } |
---|
3619 | | -out: |
---|
3620 | | - return err; |
---|
3621 | | -} |
---|
3622 | | - |
---|
3623 | | -/** |
---|
3624 | | - * ndo_dflt_fdb_del - default netdevice operation to delete an FDB entry |
---|
3625 | | - */ |
---|
3626 | | -int ndo_dflt_fdb_del(struct ndmsg *ndm, |
---|
3627 | | - struct nlattr *tb[], |
---|
3628 | | - struct net_device *dev, |
---|
3629 | | - const unsigned char *addr, u16 vid) |
---|
3630 | | -{ |
---|
3631 | | - int err = -EINVAL; |
---|
3632 | | - |
---|
3633 | | - /* If aging addresses are supported device will need to |
---|
3634 | | - * implement its own handler for this. |
---|
3635 | | - */ |
---|
3636 | | - if (!(ndm->ndm_state & NUD_PERMANENT)) { |
---|
3637 | | - pr_info("%s: FDB only supports static addresses\n", dev->name); |
---|
3638 | | - return err; |
---|
3639 | | - } |
---|
3640 | | - |
---|
3641 | | - if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) |
---|
3642 | | - err = dev_uc_del(dev, addr); |
---|
3643 | | - else if (is_multicast_ether_addr(addr)) |
---|
3644 | | - err = dev_mc_del(dev, addr); |
---|
3645 | | - |
---|
3646 | | - return err; |
---|
3647 | | -} |
---|
3648 | | -EXPORT_SYMBOL(ndo_dflt_fdb_del); |
---|
3649 | | - |
---|
3650 | | -static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
3651 | | - struct netlink_ext_ack *extack) |
---|
3652 | | -{ |
---|
3653 | | - struct net *net = sock_net(skb->sk); |
---|
3654 | | - struct ndmsg *ndm; |
---|
3655 | | - struct nlattr *tb[NDA_MAX+1]; |
---|
3656 | | - struct net_device *dev; |
---|
3657 | | - int err = -EINVAL; |
---|
3658 | | - __u8 *addr; |
---|
3659 | | - u16 vid; |
---|
3660 | | - |
---|
3661 | | - if (!netlink_capable(skb, CAP_NET_ADMIN)) |
---|
3662 | | - return -EPERM; |
---|
3663 | | - |
---|
3664 | | - err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, extack); |
---|
| 4002 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, |
---|
| 4003 | + extack); |
---|
3665 | 4004 | if (err < 0) |
---|
3666 | 4005 | return err; |
---|
3667 | 4006 | |
---|
.. | .. |
---|
3697 | 4036 | |
---|
3698 | 4037 | /* Support fdb on master device the net/bridge default case */ |
---|
3699 | 4038 | if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && |
---|
3700 | | - (dev->priv_flags & IFF_BRIDGE_PORT)) { |
---|
| 4039 | + netif_is_bridge_port(dev)) { |
---|
| 4040 | + struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
---|
| 4041 | + const struct net_device_ops *ops = br_dev->netdev_ops; |
---|
| 4042 | + |
---|
| 4043 | + err = ops->ndo_fdb_add(ndm, tb, dev, addr, vid, |
---|
| 4044 | + nlh->nlmsg_flags, extack); |
---|
| 4045 | + if (err) |
---|
| 4046 | + goto out; |
---|
| 4047 | + else |
---|
| 4048 | + ndm->ndm_flags &= ~NTF_MASTER; |
---|
| 4049 | + } |
---|
| 4050 | + |
---|
| 4051 | + /* Embedded bridge, macvlan, and any other device support */ |
---|
| 4052 | + if ((ndm->ndm_flags & NTF_SELF)) { |
---|
| 4053 | + if (dev->netdev_ops->ndo_fdb_add) |
---|
| 4054 | + err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr, |
---|
| 4055 | + vid, |
---|
| 4056 | + nlh->nlmsg_flags, |
---|
| 4057 | + extack); |
---|
| 4058 | + else |
---|
| 4059 | + err = ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, |
---|
| 4060 | + nlh->nlmsg_flags); |
---|
| 4061 | + |
---|
| 4062 | + if (!err) { |
---|
| 4063 | + rtnl_fdb_notify(dev, addr, vid, RTM_NEWNEIGH, |
---|
| 4064 | + ndm->ndm_state); |
---|
| 4065 | + ndm->ndm_flags &= ~NTF_SELF; |
---|
| 4066 | + } |
---|
| 4067 | + } |
---|
| 4068 | +out: |
---|
| 4069 | + return err; |
---|
| 4070 | +} |
---|
| 4071 | + |
---|
| 4072 | +/* |
---|
| 4073 | + * ndo_dflt_fdb_del - default netdevice operation to delete an FDB entry |
---|
| 4074 | + */ |
---|
| 4075 | +int ndo_dflt_fdb_del(struct ndmsg *ndm, |
---|
| 4076 | + struct nlattr *tb[], |
---|
| 4077 | + struct net_device *dev, |
---|
| 4078 | + const unsigned char *addr, u16 vid) |
---|
| 4079 | +{ |
---|
| 4080 | + int err = -EINVAL; |
---|
| 4081 | + |
---|
| 4082 | + /* If aging addresses are supported device will need to |
---|
| 4083 | + * implement its own handler for this. |
---|
| 4084 | + */ |
---|
| 4085 | + if (!(ndm->ndm_state & NUD_PERMANENT)) { |
---|
| 4086 | + pr_info("%s: FDB only supports static addresses\n", dev->name); |
---|
| 4087 | + return err; |
---|
| 4088 | + } |
---|
| 4089 | + |
---|
| 4090 | + if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) |
---|
| 4091 | + err = dev_uc_del(dev, addr); |
---|
| 4092 | + else if (is_multicast_ether_addr(addr)) |
---|
| 4093 | + err = dev_mc_del(dev, addr); |
---|
| 4094 | + |
---|
| 4095 | + return err; |
---|
| 4096 | +} |
---|
| 4097 | +EXPORT_SYMBOL(ndo_dflt_fdb_del); |
---|
| 4098 | + |
---|
| 4099 | +static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 4100 | + struct netlink_ext_ack *extack) |
---|
| 4101 | +{ |
---|
| 4102 | + struct net *net = sock_net(skb->sk); |
---|
| 4103 | + struct ndmsg *ndm; |
---|
| 4104 | + struct nlattr *tb[NDA_MAX+1]; |
---|
| 4105 | + struct net_device *dev; |
---|
| 4106 | + __u8 *addr; |
---|
| 4107 | + int err; |
---|
| 4108 | + u16 vid; |
---|
| 4109 | + |
---|
| 4110 | + if (!netlink_capable(skb, CAP_NET_ADMIN)) |
---|
| 4111 | + return -EPERM; |
---|
| 4112 | + |
---|
| 4113 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, |
---|
| 4114 | + extack); |
---|
| 4115 | + if (err < 0) |
---|
| 4116 | + return err; |
---|
| 4117 | + |
---|
| 4118 | + ndm = nlmsg_data(nlh); |
---|
| 4119 | + if (ndm->ndm_ifindex == 0) { |
---|
| 4120 | + NL_SET_ERR_MSG(extack, "invalid ifindex"); |
---|
| 4121 | + return -EINVAL; |
---|
| 4122 | + } |
---|
| 4123 | + |
---|
| 4124 | + dev = __dev_get_by_index(net, ndm->ndm_ifindex); |
---|
| 4125 | + if (dev == NULL) { |
---|
| 4126 | + NL_SET_ERR_MSG(extack, "unknown ifindex"); |
---|
| 4127 | + return -ENODEV; |
---|
| 4128 | + } |
---|
| 4129 | + |
---|
| 4130 | + if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) { |
---|
| 4131 | + NL_SET_ERR_MSG(extack, "invalid address"); |
---|
| 4132 | + return -EINVAL; |
---|
| 4133 | + } |
---|
| 4134 | + |
---|
| 4135 | + if (dev->type != ARPHRD_ETHER) { |
---|
| 4136 | + NL_SET_ERR_MSG(extack, "FDB delete only supported for Ethernet devices"); |
---|
| 4137 | + return -EINVAL; |
---|
| 4138 | + } |
---|
| 4139 | + |
---|
| 4140 | + addr = nla_data(tb[NDA_LLADDR]); |
---|
| 4141 | + |
---|
| 4142 | + err = fdb_vid_parse(tb[NDA_VLAN], &vid, extack); |
---|
| 4143 | + if (err) |
---|
| 4144 | + return err; |
---|
| 4145 | + |
---|
| 4146 | + err = -EOPNOTSUPP; |
---|
| 4147 | + |
---|
| 4148 | + /* Support fdb on master device the net/bridge default case */ |
---|
| 4149 | + if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && |
---|
| 4150 | + netif_is_bridge_port(dev)) { |
---|
3701 | 4151 | struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
---|
3702 | 4152 | const struct net_device_ops *ops = br_dev->netdev_ops; |
---|
3703 | 4153 | |
---|
.. | .. |
---|
3759 | 4209 | |
---|
3760 | 4210 | /** |
---|
3761 | 4211 | * ndo_dflt_fdb_dump - default netdevice operation to dump an FDB table. |
---|
3762 | | - * @nlh: netlink message header |
---|
| 4212 | + * @skb: socket buffer to store message in |
---|
| 4213 | + * @cb: netlink callback |
---|
3763 | 4214 | * @dev: netdevice |
---|
| 4215 | + * @filter_dev: ignored |
---|
| 4216 | + * @idx: the number of FDB table entries dumped is added to *@idx |
---|
3764 | 4217 | * |
---|
3765 | 4218 | * Default netdevice operation to dump the existing unicast address list. |
---|
3766 | 4219 | * Returns number of addresses from list put in skb. |
---|
.. | .. |
---|
3787 | 4240 | } |
---|
3788 | 4241 | EXPORT_SYMBOL(ndo_dflt_fdb_dump); |
---|
3789 | 4242 | |
---|
| 4243 | +static int valid_fdb_dump_strict(const struct nlmsghdr *nlh, |
---|
| 4244 | + int *br_idx, int *brport_idx, |
---|
| 4245 | + struct netlink_ext_ack *extack) |
---|
| 4246 | +{ |
---|
| 4247 | + struct nlattr *tb[NDA_MAX + 1]; |
---|
| 4248 | + struct ndmsg *ndm; |
---|
| 4249 | + int err, i; |
---|
| 4250 | + |
---|
| 4251 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) { |
---|
| 4252 | + NL_SET_ERR_MSG(extack, "Invalid header for fdb dump request"); |
---|
| 4253 | + return -EINVAL; |
---|
| 4254 | + } |
---|
| 4255 | + |
---|
| 4256 | + ndm = nlmsg_data(nlh); |
---|
| 4257 | + if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state || |
---|
| 4258 | + ndm->ndm_flags || ndm->ndm_type) { |
---|
| 4259 | + NL_SET_ERR_MSG(extack, "Invalid values in header for fdb dump request"); |
---|
| 4260 | + return -EINVAL; |
---|
| 4261 | + } |
---|
| 4262 | + |
---|
| 4263 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb, |
---|
| 4264 | + NDA_MAX, NULL, extack); |
---|
| 4265 | + if (err < 0) |
---|
| 4266 | + return err; |
---|
| 4267 | + |
---|
| 4268 | + *brport_idx = ndm->ndm_ifindex; |
---|
| 4269 | + for (i = 0; i <= NDA_MAX; ++i) { |
---|
| 4270 | + if (!tb[i]) |
---|
| 4271 | + continue; |
---|
| 4272 | + |
---|
| 4273 | + switch (i) { |
---|
| 4274 | + case NDA_IFINDEX: |
---|
| 4275 | + if (nla_len(tb[i]) != sizeof(u32)) { |
---|
| 4276 | + NL_SET_ERR_MSG(extack, "Invalid IFINDEX attribute in fdb dump request"); |
---|
| 4277 | + return -EINVAL; |
---|
| 4278 | + } |
---|
| 4279 | + *brport_idx = nla_get_u32(tb[NDA_IFINDEX]); |
---|
| 4280 | + break; |
---|
| 4281 | + case NDA_MASTER: |
---|
| 4282 | + if (nla_len(tb[i]) != sizeof(u32)) { |
---|
| 4283 | + NL_SET_ERR_MSG(extack, "Invalid MASTER attribute in fdb dump request"); |
---|
| 4284 | + return -EINVAL; |
---|
| 4285 | + } |
---|
| 4286 | + *br_idx = nla_get_u32(tb[NDA_MASTER]); |
---|
| 4287 | + break; |
---|
| 4288 | + default: |
---|
| 4289 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in fdb dump request"); |
---|
| 4290 | + return -EINVAL; |
---|
| 4291 | + } |
---|
| 4292 | + } |
---|
| 4293 | + |
---|
| 4294 | + return 0; |
---|
| 4295 | +} |
---|
| 4296 | + |
---|
| 4297 | +static int valid_fdb_dump_legacy(const struct nlmsghdr *nlh, |
---|
| 4298 | + int *br_idx, int *brport_idx, |
---|
| 4299 | + struct netlink_ext_ack *extack) |
---|
| 4300 | +{ |
---|
| 4301 | + struct nlattr *tb[IFLA_MAX+1]; |
---|
| 4302 | + int err; |
---|
| 4303 | + |
---|
| 4304 | + /* A hack to preserve kernel<->userspace interface. |
---|
| 4305 | + * Before Linux v4.12 this code accepted ndmsg since iproute2 v3.3.0. |
---|
| 4306 | + * However, ndmsg is shorter than ifinfomsg thus nlmsg_parse() bails. |
---|
| 4307 | + * So, check for ndmsg with an optional u32 attribute (not used here). |
---|
| 4308 | + * Fortunately these sizes don't conflict with the size of ifinfomsg |
---|
| 4309 | + * with an optional attribute. |
---|
| 4310 | + */ |
---|
| 4311 | + if (nlmsg_len(nlh) != sizeof(struct ndmsg) && |
---|
| 4312 | + (nlmsg_len(nlh) != sizeof(struct ndmsg) + |
---|
| 4313 | + nla_attr_size(sizeof(u32)))) { |
---|
| 4314 | + struct ifinfomsg *ifm; |
---|
| 4315 | + |
---|
| 4316 | + err = nlmsg_parse_deprecated(nlh, sizeof(struct ifinfomsg), |
---|
| 4317 | + tb, IFLA_MAX, ifla_policy, |
---|
| 4318 | + extack); |
---|
| 4319 | + if (err < 0) { |
---|
| 4320 | + return -EINVAL; |
---|
| 4321 | + } else if (err == 0) { |
---|
| 4322 | + if (tb[IFLA_MASTER]) |
---|
| 4323 | + *br_idx = nla_get_u32(tb[IFLA_MASTER]); |
---|
| 4324 | + } |
---|
| 4325 | + |
---|
| 4326 | + ifm = nlmsg_data(nlh); |
---|
| 4327 | + *brport_idx = ifm->ifi_index; |
---|
| 4328 | + } |
---|
| 4329 | + return 0; |
---|
| 4330 | +} |
---|
| 4331 | + |
---|
3790 | 4332 | static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) |
---|
3791 | 4333 | { |
---|
3792 | 4334 | struct net_device *dev; |
---|
3793 | | - struct nlattr *tb[IFLA_MAX+1]; |
---|
3794 | 4335 | struct net_device *br_dev = NULL; |
---|
3795 | 4336 | const struct net_device_ops *ops = NULL; |
---|
3796 | 4337 | const struct net_device_ops *cops = NULL; |
---|
3797 | | - struct ifinfomsg *ifm = nlmsg_data(cb->nlh); |
---|
3798 | 4338 | struct net *net = sock_net(skb->sk); |
---|
3799 | 4339 | struct hlist_head *head; |
---|
3800 | 4340 | int brport_idx = 0; |
---|
.. | .. |
---|
3804 | 4344 | int err = 0; |
---|
3805 | 4345 | int fidx = 0; |
---|
3806 | 4346 | |
---|
3807 | | - /* A hack to preserve kernel<->userspace interface. |
---|
3808 | | - * Before Linux v4.12 this code accepted ndmsg since iproute2 v3.3.0. |
---|
3809 | | - * However, ndmsg is shorter than ifinfomsg thus nlmsg_parse() bails. |
---|
3810 | | - * So, check for ndmsg with an optional u32 attribute (not used here). |
---|
3811 | | - * Fortunately these sizes don't conflict with the size of ifinfomsg |
---|
3812 | | - * with an optional attribute. |
---|
3813 | | - */ |
---|
3814 | | - if (nlmsg_len(cb->nlh) != sizeof(struct ndmsg) && |
---|
3815 | | - (nlmsg_len(cb->nlh) != sizeof(struct ndmsg) + |
---|
3816 | | - nla_attr_size(sizeof(u32)))) { |
---|
3817 | | - err = nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, |
---|
3818 | | - IFLA_MAX, ifla_policy, NULL); |
---|
3819 | | - if (err < 0) { |
---|
3820 | | - return -EINVAL; |
---|
3821 | | - } else if (err == 0) { |
---|
3822 | | - if (tb[IFLA_MASTER]) |
---|
3823 | | - br_idx = nla_get_u32(tb[IFLA_MASTER]); |
---|
3824 | | - } |
---|
3825 | | - |
---|
3826 | | - brport_idx = ifm->ifi_index; |
---|
3827 | | - } |
---|
| 4347 | + if (cb->strict_check) |
---|
| 4348 | + err = valid_fdb_dump_strict(cb->nlh, &br_idx, &brport_idx, |
---|
| 4349 | + cb->extack); |
---|
| 4350 | + else |
---|
| 4351 | + err = valid_fdb_dump_legacy(cb->nlh, &br_idx, &brport_idx, |
---|
| 4352 | + cb->extack); |
---|
| 4353 | + if (err < 0) |
---|
| 4354 | + return err; |
---|
3828 | 4355 | |
---|
3829 | 4356 | if (br_idx) { |
---|
3830 | 4357 | br_dev = __dev_get_by_index(net, br_idx); |
---|
.. | .. |
---|
3846 | 4373 | continue; |
---|
3847 | 4374 | |
---|
3848 | 4375 | if (!br_idx) { /* user did not specify a specific bridge */ |
---|
3849 | | - if (dev->priv_flags & IFF_BRIDGE_PORT) { |
---|
| 4376 | + if (netif_is_bridge_port(dev)) { |
---|
3850 | 4377 | br_dev = netdev_master_upper_dev_get(dev); |
---|
3851 | 4378 | cops = br_dev->netdev_ops; |
---|
3852 | 4379 | } |
---|
3853 | 4380 | } else { |
---|
3854 | 4381 | if (dev != br_dev && |
---|
3855 | | - !(dev->priv_flags & IFF_BRIDGE_PORT)) |
---|
| 4382 | + !netif_is_bridge_port(dev)) |
---|
3856 | 4383 | continue; |
---|
3857 | 4384 | |
---|
3858 | 4385 | if (br_dev != netdev_master_upper_dev_get(dev) && |
---|
.. | .. |
---|
3864 | 4391 | if (idx < s_idx) |
---|
3865 | 4392 | goto cont; |
---|
3866 | 4393 | |
---|
3867 | | - if (dev->priv_flags & IFF_BRIDGE_PORT) { |
---|
| 4394 | + if (netif_is_bridge_port(dev)) { |
---|
3868 | 4395 | if (cops && cops->ndo_fdb_dump) { |
---|
3869 | 4396 | err = cops->ndo_fdb_dump(skb, cb, |
---|
3870 | 4397 | br_dev, dev, |
---|
.. | .. |
---|
3900 | 4427 | cb->args[2] = fidx; |
---|
3901 | 4428 | |
---|
3902 | 4429 | return skb->len; |
---|
| 4430 | +} |
---|
| 4431 | + |
---|
| 4432 | +static int valid_fdb_get_strict(const struct nlmsghdr *nlh, |
---|
| 4433 | + struct nlattr **tb, u8 *ndm_flags, |
---|
| 4434 | + int *br_idx, int *brport_idx, u8 **addr, |
---|
| 4435 | + u16 *vid, struct netlink_ext_ack *extack) |
---|
| 4436 | +{ |
---|
| 4437 | + struct ndmsg *ndm; |
---|
| 4438 | + int err, i; |
---|
| 4439 | + |
---|
| 4440 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) { |
---|
| 4441 | + NL_SET_ERR_MSG(extack, "Invalid header for fdb get request"); |
---|
| 4442 | + return -EINVAL; |
---|
| 4443 | + } |
---|
| 4444 | + |
---|
| 4445 | + ndm = nlmsg_data(nlh); |
---|
| 4446 | + if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state || |
---|
| 4447 | + ndm->ndm_type) { |
---|
| 4448 | + NL_SET_ERR_MSG(extack, "Invalid values in header for fdb get request"); |
---|
| 4449 | + return -EINVAL; |
---|
| 4450 | + } |
---|
| 4451 | + |
---|
| 4452 | + if (ndm->ndm_flags & ~(NTF_MASTER | NTF_SELF)) { |
---|
| 4453 | + NL_SET_ERR_MSG(extack, "Invalid flags in header for fdb get request"); |
---|
| 4454 | + return -EINVAL; |
---|
| 4455 | + } |
---|
| 4456 | + |
---|
| 4457 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb, |
---|
| 4458 | + NDA_MAX, nda_policy, extack); |
---|
| 4459 | + if (err < 0) |
---|
| 4460 | + return err; |
---|
| 4461 | + |
---|
| 4462 | + *ndm_flags = ndm->ndm_flags; |
---|
| 4463 | + *brport_idx = ndm->ndm_ifindex; |
---|
| 4464 | + for (i = 0; i <= NDA_MAX; ++i) { |
---|
| 4465 | + if (!tb[i]) |
---|
| 4466 | + continue; |
---|
| 4467 | + |
---|
| 4468 | + switch (i) { |
---|
| 4469 | + case NDA_MASTER: |
---|
| 4470 | + *br_idx = nla_get_u32(tb[i]); |
---|
| 4471 | + break; |
---|
| 4472 | + case NDA_LLADDR: |
---|
| 4473 | + if (nla_len(tb[i]) != ETH_ALEN) { |
---|
| 4474 | + NL_SET_ERR_MSG(extack, "Invalid address in fdb get request"); |
---|
| 4475 | + return -EINVAL; |
---|
| 4476 | + } |
---|
| 4477 | + *addr = nla_data(tb[i]); |
---|
| 4478 | + break; |
---|
| 4479 | + case NDA_VLAN: |
---|
| 4480 | + err = fdb_vid_parse(tb[i], vid, extack); |
---|
| 4481 | + if (err) |
---|
| 4482 | + return err; |
---|
| 4483 | + break; |
---|
| 4484 | + case NDA_VNI: |
---|
| 4485 | + break; |
---|
| 4486 | + default: |
---|
| 4487 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in fdb get request"); |
---|
| 4488 | + return -EINVAL; |
---|
| 4489 | + } |
---|
| 4490 | + } |
---|
| 4491 | + |
---|
| 4492 | + return 0; |
---|
| 4493 | +} |
---|
| 4494 | + |
---|
| 4495 | +static int rtnl_fdb_get(struct sk_buff *in_skb, struct nlmsghdr *nlh, |
---|
| 4496 | + struct netlink_ext_ack *extack) |
---|
| 4497 | +{ |
---|
| 4498 | + struct net_device *dev = NULL, *br_dev = NULL; |
---|
| 4499 | + const struct net_device_ops *ops = NULL; |
---|
| 4500 | + struct net *net = sock_net(in_skb->sk); |
---|
| 4501 | + struct nlattr *tb[NDA_MAX + 1]; |
---|
| 4502 | + struct sk_buff *skb; |
---|
| 4503 | + int brport_idx = 0; |
---|
| 4504 | + u8 ndm_flags = 0; |
---|
| 4505 | + int br_idx = 0; |
---|
| 4506 | + u8 *addr = NULL; |
---|
| 4507 | + u16 vid = 0; |
---|
| 4508 | + int err; |
---|
| 4509 | + |
---|
| 4510 | + err = valid_fdb_get_strict(nlh, tb, &ndm_flags, &br_idx, |
---|
| 4511 | + &brport_idx, &addr, &vid, extack); |
---|
| 4512 | + if (err < 0) |
---|
| 4513 | + return err; |
---|
| 4514 | + |
---|
| 4515 | + if (!addr) { |
---|
| 4516 | + NL_SET_ERR_MSG(extack, "Missing lookup address for fdb get request"); |
---|
| 4517 | + return -EINVAL; |
---|
| 4518 | + } |
---|
| 4519 | + |
---|
| 4520 | + if (brport_idx) { |
---|
| 4521 | + dev = __dev_get_by_index(net, brport_idx); |
---|
| 4522 | + if (!dev) { |
---|
| 4523 | + NL_SET_ERR_MSG(extack, "Unknown device ifindex"); |
---|
| 4524 | + return -ENODEV; |
---|
| 4525 | + } |
---|
| 4526 | + } |
---|
| 4527 | + |
---|
| 4528 | + if (br_idx) { |
---|
| 4529 | + if (dev) { |
---|
| 4530 | + NL_SET_ERR_MSG(extack, "Master and device are mutually exclusive"); |
---|
| 4531 | + return -EINVAL; |
---|
| 4532 | + } |
---|
| 4533 | + |
---|
| 4534 | + br_dev = __dev_get_by_index(net, br_idx); |
---|
| 4535 | + if (!br_dev) { |
---|
| 4536 | + NL_SET_ERR_MSG(extack, "Invalid master ifindex"); |
---|
| 4537 | + return -EINVAL; |
---|
| 4538 | + } |
---|
| 4539 | + ops = br_dev->netdev_ops; |
---|
| 4540 | + } |
---|
| 4541 | + |
---|
| 4542 | + if (dev) { |
---|
| 4543 | + if (!ndm_flags || (ndm_flags & NTF_MASTER)) { |
---|
| 4544 | + if (!netif_is_bridge_port(dev)) { |
---|
| 4545 | + NL_SET_ERR_MSG(extack, "Device is not a bridge port"); |
---|
| 4546 | + return -EINVAL; |
---|
| 4547 | + } |
---|
| 4548 | + br_dev = netdev_master_upper_dev_get(dev); |
---|
| 4549 | + if (!br_dev) { |
---|
| 4550 | + NL_SET_ERR_MSG(extack, "Master of device not found"); |
---|
| 4551 | + return -EINVAL; |
---|
| 4552 | + } |
---|
| 4553 | + ops = br_dev->netdev_ops; |
---|
| 4554 | + } else { |
---|
| 4555 | + if (!(ndm_flags & NTF_SELF)) { |
---|
| 4556 | + NL_SET_ERR_MSG(extack, "Missing NTF_SELF"); |
---|
| 4557 | + return -EINVAL; |
---|
| 4558 | + } |
---|
| 4559 | + ops = dev->netdev_ops; |
---|
| 4560 | + } |
---|
| 4561 | + } |
---|
| 4562 | + |
---|
| 4563 | + if (!br_dev && !dev) { |
---|
| 4564 | + NL_SET_ERR_MSG(extack, "No device specified"); |
---|
| 4565 | + return -ENODEV; |
---|
| 4566 | + } |
---|
| 4567 | + |
---|
| 4568 | + if (!ops || !ops->ndo_fdb_get) { |
---|
| 4569 | + NL_SET_ERR_MSG(extack, "Fdb get operation not supported by device"); |
---|
| 4570 | + return -EOPNOTSUPP; |
---|
| 4571 | + } |
---|
| 4572 | + |
---|
| 4573 | + skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
---|
| 4574 | + if (!skb) |
---|
| 4575 | + return -ENOBUFS; |
---|
| 4576 | + |
---|
| 4577 | + if (br_dev) |
---|
| 4578 | + dev = br_dev; |
---|
| 4579 | + err = ops->ndo_fdb_get(skb, tb, dev, addr, vid, |
---|
| 4580 | + NETLINK_CB(in_skb).portid, |
---|
| 4581 | + nlh->nlmsg_seq, extack); |
---|
| 4582 | + if (err) |
---|
| 4583 | + goto out; |
---|
| 4584 | + |
---|
| 4585 | + return rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); |
---|
| 4586 | +out: |
---|
| 4587 | + kfree_skb(skb); |
---|
| 4588 | + return err; |
---|
3903 | 4589 | } |
---|
3904 | 4590 | |
---|
3905 | 4591 | static int brport_nla_put_flag(struct sk_buff *skb, u32 flags, u32 mask, |
---|
.. | .. |
---|
3950 | 4636 | nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev)))) |
---|
3951 | 4637 | goto nla_put_failure; |
---|
3952 | 4638 | |
---|
3953 | | - br_afspec = nla_nest_start(skb, IFLA_AF_SPEC); |
---|
| 4639 | + br_afspec = nla_nest_start_noflag(skb, IFLA_AF_SPEC); |
---|
3954 | 4640 | if (!br_afspec) |
---|
3955 | 4641 | goto nla_put_failure; |
---|
3956 | 4642 | |
---|
.. | .. |
---|
3974 | 4660 | } |
---|
3975 | 4661 | nla_nest_end(skb, br_afspec); |
---|
3976 | 4662 | |
---|
3977 | | - protinfo = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); |
---|
| 4663 | + protinfo = nla_nest_start(skb, IFLA_PROTINFO); |
---|
3978 | 4664 | if (!protinfo) |
---|
3979 | 4665 | goto nla_put_failure; |
---|
3980 | 4666 | |
---|
.. | .. |
---|
3994 | 4680 | brport_nla_put_flag(skb, flags, mask, |
---|
3995 | 4681 | IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD) || |
---|
3996 | 4682 | brport_nla_put_flag(skb, flags, mask, |
---|
3997 | | - IFLA_BRPORT_PROXYARP, BR_PROXYARP)) { |
---|
| 4683 | + IFLA_BRPORT_PROXYARP, BR_PROXYARP) || |
---|
| 4684 | + brport_nla_put_flag(skb, flags, mask, |
---|
| 4685 | + IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD) || |
---|
| 4686 | + brport_nla_put_flag(skb, flags, mask, |
---|
| 4687 | + IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD)) { |
---|
3998 | 4688 | nla_nest_cancel(skb, protinfo); |
---|
3999 | 4689 | goto nla_put_failure; |
---|
4000 | 4690 | } |
---|
.. | .. |
---|
4009 | 4699 | } |
---|
4010 | 4700 | EXPORT_SYMBOL_GPL(ndo_dflt_bridge_getlink); |
---|
4011 | 4701 | |
---|
| 4702 | +static int valid_bridge_getlink_req(const struct nlmsghdr *nlh, |
---|
| 4703 | + bool strict_check, u32 *filter_mask, |
---|
| 4704 | + struct netlink_ext_ack *extack) |
---|
| 4705 | +{ |
---|
| 4706 | + struct nlattr *tb[IFLA_MAX+1]; |
---|
| 4707 | + int err, i; |
---|
| 4708 | + |
---|
| 4709 | + if (strict_check) { |
---|
| 4710 | + struct ifinfomsg *ifm; |
---|
| 4711 | + |
---|
| 4712 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
---|
| 4713 | + NL_SET_ERR_MSG(extack, "Invalid header for bridge link dump"); |
---|
| 4714 | + return -EINVAL; |
---|
| 4715 | + } |
---|
| 4716 | + |
---|
| 4717 | + ifm = nlmsg_data(nlh); |
---|
| 4718 | + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || |
---|
| 4719 | + ifm->ifi_change || ifm->ifi_index) { |
---|
| 4720 | + NL_SET_ERR_MSG(extack, "Invalid values in header for bridge link dump request"); |
---|
| 4721 | + return -EINVAL; |
---|
| 4722 | + } |
---|
| 4723 | + |
---|
| 4724 | + err = nlmsg_parse_deprecated_strict(nlh, |
---|
| 4725 | + sizeof(struct ifinfomsg), |
---|
| 4726 | + tb, IFLA_MAX, ifla_policy, |
---|
| 4727 | + extack); |
---|
| 4728 | + } else { |
---|
| 4729 | + err = nlmsg_parse_deprecated(nlh, sizeof(struct ifinfomsg), |
---|
| 4730 | + tb, IFLA_MAX, ifla_policy, |
---|
| 4731 | + extack); |
---|
| 4732 | + } |
---|
| 4733 | + if (err < 0) |
---|
| 4734 | + return err; |
---|
| 4735 | + |
---|
| 4736 | + /* new attributes should only be added with strict checking */ |
---|
| 4737 | + for (i = 0; i <= IFLA_MAX; ++i) { |
---|
| 4738 | + if (!tb[i]) |
---|
| 4739 | + continue; |
---|
| 4740 | + |
---|
| 4741 | + switch (i) { |
---|
| 4742 | + case IFLA_EXT_MASK: |
---|
| 4743 | + *filter_mask = nla_get_u32(tb[i]); |
---|
| 4744 | + break; |
---|
| 4745 | + default: |
---|
| 4746 | + if (strict_check) { |
---|
| 4747 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in bridge link dump request"); |
---|
| 4748 | + return -EINVAL; |
---|
| 4749 | + } |
---|
| 4750 | + } |
---|
| 4751 | + } |
---|
| 4752 | + |
---|
| 4753 | + return 0; |
---|
| 4754 | +} |
---|
| 4755 | + |
---|
4012 | 4756 | static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb) |
---|
4013 | 4757 | { |
---|
| 4758 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
4014 | 4759 | struct net *net = sock_net(skb->sk); |
---|
4015 | 4760 | struct net_device *dev; |
---|
4016 | 4761 | int idx = 0; |
---|
4017 | 4762 | u32 portid = NETLINK_CB(cb->skb).portid; |
---|
4018 | | - u32 seq = cb->nlh->nlmsg_seq; |
---|
| 4763 | + u32 seq = nlh->nlmsg_seq; |
---|
4019 | 4764 | u32 filter_mask = 0; |
---|
4020 | 4765 | int err; |
---|
4021 | 4766 | |
---|
4022 | | - if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) { |
---|
4023 | | - struct nlattr *extfilt; |
---|
4024 | | - |
---|
4025 | | - extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct ifinfomsg), |
---|
4026 | | - IFLA_EXT_MASK); |
---|
4027 | | - if (extfilt) { |
---|
4028 | | - if (nla_len(extfilt) < sizeof(filter_mask)) |
---|
4029 | | - return -EINVAL; |
---|
4030 | | - |
---|
4031 | | - filter_mask = nla_get_u32(extfilt); |
---|
4032 | | - } |
---|
4033 | | - } |
---|
| 4767 | + err = valid_bridge_getlink_req(nlh, cb->strict_check, &filter_mask, |
---|
| 4768 | + cb->extack); |
---|
| 4769 | + if (err < 0 && cb->strict_check) |
---|
| 4770 | + return err; |
---|
4034 | 4771 | |
---|
4035 | 4772 | rcu_read_lock(); |
---|
4036 | 4773 | for_each_netdev_rcu(net, dev) { |
---|
.. | .. |
---|
4173 | 4910 | goto out; |
---|
4174 | 4911 | } |
---|
4175 | 4912 | |
---|
4176 | | - err = br_dev->netdev_ops->ndo_bridge_setlink(dev, nlh, flags); |
---|
| 4913 | + err = br_dev->netdev_ops->ndo_bridge_setlink(dev, nlh, flags, |
---|
| 4914 | + extack); |
---|
4177 | 4915 | if (err) |
---|
4178 | 4916 | goto out; |
---|
4179 | 4917 | |
---|
.. | .. |
---|
4185 | 4923 | err = -EOPNOTSUPP; |
---|
4186 | 4924 | else |
---|
4187 | 4925 | err = dev->netdev_ops->ndo_bridge_setlink(dev, nlh, |
---|
4188 | | - flags); |
---|
| 4926 | + flags, |
---|
| 4927 | + extack); |
---|
4189 | 4928 | if (!err) { |
---|
4190 | 4929 | flags &= ~BRIDGE_FLAGS_SELF; |
---|
4191 | 4930 | |
---|
.. | .. |
---|
4411 | 5150 | |
---|
4412 | 5151 | if (ops && ops->fill_linkxstats) { |
---|
4413 | 5152 | *idxattr = IFLA_STATS_LINK_XSTATS; |
---|
4414 | | - attr = nla_nest_start(skb, |
---|
4415 | | - IFLA_STATS_LINK_XSTATS); |
---|
| 5153 | + attr = nla_nest_start_noflag(skb, |
---|
| 5154 | + IFLA_STATS_LINK_XSTATS); |
---|
4416 | 5155 | if (!attr) |
---|
4417 | 5156 | goto nla_put_failure; |
---|
4418 | 5157 | |
---|
.. | .. |
---|
4434 | 5173 | ops = master->rtnl_link_ops; |
---|
4435 | 5174 | if (ops && ops->fill_linkxstats) { |
---|
4436 | 5175 | *idxattr = IFLA_STATS_LINK_XSTATS_SLAVE; |
---|
4437 | | - attr = nla_nest_start(skb, |
---|
4438 | | - IFLA_STATS_LINK_XSTATS_SLAVE); |
---|
| 5176 | + attr = nla_nest_start_noflag(skb, |
---|
| 5177 | + IFLA_STATS_LINK_XSTATS_SLAVE); |
---|
4439 | 5178 | if (!attr) |
---|
4440 | 5179 | goto nla_put_failure; |
---|
4441 | 5180 | |
---|
.. | .. |
---|
4450 | 5189 | if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_OFFLOAD_XSTATS, |
---|
4451 | 5190 | *idxattr)) { |
---|
4452 | 5191 | *idxattr = IFLA_STATS_LINK_OFFLOAD_XSTATS; |
---|
4453 | | - attr = nla_nest_start(skb, IFLA_STATS_LINK_OFFLOAD_XSTATS); |
---|
| 5192 | + attr = nla_nest_start_noflag(skb, |
---|
| 5193 | + IFLA_STATS_LINK_OFFLOAD_XSTATS); |
---|
4454 | 5194 | if (!attr) |
---|
4455 | 5195 | goto nla_put_failure; |
---|
4456 | 5196 | |
---|
.. | .. |
---|
4469 | 5209 | struct rtnl_af_ops *af_ops; |
---|
4470 | 5210 | |
---|
4471 | 5211 | *idxattr = IFLA_STATS_AF_SPEC; |
---|
4472 | | - attr = nla_nest_start(skb, IFLA_STATS_AF_SPEC); |
---|
| 5212 | + attr = nla_nest_start_noflag(skb, IFLA_STATS_AF_SPEC); |
---|
4473 | 5213 | if (!attr) |
---|
4474 | 5214 | goto nla_put_failure; |
---|
4475 | 5215 | |
---|
.. | .. |
---|
4479 | 5219 | struct nlattr *af; |
---|
4480 | 5220 | int err; |
---|
4481 | 5221 | |
---|
4482 | | - af = nla_nest_start(skb, af_ops->family); |
---|
| 5222 | + af = nla_nest_start_noflag(skb, |
---|
| 5223 | + af_ops->family); |
---|
4483 | 5224 | if (!af) { |
---|
4484 | 5225 | rcu_read_unlock(); |
---|
4485 | 5226 | goto nla_put_failure; |
---|
.. | .. |
---|
4581 | 5322 | return size; |
---|
4582 | 5323 | } |
---|
4583 | 5324 | |
---|
| 5325 | +static int rtnl_valid_stats_req(const struct nlmsghdr *nlh, bool strict_check, |
---|
| 5326 | + bool is_dump, struct netlink_ext_ack *extack) |
---|
| 5327 | +{ |
---|
| 5328 | + struct if_stats_msg *ifsm; |
---|
| 5329 | + |
---|
| 5330 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifsm))) { |
---|
| 5331 | + NL_SET_ERR_MSG(extack, "Invalid header for stats dump"); |
---|
| 5332 | + return -EINVAL; |
---|
| 5333 | + } |
---|
| 5334 | + |
---|
| 5335 | + if (!strict_check) |
---|
| 5336 | + return 0; |
---|
| 5337 | + |
---|
| 5338 | + ifsm = nlmsg_data(nlh); |
---|
| 5339 | + |
---|
| 5340 | + /* only requests using strict checks can pass data to influence |
---|
| 5341 | + * the dump. The legacy exception is filter_mask. |
---|
| 5342 | + */ |
---|
| 5343 | + if (ifsm->pad1 || ifsm->pad2 || (is_dump && ifsm->ifindex)) { |
---|
| 5344 | + NL_SET_ERR_MSG(extack, "Invalid values in header for stats dump request"); |
---|
| 5345 | + return -EINVAL; |
---|
| 5346 | + } |
---|
| 5347 | + if (nlmsg_attrlen(nlh, sizeof(*ifsm))) { |
---|
| 5348 | + NL_SET_ERR_MSG(extack, "Invalid attributes after stats header"); |
---|
| 5349 | + return -EINVAL; |
---|
| 5350 | + } |
---|
| 5351 | + if (ifsm->filter_mask >= IFLA_STATS_FILTER_BIT(IFLA_STATS_MAX + 1)) { |
---|
| 5352 | + NL_SET_ERR_MSG(extack, "Invalid stats requested through filter mask"); |
---|
| 5353 | + return -EINVAL; |
---|
| 5354 | + } |
---|
| 5355 | + |
---|
| 5356 | + return 0; |
---|
| 5357 | +} |
---|
| 5358 | + |
---|
4584 | 5359 | static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
4585 | 5360 | struct netlink_ext_ack *extack) |
---|
4586 | 5361 | { |
---|
.. | .. |
---|
4592 | 5367 | u32 filter_mask; |
---|
4593 | 5368 | int err; |
---|
4594 | 5369 | |
---|
4595 | | - if (nlmsg_len(nlh) < sizeof(*ifsm)) |
---|
4596 | | - return -EINVAL; |
---|
| 5370 | + err = rtnl_valid_stats_req(nlh, netlink_strict_get_check(skb), |
---|
| 5371 | + false, extack); |
---|
| 5372 | + if (err) |
---|
| 5373 | + return err; |
---|
4597 | 5374 | |
---|
4598 | 5375 | ifsm = nlmsg_data(nlh); |
---|
4599 | 5376 | if (ifsm->ifindex > 0) |
---|
.. | .. |
---|
4628 | 5405 | |
---|
4629 | 5406 | static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb) |
---|
4630 | 5407 | { |
---|
| 5408 | + struct netlink_ext_ack *extack = cb->extack; |
---|
4631 | 5409 | int h, s_h, err, s_idx, s_idxattr, s_prividx; |
---|
4632 | 5410 | struct net *net = sock_net(skb->sk); |
---|
4633 | 5411 | unsigned int flags = NLM_F_MULTI; |
---|
.. | .. |
---|
4644 | 5422 | |
---|
4645 | 5423 | cb->seq = net->dev_base_seq; |
---|
4646 | 5424 | |
---|
4647 | | - if (nlmsg_len(cb->nlh) < sizeof(*ifsm)) |
---|
4648 | | - return -EINVAL; |
---|
| 5425 | + err = rtnl_valid_stats_req(cb->nlh, cb->strict_check, true, extack); |
---|
| 5426 | + if (err) |
---|
| 5427 | + return err; |
---|
4649 | 5428 | |
---|
4650 | 5429 | ifsm = nlmsg_data(cb->nlh); |
---|
4651 | 5430 | filter_mask = ifsm->filter_mask; |
---|
4652 | | - if (!filter_mask) |
---|
| 5431 | + if (!filter_mask) { |
---|
| 5432 | + NL_SET_ERR_MSG(extack, "Filter mask must be set for stats dump"); |
---|
4653 | 5433 | return -EINVAL; |
---|
| 5434 | + } |
---|
4654 | 5435 | |
---|
4655 | 5436 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
---|
4656 | 5437 | idx = 0; |
---|
.. | .. |
---|
4721 | 5502 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { |
---|
4722 | 5503 | struct sock *rtnl; |
---|
4723 | 5504 | rtnl_dumpit_func dumpit; |
---|
4724 | | - u16 min_dump_alloc = 0; |
---|
| 5505 | + u32 min_dump_alloc = 0; |
---|
4725 | 5506 | |
---|
4726 | 5507 | link = rtnl_get_link(family, type); |
---|
4727 | 5508 | if (!link || !link->dumpit) { |
---|
.. | .. |
---|
4898 | 5679 | rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, 0); |
---|
4899 | 5680 | rtnl_register(PF_UNSPEC, RTM_GETNETCONF, NULL, rtnl_dump_all, 0); |
---|
4900 | 5681 | |
---|
| 5682 | + rtnl_register(PF_UNSPEC, RTM_NEWLINKPROP, rtnl_newlinkprop, NULL, 0); |
---|
| 5683 | + rtnl_register(PF_UNSPEC, RTM_DELLINKPROP, rtnl_dellinkprop, NULL, 0); |
---|
| 5684 | + |
---|
4901 | 5685 | rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, rtnl_fdb_add, NULL, 0); |
---|
4902 | 5686 | rtnl_register(PF_BRIDGE, RTM_DELNEIGH, rtnl_fdb_del, NULL, 0); |
---|
4903 | | - rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, 0); |
---|
| 5687 | + rtnl_register(PF_BRIDGE, RTM_GETNEIGH, rtnl_fdb_get, rtnl_fdb_dump, 0); |
---|
4904 | 5688 | |
---|
4905 | 5689 | rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, 0); |
---|
4906 | 5690 | rtnl_register(PF_BRIDGE, RTM_DELLINK, rtnl_bridge_dellink, NULL, 0); |
---|