.. | .. |
---|
| 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 * |
---|
.. | .. |
---|
922 | 929 | nla_total_size(sizeof(struct ifla_vf_rate)) + |
---|
923 | 930 | nla_total_size(sizeof(struct ifla_vf_link_state)) + |
---|
924 | 931 | nla_total_size(sizeof(struct ifla_vf_rss_query_en)) + |
---|
925 | | - nla_total_size(0) + /* nest IFLA_VF_STATS */ |
---|
926 | | - /* IFLA_VF_STATS_RX_PACKETS */ |
---|
927 | | - nla_total_size_64bit(sizeof(__u64)) + |
---|
928 | | - /* IFLA_VF_STATS_TX_PACKETS */ |
---|
929 | | - nla_total_size_64bit(sizeof(__u64)) + |
---|
930 | | - /* IFLA_VF_STATS_RX_BYTES */ |
---|
931 | | - nla_total_size_64bit(sizeof(__u64)) + |
---|
932 | | - /* IFLA_VF_STATS_TX_BYTES */ |
---|
933 | | - nla_total_size_64bit(sizeof(__u64)) + |
---|
934 | | - /* IFLA_VF_STATS_BROADCAST */ |
---|
935 | | - nla_total_size_64bit(sizeof(__u64)) + |
---|
936 | | - /* IFLA_VF_STATS_MULTICAST */ |
---|
937 | | - nla_total_size_64bit(sizeof(__u64)) + |
---|
938 | | - /* IFLA_VF_STATS_RX_DROPPED */ |
---|
939 | | - nla_total_size_64bit(sizeof(__u64)) + |
---|
940 | | - /* IFLA_VF_STATS_TX_DROPPED */ |
---|
941 | | - nla_total_size_64bit(sizeof(__u64)) + |
---|
942 | 932 | nla_total_size(sizeof(struct ifla_vf_trust))); |
---|
| 933 | + if (~ext_filter_mask & RTEXT_FILTER_SKIP_STATS) { |
---|
| 934 | + size += num_vfs * |
---|
| 935 | + (nla_total_size(0) + /* nest IFLA_VF_STATS */ |
---|
| 936 | + /* IFLA_VF_STATS_RX_PACKETS */ |
---|
| 937 | + nla_total_size_64bit(sizeof(__u64)) + |
---|
| 938 | + /* IFLA_VF_STATS_TX_PACKETS */ |
---|
| 939 | + nla_total_size_64bit(sizeof(__u64)) + |
---|
| 940 | + /* IFLA_VF_STATS_RX_BYTES */ |
---|
| 941 | + nla_total_size_64bit(sizeof(__u64)) + |
---|
| 942 | + /* IFLA_VF_STATS_TX_BYTES */ |
---|
| 943 | + nla_total_size_64bit(sizeof(__u64)) + |
---|
| 944 | + /* IFLA_VF_STATS_BROADCAST */ |
---|
| 945 | + nla_total_size_64bit(sizeof(__u64)) + |
---|
| 946 | + /* IFLA_VF_STATS_MULTICAST */ |
---|
| 947 | + nla_total_size_64bit(sizeof(__u64)) + |
---|
| 948 | + /* IFLA_VF_STATS_RX_DROPPED */ |
---|
| 949 | + nla_total_size_64bit(sizeof(__u64)) + |
---|
| 950 | + /* IFLA_VF_STATS_TX_DROPPED */ |
---|
| 951 | + nla_total_size_64bit(sizeof(__u64))); |
---|
| 952 | + } |
---|
943 | 953 | return size; |
---|
944 | 954 | } else |
---|
945 | 955 | return 0; |
---|
.. | .. |
---|
978 | 988 | nla_total_size(4); /* XDP_<mode>_PROG_ID */ |
---|
979 | 989 | |
---|
980 | 990 | return xdp_size; |
---|
| 991 | +} |
---|
| 992 | + |
---|
| 993 | +static size_t rtnl_prop_list_size(const struct net_device *dev) |
---|
| 994 | +{ |
---|
| 995 | + struct netdev_name_node *name_node; |
---|
| 996 | + size_t size; |
---|
| 997 | + |
---|
| 998 | + if (list_empty(&dev->name_node->list)) |
---|
| 999 | + return 0; |
---|
| 1000 | + size = nla_total_size(0); |
---|
| 1001 | + list_for_each_entry(name_node, &dev->name_node->list, list) |
---|
| 1002 | + size += nla_total_size(ALTIFNAMSIZ); |
---|
| 1003 | + return size; |
---|
| 1004 | +} |
---|
| 1005 | + |
---|
| 1006 | +static size_t rtnl_proto_down_size(const struct net_device *dev) |
---|
| 1007 | +{ |
---|
| 1008 | + size_t size = nla_total_size(1); |
---|
| 1009 | + |
---|
| 1010 | + if (dev->proto_down_reason) |
---|
| 1011 | + size += nla_total_size(0) + nla_total_size(4); |
---|
| 1012 | + |
---|
| 1013 | + return size; |
---|
981 | 1014 | } |
---|
982 | 1015 | |
---|
983 | 1016 | static noinline size_t if_nlmsg_size(const struct net_device *dev, |
---|
.. | .. |
---|
1021 | 1054 | + nla_total_size(4) /* IFLA_EVENT */ |
---|
1022 | 1055 | + nla_total_size(4) /* IFLA_NEW_NETNSID */ |
---|
1023 | 1056 | + nla_total_size(4) /* IFLA_NEW_IFINDEX */ |
---|
1024 | | - + nla_total_size(1) /* IFLA_PROTO_DOWN */ |
---|
1025 | | - + nla_total_size(4) /* IFLA_IF_NETNSID */ |
---|
| 1057 | + + rtnl_proto_down_size(dev) /* proto down */ |
---|
| 1058 | + + nla_total_size(4) /* IFLA_TARGET_NETNSID */ |
---|
1026 | 1059 | + nla_total_size(4) /* IFLA_CARRIER_UP_COUNT */ |
---|
1027 | 1060 | + nla_total_size(4) /* IFLA_CARRIER_DOWN_COUNT */ |
---|
1028 | 1061 | + nla_total_size(4) /* IFLA_MIN_MTU */ |
---|
1029 | 1062 | + nla_total_size(4) /* IFLA_MAX_MTU */ |
---|
| 1063 | + + rtnl_prop_list_size(dev) |
---|
| 1064 | + + nla_total_size(MAX_ADDR_LEN) /* IFLA_PERM_ADDRESS */ |
---|
1030 | 1065 | + 0; |
---|
1031 | 1066 | } |
---|
1032 | 1067 | |
---|
.. | .. |
---|
1037 | 1072 | int vf; |
---|
1038 | 1073 | int err; |
---|
1039 | 1074 | |
---|
1040 | | - vf_ports = nla_nest_start(skb, IFLA_VF_PORTS); |
---|
| 1075 | + vf_ports = nla_nest_start_noflag(skb, IFLA_VF_PORTS); |
---|
1041 | 1076 | if (!vf_ports) |
---|
1042 | 1077 | return -EMSGSIZE; |
---|
1043 | 1078 | |
---|
1044 | 1079 | for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++) { |
---|
1045 | | - vf_port = nla_nest_start(skb, IFLA_VF_PORT); |
---|
| 1080 | + vf_port = nla_nest_start_noflag(skb, IFLA_VF_PORT); |
---|
1046 | 1081 | if (!vf_port) |
---|
1047 | 1082 | goto nla_put_failure; |
---|
1048 | 1083 | if (nla_put_u32(skb, IFLA_PORT_VF, vf)) |
---|
.. | .. |
---|
1071 | 1106 | struct nlattr *port_self; |
---|
1072 | 1107 | int err; |
---|
1073 | 1108 | |
---|
1074 | | - port_self = nla_nest_start(skb, IFLA_PORT_SELF); |
---|
| 1109 | + port_self = nla_nest_start_noflag(skb, IFLA_PORT_SELF); |
---|
1075 | 1110 | if (!port_self) |
---|
1076 | 1111 | return -EMSGSIZE; |
---|
1077 | 1112 | |
---|
.. | .. |
---|
1146 | 1181 | |
---|
1147 | 1182 | static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev) |
---|
1148 | 1183 | { |
---|
| 1184 | + struct netdev_phys_item_id ppid = { }; |
---|
1149 | 1185 | 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 | 1186 | |
---|
1156 | | - err = switchdev_port_attr_get(dev, &attr); |
---|
| 1187 | + err = dev_get_port_parent_id(dev, &ppid, false); |
---|
1157 | 1188 | if (err) { |
---|
1158 | 1189 | if (err == -EOPNOTSUPP) |
---|
1159 | 1190 | return 0; |
---|
1160 | 1191 | return err; |
---|
1161 | 1192 | } |
---|
1162 | 1193 | |
---|
1163 | | - if (nla_put(skb, IFLA_PHYS_SWITCH_ID, attr.u.ppid.id_len, |
---|
1164 | | - attr.u.ppid.id)) |
---|
| 1194 | + if (nla_put(skb, IFLA_PHYS_SWITCH_ID, ppid.id_len, ppid.id)) |
---|
1165 | 1195 | return -EMSGSIZE; |
---|
1166 | 1196 | |
---|
1167 | 1197 | return 0; |
---|
.. | .. |
---|
1194 | 1224 | static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb, |
---|
1195 | 1225 | struct net_device *dev, |
---|
1196 | 1226 | int vfs_num, |
---|
1197 | | - struct nlattr *vfinfo) |
---|
| 1227 | + struct nlattr *vfinfo, |
---|
| 1228 | + u32 ext_filter_mask) |
---|
1198 | 1229 | { |
---|
1199 | 1230 | struct ifla_vf_rss_query_en vf_rss_query_en; |
---|
1200 | 1231 | struct nlattr *vf, *vfstats, *vfvlanlist; |
---|
.. | .. |
---|
1207 | 1238 | struct ifla_vf_vlan vf_vlan; |
---|
1208 | 1239 | struct ifla_vf_rate vf_rate; |
---|
1209 | 1240 | struct ifla_vf_mac vf_mac; |
---|
| 1241 | + struct ifla_vf_broadcast vf_broadcast; |
---|
1210 | 1242 | struct ifla_vf_info ivi; |
---|
| 1243 | + struct ifla_vf_guid node_guid; |
---|
| 1244 | + struct ifla_vf_guid port_guid; |
---|
1211 | 1245 | |
---|
1212 | 1246 | memset(&ivi, 0, sizeof(ivi)); |
---|
1213 | 1247 | |
---|
.. | .. |
---|
1229 | 1263 | return 0; |
---|
1230 | 1264 | |
---|
1231 | 1265 | memset(&vf_vlan_info, 0, sizeof(vf_vlan_info)); |
---|
| 1266 | + memset(&node_guid, 0, sizeof(node_guid)); |
---|
| 1267 | + memset(&port_guid, 0, sizeof(port_guid)); |
---|
1232 | 1268 | |
---|
1233 | 1269 | vf_mac.vf = |
---|
1234 | 1270 | vf_vlan.vf = |
---|
.. | .. |
---|
1238 | 1274 | vf_spoofchk.vf = |
---|
1239 | 1275 | vf_linkstate.vf = |
---|
1240 | 1276 | vf_rss_query_en.vf = |
---|
1241 | | - vf_trust.vf = ivi.vf; |
---|
| 1277 | + vf_trust.vf = |
---|
| 1278 | + node_guid.vf = |
---|
| 1279 | + port_guid.vf = ivi.vf; |
---|
1242 | 1280 | |
---|
1243 | 1281 | memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac)); |
---|
| 1282 | + memcpy(vf_broadcast.broadcast, dev->broadcast, dev->addr_len); |
---|
1244 | 1283 | vf_vlan.vlan = ivi.vlan; |
---|
1245 | 1284 | vf_vlan.qos = ivi.qos; |
---|
1246 | 1285 | vf_vlan_info.vlan = ivi.vlan; |
---|
.. | .. |
---|
1253 | 1292 | vf_linkstate.link_state = ivi.linkstate; |
---|
1254 | 1293 | vf_rss_query_en.setting = ivi.rss_query_en; |
---|
1255 | 1294 | vf_trust.setting = ivi.trusted; |
---|
1256 | | - vf = nla_nest_start(skb, IFLA_VF_INFO); |
---|
| 1295 | + vf = nla_nest_start_noflag(skb, IFLA_VF_INFO); |
---|
1257 | 1296 | if (!vf) |
---|
1258 | 1297 | goto nla_put_vfinfo_failure; |
---|
1259 | 1298 | if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) || |
---|
| 1299 | + nla_put(skb, IFLA_VF_BROADCAST, sizeof(vf_broadcast), &vf_broadcast) || |
---|
1260 | 1300 | nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) || |
---|
1261 | 1301 | nla_put(skb, IFLA_VF_RATE, sizeof(vf_rate), |
---|
1262 | 1302 | &vf_rate) || |
---|
.. | .. |
---|
1272 | 1312 | nla_put(skb, IFLA_VF_TRUST, |
---|
1273 | 1313 | sizeof(vf_trust), &vf_trust)) |
---|
1274 | 1314 | goto nla_put_vf_failure; |
---|
1275 | | - vfvlanlist = nla_nest_start(skb, IFLA_VF_VLAN_LIST); |
---|
| 1315 | + |
---|
| 1316 | + if (dev->netdev_ops->ndo_get_vf_guid && |
---|
| 1317 | + !dev->netdev_ops->ndo_get_vf_guid(dev, vfs_num, &node_guid, |
---|
| 1318 | + &port_guid)) { |
---|
| 1319 | + if (nla_put(skb, IFLA_VF_IB_NODE_GUID, sizeof(node_guid), |
---|
| 1320 | + &node_guid) || |
---|
| 1321 | + nla_put(skb, IFLA_VF_IB_PORT_GUID, sizeof(port_guid), |
---|
| 1322 | + &port_guid)) |
---|
| 1323 | + goto nla_put_vf_failure; |
---|
| 1324 | + } |
---|
| 1325 | + vfvlanlist = nla_nest_start_noflag(skb, IFLA_VF_VLAN_LIST); |
---|
1276 | 1326 | if (!vfvlanlist) |
---|
1277 | 1327 | goto nla_put_vf_failure; |
---|
1278 | 1328 | if (nla_put(skb, IFLA_VF_VLAN_INFO, sizeof(vf_vlan_info), |
---|
.. | .. |
---|
1281 | 1331 | goto nla_put_vf_failure; |
---|
1282 | 1332 | } |
---|
1283 | 1333 | nla_nest_end(skb, vfvlanlist); |
---|
1284 | | - memset(&vf_stats, 0, sizeof(vf_stats)); |
---|
1285 | | - if (dev->netdev_ops->ndo_get_vf_stats) |
---|
1286 | | - dev->netdev_ops->ndo_get_vf_stats(dev, vfs_num, |
---|
1287 | | - &vf_stats); |
---|
1288 | | - vfstats = nla_nest_start(skb, IFLA_VF_STATS); |
---|
1289 | | - if (!vfstats) |
---|
1290 | | - goto nla_put_vf_failure; |
---|
1291 | | - if (nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_PACKETS, |
---|
1292 | | - vf_stats.rx_packets, IFLA_VF_STATS_PAD) || |
---|
1293 | | - nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_PACKETS, |
---|
1294 | | - vf_stats.tx_packets, IFLA_VF_STATS_PAD) || |
---|
1295 | | - nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_BYTES, |
---|
1296 | | - vf_stats.rx_bytes, IFLA_VF_STATS_PAD) || |
---|
1297 | | - nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_BYTES, |
---|
1298 | | - vf_stats.tx_bytes, IFLA_VF_STATS_PAD) || |
---|
1299 | | - nla_put_u64_64bit(skb, IFLA_VF_STATS_BROADCAST, |
---|
1300 | | - vf_stats.broadcast, IFLA_VF_STATS_PAD) || |
---|
1301 | | - nla_put_u64_64bit(skb, IFLA_VF_STATS_MULTICAST, |
---|
1302 | | - vf_stats.multicast, IFLA_VF_STATS_PAD) || |
---|
1303 | | - nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_DROPPED, |
---|
1304 | | - vf_stats.rx_dropped, IFLA_VF_STATS_PAD) || |
---|
1305 | | - nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_DROPPED, |
---|
1306 | | - vf_stats.tx_dropped, IFLA_VF_STATS_PAD)) { |
---|
1307 | | - nla_nest_cancel(skb, vfstats); |
---|
1308 | | - goto nla_put_vf_failure; |
---|
| 1334 | + if (~ext_filter_mask & RTEXT_FILTER_SKIP_STATS) { |
---|
| 1335 | + memset(&vf_stats, 0, sizeof(vf_stats)); |
---|
| 1336 | + if (dev->netdev_ops->ndo_get_vf_stats) |
---|
| 1337 | + dev->netdev_ops->ndo_get_vf_stats(dev, vfs_num, |
---|
| 1338 | + &vf_stats); |
---|
| 1339 | + vfstats = nla_nest_start_noflag(skb, IFLA_VF_STATS); |
---|
| 1340 | + if (!vfstats) |
---|
| 1341 | + goto nla_put_vf_failure; |
---|
| 1342 | + if (nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_PACKETS, |
---|
| 1343 | + vf_stats.rx_packets, IFLA_VF_STATS_PAD) || |
---|
| 1344 | + nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_PACKETS, |
---|
| 1345 | + vf_stats.tx_packets, IFLA_VF_STATS_PAD) || |
---|
| 1346 | + nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_BYTES, |
---|
| 1347 | + vf_stats.rx_bytes, IFLA_VF_STATS_PAD) || |
---|
| 1348 | + nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_BYTES, |
---|
| 1349 | + vf_stats.tx_bytes, IFLA_VF_STATS_PAD) || |
---|
| 1350 | + nla_put_u64_64bit(skb, IFLA_VF_STATS_BROADCAST, |
---|
| 1351 | + vf_stats.broadcast, IFLA_VF_STATS_PAD) || |
---|
| 1352 | + nla_put_u64_64bit(skb, IFLA_VF_STATS_MULTICAST, |
---|
| 1353 | + vf_stats.multicast, IFLA_VF_STATS_PAD) || |
---|
| 1354 | + nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_DROPPED, |
---|
| 1355 | + vf_stats.rx_dropped, IFLA_VF_STATS_PAD) || |
---|
| 1356 | + nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_DROPPED, |
---|
| 1357 | + vf_stats.tx_dropped, IFLA_VF_STATS_PAD)) { |
---|
| 1358 | + nla_nest_cancel(skb, vfstats); |
---|
| 1359 | + goto nla_put_vf_failure; |
---|
| 1360 | + } |
---|
| 1361 | + nla_nest_end(skb, vfstats); |
---|
1309 | 1362 | } |
---|
1310 | | - nla_nest_end(skb, vfstats); |
---|
1311 | 1363 | nla_nest_end(skb, vf); |
---|
1312 | 1364 | return 0; |
---|
1313 | 1365 | |
---|
.. | .. |
---|
1335 | 1387 | if (!dev->netdev_ops->ndo_get_vf_config) |
---|
1336 | 1388 | return 0; |
---|
1337 | 1389 | |
---|
1338 | | - vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); |
---|
| 1390 | + vfinfo = nla_nest_start_noflag(skb, IFLA_VFINFO_LIST); |
---|
1339 | 1391 | if (!vfinfo) |
---|
1340 | 1392 | return -EMSGSIZE; |
---|
1341 | 1393 | |
---|
1342 | 1394 | for (i = 0; i < num_vfs; i++) { |
---|
1343 | | - if (rtnl_fill_vfinfo(skb, dev, i, vfinfo)) |
---|
| 1395 | + if (rtnl_fill_vfinfo(skb, dev, i, vfinfo, ext_filter_mask)) |
---|
1344 | 1396 | return -EMSGSIZE; |
---|
1345 | 1397 | } |
---|
1346 | 1398 | |
---|
.. | .. |
---|
1380 | 1432 | |
---|
1381 | 1433 | static u32 rtnl_xdp_prog_drv(struct net_device *dev) |
---|
1382 | 1434 | { |
---|
1383 | | - return __dev_xdp_query(dev, dev->netdev_ops->ndo_bpf, XDP_QUERY_PROG); |
---|
| 1435 | + return dev_xdp_prog_id(dev, XDP_MODE_DRV); |
---|
1384 | 1436 | } |
---|
1385 | 1437 | |
---|
1386 | 1438 | static u32 rtnl_xdp_prog_hw(struct net_device *dev) |
---|
1387 | 1439 | { |
---|
1388 | | - return __dev_xdp_query(dev, dev->netdev_ops->ndo_bpf, |
---|
1389 | | - XDP_QUERY_PROG_HW); |
---|
| 1440 | + return dev_xdp_prog_id(dev, XDP_MODE_HW); |
---|
1390 | 1441 | } |
---|
1391 | 1442 | |
---|
1392 | 1443 | static int rtnl_xdp_report_one(struct sk_buff *skb, struct net_device *dev, |
---|
.. | .. |
---|
1420 | 1471 | int err; |
---|
1421 | 1472 | u8 mode; |
---|
1422 | 1473 | |
---|
1423 | | - xdp = nla_nest_start(skb, IFLA_XDP); |
---|
| 1474 | + xdp = nla_nest_start_noflag(skb, IFLA_XDP); |
---|
1424 | 1475 | if (!xdp) |
---|
1425 | 1476 | return -EMSGSIZE; |
---|
1426 | 1477 | |
---|
.. | .. |
---|
1552 | 1603 | const struct rtnl_af_ops *af_ops; |
---|
1553 | 1604 | struct nlattr *af_spec; |
---|
1554 | 1605 | |
---|
1555 | | - af_spec = nla_nest_start(skb, IFLA_AF_SPEC); |
---|
| 1606 | + af_spec = nla_nest_start_noflag(skb, IFLA_AF_SPEC); |
---|
1556 | 1607 | if (!af_spec) |
---|
1557 | 1608 | return -EMSGSIZE; |
---|
1558 | 1609 | |
---|
.. | .. |
---|
1563 | 1614 | if (!af_ops->fill_link_af) |
---|
1564 | 1615 | continue; |
---|
1565 | 1616 | |
---|
1566 | | - af = nla_nest_start(skb, af_ops->family); |
---|
| 1617 | + af = nla_nest_start_noflag(skb, af_ops->family); |
---|
1567 | 1618 | if (!af) |
---|
1568 | 1619 | return -EMSGSIZE; |
---|
1569 | 1620 | |
---|
.. | .. |
---|
1586 | 1637 | return 0; |
---|
1587 | 1638 | } |
---|
1588 | 1639 | |
---|
| 1640 | +static int rtnl_fill_alt_ifnames(struct sk_buff *skb, |
---|
| 1641 | + const struct net_device *dev) |
---|
| 1642 | +{ |
---|
| 1643 | + struct netdev_name_node *name_node; |
---|
| 1644 | + int count = 0; |
---|
| 1645 | + |
---|
| 1646 | + list_for_each_entry(name_node, &dev->name_node->list, list) { |
---|
| 1647 | + if (nla_put_string(skb, IFLA_ALT_IFNAME, name_node->name)) |
---|
| 1648 | + return -EMSGSIZE; |
---|
| 1649 | + count++; |
---|
| 1650 | + } |
---|
| 1651 | + return count; |
---|
| 1652 | +} |
---|
| 1653 | + |
---|
| 1654 | +static int rtnl_fill_prop_list(struct sk_buff *skb, |
---|
| 1655 | + const struct net_device *dev) |
---|
| 1656 | +{ |
---|
| 1657 | + struct nlattr *prop_list; |
---|
| 1658 | + int ret; |
---|
| 1659 | + |
---|
| 1660 | + prop_list = nla_nest_start(skb, IFLA_PROP_LIST); |
---|
| 1661 | + if (!prop_list) |
---|
| 1662 | + return -EMSGSIZE; |
---|
| 1663 | + |
---|
| 1664 | + ret = rtnl_fill_alt_ifnames(skb, dev); |
---|
| 1665 | + if (ret <= 0) |
---|
| 1666 | + goto nest_cancel; |
---|
| 1667 | + |
---|
| 1668 | + nla_nest_end(skb, prop_list); |
---|
| 1669 | + return 0; |
---|
| 1670 | + |
---|
| 1671 | +nest_cancel: |
---|
| 1672 | + nla_nest_cancel(skb, prop_list); |
---|
| 1673 | + return ret; |
---|
| 1674 | +} |
---|
| 1675 | + |
---|
| 1676 | +static int rtnl_fill_proto_down(struct sk_buff *skb, |
---|
| 1677 | + const struct net_device *dev) |
---|
| 1678 | +{ |
---|
| 1679 | + struct nlattr *pr; |
---|
| 1680 | + u32 preason; |
---|
| 1681 | + |
---|
| 1682 | + if (nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down)) |
---|
| 1683 | + goto nla_put_failure; |
---|
| 1684 | + |
---|
| 1685 | + preason = dev->proto_down_reason; |
---|
| 1686 | + if (!preason) |
---|
| 1687 | + return 0; |
---|
| 1688 | + |
---|
| 1689 | + pr = nla_nest_start(skb, IFLA_PROTO_DOWN_REASON); |
---|
| 1690 | + if (!pr) |
---|
| 1691 | + return -EMSGSIZE; |
---|
| 1692 | + |
---|
| 1693 | + if (nla_put_u32(skb, IFLA_PROTO_DOWN_REASON_VALUE, preason)) { |
---|
| 1694 | + nla_nest_cancel(skb, pr); |
---|
| 1695 | + goto nla_put_failure; |
---|
| 1696 | + } |
---|
| 1697 | + |
---|
| 1698 | + nla_nest_end(skb, pr); |
---|
| 1699 | + return 0; |
---|
| 1700 | + |
---|
| 1701 | +nla_put_failure: |
---|
| 1702 | + return -EMSGSIZE; |
---|
| 1703 | +} |
---|
| 1704 | + |
---|
1589 | 1705 | static int rtnl_fill_ifinfo(struct sk_buff *skb, |
---|
1590 | 1706 | struct net_device *dev, struct net *src_net, |
---|
1591 | 1707 | int type, u32 pid, u32 seq, u32 change, |
---|
.. | .. |
---|
1595 | 1711 | { |
---|
1596 | 1712 | struct ifinfomsg *ifm; |
---|
1597 | 1713 | struct nlmsghdr *nlh; |
---|
| 1714 | + struct Qdisc *qdisc; |
---|
1598 | 1715 | |
---|
1599 | 1716 | ASSERT_RTNL(); |
---|
1600 | 1717 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); |
---|
.. | .. |
---|
1609 | 1726 | ifm->ifi_flags = dev_get_flags(dev); |
---|
1610 | 1727 | ifm->ifi_change = change; |
---|
1611 | 1728 | |
---|
1612 | | - if (tgt_netnsid >= 0 && nla_put_s32(skb, IFLA_IF_NETNSID, tgt_netnsid)) |
---|
| 1729 | + if (tgt_netnsid >= 0 && nla_put_s32(skb, IFLA_TARGET_NETNSID, tgt_netnsid)) |
---|
1613 | 1730 | goto nla_put_failure; |
---|
1614 | 1731 | |
---|
| 1732 | + qdisc = rtnl_dereference(dev->qdisc); |
---|
1615 | 1733 | if (nla_put_string(skb, IFLA_IFNAME, dev->name) || |
---|
1616 | 1734 | nla_put_u32(skb, IFLA_TXQLEN, dev->tx_queue_len) || |
---|
1617 | 1735 | nla_put_u8(skb, IFLA_OPERSTATE, |
---|
.. | .. |
---|
1630 | 1748 | #endif |
---|
1631 | 1749 | put_master_ifindex(skb, dev) || |
---|
1632 | 1750 | nla_put_u8(skb, IFLA_CARRIER, netif_carrier_ok(dev)) || |
---|
1633 | | - (dev->qdisc && |
---|
1634 | | - nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) || |
---|
| 1751 | + (qdisc && |
---|
| 1752 | + nla_put_string(skb, IFLA_QDISC, qdisc->ops->id)) || |
---|
1635 | 1753 | nla_put_ifalias(skb, dev) || |
---|
1636 | 1754 | nla_put_u32(skb, IFLA_CARRIER_CHANGES, |
---|
1637 | 1755 | atomic_read(&dev->carrier_up_count) + |
---|
1638 | 1756 | atomic_read(&dev->carrier_down_count)) || |
---|
1639 | | - nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down) || |
---|
1640 | 1757 | nla_put_u32(skb, IFLA_CARRIER_UP_COUNT, |
---|
1641 | 1758 | atomic_read(&dev->carrier_up_count)) || |
---|
1642 | 1759 | nla_put_u32(skb, IFLA_CARRIER_DOWN_COUNT, |
---|
1643 | 1760 | atomic_read(&dev->carrier_down_count))) |
---|
| 1761 | + goto nla_put_failure; |
---|
| 1762 | + |
---|
| 1763 | + if (rtnl_fill_proto_down(skb, dev)) |
---|
1644 | 1764 | goto nla_put_failure; |
---|
1645 | 1765 | |
---|
1646 | 1766 | if (event != IFLA_EVENT_NONE) { |
---|
.. | .. |
---|
1693 | 1813 | nla_put_s32(skb, IFLA_NEW_IFINDEX, new_ifindex) < 0) |
---|
1694 | 1814 | goto nla_put_failure; |
---|
1695 | 1815 | |
---|
| 1816 | + if (memchr_inv(dev->perm_addr, '\0', dev->addr_len) && |
---|
| 1817 | + nla_put(skb, IFLA_PERM_ADDRESS, dev->addr_len, dev->perm_addr)) |
---|
| 1818 | + goto nla_put_failure; |
---|
1696 | 1819 | |
---|
1697 | 1820 | rcu_read_lock(); |
---|
1698 | 1821 | if (rtnl_fill_link_af(skb, dev, ext_filter_mask)) |
---|
1699 | 1822 | goto nla_put_failure_rcu; |
---|
1700 | 1823 | rcu_read_unlock(); |
---|
| 1824 | + |
---|
| 1825 | + if (rtnl_fill_prop_list(skb, dev)) |
---|
| 1826 | + goto nla_put_failure; |
---|
1701 | 1827 | |
---|
1702 | 1828 | nlmsg_end(skb, nlh); |
---|
1703 | 1829 | return 0; |
---|
.. | .. |
---|
1747 | 1873 | [IFLA_XDP] = { .type = NLA_NESTED }, |
---|
1748 | 1874 | [IFLA_EVENT] = { .type = NLA_U32 }, |
---|
1749 | 1875 | [IFLA_GROUP] = { .type = NLA_U32 }, |
---|
1750 | | - [IFLA_IF_NETNSID] = { .type = NLA_S32 }, |
---|
| 1876 | + [IFLA_TARGET_NETNSID] = { .type = NLA_S32 }, |
---|
1751 | 1877 | [IFLA_CARRIER_UP_COUNT] = { .type = NLA_U32 }, |
---|
1752 | 1878 | [IFLA_CARRIER_DOWN_COUNT] = { .type = NLA_U32 }, |
---|
1753 | 1879 | [IFLA_MIN_MTU] = { .type = NLA_U32 }, |
---|
1754 | 1880 | [IFLA_MAX_MTU] = { .type = NLA_U32 }, |
---|
| 1881 | + [IFLA_PROP_LIST] = { .type = NLA_NESTED }, |
---|
| 1882 | + [IFLA_ALT_IFNAME] = { .type = NLA_STRING, |
---|
| 1883 | + .len = ALTIFNAMSIZ - 1 }, |
---|
| 1884 | + [IFLA_PERM_ADDRESS] = { .type = NLA_REJECT }, |
---|
| 1885 | + [IFLA_PROTO_DOWN_REASON] = { .type = NLA_NESTED }, |
---|
1755 | 1886 | }; |
---|
1756 | 1887 | |
---|
1757 | 1888 | static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { |
---|
.. | .. |
---|
1763 | 1894 | |
---|
1764 | 1895 | static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { |
---|
1765 | 1896 | [IFLA_VF_MAC] = { .len = sizeof(struct ifla_vf_mac) }, |
---|
| 1897 | + [IFLA_VF_BROADCAST] = { .type = NLA_REJECT }, |
---|
1766 | 1898 | [IFLA_VF_VLAN] = { .len = sizeof(struct ifla_vf_vlan) }, |
---|
1767 | 1899 | [IFLA_VF_VLAN_LIST] = { .type = NLA_NESTED }, |
---|
1768 | 1900 | [IFLA_VF_TX_RATE] = { .len = sizeof(struct ifla_vf_tx_rate) }, |
---|
.. | .. |
---|
1796 | 1928 | }; |
---|
1797 | 1929 | |
---|
1798 | 1930 | static const struct nla_policy ifla_xdp_policy[IFLA_XDP_MAX + 1] = { |
---|
| 1931 | + [IFLA_XDP_UNSPEC] = { .strict_start_type = IFLA_XDP_EXPECTED_FD }, |
---|
1799 | 1932 | [IFLA_XDP_FD] = { .type = NLA_S32 }, |
---|
| 1933 | + [IFLA_XDP_EXPECTED_FD] = { .type = NLA_S32 }, |
---|
1800 | 1934 | [IFLA_XDP_ATTACHED] = { .type = NLA_U8 }, |
---|
1801 | 1935 | [IFLA_XDP_FLAGS] = { .type = NLA_U32 }, |
---|
1802 | 1936 | [IFLA_XDP_PROG_ID] = { .type = NLA_U32 }, |
---|
.. | .. |
---|
1807 | 1941 | const struct rtnl_link_ops *ops = NULL; |
---|
1808 | 1942 | struct nlattr *linfo[IFLA_INFO_MAX + 1]; |
---|
1809 | 1943 | |
---|
1810 | | - if (nla_parse_nested(linfo, IFLA_INFO_MAX, nla, |
---|
1811 | | - ifla_info_policy, NULL) < 0) |
---|
| 1944 | + if (nla_parse_nested_deprecated(linfo, IFLA_INFO_MAX, nla, ifla_info_policy, NULL) < 0) |
---|
1812 | 1945 | return NULL; |
---|
1813 | 1946 | |
---|
1814 | 1947 | if (linfo[IFLA_INFO_KIND]) { |
---|
.. | .. |
---|
1855 | 1988 | return false; |
---|
1856 | 1989 | } |
---|
1857 | 1990 | |
---|
1858 | | -static struct net *get_target_net(struct sock *sk, int netnsid) |
---|
| 1991 | +/** |
---|
| 1992 | + * rtnl_get_net_ns_capable - Get netns if sufficiently privileged. |
---|
| 1993 | + * @sk: netlink socket |
---|
| 1994 | + * @netnsid: network namespace identifier |
---|
| 1995 | + * |
---|
| 1996 | + * Returns the network namespace identified by netnsid on success or an error |
---|
| 1997 | + * pointer on failure. |
---|
| 1998 | + */ |
---|
| 1999 | +struct net *rtnl_get_net_ns_capable(struct sock *sk, int netnsid) |
---|
1859 | 2000 | { |
---|
1860 | 2001 | struct net *net; |
---|
1861 | 2002 | |
---|
.. | .. |
---|
1872 | 2013 | } |
---|
1873 | 2014 | return net; |
---|
1874 | 2015 | } |
---|
| 2016 | +EXPORT_SYMBOL_GPL(rtnl_get_net_ns_capable); |
---|
| 2017 | + |
---|
| 2018 | +static int rtnl_valid_dump_ifinfo_req(const struct nlmsghdr *nlh, |
---|
| 2019 | + bool strict_check, struct nlattr **tb, |
---|
| 2020 | + struct netlink_ext_ack *extack) |
---|
| 2021 | +{ |
---|
| 2022 | + int hdrlen; |
---|
| 2023 | + |
---|
| 2024 | + if (strict_check) { |
---|
| 2025 | + struct ifinfomsg *ifm; |
---|
| 2026 | + |
---|
| 2027 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
---|
| 2028 | + NL_SET_ERR_MSG(extack, "Invalid header for link dump"); |
---|
| 2029 | + return -EINVAL; |
---|
| 2030 | + } |
---|
| 2031 | + |
---|
| 2032 | + ifm = nlmsg_data(nlh); |
---|
| 2033 | + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || |
---|
| 2034 | + ifm->ifi_change) { |
---|
| 2035 | + NL_SET_ERR_MSG(extack, "Invalid values in header for link dump request"); |
---|
| 2036 | + return -EINVAL; |
---|
| 2037 | + } |
---|
| 2038 | + if (ifm->ifi_index) { |
---|
| 2039 | + NL_SET_ERR_MSG(extack, "Filter by device index not supported for link dumps"); |
---|
| 2040 | + return -EINVAL; |
---|
| 2041 | + } |
---|
| 2042 | + |
---|
| 2043 | + return nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, |
---|
| 2044 | + IFLA_MAX, ifla_policy, |
---|
| 2045 | + extack); |
---|
| 2046 | + } |
---|
| 2047 | + |
---|
| 2048 | + /* A hack to preserve kernel<->userspace interface. |
---|
| 2049 | + * The correct header is ifinfomsg. It is consistent with rtnl_getlink. |
---|
| 2050 | + * However, before Linux v3.9 the code here assumed rtgenmsg and that's |
---|
| 2051 | + * what iproute2 < v3.9.0 used. |
---|
| 2052 | + * We can detect the old iproute2. Even including the IFLA_EXT_MASK |
---|
| 2053 | + * attribute, its netlink message is shorter than struct ifinfomsg. |
---|
| 2054 | + */ |
---|
| 2055 | + hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ? |
---|
| 2056 | + sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); |
---|
| 2057 | + |
---|
| 2058 | + return nlmsg_parse_deprecated(nlh, hdrlen, tb, IFLA_MAX, ifla_policy, |
---|
| 2059 | + extack); |
---|
| 2060 | +} |
---|
1875 | 2061 | |
---|
1876 | 2062 | static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) |
---|
1877 | 2063 | { |
---|
| 2064 | + struct netlink_ext_ack *extack = cb->extack; |
---|
| 2065 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
1878 | 2066 | struct net *net = sock_net(skb->sk); |
---|
1879 | 2067 | struct net *tgt_net = net; |
---|
1880 | 2068 | int h, s_h; |
---|
.. | .. |
---|
1887 | 2075 | unsigned int flags = NLM_F_MULTI; |
---|
1888 | 2076 | int master_idx = 0; |
---|
1889 | 2077 | int netnsid = -1; |
---|
1890 | | - int err; |
---|
1891 | | - int hdrlen; |
---|
| 2078 | + int err, i; |
---|
1892 | 2079 | |
---|
1893 | 2080 | s_h = cb->args[0]; |
---|
1894 | 2081 | s_idx = cb->args[1]; |
---|
1895 | 2082 | |
---|
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); |
---|
| 2083 | + err = rtnl_valid_dump_ifinfo_req(nlh, cb->strict_check, tb, extack); |
---|
| 2084 | + if (err < 0) { |
---|
| 2085 | + if (cb->strict_check) |
---|
| 2086 | + return err; |
---|
1905 | 2087 | |
---|
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; |
---|
| 2088 | + goto walk_entries; |
---|
1926 | 2089 | } |
---|
1927 | 2090 | |
---|
| 2091 | + for (i = 0; i <= IFLA_MAX; ++i) { |
---|
| 2092 | + if (!tb[i]) |
---|
| 2093 | + continue; |
---|
| 2094 | + |
---|
| 2095 | + /* new attributes should only be added with strict checking */ |
---|
| 2096 | + switch (i) { |
---|
| 2097 | + case IFLA_TARGET_NETNSID: |
---|
| 2098 | + netnsid = nla_get_s32(tb[i]); |
---|
| 2099 | + tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid); |
---|
| 2100 | + if (IS_ERR(tgt_net)) { |
---|
| 2101 | + NL_SET_ERR_MSG(extack, "Invalid target network namespace id"); |
---|
| 2102 | + return PTR_ERR(tgt_net); |
---|
| 2103 | + } |
---|
| 2104 | + break; |
---|
| 2105 | + case IFLA_EXT_MASK: |
---|
| 2106 | + ext_filter_mask = nla_get_u32(tb[i]); |
---|
| 2107 | + break; |
---|
| 2108 | + case IFLA_MASTER: |
---|
| 2109 | + master_idx = nla_get_u32(tb[i]); |
---|
| 2110 | + break; |
---|
| 2111 | + case IFLA_LINKINFO: |
---|
| 2112 | + kind_ops = linkinfo_to_kind_ops(tb[i]); |
---|
| 2113 | + break; |
---|
| 2114 | + default: |
---|
| 2115 | + if (cb->strict_check) { |
---|
| 2116 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in link dump request"); |
---|
| 2117 | + return -EINVAL; |
---|
| 2118 | + } |
---|
| 2119 | + } |
---|
| 2120 | + } |
---|
| 2121 | + |
---|
| 2122 | + if (master_idx || kind_ops) |
---|
| 2123 | + flags |= NLM_F_DUMP_FILTERED; |
---|
| 2124 | + |
---|
| 2125 | +walk_entries: |
---|
1928 | 2126 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
---|
1929 | 2127 | idx = 0; |
---|
1930 | 2128 | head = &tgt_net->dev_index_head[h]; |
---|
.. | .. |
---|
1936 | 2134 | err = rtnl_fill_ifinfo(skb, dev, net, |
---|
1937 | 2135 | RTM_NEWLINK, |
---|
1938 | 2136 | NETLINK_CB(cb->skb).portid, |
---|
1939 | | - cb->nlh->nlmsg_seq, 0, |
---|
1940 | | - flags, |
---|
| 2137 | + nlh->nlmsg_seq, 0, flags, |
---|
1941 | 2138 | ext_filter_mask, 0, NULL, 0, |
---|
1942 | 2139 | netnsid, GFP_KERNEL); |
---|
1943 | 2140 | |
---|
.. | .. |
---|
1964 | 2161 | return err; |
---|
1965 | 2162 | } |
---|
1966 | 2163 | |
---|
1967 | | -int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len, |
---|
1968 | | - struct netlink_ext_ack *exterr) |
---|
| 2164 | +int rtnl_nla_parse_ifinfomsg(struct nlattr **tb, const struct nlattr *nla_peer, |
---|
| 2165 | + struct netlink_ext_ack *exterr) |
---|
1969 | 2166 | { |
---|
1970 | | - return nla_parse(tb, IFLA_MAX, head, len, ifla_policy, exterr); |
---|
| 2167 | + const struct ifinfomsg *ifmp; |
---|
| 2168 | + const struct nlattr *attrs; |
---|
| 2169 | + size_t len; |
---|
| 2170 | + |
---|
| 2171 | + ifmp = nla_data(nla_peer); |
---|
| 2172 | + attrs = nla_data(nla_peer) + sizeof(struct ifinfomsg); |
---|
| 2173 | + len = nla_len(nla_peer) - sizeof(struct ifinfomsg); |
---|
| 2174 | + |
---|
| 2175 | + if (ifmp->ifi_index < 0) { |
---|
| 2176 | + NL_SET_ERR_MSG_ATTR(exterr, nla_peer, |
---|
| 2177 | + "ifindex can't be negative"); |
---|
| 2178 | + return -EINVAL; |
---|
| 2179 | + } |
---|
| 2180 | + |
---|
| 2181 | + return nla_parse_deprecated(tb, IFLA_MAX, attrs, len, ifla_policy, |
---|
| 2182 | + exterr); |
---|
1971 | 2183 | } |
---|
1972 | | -EXPORT_SYMBOL(rtnl_nla_parse_ifla); |
---|
| 2184 | +EXPORT_SYMBOL(rtnl_nla_parse_ifinfomsg); |
---|
1973 | 2185 | |
---|
1974 | 2186 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) |
---|
1975 | 2187 | { |
---|
.. | .. |
---|
1992 | 2204 | * |
---|
1993 | 2205 | * 1. IFLA_NET_NS_PID |
---|
1994 | 2206 | * 2. IFLA_NET_NS_FD |
---|
1995 | | - * 3. IFLA_IF_NETNSID |
---|
| 2207 | + * 3. IFLA_TARGET_NETNSID |
---|
1996 | 2208 | */ |
---|
1997 | 2209 | static struct net *rtnl_link_get_net_by_nlattr(struct net *src_net, |
---|
1998 | 2210 | struct nlattr *tb[]) |
---|
.. | .. |
---|
2002 | 2214 | if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) |
---|
2003 | 2215 | return rtnl_link_get_net(src_net, tb); |
---|
2004 | 2216 | |
---|
2005 | | - if (!tb[IFLA_IF_NETNSID]) |
---|
| 2217 | + if (!tb[IFLA_TARGET_NETNSID]) |
---|
2006 | 2218 | return get_net(src_net); |
---|
2007 | 2219 | |
---|
2008 | | - net = get_net_ns_by_id(src_net, nla_get_u32(tb[IFLA_IF_NETNSID])); |
---|
| 2220 | + net = get_net_ns_by_id(src_net, nla_get_u32(tb[IFLA_TARGET_NETNSID])); |
---|
2009 | 2221 | if (!net) |
---|
2010 | 2222 | return ERR_PTR(-EINVAL); |
---|
2011 | 2223 | |
---|
.. | .. |
---|
2046 | 2258 | return -EOPNOTSUPP; |
---|
2047 | 2259 | } |
---|
2048 | 2260 | |
---|
2049 | | - if (tb[IFLA_IF_NETNSID] && (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD])) |
---|
| 2261 | + if (tb[IFLA_TARGET_NETNSID] && (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD])) |
---|
2050 | 2262 | goto invalid_attr; |
---|
2051 | 2263 | |
---|
2052 | | - if (tb[IFLA_NET_NS_PID] && (tb[IFLA_IF_NETNSID] || tb[IFLA_NET_NS_FD])) |
---|
| 2264 | + if (tb[IFLA_NET_NS_PID] && (tb[IFLA_TARGET_NETNSID] || tb[IFLA_NET_NS_FD])) |
---|
2053 | 2265 | goto invalid_attr; |
---|
2054 | 2266 | |
---|
2055 | | - if (tb[IFLA_NET_NS_FD] && (tb[IFLA_IF_NETNSID] || tb[IFLA_NET_NS_PID])) |
---|
| 2267 | + if (tb[IFLA_NET_NS_FD] && (tb[IFLA_TARGET_NETNSID] || tb[IFLA_NET_NS_PID])) |
---|
2056 | 2268 | goto invalid_attr; |
---|
2057 | 2269 | |
---|
2058 | 2270 | return 0; |
---|
.. | .. |
---|
2334 | 2546 | return 0; |
---|
2335 | 2547 | } |
---|
2336 | 2548 | |
---|
| 2549 | +static const struct nla_policy ifla_proto_down_reason_policy[IFLA_PROTO_DOWN_REASON_VALUE + 1] = { |
---|
| 2550 | + [IFLA_PROTO_DOWN_REASON_MASK] = { .type = NLA_U32 }, |
---|
| 2551 | + [IFLA_PROTO_DOWN_REASON_VALUE] = { .type = NLA_U32 }, |
---|
| 2552 | +}; |
---|
| 2553 | + |
---|
| 2554 | +static int do_set_proto_down(struct net_device *dev, |
---|
| 2555 | + struct nlattr *nl_proto_down, |
---|
| 2556 | + struct nlattr *nl_proto_down_reason, |
---|
| 2557 | + struct netlink_ext_ack *extack) |
---|
| 2558 | +{ |
---|
| 2559 | + struct nlattr *pdreason[IFLA_PROTO_DOWN_REASON_MAX + 1]; |
---|
| 2560 | + const struct net_device_ops *ops = dev->netdev_ops; |
---|
| 2561 | + unsigned long mask = 0; |
---|
| 2562 | + u32 value; |
---|
| 2563 | + bool proto_down; |
---|
| 2564 | + int err; |
---|
| 2565 | + |
---|
| 2566 | + if (!ops->ndo_change_proto_down) { |
---|
| 2567 | + NL_SET_ERR_MSG(extack, "Protodown not supported by device"); |
---|
| 2568 | + return -EOPNOTSUPP; |
---|
| 2569 | + } |
---|
| 2570 | + |
---|
| 2571 | + if (nl_proto_down_reason) { |
---|
| 2572 | + err = nla_parse_nested_deprecated(pdreason, |
---|
| 2573 | + IFLA_PROTO_DOWN_REASON_MAX, |
---|
| 2574 | + nl_proto_down_reason, |
---|
| 2575 | + ifla_proto_down_reason_policy, |
---|
| 2576 | + NULL); |
---|
| 2577 | + if (err < 0) |
---|
| 2578 | + return err; |
---|
| 2579 | + |
---|
| 2580 | + if (!pdreason[IFLA_PROTO_DOWN_REASON_VALUE]) { |
---|
| 2581 | + NL_SET_ERR_MSG(extack, "Invalid protodown reason value"); |
---|
| 2582 | + return -EINVAL; |
---|
| 2583 | + } |
---|
| 2584 | + |
---|
| 2585 | + value = nla_get_u32(pdreason[IFLA_PROTO_DOWN_REASON_VALUE]); |
---|
| 2586 | + |
---|
| 2587 | + if (pdreason[IFLA_PROTO_DOWN_REASON_MASK]) |
---|
| 2588 | + mask = nla_get_u32(pdreason[IFLA_PROTO_DOWN_REASON_MASK]); |
---|
| 2589 | + |
---|
| 2590 | + dev_change_proto_down_reason(dev, mask, value); |
---|
| 2591 | + } |
---|
| 2592 | + |
---|
| 2593 | + if (nl_proto_down) { |
---|
| 2594 | + proto_down = nla_get_u8(nl_proto_down); |
---|
| 2595 | + |
---|
| 2596 | + /* Dont turn off protodown if there are active reasons */ |
---|
| 2597 | + if (!proto_down && dev->proto_down_reason) { |
---|
| 2598 | + NL_SET_ERR_MSG(extack, "Cannot clear protodown, active reasons"); |
---|
| 2599 | + return -EBUSY; |
---|
| 2600 | + } |
---|
| 2601 | + err = dev_change_proto_down(dev, |
---|
| 2602 | + proto_down); |
---|
| 2603 | + if (err) |
---|
| 2604 | + return err; |
---|
| 2605 | + } |
---|
| 2606 | + |
---|
| 2607 | + return 0; |
---|
| 2608 | +} |
---|
| 2609 | + |
---|
2337 | 2610 | #define DO_SETLINK_MODIFIED 0x01 |
---|
2338 | 2611 | /* notify flag means notify + modified. */ |
---|
2339 | 2612 | #define DO_SETLINK_NOTIFY 0x03 |
---|
.. | .. |
---|
2349 | 2622 | if (err < 0) |
---|
2350 | 2623 | return err; |
---|
2351 | 2624 | |
---|
2352 | | - if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_IF_NETNSID]) { |
---|
| 2625 | + if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_TARGET_NETNSID]) { |
---|
| 2626 | + const char *pat = ifname && ifname[0] ? ifname : NULL; |
---|
2353 | 2627 | struct net *net = rtnl_link_get_net_capable(skb, dev_net(dev), |
---|
2354 | 2628 | tb, CAP_NET_ADMIN); |
---|
2355 | 2629 | if (IS_ERR(net)) { |
---|
.. | .. |
---|
2357 | 2631 | goto errout; |
---|
2358 | 2632 | } |
---|
2359 | 2633 | |
---|
2360 | | - err = dev_change_net_namespace(dev, net, ifname); |
---|
| 2634 | + err = dev_change_net_namespace(dev, net, pat); |
---|
2361 | 2635 | put_net(net); |
---|
2362 | 2636 | if (err) |
---|
2363 | 2637 | goto errout; |
---|
.. | .. |
---|
2407 | 2681 | sa->sa_family = dev->type; |
---|
2408 | 2682 | memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]), |
---|
2409 | 2683 | dev->addr_len); |
---|
2410 | | - err = dev_set_mac_address(dev, sa); |
---|
| 2684 | + err = dev_set_mac_address_user(dev, sa, extack); |
---|
2411 | 2685 | kfree(sa); |
---|
2412 | 2686 | if (err) |
---|
2413 | 2687 | goto errout; |
---|
.. | .. |
---|
2452 | 2726 | } |
---|
2453 | 2727 | |
---|
2454 | 2728 | if (ifm->ifi_flags || ifm->ifi_change) { |
---|
2455 | | - err = dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm)); |
---|
| 2729 | + err = dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm), |
---|
| 2730 | + extack); |
---|
2456 | 2731 | if (err < 0) |
---|
2457 | 2732 | goto errout; |
---|
2458 | 2733 | } |
---|
.. | .. |
---|
2532 | 2807 | err = -EINVAL; |
---|
2533 | 2808 | goto errout; |
---|
2534 | 2809 | } |
---|
2535 | | - err = nla_parse_nested(vfinfo, IFLA_VF_MAX, attr, |
---|
2536 | | - ifla_vf_policy, NULL); |
---|
| 2810 | + err = nla_parse_nested_deprecated(vfinfo, IFLA_VF_MAX, |
---|
| 2811 | + attr, |
---|
| 2812 | + ifla_vf_policy, |
---|
| 2813 | + NULL); |
---|
2537 | 2814 | if (err < 0) |
---|
2538 | 2815 | goto errout; |
---|
2539 | 2816 | err = do_setvfinfo(dev, vfinfo); |
---|
.. | .. |
---|
2560 | 2837 | err = -EINVAL; |
---|
2561 | 2838 | goto errout; |
---|
2562 | 2839 | } |
---|
2563 | | - err = nla_parse_nested(port, IFLA_PORT_MAX, attr, |
---|
2564 | | - ifla_port_policy, NULL); |
---|
| 2840 | + err = nla_parse_nested_deprecated(port, IFLA_PORT_MAX, |
---|
| 2841 | + attr, |
---|
| 2842 | + ifla_port_policy, |
---|
| 2843 | + NULL); |
---|
2565 | 2844 | if (err < 0) |
---|
2566 | 2845 | goto errout; |
---|
2567 | 2846 | if (!port[IFLA_PORT_VF]) { |
---|
.. | .. |
---|
2580 | 2859 | if (tb[IFLA_PORT_SELF]) { |
---|
2581 | 2860 | struct nlattr *port[IFLA_PORT_MAX+1]; |
---|
2582 | 2861 | |
---|
2583 | | - err = nla_parse_nested(port, IFLA_PORT_MAX, |
---|
2584 | | - tb[IFLA_PORT_SELF], ifla_port_policy, |
---|
2585 | | - NULL); |
---|
| 2862 | + err = nla_parse_nested_deprecated(port, IFLA_PORT_MAX, |
---|
| 2863 | + tb[IFLA_PORT_SELF], |
---|
| 2864 | + ifla_port_policy, NULL); |
---|
2586 | 2865 | if (err < 0) |
---|
2587 | 2866 | goto errout; |
---|
2588 | 2867 | |
---|
.. | .. |
---|
2617 | 2896 | } |
---|
2618 | 2897 | err = 0; |
---|
2619 | 2898 | |
---|
2620 | | - if (tb[IFLA_PROTO_DOWN]) { |
---|
2621 | | - err = dev_change_proto_down(dev, |
---|
2622 | | - nla_get_u8(tb[IFLA_PROTO_DOWN])); |
---|
| 2899 | + if (tb[IFLA_PROTO_DOWN] || tb[IFLA_PROTO_DOWN_REASON]) { |
---|
| 2900 | + err = do_set_proto_down(dev, tb[IFLA_PROTO_DOWN], |
---|
| 2901 | + tb[IFLA_PROTO_DOWN_REASON], extack); |
---|
2623 | 2902 | if (err) |
---|
2624 | 2903 | goto errout; |
---|
2625 | 2904 | status |= DO_SETLINK_NOTIFY; |
---|
.. | .. |
---|
2629 | 2908 | struct nlattr *xdp[IFLA_XDP_MAX + 1]; |
---|
2630 | 2909 | u32 xdp_flags = 0; |
---|
2631 | 2910 | |
---|
2632 | | - err = nla_parse_nested(xdp, IFLA_XDP_MAX, tb[IFLA_XDP], |
---|
2633 | | - ifla_xdp_policy, NULL); |
---|
| 2911 | + err = nla_parse_nested_deprecated(xdp, IFLA_XDP_MAX, |
---|
| 2912 | + tb[IFLA_XDP], |
---|
| 2913 | + ifla_xdp_policy, NULL); |
---|
2634 | 2914 | if (err < 0) |
---|
2635 | 2915 | goto errout; |
---|
2636 | 2916 | |
---|
.. | .. |
---|
2652 | 2932 | } |
---|
2653 | 2933 | |
---|
2654 | 2934 | if (xdp[IFLA_XDP_FD]) { |
---|
| 2935 | + int expected_fd = -1; |
---|
| 2936 | + |
---|
| 2937 | + if (xdp_flags & XDP_FLAGS_REPLACE) { |
---|
| 2938 | + if (!xdp[IFLA_XDP_EXPECTED_FD]) { |
---|
| 2939 | + err = -EINVAL; |
---|
| 2940 | + goto errout; |
---|
| 2941 | + } |
---|
| 2942 | + expected_fd = |
---|
| 2943 | + nla_get_s32(xdp[IFLA_XDP_EXPECTED_FD]); |
---|
| 2944 | + } |
---|
| 2945 | + |
---|
2655 | 2946 | err = dev_change_xdp_fd(dev, extack, |
---|
2656 | 2947 | nla_get_s32(xdp[IFLA_XDP_FD]), |
---|
| 2948 | + expected_fd, |
---|
2657 | 2949 | xdp_flags); |
---|
2658 | 2950 | if (err) |
---|
2659 | 2951 | goto errout; |
---|
.. | .. |
---|
2674 | 2966 | return err; |
---|
2675 | 2967 | } |
---|
2676 | 2968 | |
---|
| 2969 | +static struct net_device *rtnl_dev_get(struct net *net, |
---|
| 2970 | + struct nlattr *ifname_attr, |
---|
| 2971 | + struct nlattr *altifname_attr, |
---|
| 2972 | + char *ifname) |
---|
| 2973 | +{ |
---|
| 2974 | + char buffer[ALTIFNAMSIZ]; |
---|
| 2975 | + |
---|
| 2976 | + if (!ifname) { |
---|
| 2977 | + ifname = buffer; |
---|
| 2978 | + if (ifname_attr) |
---|
| 2979 | + nla_strlcpy(ifname, ifname_attr, IFNAMSIZ); |
---|
| 2980 | + else if (altifname_attr) |
---|
| 2981 | + nla_strlcpy(ifname, altifname_attr, ALTIFNAMSIZ); |
---|
| 2982 | + else |
---|
| 2983 | + return NULL; |
---|
| 2984 | + } |
---|
| 2985 | + |
---|
| 2986 | + return __dev_get_by_name(net, ifname); |
---|
| 2987 | +} |
---|
| 2988 | + |
---|
2677 | 2989 | static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
2678 | 2990 | struct netlink_ext_ack *extack) |
---|
2679 | 2991 | { |
---|
.. | .. |
---|
2684 | 2996 | struct nlattr *tb[IFLA_MAX+1]; |
---|
2685 | 2997 | char ifname[IFNAMSIZ]; |
---|
2686 | 2998 | |
---|
2687 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, |
---|
2688 | | - extack); |
---|
| 2999 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFLA_MAX, |
---|
| 3000 | + ifla_policy, extack); |
---|
2689 | 3001 | if (err < 0) |
---|
2690 | 3002 | goto errout; |
---|
2691 | 3003 | |
---|
.. | .. |
---|
2702 | 3014 | ifm = nlmsg_data(nlh); |
---|
2703 | 3015 | if (ifm->ifi_index > 0) |
---|
2704 | 3016 | dev = __dev_get_by_index(net, ifm->ifi_index); |
---|
2705 | | - else if (tb[IFLA_IFNAME]) |
---|
2706 | | - dev = __dev_get_by_name(net, ifname); |
---|
| 3017 | + else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) |
---|
| 3018 | + dev = rtnl_dev_get(net, NULL, tb[IFLA_ALT_IFNAME], ifname); |
---|
2707 | 3019 | else |
---|
2708 | 3020 | goto errout; |
---|
2709 | 3021 | |
---|
.. | .. |
---|
2776 | 3088 | struct net *tgt_net = net; |
---|
2777 | 3089 | struct net_device *dev = NULL; |
---|
2778 | 3090 | struct ifinfomsg *ifm; |
---|
2779 | | - char ifname[IFNAMSIZ]; |
---|
2780 | 3091 | struct nlattr *tb[IFLA_MAX+1]; |
---|
2781 | 3092 | int err; |
---|
2782 | 3093 | int netnsid = -1; |
---|
2783 | 3094 | |
---|
2784 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack); |
---|
| 3095 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFLA_MAX, |
---|
| 3096 | + ifla_policy, extack); |
---|
2785 | 3097 | if (err < 0) |
---|
2786 | 3098 | return err; |
---|
2787 | 3099 | |
---|
.. | .. |
---|
2789 | 3101 | if (err < 0) |
---|
2790 | 3102 | return err; |
---|
2791 | 3103 | |
---|
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); |
---|
| 3104 | + if (tb[IFLA_TARGET_NETNSID]) { |
---|
| 3105 | + netnsid = nla_get_s32(tb[IFLA_TARGET_NETNSID]); |
---|
| 3106 | + tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, netnsid); |
---|
2798 | 3107 | if (IS_ERR(tgt_net)) |
---|
2799 | 3108 | return PTR_ERR(tgt_net); |
---|
2800 | 3109 | } |
---|
.. | .. |
---|
2803 | 3112 | ifm = nlmsg_data(nlh); |
---|
2804 | 3113 | if (ifm->ifi_index > 0) |
---|
2805 | 3114 | 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); |
---|
| 3115 | + else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) |
---|
| 3116 | + dev = rtnl_dev_get(net, tb[IFLA_IFNAME], |
---|
| 3117 | + tb[IFLA_ALT_IFNAME], NULL); |
---|
2808 | 3118 | else if (tb[IFLA_GROUP]) |
---|
2809 | 3119 | err = rtnl_group_dellink(tgt_net, nla_get_u32(tb[IFLA_GROUP])); |
---|
2810 | 3120 | else |
---|
.. | .. |
---|
2833 | 3143 | |
---|
2834 | 3144 | old_flags = dev->flags; |
---|
2835 | 3145 | if (ifm && (ifm->ifi_flags || ifm->ifi_change)) { |
---|
2836 | | - err = __dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm)); |
---|
| 3146 | + err = __dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm), |
---|
| 3147 | + NULL); |
---|
2837 | 3148 | if (err < 0) |
---|
2838 | 3149 | return err; |
---|
2839 | 3150 | } |
---|
.. | .. |
---|
2848 | 3159 | } |
---|
2849 | 3160 | EXPORT_SYMBOL(rtnl_configure_link); |
---|
2850 | 3161 | |
---|
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[]) |
---|
| 3162 | +struct net_device *rtnl_create_link(struct net *net, const char *ifname, |
---|
| 3163 | + unsigned char name_assign_type, |
---|
| 3164 | + const struct rtnl_link_ops *ops, |
---|
| 3165 | + struct nlattr *tb[], |
---|
| 3166 | + struct netlink_ext_ack *extack) |
---|
2854 | 3167 | { |
---|
2855 | 3168 | struct net_device *dev; |
---|
2856 | 3169 | unsigned int num_tx_queues = 1; |
---|
.. | .. |
---|
2866 | 3179 | else if (ops->get_num_rx_queues) |
---|
2867 | 3180 | num_rx_queues = ops->get_num_rx_queues(); |
---|
2868 | 3181 | |
---|
2869 | | - if (num_tx_queues < 1 || num_tx_queues > 4096) |
---|
| 3182 | + if (num_tx_queues < 1 || num_tx_queues > 4096) { |
---|
| 3183 | + NL_SET_ERR_MSG(extack, "Invalid number of transmit queues"); |
---|
2870 | 3184 | return ERR_PTR(-EINVAL); |
---|
| 3185 | + } |
---|
2871 | 3186 | |
---|
2872 | | - if (num_rx_queues < 1 || num_rx_queues > 4096) |
---|
| 3187 | + if (num_rx_queues < 1 || num_rx_queues > 4096) { |
---|
| 3188 | + NL_SET_ERR_MSG(extack, "Invalid number of receive queues"); |
---|
2873 | 3189 | return ERR_PTR(-EINVAL); |
---|
| 3190 | + } |
---|
2874 | 3191 | |
---|
2875 | 3192 | dev = alloc_netdev_mqs(ops->priv_size, ifname, name_assign_type, |
---|
2876 | 3193 | ops->setup, num_tx_queues, num_rx_queues); |
---|
.. | .. |
---|
2885 | 3202 | u32 mtu = nla_get_u32(tb[IFLA_MTU]); |
---|
2886 | 3203 | int err; |
---|
2887 | 3204 | |
---|
2888 | | - err = dev_validate_mtu(dev, mtu, NULL); |
---|
| 3205 | + err = dev_validate_mtu(dev, mtu, extack); |
---|
2889 | 3206 | if (err) { |
---|
2890 | 3207 | free_netdev(dev); |
---|
2891 | 3208 | return ERR_PTR(err); |
---|
.. | .. |
---|
2937 | 3254 | return 0; |
---|
2938 | 3255 | } |
---|
2939 | 3256 | |
---|
2940 | | -static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
2941 | | - struct netlink_ext_ack *extack) |
---|
| 3257 | +static int __rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 3258 | + struct nlattr **attr, struct netlink_ext_ack *extack) |
---|
2942 | 3259 | { |
---|
| 3260 | + struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1]; |
---|
| 3261 | + unsigned char name_assign_type = NET_NAME_USER; |
---|
| 3262 | + struct nlattr *linkinfo[IFLA_INFO_MAX + 1]; |
---|
| 3263 | + const struct rtnl_link_ops *m_ops; |
---|
| 3264 | + struct net_device *master_dev; |
---|
2943 | 3265 | struct net *net = sock_net(skb->sk); |
---|
2944 | 3266 | 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; |
---|
| 3267 | + struct nlattr *tb[IFLA_MAX + 1]; |
---|
| 3268 | + struct net *dest_net, *link_net; |
---|
| 3269 | + struct nlattr **slave_data; |
---|
2949 | 3270 | char kind[MODULE_NAME_LEN]; |
---|
| 3271 | + struct net_device *dev; |
---|
| 3272 | + struct ifinfomsg *ifm; |
---|
2950 | 3273 | 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; |
---|
| 3274 | + struct nlattr **data; |
---|
| 3275 | + bool link_specified; |
---|
2954 | 3276 | int err; |
---|
2955 | 3277 | |
---|
2956 | 3278 | #ifdef CONFIG_MODULES |
---|
2957 | 3279 | replay: |
---|
2958 | 3280 | #endif |
---|
2959 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack); |
---|
| 3281 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFLA_MAX, |
---|
| 3282 | + ifla_policy, extack); |
---|
2960 | 3283 | if (err < 0) |
---|
2961 | 3284 | return err; |
---|
2962 | 3285 | |
---|
.. | .. |
---|
2970 | 3293 | ifname[0] = '\0'; |
---|
2971 | 3294 | |
---|
2972 | 3295 | ifm = nlmsg_data(nlh); |
---|
2973 | | - if (ifm->ifi_index > 0) |
---|
| 3296 | + if (ifm->ifi_index > 0) { |
---|
| 3297 | + link_specified = true; |
---|
2974 | 3298 | 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; |
---|
| 3299 | + } else if (ifm->ifi_index < 0) { |
---|
| 3300 | + NL_SET_ERR_MSG(extack, "ifindex can't be negative"); |
---|
| 3301 | + return -EINVAL; |
---|
| 3302 | + } else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) { |
---|
| 3303 | + link_specified = true; |
---|
| 3304 | + dev = rtnl_dev_get(net, NULL, tb[IFLA_ALT_IFNAME], ifname); |
---|
| 3305 | + } else { |
---|
| 3306 | + link_specified = false; |
---|
| 3307 | + dev = NULL; |
---|
2980 | 3308 | } |
---|
2981 | 3309 | |
---|
2982 | 3310 | master_dev = NULL; |
---|
.. | .. |
---|
2992 | 3320 | return err; |
---|
2993 | 3321 | |
---|
2994 | 3322 | if (tb[IFLA_LINKINFO]) { |
---|
2995 | | - err = nla_parse_nested(linkinfo, IFLA_INFO_MAX, |
---|
2996 | | - tb[IFLA_LINKINFO], ifla_info_policy, |
---|
2997 | | - NULL); |
---|
| 3323 | + err = nla_parse_nested_deprecated(linkinfo, IFLA_INFO_MAX, |
---|
| 3324 | + tb[IFLA_LINKINFO], |
---|
| 3325 | + ifla_info_policy, NULL); |
---|
2998 | 3326 | if (err < 0) |
---|
2999 | 3327 | return err; |
---|
3000 | 3328 | } else |
---|
.. | .. |
---|
3008 | 3336 | ops = NULL; |
---|
3009 | 3337 | } |
---|
3010 | 3338 | |
---|
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; |
---|
| 3339 | + data = NULL; |
---|
| 3340 | + if (ops) { |
---|
| 3341 | + if (ops->maxtype > RTNL_MAX_TYPE) |
---|
| 3342 | + return -EINVAL; |
---|
3017 | 3343 | |
---|
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 | | - } |
---|
| 3344 | + if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { |
---|
| 3345 | + err = nla_parse_nested_deprecated(attr, ops->maxtype, |
---|
| 3346 | + linkinfo[IFLA_INFO_DATA], |
---|
| 3347 | + ops->policy, extack); |
---|
| 3348 | + if (err < 0) |
---|
| 3349 | + return err; |
---|
| 3350 | + data = attr; |
---|
3035 | 3351 | } |
---|
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 | | - } |
---|
| 3352 | + if (ops->validate) { |
---|
| 3353 | + err = ops->validate(tb, data, extack); |
---|
| 3354 | + if (err < 0) |
---|
| 3355 | + return err; |
---|
3052 | 3356 | } |
---|
| 3357 | + } |
---|
3053 | 3358 | |
---|
3054 | | - if (dev) { |
---|
3055 | | - int status = 0; |
---|
| 3359 | + slave_data = NULL; |
---|
| 3360 | + if (m_ops) { |
---|
| 3361 | + if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE) |
---|
| 3362 | + return -EINVAL; |
---|
3056 | 3363 | |
---|
3057 | | - if (nlh->nlmsg_flags & NLM_F_EXCL) |
---|
3058 | | - return -EEXIST; |
---|
3059 | | - if (nlh->nlmsg_flags & NLM_F_REPLACE) |
---|
| 3364 | + if (m_ops->slave_maxtype && |
---|
| 3365 | + linkinfo[IFLA_INFO_SLAVE_DATA]) { |
---|
| 3366 | + err = nla_parse_nested_deprecated(slave_attr, |
---|
| 3367 | + m_ops->slave_maxtype, |
---|
| 3368 | + linkinfo[IFLA_INFO_SLAVE_DATA], |
---|
| 3369 | + m_ops->slave_policy, |
---|
| 3370 | + extack); |
---|
| 3371 | + if (err < 0) |
---|
| 3372 | + return err; |
---|
| 3373 | + slave_data = slave_attr; |
---|
| 3374 | + } |
---|
| 3375 | + } |
---|
| 3376 | + |
---|
| 3377 | + if (dev) { |
---|
| 3378 | + int status = 0; |
---|
| 3379 | + |
---|
| 3380 | + if (nlh->nlmsg_flags & NLM_F_EXCL) |
---|
| 3381 | + return -EEXIST; |
---|
| 3382 | + if (nlh->nlmsg_flags & NLM_F_REPLACE) |
---|
| 3383 | + return -EOPNOTSUPP; |
---|
| 3384 | + |
---|
| 3385 | + if (linkinfo[IFLA_INFO_DATA]) { |
---|
| 3386 | + if (!ops || ops != dev->rtnl_link_ops || |
---|
| 3387 | + !ops->changelink) |
---|
3060 | 3388 | return -EOPNOTSUPP; |
---|
3061 | 3389 | |
---|
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); |
---|
| 3390 | + err = ops->changelink(dev, tb, data, extack); |
---|
| 3391 | + if (err < 0) |
---|
| 3392 | + return err; |
---|
| 3393 | + status |= DO_SETLINK_NOTIFY; |
---|
3087 | 3394 | } |
---|
3088 | 3395 | |
---|
3089 | | - if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { |
---|
3090 | | - if (ifm->ifi_index == 0 && tb[IFLA_GROUP]) |
---|
3091 | | - return rtnl_group_changelink(skb, net, |
---|
| 3396 | + if (linkinfo[IFLA_INFO_SLAVE_DATA]) { |
---|
| 3397 | + if (!m_ops || !m_ops->slave_changelink) |
---|
| 3398 | + return -EOPNOTSUPP; |
---|
| 3399 | + |
---|
| 3400 | + err = m_ops->slave_changelink(master_dev, dev, tb, |
---|
| 3401 | + slave_data, extack); |
---|
| 3402 | + if (err < 0) |
---|
| 3403 | + return err; |
---|
| 3404 | + status |= DO_SETLINK_NOTIFY; |
---|
| 3405 | + } |
---|
| 3406 | + |
---|
| 3407 | + return do_setlink(skb, dev, ifm, extack, tb, ifname, status); |
---|
| 3408 | + } |
---|
| 3409 | + |
---|
| 3410 | + if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { |
---|
| 3411 | + /* No dev found and NLM_F_CREATE not set. Requested dev does not exist, |
---|
| 3412 | + * or it's for a group |
---|
| 3413 | + */ |
---|
| 3414 | + if (link_specified) |
---|
| 3415 | + return -ENODEV; |
---|
| 3416 | + if (tb[IFLA_GROUP]) |
---|
| 3417 | + return rtnl_group_changelink(skb, net, |
---|
3092 | 3418 | nla_get_u32(tb[IFLA_GROUP]), |
---|
3093 | 3419 | ifm, extack, tb); |
---|
3094 | | - return -ENODEV; |
---|
3095 | | - } |
---|
| 3420 | + return -ENODEV; |
---|
| 3421 | + } |
---|
3096 | 3422 | |
---|
3097 | | - if (tb[IFLA_MAP] || tb[IFLA_PROTINFO]) |
---|
3098 | | - return -EOPNOTSUPP; |
---|
| 3423 | + if (tb[IFLA_MAP] || tb[IFLA_PROTINFO]) |
---|
| 3424 | + return -EOPNOTSUPP; |
---|
3099 | 3425 | |
---|
3100 | | - if (!ops) { |
---|
| 3426 | + if (!ops) { |
---|
3101 | 3427 | #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 | | - } |
---|
| 3428 | + if (kind[0]) { |
---|
| 3429 | + __rtnl_unlock(); |
---|
| 3430 | + request_module("rtnl-link-%s", kind); |
---|
| 3431 | + rtnl_lock(); |
---|
| 3432 | + ops = rtnl_link_ops_get(kind); |
---|
| 3433 | + if (ops) |
---|
| 3434 | + goto replay; |
---|
| 3435 | + } |
---|
3110 | 3436 | #endif |
---|
3111 | | - return -EOPNOTSUPP; |
---|
3112 | | - } |
---|
| 3437 | + NL_SET_ERR_MSG(extack, "Unknown device type"); |
---|
| 3438 | + return -EOPNOTSUPP; |
---|
| 3439 | + } |
---|
3113 | 3440 | |
---|
3114 | | - if (!ops->setup) |
---|
3115 | | - return -EOPNOTSUPP; |
---|
| 3441 | + if (!ops->setup) |
---|
| 3442 | + return -EOPNOTSUPP; |
---|
3116 | 3443 | |
---|
3117 | | - if (!ifname[0]) { |
---|
3118 | | - snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); |
---|
3119 | | - name_assign_type = NET_NAME_ENUM; |
---|
3120 | | - } |
---|
| 3444 | + if (!ifname[0]) { |
---|
| 3445 | + snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); |
---|
| 3446 | + name_assign_type = NET_NAME_ENUM; |
---|
| 3447 | + } |
---|
3121 | 3448 | |
---|
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); |
---|
| 3449 | + dest_net = rtnl_link_get_net_capable(skb, net, tb, CAP_NET_ADMIN); |
---|
| 3450 | + if (IS_ERR(dest_net)) |
---|
| 3451 | + return PTR_ERR(dest_net); |
---|
3125 | 3452 | |
---|
3126 | | - if (tb[IFLA_LINK_NETNSID]) { |
---|
3127 | | - int id = nla_get_s32(tb[IFLA_LINK_NETNSID]); |
---|
| 3453 | + if (tb[IFLA_LINK_NETNSID]) { |
---|
| 3454 | + int id = nla_get_s32(tb[IFLA_LINK_NETNSID]); |
---|
3128 | 3455 | |
---|
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); |
---|
| 3456 | + link_net = get_net_ns_by_id(dest_net, id); |
---|
| 3457 | + if (!link_net) { |
---|
| 3458 | + NL_SET_ERR_MSG(extack, "Unknown network namespace id"); |
---|
| 3459 | + err = -EINVAL; |
---|
3143 | 3460 | goto out; |
---|
3144 | 3461 | } |
---|
| 3462 | + err = -EPERM; |
---|
| 3463 | + if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN)) |
---|
| 3464 | + goto out; |
---|
| 3465 | + } else { |
---|
| 3466 | + link_net = NULL; |
---|
| 3467 | + } |
---|
3145 | 3468 | |
---|
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 | | - } |
---|
| 3469 | + dev = rtnl_create_link(link_net ? : dest_net, ifname, |
---|
| 3470 | + name_assign_type, ops, tb, extack); |
---|
| 3471 | + if (IS_ERR(dev)) { |
---|
| 3472 | + err = PTR_ERR(dev); |
---|
3197 | 3473 | goto out; |
---|
3198 | 3474 | } |
---|
| 3475 | + |
---|
| 3476 | + dev->ifindex = ifm->ifi_index; |
---|
| 3477 | + |
---|
| 3478 | + if (ops->newlink) |
---|
| 3479 | + err = ops->newlink(link_net ? : net, dev, tb, data, extack); |
---|
| 3480 | + else |
---|
| 3481 | + err = register_netdevice(dev); |
---|
| 3482 | + if (err < 0) { |
---|
| 3483 | + free_netdev(dev); |
---|
| 3484 | + goto out; |
---|
| 3485 | + } |
---|
| 3486 | + |
---|
| 3487 | + err = rtnl_configure_link(dev, ifm); |
---|
| 3488 | + if (err < 0) |
---|
| 3489 | + goto out_unregister; |
---|
| 3490 | + if (link_net) { |
---|
| 3491 | + err = dev_change_net_namespace(dev, dest_net, ifname); |
---|
| 3492 | + if (err < 0) |
---|
| 3493 | + goto out_unregister; |
---|
| 3494 | + } |
---|
| 3495 | + if (tb[IFLA_MASTER]) { |
---|
| 3496 | + err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]), extack); |
---|
| 3497 | + if (err) |
---|
| 3498 | + goto out_unregister; |
---|
| 3499 | + } |
---|
| 3500 | +out: |
---|
| 3501 | + if (link_net) |
---|
| 3502 | + put_net(link_net); |
---|
| 3503 | + put_net(dest_net); |
---|
| 3504 | + return err; |
---|
| 3505 | +out_unregister: |
---|
| 3506 | + if (ops->newlink) { |
---|
| 3507 | + LIST_HEAD(list_kill); |
---|
| 3508 | + |
---|
| 3509 | + ops->dellink(dev, &list_kill); |
---|
| 3510 | + unregister_netdevice_many(&list_kill); |
---|
| 3511 | + } else { |
---|
| 3512 | + unregister_netdevice(dev); |
---|
| 3513 | + } |
---|
| 3514 | + goto out; |
---|
| 3515 | +} |
---|
| 3516 | + |
---|
| 3517 | +static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 3518 | + struct netlink_ext_ack *extack) |
---|
| 3519 | +{ |
---|
| 3520 | + struct nlattr **attr; |
---|
| 3521 | + int ret; |
---|
| 3522 | + |
---|
| 3523 | + attr = kmalloc_array(RTNL_MAX_TYPE + 1, sizeof(*attr), GFP_KERNEL); |
---|
| 3524 | + if (!attr) |
---|
| 3525 | + return -ENOMEM; |
---|
| 3526 | + |
---|
| 3527 | + ret = __rtnl_newlink(skb, nlh, attr, extack); |
---|
| 3528 | + kfree(attr); |
---|
| 3529 | + return ret; |
---|
| 3530 | +} |
---|
| 3531 | + |
---|
| 3532 | +static int rtnl_valid_getlink_req(struct sk_buff *skb, |
---|
| 3533 | + const struct nlmsghdr *nlh, |
---|
| 3534 | + struct nlattr **tb, |
---|
| 3535 | + struct netlink_ext_ack *extack) |
---|
| 3536 | +{ |
---|
| 3537 | + struct ifinfomsg *ifm; |
---|
| 3538 | + int i, err; |
---|
| 3539 | + |
---|
| 3540 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
---|
| 3541 | + NL_SET_ERR_MSG(extack, "Invalid header for get link"); |
---|
| 3542 | + return -EINVAL; |
---|
| 3543 | + } |
---|
| 3544 | + |
---|
| 3545 | + if (!netlink_strict_get_check(skb)) |
---|
| 3546 | + return nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFLA_MAX, |
---|
| 3547 | + ifla_policy, extack); |
---|
| 3548 | + |
---|
| 3549 | + ifm = nlmsg_data(nlh); |
---|
| 3550 | + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || |
---|
| 3551 | + ifm->ifi_change) { |
---|
| 3552 | + NL_SET_ERR_MSG(extack, "Invalid values in header for get link request"); |
---|
| 3553 | + return -EINVAL; |
---|
| 3554 | + } |
---|
| 3555 | + |
---|
| 3556 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, IFLA_MAX, |
---|
| 3557 | + ifla_policy, extack); |
---|
| 3558 | + if (err) |
---|
| 3559 | + return err; |
---|
| 3560 | + |
---|
| 3561 | + for (i = 0; i <= IFLA_MAX; i++) { |
---|
| 3562 | + if (!tb[i]) |
---|
| 3563 | + continue; |
---|
| 3564 | + |
---|
| 3565 | + switch (i) { |
---|
| 3566 | + case IFLA_IFNAME: |
---|
| 3567 | + case IFLA_ALT_IFNAME: |
---|
| 3568 | + case IFLA_EXT_MASK: |
---|
| 3569 | + case IFLA_TARGET_NETNSID: |
---|
| 3570 | + break; |
---|
| 3571 | + default: |
---|
| 3572 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in get link request"); |
---|
| 3573 | + return -EINVAL; |
---|
| 3574 | + } |
---|
| 3575 | + } |
---|
| 3576 | + |
---|
| 3577 | + return 0; |
---|
3199 | 3578 | } |
---|
3200 | 3579 | |
---|
3201 | 3580 | static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
.. | .. |
---|
3204 | 3583 | struct net *net = sock_net(skb->sk); |
---|
3205 | 3584 | struct net *tgt_net = net; |
---|
3206 | 3585 | struct ifinfomsg *ifm; |
---|
3207 | | - char ifname[IFNAMSIZ]; |
---|
3208 | 3586 | struct nlattr *tb[IFLA_MAX+1]; |
---|
3209 | 3587 | struct net_device *dev = NULL; |
---|
3210 | 3588 | struct sk_buff *nskb; |
---|
.. | .. |
---|
3212 | 3590 | int err; |
---|
3213 | 3591 | u32 ext_filter_mask = 0; |
---|
3214 | 3592 | |
---|
3215 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack); |
---|
| 3593 | + err = rtnl_valid_getlink_req(skb, nlh, tb, extack); |
---|
3216 | 3594 | if (err < 0) |
---|
3217 | 3595 | return err; |
---|
3218 | 3596 | |
---|
.. | .. |
---|
3220 | 3598 | if (err < 0) |
---|
3221 | 3599 | return err; |
---|
3222 | 3600 | |
---|
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); |
---|
| 3601 | + if (tb[IFLA_TARGET_NETNSID]) { |
---|
| 3602 | + netnsid = nla_get_s32(tb[IFLA_TARGET_NETNSID]); |
---|
| 3603 | + tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, netnsid); |
---|
3226 | 3604 | if (IS_ERR(tgt_net)) |
---|
3227 | 3605 | return PTR_ERR(tgt_net); |
---|
3228 | 3606 | } |
---|
3229 | | - |
---|
3230 | | - if (tb[IFLA_IFNAME]) |
---|
3231 | | - nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); |
---|
3232 | 3607 | |
---|
3233 | 3608 | if (tb[IFLA_EXT_MASK]) |
---|
3234 | 3609 | ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); |
---|
.. | .. |
---|
3237 | 3612 | ifm = nlmsg_data(nlh); |
---|
3238 | 3613 | if (ifm->ifi_index > 0) |
---|
3239 | 3614 | 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); |
---|
| 3615 | + else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) |
---|
| 3616 | + dev = rtnl_dev_get(tgt_net, tb[IFLA_IFNAME], |
---|
| 3617 | + tb[IFLA_ALT_IFNAME], NULL); |
---|
3242 | 3618 | else |
---|
3243 | 3619 | goto out; |
---|
3244 | 3620 | |
---|
.. | .. |
---|
3268 | 3644 | return err; |
---|
3269 | 3645 | } |
---|
3270 | 3646 | |
---|
3271 | | -static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh) |
---|
| 3647 | +static int rtnl_alt_ifname(int cmd, struct net_device *dev, struct nlattr *attr, |
---|
| 3648 | + bool *changed, struct netlink_ext_ack *extack) |
---|
| 3649 | +{ |
---|
| 3650 | + char *alt_ifname; |
---|
| 3651 | + size_t size; |
---|
| 3652 | + int err; |
---|
| 3653 | + |
---|
| 3654 | + err = nla_validate(attr, attr->nla_len, IFLA_MAX, ifla_policy, extack); |
---|
| 3655 | + if (err) |
---|
| 3656 | + return err; |
---|
| 3657 | + |
---|
| 3658 | + if (cmd == RTM_NEWLINKPROP) { |
---|
| 3659 | + size = rtnl_prop_list_size(dev); |
---|
| 3660 | + size += nla_total_size(ALTIFNAMSIZ); |
---|
| 3661 | + if (size >= U16_MAX) { |
---|
| 3662 | + NL_SET_ERR_MSG(extack, |
---|
| 3663 | + "effective property list too long"); |
---|
| 3664 | + return -EINVAL; |
---|
| 3665 | + } |
---|
| 3666 | + } |
---|
| 3667 | + |
---|
| 3668 | + alt_ifname = nla_strdup(attr, GFP_KERNEL_ACCOUNT); |
---|
| 3669 | + if (!alt_ifname) |
---|
| 3670 | + return -ENOMEM; |
---|
| 3671 | + |
---|
| 3672 | + if (cmd == RTM_NEWLINKPROP) { |
---|
| 3673 | + err = netdev_name_node_alt_create(dev, alt_ifname); |
---|
| 3674 | + if (!err) |
---|
| 3675 | + alt_ifname = NULL; |
---|
| 3676 | + } else if (cmd == RTM_DELLINKPROP) { |
---|
| 3677 | + err = netdev_name_node_alt_destroy(dev, alt_ifname); |
---|
| 3678 | + } else { |
---|
| 3679 | + WARN_ON_ONCE(1); |
---|
| 3680 | + err = -EINVAL; |
---|
| 3681 | + } |
---|
| 3682 | + |
---|
| 3683 | + kfree(alt_ifname); |
---|
| 3684 | + if (!err) |
---|
| 3685 | + *changed = true; |
---|
| 3686 | + return err; |
---|
| 3687 | +} |
---|
| 3688 | + |
---|
| 3689 | +static int rtnl_linkprop(int cmd, struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 3690 | + struct netlink_ext_ack *extack) |
---|
3272 | 3691 | { |
---|
3273 | 3692 | struct net *net = sock_net(skb->sk); |
---|
| 3693 | + struct nlattr *tb[IFLA_MAX + 1]; |
---|
3274 | 3694 | struct net_device *dev; |
---|
| 3695 | + struct ifinfomsg *ifm; |
---|
| 3696 | + bool changed = false; |
---|
| 3697 | + struct nlattr *attr; |
---|
| 3698 | + int err, rem; |
---|
| 3699 | + |
---|
| 3700 | + err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack); |
---|
| 3701 | + if (err) |
---|
| 3702 | + return err; |
---|
| 3703 | + |
---|
| 3704 | + err = rtnl_ensure_unique_netns(tb, extack, true); |
---|
| 3705 | + if (err) |
---|
| 3706 | + return err; |
---|
| 3707 | + |
---|
| 3708 | + ifm = nlmsg_data(nlh); |
---|
| 3709 | + if (ifm->ifi_index > 0) |
---|
| 3710 | + dev = __dev_get_by_index(net, ifm->ifi_index); |
---|
| 3711 | + else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) |
---|
| 3712 | + dev = rtnl_dev_get(net, tb[IFLA_IFNAME], |
---|
| 3713 | + tb[IFLA_ALT_IFNAME], NULL); |
---|
| 3714 | + else |
---|
| 3715 | + return -EINVAL; |
---|
| 3716 | + |
---|
| 3717 | + if (!dev) |
---|
| 3718 | + return -ENODEV; |
---|
| 3719 | + |
---|
| 3720 | + if (!tb[IFLA_PROP_LIST]) |
---|
| 3721 | + return 0; |
---|
| 3722 | + |
---|
| 3723 | + nla_for_each_nested(attr, tb[IFLA_PROP_LIST], rem) { |
---|
| 3724 | + switch (nla_type(attr)) { |
---|
| 3725 | + case IFLA_ALT_IFNAME: |
---|
| 3726 | + err = rtnl_alt_ifname(cmd, dev, attr, &changed, extack); |
---|
| 3727 | + if (err) |
---|
| 3728 | + return err; |
---|
| 3729 | + break; |
---|
| 3730 | + } |
---|
| 3731 | + } |
---|
| 3732 | + |
---|
| 3733 | + if (changed) |
---|
| 3734 | + netdev_state_change(dev); |
---|
| 3735 | + return 0; |
---|
| 3736 | +} |
---|
| 3737 | + |
---|
| 3738 | +static int rtnl_newlinkprop(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 3739 | + struct netlink_ext_ack *extack) |
---|
| 3740 | +{ |
---|
| 3741 | + return rtnl_linkprop(RTM_NEWLINKPROP, skb, nlh, extack); |
---|
| 3742 | +} |
---|
| 3743 | + |
---|
| 3744 | +static int rtnl_dellinkprop(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 3745 | + struct netlink_ext_ack *extack) |
---|
| 3746 | +{ |
---|
| 3747 | + return rtnl_linkprop(RTM_DELLINKPROP, skb, nlh, extack); |
---|
| 3748 | +} |
---|
| 3749 | + |
---|
| 3750 | +static u32 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh) |
---|
| 3751 | +{ |
---|
| 3752 | + struct net *net = sock_net(skb->sk); |
---|
| 3753 | + size_t min_ifinfo_dump_size = 0; |
---|
3275 | 3754 | struct nlattr *tb[IFLA_MAX+1]; |
---|
3276 | 3755 | u32 ext_filter_mask = 0; |
---|
3277 | | - u16 min_ifinfo_dump_size = 0; |
---|
| 3756 | + struct net_device *dev; |
---|
3278 | 3757 | int hdrlen; |
---|
3279 | 3758 | |
---|
3280 | 3759 | /* Same kernel<->userspace interface hack as in rtnl_dump_ifinfo. */ |
---|
3281 | 3760 | hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ? |
---|
3282 | 3761 | sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); |
---|
3283 | 3762 | |
---|
3284 | | - if (nlmsg_parse(nlh, hdrlen, tb, IFLA_MAX, ifla_policy, NULL) >= 0) { |
---|
| 3763 | + if (nlmsg_parse_deprecated(nlh, hdrlen, tb, IFLA_MAX, ifla_policy, NULL) >= 0) { |
---|
3285 | 3764 | if (tb[IFLA_EXT_MASK]) |
---|
3286 | 3765 | ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); |
---|
3287 | 3766 | } |
---|
.. | .. |
---|
3294 | 3773 | */ |
---|
3295 | 3774 | rcu_read_lock(); |
---|
3296 | 3775 | 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)); |
---|
| 3776 | + min_ifinfo_dump_size = max(min_ifinfo_dump_size, |
---|
| 3777 | + if_nlmsg_size(dev, ext_filter_mask)); |
---|
3300 | 3778 | } |
---|
3301 | 3779 | rcu_read_unlock(); |
---|
3302 | 3780 | |
---|
.. | .. |
---|
3308 | 3786 | int idx; |
---|
3309 | 3787 | int s_idx = cb->family; |
---|
3310 | 3788 | int type = cb->nlh->nlmsg_type - RTM_BASE; |
---|
| 3789 | + int ret = 0; |
---|
3311 | 3790 | |
---|
3312 | 3791 | if (s_idx == 0) |
---|
3313 | 3792 | s_idx = 1; |
---|
.. | .. |
---|
3340 | 3819 | cb->prev_seq = 0; |
---|
3341 | 3820 | cb->seq = 0; |
---|
3342 | 3821 | } |
---|
3343 | | - if (dumpit(skb, cb)) |
---|
| 3822 | + ret = dumpit(skb, cb); |
---|
| 3823 | + if (ret) |
---|
3344 | 3824 | break; |
---|
3345 | 3825 | } |
---|
3346 | 3826 | cb->family = idx; |
---|
3347 | 3827 | |
---|
3348 | | - return skb->len; |
---|
| 3828 | + return skb->len ? : ret; |
---|
3349 | 3829 | } |
---|
3350 | 3830 | |
---|
3351 | 3831 | struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev, |
---|
.. | .. |
---|
3436 | 3916 | ndm->ndm_ifindex = dev->ifindex; |
---|
3437 | 3917 | ndm->ndm_state = ndm_state; |
---|
3438 | 3918 | |
---|
3439 | | - if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr)) |
---|
| 3919 | + if (nla_put(skb, NDA_LLADDR, dev->addr_len, addr)) |
---|
3440 | 3920 | goto nla_put_failure; |
---|
3441 | 3921 | if (vid) |
---|
3442 | 3922 | if (nla_put(skb, NDA_VLAN, sizeof(u16), &vid)) |
---|
.. | .. |
---|
3450 | 3930 | return -EMSGSIZE; |
---|
3451 | 3931 | } |
---|
3452 | 3932 | |
---|
3453 | | -static inline size_t rtnl_fdb_nlmsg_size(void) |
---|
| 3933 | +static inline size_t rtnl_fdb_nlmsg_size(const struct net_device *dev) |
---|
3454 | 3934 | { |
---|
3455 | 3935 | return NLMSG_ALIGN(sizeof(struct ndmsg)) + |
---|
3456 | | - nla_total_size(ETH_ALEN) + /* NDA_LLADDR */ |
---|
| 3936 | + nla_total_size(dev->addr_len) + /* NDA_LLADDR */ |
---|
3457 | 3937 | nla_total_size(sizeof(u16)) + /* NDA_VLAN */ |
---|
3458 | 3938 | 0; |
---|
3459 | 3939 | } |
---|
.. | .. |
---|
3465 | 3945 | struct sk_buff *skb; |
---|
3466 | 3946 | int err = -ENOBUFS; |
---|
3467 | 3947 | |
---|
3468 | | - skb = nlmsg_new(rtnl_fdb_nlmsg_size(), GFP_ATOMIC); |
---|
| 3948 | + skb = nlmsg_new(rtnl_fdb_nlmsg_size(dev), GFP_ATOMIC); |
---|
3469 | 3949 | if (!skb) |
---|
3470 | 3950 | goto errout; |
---|
3471 | 3951 | |
---|
.. | .. |
---|
3482 | 3962 | rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); |
---|
3483 | 3963 | } |
---|
3484 | 3964 | |
---|
3485 | | -/** |
---|
| 3965 | +/* |
---|
3486 | 3966 | * ndo_dflt_fdb_add - default netdevice operation to add an FDB entry |
---|
3487 | 3967 | */ |
---|
3488 | 3968 | int ndo_dflt_fdb_add(struct ndmsg *ndm, |
---|
.. | .. |
---|
3552 | 4032 | u16 vid; |
---|
3553 | 4033 | int err; |
---|
3554 | 4034 | |
---|
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); |
---|
| 4035 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, |
---|
| 4036 | + extack); |
---|
3665 | 4037 | if (err < 0) |
---|
3666 | 4038 | return err; |
---|
3667 | 4039 | |
---|
.. | .. |
---|
3697 | 4069 | |
---|
3698 | 4070 | /* Support fdb on master device the net/bridge default case */ |
---|
3699 | 4071 | if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && |
---|
3700 | | - (dev->priv_flags & IFF_BRIDGE_PORT)) { |
---|
| 4072 | + netif_is_bridge_port(dev)) { |
---|
| 4073 | + struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
---|
| 4074 | + const struct net_device_ops *ops = br_dev->netdev_ops; |
---|
| 4075 | + |
---|
| 4076 | + err = ops->ndo_fdb_add(ndm, tb, dev, addr, vid, |
---|
| 4077 | + nlh->nlmsg_flags, extack); |
---|
| 4078 | + if (err) |
---|
| 4079 | + goto out; |
---|
| 4080 | + else |
---|
| 4081 | + ndm->ndm_flags &= ~NTF_MASTER; |
---|
| 4082 | + } |
---|
| 4083 | + |
---|
| 4084 | + /* Embedded bridge, macvlan, and any other device support */ |
---|
| 4085 | + if ((ndm->ndm_flags & NTF_SELF)) { |
---|
| 4086 | + if (dev->netdev_ops->ndo_fdb_add) |
---|
| 4087 | + err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr, |
---|
| 4088 | + vid, |
---|
| 4089 | + nlh->nlmsg_flags, |
---|
| 4090 | + extack); |
---|
| 4091 | + else |
---|
| 4092 | + err = ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, |
---|
| 4093 | + nlh->nlmsg_flags); |
---|
| 4094 | + |
---|
| 4095 | + if (!err) { |
---|
| 4096 | + rtnl_fdb_notify(dev, addr, vid, RTM_NEWNEIGH, |
---|
| 4097 | + ndm->ndm_state); |
---|
| 4098 | + ndm->ndm_flags &= ~NTF_SELF; |
---|
| 4099 | + } |
---|
| 4100 | + } |
---|
| 4101 | +out: |
---|
| 4102 | + return err; |
---|
| 4103 | +} |
---|
| 4104 | + |
---|
| 4105 | +/* |
---|
| 4106 | + * ndo_dflt_fdb_del - default netdevice operation to delete an FDB entry |
---|
| 4107 | + */ |
---|
| 4108 | +int ndo_dflt_fdb_del(struct ndmsg *ndm, |
---|
| 4109 | + struct nlattr *tb[], |
---|
| 4110 | + struct net_device *dev, |
---|
| 4111 | + const unsigned char *addr, u16 vid) |
---|
| 4112 | +{ |
---|
| 4113 | + int err = -EINVAL; |
---|
| 4114 | + |
---|
| 4115 | + /* If aging addresses are supported device will need to |
---|
| 4116 | + * implement its own handler for this. |
---|
| 4117 | + */ |
---|
| 4118 | + if (!(ndm->ndm_state & NUD_PERMANENT)) { |
---|
| 4119 | + pr_info("%s: FDB only supports static addresses\n", dev->name); |
---|
| 4120 | + return err; |
---|
| 4121 | + } |
---|
| 4122 | + |
---|
| 4123 | + if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) |
---|
| 4124 | + err = dev_uc_del(dev, addr); |
---|
| 4125 | + else if (is_multicast_ether_addr(addr)) |
---|
| 4126 | + err = dev_mc_del(dev, addr); |
---|
| 4127 | + |
---|
| 4128 | + return err; |
---|
| 4129 | +} |
---|
| 4130 | +EXPORT_SYMBOL(ndo_dflt_fdb_del); |
---|
| 4131 | + |
---|
| 4132 | +static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
| 4133 | + struct netlink_ext_ack *extack) |
---|
| 4134 | +{ |
---|
| 4135 | + struct net *net = sock_net(skb->sk); |
---|
| 4136 | + struct ndmsg *ndm; |
---|
| 4137 | + struct nlattr *tb[NDA_MAX+1]; |
---|
| 4138 | + struct net_device *dev; |
---|
| 4139 | + __u8 *addr; |
---|
| 4140 | + int err; |
---|
| 4141 | + u16 vid; |
---|
| 4142 | + |
---|
| 4143 | + if (!netlink_capable(skb, CAP_NET_ADMIN)) |
---|
| 4144 | + return -EPERM; |
---|
| 4145 | + |
---|
| 4146 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, |
---|
| 4147 | + extack); |
---|
| 4148 | + if (err < 0) |
---|
| 4149 | + return err; |
---|
| 4150 | + |
---|
| 4151 | + ndm = nlmsg_data(nlh); |
---|
| 4152 | + if (ndm->ndm_ifindex == 0) { |
---|
| 4153 | + NL_SET_ERR_MSG(extack, "invalid ifindex"); |
---|
| 4154 | + return -EINVAL; |
---|
| 4155 | + } |
---|
| 4156 | + |
---|
| 4157 | + dev = __dev_get_by_index(net, ndm->ndm_ifindex); |
---|
| 4158 | + if (dev == NULL) { |
---|
| 4159 | + NL_SET_ERR_MSG(extack, "unknown ifindex"); |
---|
| 4160 | + return -ENODEV; |
---|
| 4161 | + } |
---|
| 4162 | + |
---|
| 4163 | + if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) { |
---|
| 4164 | + NL_SET_ERR_MSG(extack, "invalid address"); |
---|
| 4165 | + return -EINVAL; |
---|
| 4166 | + } |
---|
| 4167 | + |
---|
| 4168 | + if (dev->type != ARPHRD_ETHER) { |
---|
| 4169 | + NL_SET_ERR_MSG(extack, "FDB delete only supported for Ethernet devices"); |
---|
| 4170 | + return -EINVAL; |
---|
| 4171 | + } |
---|
| 4172 | + |
---|
| 4173 | + addr = nla_data(tb[NDA_LLADDR]); |
---|
| 4174 | + |
---|
| 4175 | + err = fdb_vid_parse(tb[NDA_VLAN], &vid, extack); |
---|
| 4176 | + if (err) |
---|
| 4177 | + return err; |
---|
| 4178 | + |
---|
| 4179 | + err = -EOPNOTSUPP; |
---|
| 4180 | + |
---|
| 4181 | + /* Support fdb on master device the net/bridge default case */ |
---|
| 4182 | + if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && |
---|
| 4183 | + netif_is_bridge_port(dev)) { |
---|
3701 | 4184 | struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
---|
3702 | 4185 | const struct net_device_ops *ops = br_dev->netdev_ops; |
---|
3703 | 4186 | |
---|
.. | .. |
---|
3759 | 4242 | |
---|
3760 | 4243 | /** |
---|
3761 | 4244 | * ndo_dflt_fdb_dump - default netdevice operation to dump an FDB table. |
---|
3762 | | - * @nlh: netlink message header |
---|
| 4245 | + * @skb: socket buffer to store message in |
---|
| 4246 | + * @cb: netlink callback |
---|
3763 | 4247 | * @dev: netdevice |
---|
| 4248 | + * @filter_dev: ignored |
---|
| 4249 | + * @idx: the number of FDB table entries dumped is added to *@idx |
---|
3764 | 4250 | * |
---|
3765 | 4251 | * Default netdevice operation to dump the existing unicast address list. |
---|
3766 | 4252 | * Returns number of addresses from list put in skb. |
---|
.. | .. |
---|
3787 | 4273 | } |
---|
3788 | 4274 | EXPORT_SYMBOL(ndo_dflt_fdb_dump); |
---|
3789 | 4275 | |
---|
| 4276 | +static int valid_fdb_dump_strict(const struct nlmsghdr *nlh, |
---|
| 4277 | + int *br_idx, int *brport_idx, |
---|
| 4278 | + struct netlink_ext_ack *extack) |
---|
| 4279 | +{ |
---|
| 4280 | + struct nlattr *tb[NDA_MAX + 1]; |
---|
| 4281 | + struct ndmsg *ndm; |
---|
| 4282 | + int err, i; |
---|
| 4283 | + |
---|
| 4284 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) { |
---|
| 4285 | + NL_SET_ERR_MSG(extack, "Invalid header for fdb dump request"); |
---|
| 4286 | + return -EINVAL; |
---|
| 4287 | + } |
---|
| 4288 | + |
---|
| 4289 | + ndm = nlmsg_data(nlh); |
---|
| 4290 | + if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state || |
---|
| 4291 | + ndm->ndm_flags || ndm->ndm_type) { |
---|
| 4292 | + NL_SET_ERR_MSG(extack, "Invalid values in header for fdb dump request"); |
---|
| 4293 | + return -EINVAL; |
---|
| 4294 | + } |
---|
| 4295 | + |
---|
| 4296 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb, |
---|
| 4297 | + NDA_MAX, NULL, extack); |
---|
| 4298 | + if (err < 0) |
---|
| 4299 | + return err; |
---|
| 4300 | + |
---|
| 4301 | + *brport_idx = ndm->ndm_ifindex; |
---|
| 4302 | + for (i = 0; i <= NDA_MAX; ++i) { |
---|
| 4303 | + if (!tb[i]) |
---|
| 4304 | + continue; |
---|
| 4305 | + |
---|
| 4306 | + switch (i) { |
---|
| 4307 | + case NDA_IFINDEX: |
---|
| 4308 | + if (nla_len(tb[i]) != sizeof(u32)) { |
---|
| 4309 | + NL_SET_ERR_MSG(extack, "Invalid IFINDEX attribute in fdb dump request"); |
---|
| 4310 | + return -EINVAL; |
---|
| 4311 | + } |
---|
| 4312 | + *brport_idx = nla_get_u32(tb[NDA_IFINDEX]); |
---|
| 4313 | + break; |
---|
| 4314 | + case NDA_MASTER: |
---|
| 4315 | + if (nla_len(tb[i]) != sizeof(u32)) { |
---|
| 4316 | + NL_SET_ERR_MSG(extack, "Invalid MASTER attribute in fdb dump request"); |
---|
| 4317 | + return -EINVAL; |
---|
| 4318 | + } |
---|
| 4319 | + *br_idx = nla_get_u32(tb[NDA_MASTER]); |
---|
| 4320 | + break; |
---|
| 4321 | + default: |
---|
| 4322 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in fdb dump request"); |
---|
| 4323 | + return -EINVAL; |
---|
| 4324 | + } |
---|
| 4325 | + } |
---|
| 4326 | + |
---|
| 4327 | + return 0; |
---|
| 4328 | +} |
---|
| 4329 | + |
---|
| 4330 | +static int valid_fdb_dump_legacy(const struct nlmsghdr *nlh, |
---|
| 4331 | + int *br_idx, int *brport_idx, |
---|
| 4332 | + struct netlink_ext_ack *extack) |
---|
| 4333 | +{ |
---|
| 4334 | + struct nlattr *tb[IFLA_MAX+1]; |
---|
| 4335 | + int err; |
---|
| 4336 | + |
---|
| 4337 | + /* A hack to preserve kernel<->userspace interface. |
---|
| 4338 | + * Before Linux v4.12 this code accepted ndmsg since iproute2 v3.3.0. |
---|
| 4339 | + * However, ndmsg is shorter than ifinfomsg thus nlmsg_parse() bails. |
---|
| 4340 | + * So, check for ndmsg with an optional u32 attribute (not used here). |
---|
| 4341 | + * Fortunately these sizes don't conflict with the size of ifinfomsg |
---|
| 4342 | + * with an optional attribute. |
---|
| 4343 | + */ |
---|
| 4344 | + if (nlmsg_len(nlh) != sizeof(struct ndmsg) && |
---|
| 4345 | + (nlmsg_len(nlh) != sizeof(struct ndmsg) + |
---|
| 4346 | + nla_attr_size(sizeof(u32)))) { |
---|
| 4347 | + struct ifinfomsg *ifm; |
---|
| 4348 | + |
---|
| 4349 | + err = nlmsg_parse_deprecated(nlh, sizeof(struct ifinfomsg), |
---|
| 4350 | + tb, IFLA_MAX, ifla_policy, |
---|
| 4351 | + extack); |
---|
| 4352 | + if (err < 0) { |
---|
| 4353 | + return -EINVAL; |
---|
| 4354 | + } else if (err == 0) { |
---|
| 4355 | + if (tb[IFLA_MASTER]) |
---|
| 4356 | + *br_idx = nla_get_u32(tb[IFLA_MASTER]); |
---|
| 4357 | + } |
---|
| 4358 | + |
---|
| 4359 | + ifm = nlmsg_data(nlh); |
---|
| 4360 | + *brport_idx = ifm->ifi_index; |
---|
| 4361 | + } |
---|
| 4362 | + return 0; |
---|
| 4363 | +} |
---|
| 4364 | + |
---|
3790 | 4365 | static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) |
---|
3791 | 4366 | { |
---|
3792 | 4367 | struct net_device *dev; |
---|
3793 | | - struct nlattr *tb[IFLA_MAX+1]; |
---|
3794 | 4368 | struct net_device *br_dev = NULL; |
---|
3795 | 4369 | const struct net_device_ops *ops = NULL; |
---|
3796 | 4370 | const struct net_device_ops *cops = NULL; |
---|
3797 | | - struct ifinfomsg *ifm = nlmsg_data(cb->nlh); |
---|
3798 | 4371 | struct net *net = sock_net(skb->sk); |
---|
3799 | 4372 | struct hlist_head *head; |
---|
3800 | 4373 | int brport_idx = 0; |
---|
.. | .. |
---|
3804 | 4377 | int err = 0; |
---|
3805 | 4378 | int fidx = 0; |
---|
3806 | 4379 | |
---|
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 | | - } |
---|
| 4380 | + if (cb->strict_check) |
---|
| 4381 | + err = valid_fdb_dump_strict(cb->nlh, &br_idx, &brport_idx, |
---|
| 4382 | + cb->extack); |
---|
| 4383 | + else |
---|
| 4384 | + err = valid_fdb_dump_legacy(cb->nlh, &br_idx, &brport_idx, |
---|
| 4385 | + cb->extack); |
---|
| 4386 | + if (err < 0) |
---|
| 4387 | + return err; |
---|
3828 | 4388 | |
---|
3829 | 4389 | if (br_idx) { |
---|
3830 | 4390 | br_dev = __dev_get_by_index(net, br_idx); |
---|
.. | .. |
---|
3846 | 4406 | continue; |
---|
3847 | 4407 | |
---|
3848 | 4408 | if (!br_idx) { /* user did not specify a specific bridge */ |
---|
3849 | | - if (dev->priv_flags & IFF_BRIDGE_PORT) { |
---|
| 4409 | + if (netif_is_bridge_port(dev)) { |
---|
3850 | 4410 | br_dev = netdev_master_upper_dev_get(dev); |
---|
3851 | 4411 | cops = br_dev->netdev_ops; |
---|
3852 | 4412 | } |
---|
3853 | 4413 | } else { |
---|
3854 | 4414 | if (dev != br_dev && |
---|
3855 | | - !(dev->priv_flags & IFF_BRIDGE_PORT)) |
---|
| 4415 | + !netif_is_bridge_port(dev)) |
---|
3856 | 4416 | continue; |
---|
3857 | 4417 | |
---|
3858 | 4418 | if (br_dev != netdev_master_upper_dev_get(dev) && |
---|
.. | .. |
---|
3864 | 4424 | if (idx < s_idx) |
---|
3865 | 4425 | goto cont; |
---|
3866 | 4426 | |
---|
3867 | | - if (dev->priv_flags & IFF_BRIDGE_PORT) { |
---|
| 4427 | + if (netif_is_bridge_port(dev)) { |
---|
3868 | 4428 | if (cops && cops->ndo_fdb_dump) { |
---|
3869 | 4429 | err = cops->ndo_fdb_dump(skb, cb, |
---|
3870 | 4430 | br_dev, dev, |
---|
.. | .. |
---|
3900 | 4460 | cb->args[2] = fidx; |
---|
3901 | 4461 | |
---|
3902 | 4462 | return skb->len; |
---|
| 4463 | +} |
---|
| 4464 | + |
---|
| 4465 | +static int valid_fdb_get_strict(const struct nlmsghdr *nlh, |
---|
| 4466 | + struct nlattr **tb, u8 *ndm_flags, |
---|
| 4467 | + int *br_idx, int *brport_idx, u8 **addr, |
---|
| 4468 | + u16 *vid, struct netlink_ext_ack *extack) |
---|
| 4469 | +{ |
---|
| 4470 | + struct ndmsg *ndm; |
---|
| 4471 | + int err, i; |
---|
| 4472 | + |
---|
| 4473 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) { |
---|
| 4474 | + NL_SET_ERR_MSG(extack, "Invalid header for fdb get request"); |
---|
| 4475 | + return -EINVAL; |
---|
| 4476 | + } |
---|
| 4477 | + |
---|
| 4478 | + ndm = nlmsg_data(nlh); |
---|
| 4479 | + if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state || |
---|
| 4480 | + ndm->ndm_type) { |
---|
| 4481 | + NL_SET_ERR_MSG(extack, "Invalid values in header for fdb get request"); |
---|
| 4482 | + return -EINVAL; |
---|
| 4483 | + } |
---|
| 4484 | + |
---|
| 4485 | + if (ndm->ndm_flags & ~(NTF_MASTER | NTF_SELF)) { |
---|
| 4486 | + NL_SET_ERR_MSG(extack, "Invalid flags in header for fdb get request"); |
---|
| 4487 | + return -EINVAL; |
---|
| 4488 | + } |
---|
| 4489 | + |
---|
| 4490 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb, |
---|
| 4491 | + NDA_MAX, nda_policy, extack); |
---|
| 4492 | + if (err < 0) |
---|
| 4493 | + return err; |
---|
| 4494 | + |
---|
| 4495 | + *ndm_flags = ndm->ndm_flags; |
---|
| 4496 | + *brport_idx = ndm->ndm_ifindex; |
---|
| 4497 | + for (i = 0; i <= NDA_MAX; ++i) { |
---|
| 4498 | + if (!tb[i]) |
---|
| 4499 | + continue; |
---|
| 4500 | + |
---|
| 4501 | + switch (i) { |
---|
| 4502 | + case NDA_MASTER: |
---|
| 4503 | + *br_idx = nla_get_u32(tb[i]); |
---|
| 4504 | + break; |
---|
| 4505 | + case NDA_LLADDR: |
---|
| 4506 | + if (nla_len(tb[i]) != ETH_ALEN) { |
---|
| 4507 | + NL_SET_ERR_MSG(extack, "Invalid address in fdb get request"); |
---|
| 4508 | + return -EINVAL; |
---|
| 4509 | + } |
---|
| 4510 | + *addr = nla_data(tb[i]); |
---|
| 4511 | + break; |
---|
| 4512 | + case NDA_VLAN: |
---|
| 4513 | + err = fdb_vid_parse(tb[i], vid, extack); |
---|
| 4514 | + if (err) |
---|
| 4515 | + return err; |
---|
| 4516 | + break; |
---|
| 4517 | + case NDA_VNI: |
---|
| 4518 | + break; |
---|
| 4519 | + default: |
---|
| 4520 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in fdb get request"); |
---|
| 4521 | + return -EINVAL; |
---|
| 4522 | + } |
---|
| 4523 | + } |
---|
| 4524 | + |
---|
| 4525 | + return 0; |
---|
| 4526 | +} |
---|
| 4527 | + |
---|
| 4528 | +static int rtnl_fdb_get(struct sk_buff *in_skb, struct nlmsghdr *nlh, |
---|
| 4529 | + struct netlink_ext_ack *extack) |
---|
| 4530 | +{ |
---|
| 4531 | + struct net_device *dev = NULL, *br_dev = NULL; |
---|
| 4532 | + const struct net_device_ops *ops = NULL; |
---|
| 4533 | + struct net *net = sock_net(in_skb->sk); |
---|
| 4534 | + struct nlattr *tb[NDA_MAX + 1]; |
---|
| 4535 | + struct sk_buff *skb; |
---|
| 4536 | + int brport_idx = 0; |
---|
| 4537 | + u8 ndm_flags = 0; |
---|
| 4538 | + int br_idx = 0; |
---|
| 4539 | + u8 *addr = NULL; |
---|
| 4540 | + u16 vid = 0; |
---|
| 4541 | + int err; |
---|
| 4542 | + |
---|
| 4543 | + err = valid_fdb_get_strict(nlh, tb, &ndm_flags, &br_idx, |
---|
| 4544 | + &brport_idx, &addr, &vid, extack); |
---|
| 4545 | + if (err < 0) |
---|
| 4546 | + return err; |
---|
| 4547 | + |
---|
| 4548 | + if (!addr) { |
---|
| 4549 | + NL_SET_ERR_MSG(extack, "Missing lookup address for fdb get request"); |
---|
| 4550 | + return -EINVAL; |
---|
| 4551 | + } |
---|
| 4552 | + |
---|
| 4553 | + if (brport_idx) { |
---|
| 4554 | + dev = __dev_get_by_index(net, brport_idx); |
---|
| 4555 | + if (!dev) { |
---|
| 4556 | + NL_SET_ERR_MSG(extack, "Unknown device ifindex"); |
---|
| 4557 | + return -ENODEV; |
---|
| 4558 | + } |
---|
| 4559 | + } |
---|
| 4560 | + |
---|
| 4561 | + if (br_idx) { |
---|
| 4562 | + if (dev) { |
---|
| 4563 | + NL_SET_ERR_MSG(extack, "Master and device are mutually exclusive"); |
---|
| 4564 | + return -EINVAL; |
---|
| 4565 | + } |
---|
| 4566 | + |
---|
| 4567 | + br_dev = __dev_get_by_index(net, br_idx); |
---|
| 4568 | + if (!br_dev) { |
---|
| 4569 | + NL_SET_ERR_MSG(extack, "Invalid master ifindex"); |
---|
| 4570 | + return -EINVAL; |
---|
| 4571 | + } |
---|
| 4572 | + ops = br_dev->netdev_ops; |
---|
| 4573 | + } |
---|
| 4574 | + |
---|
| 4575 | + if (dev) { |
---|
| 4576 | + if (!ndm_flags || (ndm_flags & NTF_MASTER)) { |
---|
| 4577 | + if (!netif_is_bridge_port(dev)) { |
---|
| 4578 | + NL_SET_ERR_MSG(extack, "Device is not a bridge port"); |
---|
| 4579 | + return -EINVAL; |
---|
| 4580 | + } |
---|
| 4581 | + br_dev = netdev_master_upper_dev_get(dev); |
---|
| 4582 | + if (!br_dev) { |
---|
| 4583 | + NL_SET_ERR_MSG(extack, "Master of device not found"); |
---|
| 4584 | + return -EINVAL; |
---|
| 4585 | + } |
---|
| 4586 | + ops = br_dev->netdev_ops; |
---|
| 4587 | + } else { |
---|
| 4588 | + if (!(ndm_flags & NTF_SELF)) { |
---|
| 4589 | + NL_SET_ERR_MSG(extack, "Missing NTF_SELF"); |
---|
| 4590 | + return -EINVAL; |
---|
| 4591 | + } |
---|
| 4592 | + ops = dev->netdev_ops; |
---|
| 4593 | + } |
---|
| 4594 | + } |
---|
| 4595 | + |
---|
| 4596 | + if (!br_dev && !dev) { |
---|
| 4597 | + NL_SET_ERR_MSG(extack, "No device specified"); |
---|
| 4598 | + return -ENODEV; |
---|
| 4599 | + } |
---|
| 4600 | + |
---|
| 4601 | + if (!ops || !ops->ndo_fdb_get) { |
---|
| 4602 | + NL_SET_ERR_MSG(extack, "Fdb get operation not supported by device"); |
---|
| 4603 | + return -EOPNOTSUPP; |
---|
| 4604 | + } |
---|
| 4605 | + |
---|
| 4606 | + skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
---|
| 4607 | + if (!skb) |
---|
| 4608 | + return -ENOBUFS; |
---|
| 4609 | + |
---|
| 4610 | + if (br_dev) |
---|
| 4611 | + dev = br_dev; |
---|
| 4612 | + err = ops->ndo_fdb_get(skb, tb, dev, addr, vid, |
---|
| 4613 | + NETLINK_CB(in_skb).portid, |
---|
| 4614 | + nlh->nlmsg_seq, extack); |
---|
| 4615 | + if (err) |
---|
| 4616 | + goto out; |
---|
| 4617 | + |
---|
| 4618 | + return rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); |
---|
| 4619 | +out: |
---|
| 4620 | + kfree_skb(skb); |
---|
| 4621 | + return err; |
---|
3903 | 4622 | } |
---|
3904 | 4623 | |
---|
3905 | 4624 | static int brport_nla_put_flag(struct sk_buff *skb, u32 flags, u32 mask, |
---|
.. | .. |
---|
3950 | 4669 | nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev)))) |
---|
3951 | 4670 | goto nla_put_failure; |
---|
3952 | 4671 | |
---|
3953 | | - br_afspec = nla_nest_start(skb, IFLA_AF_SPEC); |
---|
| 4672 | + br_afspec = nla_nest_start_noflag(skb, IFLA_AF_SPEC); |
---|
3954 | 4673 | if (!br_afspec) |
---|
3955 | 4674 | goto nla_put_failure; |
---|
3956 | 4675 | |
---|
.. | .. |
---|
3974 | 4693 | } |
---|
3975 | 4694 | nla_nest_end(skb, br_afspec); |
---|
3976 | 4695 | |
---|
3977 | | - protinfo = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); |
---|
| 4696 | + protinfo = nla_nest_start(skb, IFLA_PROTINFO); |
---|
3978 | 4697 | if (!protinfo) |
---|
3979 | 4698 | goto nla_put_failure; |
---|
3980 | 4699 | |
---|
.. | .. |
---|
3994 | 4713 | brport_nla_put_flag(skb, flags, mask, |
---|
3995 | 4714 | IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD) || |
---|
3996 | 4715 | brport_nla_put_flag(skb, flags, mask, |
---|
3997 | | - IFLA_BRPORT_PROXYARP, BR_PROXYARP)) { |
---|
| 4716 | + IFLA_BRPORT_PROXYARP, BR_PROXYARP) || |
---|
| 4717 | + brport_nla_put_flag(skb, flags, mask, |
---|
| 4718 | + IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD) || |
---|
| 4719 | + brport_nla_put_flag(skb, flags, mask, |
---|
| 4720 | + IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD)) { |
---|
3998 | 4721 | nla_nest_cancel(skb, protinfo); |
---|
3999 | 4722 | goto nla_put_failure; |
---|
4000 | 4723 | } |
---|
.. | .. |
---|
4009 | 4732 | } |
---|
4010 | 4733 | EXPORT_SYMBOL_GPL(ndo_dflt_bridge_getlink); |
---|
4011 | 4734 | |
---|
| 4735 | +static int valid_bridge_getlink_req(const struct nlmsghdr *nlh, |
---|
| 4736 | + bool strict_check, u32 *filter_mask, |
---|
| 4737 | + struct netlink_ext_ack *extack) |
---|
| 4738 | +{ |
---|
| 4739 | + struct nlattr *tb[IFLA_MAX+1]; |
---|
| 4740 | + int err, i; |
---|
| 4741 | + |
---|
| 4742 | + if (strict_check) { |
---|
| 4743 | + struct ifinfomsg *ifm; |
---|
| 4744 | + |
---|
| 4745 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
---|
| 4746 | + NL_SET_ERR_MSG(extack, "Invalid header for bridge link dump"); |
---|
| 4747 | + return -EINVAL; |
---|
| 4748 | + } |
---|
| 4749 | + |
---|
| 4750 | + ifm = nlmsg_data(nlh); |
---|
| 4751 | + if (ifm->__ifi_pad || ifm->ifi_type || ifm->ifi_flags || |
---|
| 4752 | + ifm->ifi_change || ifm->ifi_index) { |
---|
| 4753 | + NL_SET_ERR_MSG(extack, "Invalid values in header for bridge link dump request"); |
---|
| 4754 | + return -EINVAL; |
---|
| 4755 | + } |
---|
| 4756 | + |
---|
| 4757 | + err = nlmsg_parse_deprecated_strict(nlh, |
---|
| 4758 | + sizeof(struct ifinfomsg), |
---|
| 4759 | + tb, IFLA_MAX, ifla_policy, |
---|
| 4760 | + extack); |
---|
| 4761 | + } else { |
---|
| 4762 | + err = nlmsg_parse_deprecated(nlh, sizeof(struct ifinfomsg), |
---|
| 4763 | + tb, IFLA_MAX, ifla_policy, |
---|
| 4764 | + extack); |
---|
| 4765 | + } |
---|
| 4766 | + if (err < 0) |
---|
| 4767 | + return err; |
---|
| 4768 | + |
---|
| 4769 | + /* new attributes should only be added with strict checking */ |
---|
| 4770 | + for (i = 0; i <= IFLA_MAX; ++i) { |
---|
| 4771 | + if (!tb[i]) |
---|
| 4772 | + continue; |
---|
| 4773 | + |
---|
| 4774 | + switch (i) { |
---|
| 4775 | + case IFLA_EXT_MASK: |
---|
| 4776 | + *filter_mask = nla_get_u32(tb[i]); |
---|
| 4777 | + break; |
---|
| 4778 | + default: |
---|
| 4779 | + if (strict_check) { |
---|
| 4780 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in bridge link dump request"); |
---|
| 4781 | + return -EINVAL; |
---|
| 4782 | + } |
---|
| 4783 | + } |
---|
| 4784 | + } |
---|
| 4785 | + |
---|
| 4786 | + return 0; |
---|
| 4787 | +} |
---|
| 4788 | + |
---|
4012 | 4789 | static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb) |
---|
4013 | 4790 | { |
---|
| 4791 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
4014 | 4792 | struct net *net = sock_net(skb->sk); |
---|
4015 | 4793 | struct net_device *dev; |
---|
4016 | 4794 | int idx = 0; |
---|
4017 | 4795 | u32 portid = NETLINK_CB(cb->skb).portid; |
---|
4018 | | - u32 seq = cb->nlh->nlmsg_seq; |
---|
| 4796 | + u32 seq = nlh->nlmsg_seq; |
---|
4019 | 4797 | u32 filter_mask = 0; |
---|
4020 | 4798 | int err; |
---|
4021 | 4799 | |
---|
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 | | - } |
---|
| 4800 | + err = valid_bridge_getlink_req(nlh, cb->strict_check, &filter_mask, |
---|
| 4801 | + cb->extack); |
---|
| 4802 | + if (err < 0 && cb->strict_check) |
---|
| 4803 | + return err; |
---|
4034 | 4804 | |
---|
4035 | 4805 | rcu_read_lock(); |
---|
4036 | 4806 | for_each_netdev_rcu(net, dev) { |
---|
.. | .. |
---|
4154 | 4924 | br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); |
---|
4155 | 4925 | if (br_spec) { |
---|
4156 | 4926 | nla_for_each_nested(attr, br_spec, rem) { |
---|
4157 | | - if (nla_type(attr) == IFLA_BRIDGE_FLAGS) { |
---|
| 4927 | + if (nla_type(attr) == IFLA_BRIDGE_FLAGS && !have_flags) { |
---|
4158 | 4928 | if (nla_len(attr) < sizeof(flags)) |
---|
4159 | 4929 | return -EINVAL; |
---|
4160 | 4930 | |
---|
4161 | 4931 | have_flags = true; |
---|
4162 | 4932 | flags = nla_get_u16(attr); |
---|
4163 | | - break; |
---|
| 4933 | + } |
---|
| 4934 | + |
---|
| 4935 | + if (nla_type(attr) == IFLA_BRIDGE_MODE) { |
---|
| 4936 | + if (nla_len(attr) < sizeof(u16)) |
---|
| 4937 | + return -EINVAL; |
---|
4164 | 4938 | } |
---|
4165 | 4939 | } |
---|
4166 | 4940 | } |
---|
.. | .. |
---|
4173 | 4947 | goto out; |
---|
4174 | 4948 | } |
---|
4175 | 4949 | |
---|
4176 | | - err = br_dev->netdev_ops->ndo_bridge_setlink(dev, nlh, flags); |
---|
| 4950 | + err = br_dev->netdev_ops->ndo_bridge_setlink(dev, nlh, flags, |
---|
| 4951 | + extack); |
---|
4177 | 4952 | if (err) |
---|
4178 | 4953 | goto out; |
---|
4179 | 4954 | |
---|
.. | .. |
---|
4185 | 4960 | err = -EOPNOTSUPP; |
---|
4186 | 4961 | else |
---|
4187 | 4962 | err = dev->netdev_ops->ndo_bridge_setlink(dev, nlh, |
---|
4188 | | - flags); |
---|
| 4963 | + flags, |
---|
| 4964 | + extack); |
---|
4189 | 4965 | if (!err) { |
---|
4190 | 4966 | flags &= ~BRIDGE_FLAGS_SELF; |
---|
4191 | 4967 | |
---|
.. | .. |
---|
4411 | 5187 | |
---|
4412 | 5188 | if (ops && ops->fill_linkxstats) { |
---|
4413 | 5189 | *idxattr = IFLA_STATS_LINK_XSTATS; |
---|
4414 | | - attr = nla_nest_start(skb, |
---|
4415 | | - IFLA_STATS_LINK_XSTATS); |
---|
| 5190 | + attr = nla_nest_start_noflag(skb, |
---|
| 5191 | + IFLA_STATS_LINK_XSTATS); |
---|
4416 | 5192 | if (!attr) |
---|
4417 | 5193 | goto nla_put_failure; |
---|
4418 | 5194 | |
---|
.. | .. |
---|
4434 | 5210 | ops = master->rtnl_link_ops; |
---|
4435 | 5211 | if (ops && ops->fill_linkxstats) { |
---|
4436 | 5212 | *idxattr = IFLA_STATS_LINK_XSTATS_SLAVE; |
---|
4437 | | - attr = nla_nest_start(skb, |
---|
4438 | | - IFLA_STATS_LINK_XSTATS_SLAVE); |
---|
| 5213 | + attr = nla_nest_start_noflag(skb, |
---|
| 5214 | + IFLA_STATS_LINK_XSTATS_SLAVE); |
---|
4439 | 5215 | if (!attr) |
---|
4440 | 5216 | goto nla_put_failure; |
---|
4441 | 5217 | |
---|
.. | .. |
---|
4450 | 5226 | if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_OFFLOAD_XSTATS, |
---|
4451 | 5227 | *idxattr)) { |
---|
4452 | 5228 | *idxattr = IFLA_STATS_LINK_OFFLOAD_XSTATS; |
---|
4453 | | - attr = nla_nest_start(skb, IFLA_STATS_LINK_OFFLOAD_XSTATS); |
---|
| 5229 | + attr = nla_nest_start_noflag(skb, |
---|
| 5230 | + IFLA_STATS_LINK_OFFLOAD_XSTATS); |
---|
4454 | 5231 | if (!attr) |
---|
4455 | 5232 | goto nla_put_failure; |
---|
4456 | 5233 | |
---|
.. | .. |
---|
4469 | 5246 | struct rtnl_af_ops *af_ops; |
---|
4470 | 5247 | |
---|
4471 | 5248 | *idxattr = IFLA_STATS_AF_SPEC; |
---|
4472 | | - attr = nla_nest_start(skb, IFLA_STATS_AF_SPEC); |
---|
| 5249 | + attr = nla_nest_start_noflag(skb, IFLA_STATS_AF_SPEC); |
---|
4473 | 5250 | if (!attr) |
---|
4474 | 5251 | goto nla_put_failure; |
---|
4475 | 5252 | |
---|
.. | .. |
---|
4479 | 5256 | struct nlattr *af; |
---|
4480 | 5257 | int err; |
---|
4481 | 5258 | |
---|
4482 | | - af = nla_nest_start(skb, af_ops->family); |
---|
| 5259 | + af = nla_nest_start_noflag(skb, |
---|
| 5260 | + af_ops->family); |
---|
4483 | 5261 | if (!af) { |
---|
4484 | 5262 | rcu_read_unlock(); |
---|
4485 | 5263 | goto nla_put_failure; |
---|
.. | .. |
---|
4581 | 5359 | return size; |
---|
4582 | 5360 | } |
---|
4583 | 5361 | |
---|
| 5362 | +static int rtnl_valid_stats_req(const struct nlmsghdr *nlh, bool strict_check, |
---|
| 5363 | + bool is_dump, struct netlink_ext_ack *extack) |
---|
| 5364 | +{ |
---|
| 5365 | + struct if_stats_msg *ifsm; |
---|
| 5366 | + |
---|
| 5367 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifsm))) { |
---|
| 5368 | + NL_SET_ERR_MSG(extack, "Invalid header for stats dump"); |
---|
| 5369 | + return -EINVAL; |
---|
| 5370 | + } |
---|
| 5371 | + |
---|
| 5372 | + if (!strict_check) |
---|
| 5373 | + return 0; |
---|
| 5374 | + |
---|
| 5375 | + ifsm = nlmsg_data(nlh); |
---|
| 5376 | + |
---|
| 5377 | + /* only requests using strict checks can pass data to influence |
---|
| 5378 | + * the dump. The legacy exception is filter_mask. |
---|
| 5379 | + */ |
---|
| 5380 | + if (ifsm->pad1 || ifsm->pad2 || (is_dump && ifsm->ifindex)) { |
---|
| 5381 | + NL_SET_ERR_MSG(extack, "Invalid values in header for stats dump request"); |
---|
| 5382 | + return -EINVAL; |
---|
| 5383 | + } |
---|
| 5384 | + if (nlmsg_attrlen(nlh, sizeof(*ifsm))) { |
---|
| 5385 | + NL_SET_ERR_MSG(extack, "Invalid attributes after stats header"); |
---|
| 5386 | + return -EINVAL; |
---|
| 5387 | + } |
---|
| 5388 | + if (ifsm->filter_mask >= IFLA_STATS_FILTER_BIT(IFLA_STATS_MAX + 1)) { |
---|
| 5389 | + NL_SET_ERR_MSG(extack, "Invalid stats requested through filter mask"); |
---|
| 5390 | + return -EINVAL; |
---|
| 5391 | + } |
---|
| 5392 | + |
---|
| 5393 | + return 0; |
---|
| 5394 | +} |
---|
| 5395 | + |
---|
4584 | 5396 | static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
4585 | 5397 | struct netlink_ext_ack *extack) |
---|
4586 | 5398 | { |
---|
.. | .. |
---|
4592 | 5404 | u32 filter_mask; |
---|
4593 | 5405 | int err; |
---|
4594 | 5406 | |
---|
4595 | | - if (nlmsg_len(nlh) < sizeof(*ifsm)) |
---|
4596 | | - return -EINVAL; |
---|
| 5407 | + err = rtnl_valid_stats_req(nlh, netlink_strict_get_check(skb), |
---|
| 5408 | + false, extack); |
---|
| 5409 | + if (err) |
---|
| 5410 | + return err; |
---|
4597 | 5411 | |
---|
4598 | 5412 | ifsm = nlmsg_data(nlh); |
---|
4599 | 5413 | if (ifsm->ifindex > 0) |
---|
.. | .. |
---|
4628 | 5442 | |
---|
4629 | 5443 | static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb) |
---|
4630 | 5444 | { |
---|
| 5445 | + struct netlink_ext_ack *extack = cb->extack; |
---|
4631 | 5446 | int h, s_h, err, s_idx, s_idxattr, s_prividx; |
---|
4632 | 5447 | struct net *net = sock_net(skb->sk); |
---|
4633 | 5448 | unsigned int flags = NLM_F_MULTI; |
---|
.. | .. |
---|
4644 | 5459 | |
---|
4645 | 5460 | cb->seq = net->dev_base_seq; |
---|
4646 | 5461 | |
---|
4647 | | - if (nlmsg_len(cb->nlh) < sizeof(*ifsm)) |
---|
4648 | | - return -EINVAL; |
---|
| 5462 | + err = rtnl_valid_stats_req(cb->nlh, cb->strict_check, true, extack); |
---|
| 5463 | + if (err) |
---|
| 5464 | + return err; |
---|
4649 | 5465 | |
---|
4650 | 5466 | ifsm = nlmsg_data(cb->nlh); |
---|
4651 | 5467 | filter_mask = ifsm->filter_mask; |
---|
4652 | | - if (!filter_mask) |
---|
| 5468 | + if (!filter_mask) { |
---|
| 5469 | + NL_SET_ERR_MSG(extack, "Filter mask must be set for stats dump"); |
---|
4653 | 5470 | return -EINVAL; |
---|
| 5471 | + } |
---|
4654 | 5472 | |
---|
4655 | 5473 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
---|
4656 | 5474 | idx = 0; |
---|
.. | .. |
---|
4721 | 5539 | if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { |
---|
4722 | 5540 | struct sock *rtnl; |
---|
4723 | 5541 | rtnl_dumpit_func dumpit; |
---|
4724 | | - u16 min_dump_alloc = 0; |
---|
| 5542 | + u32 min_dump_alloc = 0; |
---|
4725 | 5543 | |
---|
4726 | 5544 | link = rtnl_get_link(family, type); |
---|
4727 | 5545 | if (!link || !link->dumpit) { |
---|
.. | .. |
---|
4898 | 5716 | rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, 0); |
---|
4899 | 5717 | rtnl_register(PF_UNSPEC, RTM_GETNETCONF, NULL, rtnl_dump_all, 0); |
---|
4900 | 5718 | |
---|
| 5719 | + rtnl_register(PF_UNSPEC, RTM_NEWLINKPROP, rtnl_newlinkprop, NULL, 0); |
---|
| 5720 | + rtnl_register(PF_UNSPEC, RTM_DELLINKPROP, rtnl_dellinkprop, NULL, 0); |
---|
| 5721 | + |
---|
4901 | 5722 | rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, rtnl_fdb_add, NULL, 0); |
---|
4902 | 5723 | rtnl_register(PF_BRIDGE, RTM_DELNEIGH, rtnl_fdb_del, NULL, 0); |
---|
4903 | | - rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, 0); |
---|
| 5724 | + rtnl_register(PF_BRIDGE, RTM_GETNEIGH, rtnl_fdb_get, rtnl_fdb_dump, 0); |
---|
4904 | 5725 | |
---|
4905 | 5726 | rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, 0); |
---|
4906 | 5727 | rtnl_register(PF_BRIDGE, RTM_DELLINK, rtnl_bridge_dellink, NULL, 0); |
---|