aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/rtnetlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r--net/core/rtnetlink.c113
1 files changed, 61 insertions, 52 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 120eecc0f5a4..d4ff41739b0f 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -822,6 +822,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
822 + nla_total_size(4) /* IFLA_NUM_RX_QUEUES */ 822 + nla_total_size(4) /* IFLA_NUM_RX_QUEUES */
823 + nla_total_size(1) /* IFLA_OPERSTATE */ 823 + nla_total_size(1) /* IFLA_OPERSTATE */
824 + nla_total_size(1) /* IFLA_LINKMODE */ 824 + nla_total_size(1) /* IFLA_LINKMODE */
825 + nla_total_size(4) /* IFLA_CARRIER_CHANGES */
825 + nla_total_size(ext_filter_mask 826 + nla_total_size(ext_filter_mask
826 & RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */ 827 & RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */
827 + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */ 828 + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */
@@ -970,7 +971,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
970 (dev->qdisc && 971 (dev->qdisc &&
971 nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) || 972 nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) ||
972 (dev->ifalias && 973 (dev->ifalias &&
973 nla_put_string(skb, IFLA_IFALIAS, dev->ifalias))) 974 nla_put_string(skb, IFLA_IFALIAS, dev->ifalias)) ||
975 nla_put_u32(skb, IFLA_CARRIER_CHANGES,
976 atomic_read(&dev->carrier_changes)))
974 goto nla_put_failure; 977 goto nla_put_failure;
975 978
976 if (1) { 979 if (1) {
@@ -1121,56 +1124,7 @@ nla_put_failure:
1121 return -EMSGSIZE; 1124 return -EMSGSIZE;
1122} 1125}
1123 1126
1124static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) 1127static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
1125{
1126 struct net *net = sock_net(skb->sk);
1127 int h, s_h;
1128 int idx = 0, s_idx;
1129 struct net_device *dev;
1130 struct hlist_head *head;
1131 struct nlattr *tb[IFLA_MAX+1];
1132 u32 ext_filter_mask = 0;
1133
1134 s_h = cb->args[0];
1135 s_idx = cb->args[1];
1136
1137 rcu_read_lock();
1138 cb->seq = net->dev_base_seq;
1139
1140 if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
1141 ifla_policy) >= 0) {
1142
1143 if (tb[IFLA_EXT_MASK])
1144 ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
1145 }
1146
1147 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1148 idx = 0;
1149 head = &net->dev_index_head[h];
1150 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1151 if (idx < s_idx)
1152 goto cont;
1153 if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
1154 NETLINK_CB(cb->skb).portid,
1155 cb->nlh->nlmsg_seq, 0,
1156 NLM_F_MULTI,
1157 ext_filter_mask) <= 0)
1158 goto out;
1159
1160 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1161cont:
1162 idx++;
1163 }
1164 }
1165out:
1166 rcu_read_unlock();
1167 cb->args[1] = idx;
1168 cb->args[0] = h;
1169
1170 return skb->len;
1171}
1172
1173const struct nla_policy ifla_policy[IFLA_MAX+1] = {
1174 [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 }, 1128 [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
1175 [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, 1129 [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1176 [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, 1130 [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
@@ -1196,8 +1150,8 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
1196 [IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 }, 1150 [IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 },
1197 [IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 }, 1151 [IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 },
1198 [IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN }, 1152 [IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
1153 [IFLA_CARRIER_CHANGES] = { .type = NLA_U32 }, /* ignored */
1199}; 1154};
1200EXPORT_SYMBOL(ifla_policy);
1201 1155
1202static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { 1156static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
1203 [IFLA_INFO_KIND] = { .type = NLA_STRING }, 1157 [IFLA_INFO_KIND] = { .type = NLA_STRING },
@@ -1235,6 +1189,61 @@ static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = {
1235 [IFLA_PORT_RESPONSE] = { .type = NLA_U16, }, 1189 [IFLA_PORT_RESPONSE] = { .type = NLA_U16, },
1236}; 1190};
1237 1191
1192static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1193{
1194 struct net *net = sock_net(skb->sk);
1195 int h, s_h;
1196 int idx = 0, s_idx;
1197 struct net_device *dev;
1198 struct hlist_head *head;
1199 struct nlattr *tb[IFLA_MAX+1];
1200 u32 ext_filter_mask = 0;
1201
1202 s_h = cb->args[0];
1203 s_idx = cb->args[1];
1204
1205 rcu_read_lock();
1206 cb->seq = net->dev_base_seq;
1207
1208 if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
1209 ifla_policy) >= 0) {
1210
1211 if (tb[IFLA_EXT_MASK])
1212 ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
1213 }
1214
1215 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1216 idx = 0;
1217 head = &net->dev_index_head[h];
1218 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1219 if (idx < s_idx)
1220 goto cont;
1221 if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
1222 NETLINK_CB(cb->skb).portid,
1223 cb->nlh->nlmsg_seq, 0,
1224 NLM_F_MULTI,
1225 ext_filter_mask) <= 0)
1226 goto out;
1227
1228 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1229cont:
1230 idx++;
1231 }
1232 }
1233out:
1234 rcu_read_unlock();
1235 cb->args[1] = idx;
1236 cb->args[0] = h;
1237
1238 return skb->len;
1239}
1240
1241int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len)
1242{
1243 return nla_parse(tb, IFLA_MAX, head, len, ifla_policy);
1244}
1245EXPORT_SYMBOL(rtnl_nla_parse_ifla);
1246
1238struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) 1247struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
1239{ 1248{
1240 struct net *net; 1249 struct net *net;