diff options
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 214 |
1 files changed, 149 insertions, 65 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 1868625af25e..d8aa20f6a46e 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -780,6 +780,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, | |||
780 | + nla_total_size(4) /* IFLA_MTU */ | 780 | + nla_total_size(4) /* IFLA_MTU */ |
781 | + nla_total_size(4) /* IFLA_LINK */ | 781 | + nla_total_size(4) /* IFLA_LINK */ |
782 | + nla_total_size(4) /* IFLA_MASTER */ | 782 | + nla_total_size(4) /* IFLA_MASTER */ |
783 | + nla_total_size(1) /* IFLA_CARRIER */ | ||
783 | + nla_total_size(4) /* IFLA_PROMISCUITY */ | 784 | + nla_total_size(4) /* IFLA_PROMISCUITY */ |
784 | + nla_total_size(4) /* IFLA_NUM_TX_QUEUES */ | 785 | + nla_total_size(4) /* IFLA_NUM_TX_QUEUES */ |
785 | + nla_total_size(4) /* IFLA_NUM_RX_QUEUES */ | 786 | + nla_total_size(4) /* IFLA_NUM_RX_QUEUES */ |
@@ -879,6 +880,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
879 | const struct rtnl_link_stats64 *stats; | 880 | const struct rtnl_link_stats64 *stats; |
880 | struct nlattr *attr, *af_spec; | 881 | struct nlattr *attr, *af_spec; |
881 | struct rtnl_af_ops *af_ops; | 882 | struct rtnl_af_ops *af_ops; |
883 | struct net_device *upper_dev = netdev_master_upper_dev_get(dev); | ||
882 | 884 | ||
883 | ASSERT_RTNL(); | 885 | ASSERT_RTNL(); |
884 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); | 886 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); |
@@ -907,8 +909,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
907 | #endif | 909 | #endif |
908 | (dev->ifindex != dev->iflink && | 910 | (dev->ifindex != dev->iflink && |
909 | nla_put_u32(skb, IFLA_LINK, dev->iflink)) || | 911 | nla_put_u32(skb, IFLA_LINK, dev->iflink)) || |
910 | (dev->master && | 912 | (upper_dev && |
911 | nla_put_u32(skb, IFLA_MASTER, dev->master->ifindex)) || | 913 | nla_put_u32(skb, IFLA_MASTER, upper_dev->ifindex)) || |
914 | nla_put_u8(skb, IFLA_CARRIER, netif_carrier_ok(dev)) || | ||
912 | (dev->qdisc && | 915 | (dev->qdisc && |
913 | nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) || | 916 | nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) || |
914 | (dev->ifalias && | 917 | (dev->ifalias && |
@@ -1108,6 +1111,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
1108 | [IFLA_MTU] = { .type = NLA_U32 }, | 1111 | [IFLA_MTU] = { .type = NLA_U32 }, |
1109 | [IFLA_LINK] = { .type = NLA_U32 }, | 1112 | [IFLA_LINK] = { .type = NLA_U32 }, |
1110 | [IFLA_MASTER] = { .type = NLA_U32 }, | 1113 | [IFLA_MASTER] = { .type = NLA_U32 }, |
1114 | [IFLA_CARRIER] = { .type = NLA_U8 }, | ||
1111 | [IFLA_TXQLEN] = { .type = NLA_U32 }, | 1115 | [IFLA_TXQLEN] = { .type = NLA_U32 }, |
1112 | [IFLA_WEIGHT] = { .type = NLA_U32 }, | 1116 | [IFLA_WEIGHT] = { .type = NLA_U32 }, |
1113 | [IFLA_OPERSTATE] = { .type = NLA_U8 }, | 1117 | [IFLA_OPERSTATE] = { .type = NLA_U8 }, |
@@ -1270,16 +1274,16 @@ static int do_setvfinfo(struct net_device *dev, struct nlattr *attr) | |||
1270 | 1274 | ||
1271 | static int do_set_master(struct net_device *dev, int ifindex) | 1275 | static int do_set_master(struct net_device *dev, int ifindex) |
1272 | { | 1276 | { |
1273 | struct net_device *master_dev; | 1277 | struct net_device *upper_dev = netdev_master_upper_dev_get(dev); |
1274 | const struct net_device_ops *ops; | 1278 | const struct net_device_ops *ops; |
1275 | int err; | 1279 | int err; |
1276 | 1280 | ||
1277 | if (dev->master) { | 1281 | if (upper_dev) { |
1278 | if (dev->master->ifindex == ifindex) | 1282 | if (upper_dev->ifindex == ifindex) |
1279 | return 0; | 1283 | return 0; |
1280 | ops = dev->master->netdev_ops; | 1284 | ops = upper_dev->netdev_ops; |
1281 | if (ops->ndo_del_slave) { | 1285 | if (ops->ndo_del_slave) { |
1282 | err = ops->ndo_del_slave(dev->master, dev); | 1286 | err = ops->ndo_del_slave(upper_dev, dev); |
1283 | if (err) | 1287 | if (err) |
1284 | return err; | 1288 | return err; |
1285 | } else { | 1289 | } else { |
@@ -1288,12 +1292,12 @@ static int do_set_master(struct net_device *dev, int ifindex) | |||
1288 | } | 1292 | } |
1289 | 1293 | ||
1290 | if (ifindex) { | 1294 | if (ifindex) { |
1291 | master_dev = __dev_get_by_index(dev_net(dev), ifindex); | 1295 | upper_dev = __dev_get_by_index(dev_net(dev), ifindex); |
1292 | if (!master_dev) | 1296 | if (!upper_dev) |
1293 | return -EINVAL; | 1297 | return -EINVAL; |
1294 | ops = master_dev->netdev_ops; | 1298 | ops = upper_dev->netdev_ops; |
1295 | if (ops->ndo_add_slave) { | 1299 | if (ops->ndo_add_slave) { |
1296 | err = ops->ndo_add_slave(master_dev, dev); | 1300 | err = ops->ndo_add_slave(upper_dev, dev); |
1297 | if (err) | 1301 | if (err) |
1298 | return err; | 1302 | return err; |
1299 | } else { | 1303 | } else { |
@@ -1307,7 +1311,6 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1307 | struct nlattr **tb, char *ifname, int modified) | 1311 | struct nlattr **tb, char *ifname, int modified) |
1308 | { | 1312 | { |
1309 | const struct net_device_ops *ops = dev->netdev_ops; | 1313 | const struct net_device_ops *ops = dev->netdev_ops; |
1310 | int send_addr_notify = 0; | ||
1311 | int err; | 1314 | int err; |
1312 | 1315 | ||
1313 | if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { | 1316 | if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { |
@@ -1360,16 +1363,6 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1360 | struct sockaddr *sa; | 1363 | struct sockaddr *sa; |
1361 | int len; | 1364 | int len; |
1362 | 1365 | ||
1363 | if (!ops->ndo_set_mac_address) { | ||
1364 | err = -EOPNOTSUPP; | ||
1365 | goto errout; | ||
1366 | } | ||
1367 | |||
1368 | if (!netif_device_present(dev)) { | ||
1369 | err = -ENODEV; | ||
1370 | goto errout; | ||
1371 | } | ||
1372 | |||
1373 | len = sizeof(sa_family_t) + dev->addr_len; | 1366 | len = sizeof(sa_family_t) + dev->addr_len; |
1374 | sa = kmalloc(len, GFP_KERNEL); | 1367 | sa = kmalloc(len, GFP_KERNEL); |
1375 | if (!sa) { | 1368 | if (!sa) { |
@@ -1379,13 +1372,11 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1379 | sa->sa_family = dev->type; | 1372 | sa->sa_family = dev->type; |
1380 | memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]), | 1373 | memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]), |
1381 | dev->addr_len); | 1374 | dev->addr_len); |
1382 | err = ops->ndo_set_mac_address(dev, sa); | 1375 | err = dev_set_mac_address(dev, sa); |
1383 | kfree(sa); | 1376 | kfree(sa); |
1384 | if (err) | 1377 | if (err) |
1385 | goto errout; | 1378 | goto errout; |
1386 | send_addr_notify = 1; | ||
1387 | modified = 1; | 1379 | modified = 1; |
1388 | add_device_randomness(dev->dev_addr, dev->addr_len); | ||
1389 | } | 1380 | } |
1390 | 1381 | ||
1391 | if (tb[IFLA_MTU]) { | 1382 | if (tb[IFLA_MTU]) { |
@@ -1422,7 +1413,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1422 | 1413 | ||
1423 | if (tb[IFLA_BROADCAST]) { | 1414 | if (tb[IFLA_BROADCAST]) { |
1424 | nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); | 1415 | nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); |
1425 | send_addr_notify = 1; | 1416 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); |
1426 | } | 1417 | } |
1427 | 1418 | ||
1428 | if (ifm->ifi_flags || ifm->ifi_change) { | 1419 | if (ifm->ifi_flags || ifm->ifi_change) { |
@@ -1438,6 +1429,13 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1438 | modified = 1; | 1429 | modified = 1; |
1439 | } | 1430 | } |
1440 | 1431 | ||
1432 | if (tb[IFLA_CARRIER]) { | ||
1433 | err = dev_change_carrier(dev, nla_get_u8(tb[IFLA_CARRIER])); | ||
1434 | if (err) | ||
1435 | goto errout; | ||
1436 | modified = 1; | ||
1437 | } | ||
1438 | |||
1441 | if (tb[IFLA_TXQLEN]) | 1439 | if (tb[IFLA_TXQLEN]) |
1442 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); | 1440 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); |
1443 | 1441 | ||
@@ -1536,9 +1534,6 @@ errout: | |||
1536 | net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n", | 1534 | net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n", |
1537 | dev->name); | 1535 | dev->name); |
1538 | 1536 | ||
1539 | if (send_addr_notify) | ||
1540 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | ||
1541 | |||
1542 | return err; | 1537 | return err; |
1543 | } | 1538 | } |
1544 | 1539 | ||
@@ -1672,9 +1667,11 @@ struct net_device *rtnl_create_link(struct net *net, | |||
1672 | 1667 | ||
1673 | if (tb[IFLA_MTU]) | 1668 | if (tb[IFLA_MTU]) |
1674 | dev->mtu = nla_get_u32(tb[IFLA_MTU]); | 1669 | dev->mtu = nla_get_u32(tb[IFLA_MTU]); |
1675 | if (tb[IFLA_ADDRESS]) | 1670 | if (tb[IFLA_ADDRESS]) { |
1676 | memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), | 1671 | memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), |
1677 | nla_len(tb[IFLA_ADDRESS])); | 1672 | nla_len(tb[IFLA_ADDRESS])); |
1673 | dev->addr_assign_type = NET_ADDR_SET; | ||
1674 | } | ||
1678 | if (tb[IFLA_BROADCAST]) | 1675 | if (tb[IFLA_BROADCAST]) |
1679 | memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]), | 1676 | memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]), |
1680 | nla_len(tb[IFLA_BROADCAST])); | 1677 | nla_len(tb[IFLA_BROADCAST])); |
@@ -1992,6 +1989,7 @@ errout: | |||
1992 | if (err < 0) | 1989 | if (err < 0) |
1993 | rtnl_set_sk_err(net, RTNLGRP_LINK, err); | 1990 | rtnl_set_sk_err(net, RTNLGRP_LINK, err); |
1994 | } | 1991 | } |
1992 | EXPORT_SYMBOL(rtmsg_ifinfo); | ||
1995 | 1993 | ||
1996 | static int nlmsg_populate_fdb_fill(struct sk_buff *skb, | 1994 | static int nlmsg_populate_fdb_fill(struct sk_buff *skb, |
1997 | struct net_device *dev, | 1995 | struct net_device *dev, |
@@ -2054,16 +2052,12 @@ errout: | |||
2054 | static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2052 | static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
2055 | { | 2053 | { |
2056 | struct net *net = sock_net(skb->sk); | 2054 | struct net *net = sock_net(skb->sk); |
2057 | struct net_device *master = NULL; | ||
2058 | struct ndmsg *ndm; | 2055 | struct ndmsg *ndm; |
2059 | struct nlattr *tb[NDA_MAX+1]; | 2056 | struct nlattr *tb[NDA_MAX+1]; |
2060 | struct net_device *dev; | 2057 | struct net_device *dev; |
2061 | u8 *addr; | 2058 | u8 *addr; |
2062 | int err; | 2059 | int err; |
2063 | 2060 | ||
2064 | if (!capable(CAP_NET_ADMIN)) | ||
2065 | return -EPERM; | ||
2066 | |||
2067 | err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); | 2061 | err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); |
2068 | if (err < 0) | 2062 | if (err < 0) |
2069 | return err; | 2063 | return err; |
@@ -2096,10 +2090,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2096 | /* Support fdb on master device the net/bridge default case */ | 2090 | /* Support fdb on master device the net/bridge default case */ |
2097 | if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && | 2091 | if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && |
2098 | (dev->priv_flags & IFF_BRIDGE_PORT)) { | 2092 | (dev->priv_flags & IFF_BRIDGE_PORT)) { |
2099 | master = dev->master; | 2093 | struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
2100 | err = master->netdev_ops->ndo_fdb_add(ndm, tb, | 2094 | const struct net_device_ops *ops = br_dev->netdev_ops; |
2101 | dev, addr, | 2095 | |
2102 | nlh->nlmsg_flags); | 2096 | err = ops->ndo_fdb_add(ndm, tb, dev, addr, nlh->nlmsg_flags); |
2103 | if (err) | 2097 | if (err) |
2104 | goto out; | 2098 | goto out; |
2105 | else | 2099 | else |
@@ -2125,7 +2119,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2125 | { | 2119 | { |
2126 | struct net *net = sock_net(skb->sk); | 2120 | struct net *net = sock_net(skb->sk); |
2127 | struct ndmsg *ndm; | 2121 | struct ndmsg *ndm; |
2128 | struct nlattr *llattr; | 2122 | struct nlattr *tb[NDA_MAX+1]; |
2129 | struct net_device *dev; | 2123 | struct net_device *dev; |
2130 | int err = -EINVAL; | 2124 | int err = -EINVAL; |
2131 | __u8 *addr; | 2125 | __u8 *addr; |
@@ -2133,8 +2127,9 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2133 | if (!capable(CAP_NET_ADMIN)) | 2127 | if (!capable(CAP_NET_ADMIN)) |
2134 | return -EPERM; | 2128 | return -EPERM; |
2135 | 2129 | ||
2136 | if (nlmsg_len(nlh) < sizeof(*ndm)) | 2130 | err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); |
2137 | return -EINVAL; | 2131 | if (err < 0) |
2132 | return err; | ||
2138 | 2133 | ||
2139 | ndm = nlmsg_data(nlh); | 2134 | ndm = nlmsg_data(nlh); |
2140 | if (ndm->ndm_ifindex == 0) { | 2135 | if (ndm->ndm_ifindex == 0) { |
@@ -2148,22 +2143,27 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2148 | return -ENODEV; | 2143 | return -ENODEV; |
2149 | } | 2144 | } |
2150 | 2145 | ||
2151 | llattr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_LLADDR); | 2146 | if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) { |
2152 | if (llattr == NULL || nla_len(llattr) != ETH_ALEN) { | 2147 | pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid address\n"); |
2153 | pr_info("PF_BRIGDE: RTM_DELNEIGH with invalid address\n"); | 2148 | return -EINVAL; |
2149 | } | ||
2150 | |||
2151 | addr = nla_data(tb[NDA_LLADDR]); | ||
2152 | if (!is_valid_ether_addr(addr)) { | ||
2153 | pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid ether address\n"); | ||
2154 | return -EINVAL; | 2154 | return -EINVAL; |
2155 | } | 2155 | } |
2156 | 2156 | ||
2157 | addr = nla_data(llattr); | ||
2158 | err = -EOPNOTSUPP; | 2157 | err = -EOPNOTSUPP; |
2159 | 2158 | ||
2160 | /* Support fdb on master device the net/bridge default case */ | 2159 | /* Support fdb on master device the net/bridge default case */ |
2161 | if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && | 2160 | if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && |
2162 | (dev->priv_flags & IFF_BRIDGE_PORT)) { | 2161 | (dev->priv_flags & IFF_BRIDGE_PORT)) { |
2163 | struct net_device *master = dev->master; | 2162 | struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
2163 | const struct net_device_ops *ops = br_dev->netdev_ops; | ||
2164 | 2164 | ||
2165 | if (master->netdev_ops->ndo_fdb_del) | 2165 | if (ops->ndo_fdb_del) |
2166 | err = master->netdev_ops->ndo_fdb_del(ndm, dev, addr); | 2166 | err = ops->ndo_fdb_del(ndm, tb, dev, addr); |
2167 | 2167 | ||
2168 | if (err) | 2168 | if (err) |
2169 | goto out; | 2169 | goto out; |
@@ -2173,7 +2173,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2173 | 2173 | ||
2174 | /* Embedded bridge, macvlan, and any other device support */ | 2174 | /* Embedded bridge, macvlan, and any other device support */ |
2175 | if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) { | 2175 | if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) { |
2176 | err = dev->netdev_ops->ndo_fdb_del(ndm, dev, addr); | 2176 | err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr); |
2177 | 2177 | ||
2178 | if (!err) { | 2178 | if (!err) { |
2179 | rtnl_fdb_notify(dev, addr, RTM_DELNEIGH); | 2179 | rtnl_fdb_notify(dev, addr, RTM_DELNEIGH); |
@@ -2247,9 +2247,11 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
2247 | rcu_read_lock(); | 2247 | rcu_read_lock(); |
2248 | for_each_netdev_rcu(net, dev) { | 2248 | for_each_netdev_rcu(net, dev) { |
2249 | if (dev->priv_flags & IFF_BRIDGE_PORT) { | 2249 | if (dev->priv_flags & IFF_BRIDGE_PORT) { |
2250 | struct net_device *master = dev->master; | 2250 | struct net_device *br_dev; |
2251 | const struct net_device_ops *ops = master->netdev_ops; | 2251 | const struct net_device_ops *ops; |
2252 | 2252 | ||
2253 | br_dev = netdev_master_upper_dev_get(dev); | ||
2254 | ops = br_dev->netdev_ops; | ||
2253 | if (ops->ndo_fdb_dump) | 2255 | if (ops->ndo_fdb_dump) |
2254 | idx = ops->ndo_fdb_dump(skb, cb, dev, idx); | 2256 | idx = ops->ndo_fdb_dump(skb, cb, dev, idx); |
2255 | } | 2257 | } |
@@ -2270,6 +2272,7 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, | |||
2270 | struct ifinfomsg *ifm; | 2272 | struct ifinfomsg *ifm; |
2271 | struct nlattr *br_afspec; | 2273 | struct nlattr *br_afspec; |
2272 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; | 2274 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; |
2275 | struct net_device *br_dev = netdev_master_upper_dev_get(dev); | ||
2273 | 2276 | ||
2274 | nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*ifm), NLM_F_MULTI); | 2277 | nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*ifm), NLM_F_MULTI); |
2275 | if (nlh == NULL) | 2278 | if (nlh == NULL) |
@@ -2287,8 +2290,8 @@ int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, | |||
2287 | if (nla_put_string(skb, IFLA_IFNAME, dev->name) || | 2290 | if (nla_put_string(skb, IFLA_IFNAME, dev->name) || |
2288 | nla_put_u32(skb, IFLA_MTU, dev->mtu) || | 2291 | nla_put_u32(skb, IFLA_MTU, dev->mtu) || |
2289 | nla_put_u8(skb, IFLA_OPERSTATE, operstate) || | 2292 | nla_put_u8(skb, IFLA_OPERSTATE, operstate) || |
2290 | (dev->master && | 2293 | (br_dev && |
2291 | nla_put_u32(skb, IFLA_MASTER, dev->master->ifindex)) || | 2294 | nla_put_u32(skb, IFLA_MASTER, br_dev->ifindex)) || |
2292 | (dev->addr_len && | 2295 | (dev->addr_len && |
2293 | nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || | 2296 | nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || |
2294 | (dev->ifindex != dev->iflink && | 2297 | (dev->ifindex != dev->iflink && |
@@ -2320,23 +2323,31 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb) | |||
2320 | int idx = 0; | 2323 | int idx = 0; |
2321 | u32 portid = NETLINK_CB(cb->skb).portid; | 2324 | u32 portid = NETLINK_CB(cb->skb).portid; |
2322 | u32 seq = cb->nlh->nlmsg_seq; | 2325 | u32 seq = cb->nlh->nlmsg_seq; |
2326 | struct nlattr *extfilt; | ||
2327 | u32 filter_mask = 0; | ||
2328 | |||
2329 | extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct rtgenmsg), | ||
2330 | IFLA_EXT_MASK); | ||
2331 | if (extfilt) | ||
2332 | filter_mask = nla_get_u32(extfilt); | ||
2323 | 2333 | ||
2324 | rcu_read_lock(); | 2334 | rcu_read_lock(); |
2325 | for_each_netdev_rcu(net, dev) { | 2335 | for_each_netdev_rcu(net, dev) { |
2326 | const struct net_device_ops *ops = dev->netdev_ops; | 2336 | const struct net_device_ops *ops = dev->netdev_ops; |
2327 | struct net_device *master = dev->master; | 2337 | struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
2328 | 2338 | ||
2329 | if (master && master->netdev_ops->ndo_bridge_getlink) { | 2339 | if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) { |
2330 | if (idx >= cb->args[0] && | 2340 | if (idx >= cb->args[0] && |
2331 | master->netdev_ops->ndo_bridge_getlink( | 2341 | br_dev->netdev_ops->ndo_bridge_getlink( |
2332 | skb, portid, seq, dev) < 0) | 2342 | skb, portid, seq, dev, filter_mask) < 0) |
2333 | break; | 2343 | break; |
2334 | idx++; | 2344 | idx++; |
2335 | } | 2345 | } |
2336 | 2346 | ||
2337 | if (ops->ndo_bridge_getlink) { | 2347 | if (ops->ndo_bridge_getlink) { |
2338 | if (idx >= cb->args[0] && | 2348 | if (idx >= cb->args[0] && |
2339 | ops->ndo_bridge_getlink(skb, portid, seq, dev) < 0) | 2349 | ops->ndo_bridge_getlink(skb, portid, seq, dev, |
2350 | filter_mask) < 0) | ||
2340 | break; | 2351 | break; |
2341 | idx++; | 2352 | idx++; |
2342 | } | 2353 | } |
@@ -2365,7 +2376,7 @@ static inline size_t bridge_nlmsg_size(void) | |||
2365 | static int rtnl_bridge_notify(struct net_device *dev, u16 flags) | 2376 | static int rtnl_bridge_notify(struct net_device *dev, u16 flags) |
2366 | { | 2377 | { |
2367 | struct net *net = dev_net(dev); | 2378 | struct net *net = dev_net(dev); |
2368 | struct net_device *master = dev->master; | 2379 | struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
2369 | struct sk_buff *skb; | 2380 | struct sk_buff *skb; |
2370 | int err = -EOPNOTSUPP; | 2381 | int err = -EOPNOTSUPP; |
2371 | 2382 | ||
@@ -2376,15 +2387,15 @@ static int rtnl_bridge_notify(struct net_device *dev, u16 flags) | |||
2376 | } | 2387 | } |
2377 | 2388 | ||
2378 | if ((!flags || (flags & BRIDGE_FLAGS_MASTER)) && | 2389 | if ((!flags || (flags & BRIDGE_FLAGS_MASTER)) && |
2379 | master && master->netdev_ops->ndo_bridge_getlink) { | 2390 | br_dev && br_dev->netdev_ops->ndo_bridge_getlink) { |
2380 | err = master->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev); | 2391 | err = br_dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0); |
2381 | if (err < 0) | 2392 | if (err < 0) |
2382 | goto errout; | 2393 | goto errout; |
2383 | } | 2394 | } |
2384 | 2395 | ||
2385 | if ((flags & BRIDGE_FLAGS_SELF) && | 2396 | if ((flags & BRIDGE_FLAGS_SELF) && |
2386 | dev->netdev_ops->ndo_bridge_getlink) { | 2397 | dev->netdev_ops->ndo_bridge_getlink) { |
2387 | err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev); | 2398 | err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0); |
2388 | if (err < 0) | 2399 | if (err < 0) |
2389 | goto errout; | 2400 | goto errout; |
2390 | } | 2401 | } |
@@ -2436,13 +2447,14 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2436 | oflags = flags; | 2447 | oflags = flags; |
2437 | 2448 | ||
2438 | if (!flags || (flags & BRIDGE_FLAGS_MASTER)) { | 2449 | if (!flags || (flags & BRIDGE_FLAGS_MASTER)) { |
2439 | if (!dev->master || | 2450 | struct net_device *br_dev = netdev_master_upper_dev_get(dev); |
2440 | !dev->master->netdev_ops->ndo_bridge_setlink) { | 2451 | |
2452 | if (!br_dev || !br_dev->netdev_ops->ndo_bridge_setlink) { | ||
2441 | err = -EOPNOTSUPP; | 2453 | err = -EOPNOTSUPP; |
2442 | goto out; | 2454 | goto out; |
2443 | } | 2455 | } |
2444 | 2456 | ||
2445 | err = dev->master->netdev_ops->ndo_bridge_setlink(dev, nlh); | 2457 | err = br_dev->netdev_ops->ndo_bridge_setlink(dev, nlh); |
2446 | if (err) | 2458 | if (err) |
2447 | goto out; | 2459 | goto out; |
2448 | 2460 | ||
@@ -2468,6 +2480,77 @@ out: | |||
2468 | return err; | 2480 | return err; |
2469 | } | 2481 | } |
2470 | 2482 | ||
2483 | static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, | ||
2484 | void *arg) | ||
2485 | { | ||
2486 | struct net *net = sock_net(skb->sk); | ||
2487 | struct ifinfomsg *ifm; | ||
2488 | struct net_device *dev; | ||
2489 | struct nlattr *br_spec, *attr = NULL; | ||
2490 | int rem, err = -EOPNOTSUPP; | ||
2491 | u16 oflags, flags = 0; | ||
2492 | bool have_flags = false; | ||
2493 | |||
2494 | if (nlmsg_len(nlh) < sizeof(*ifm)) | ||
2495 | return -EINVAL; | ||
2496 | |||
2497 | ifm = nlmsg_data(nlh); | ||
2498 | if (ifm->ifi_family != AF_BRIDGE) | ||
2499 | return -EPFNOSUPPORT; | ||
2500 | |||
2501 | dev = __dev_get_by_index(net, ifm->ifi_index); | ||
2502 | if (!dev) { | ||
2503 | pr_info("PF_BRIDGE: RTM_SETLINK with unknown ifindex\n"); | ||
2504 | return -ENODEV; | ||
2505 | } | ||
2506 | |||
2507 | br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); | ||
2508 | if (br_spec) { | ||
2509 | nla_for_each_nested(attr, br_spec, rem) { | ||
2510 | if (nla_type(attr) == IFLA_BRIDGE_FLAGS) { | ||
2511 | have_flags = true; | ||
2512 | flags = nla_get_u16(attr); | ||
2513 | break; | ||
2514 | } | ||
2515 | } | ||
2516 | } | ||
2517 | |||
2518 | oflags = flags; | ||
2519 | |||
2520 | if (!flags || (flags & BRIDGE_FLAGS_MASTER)) { | ||
2521 | struct net_device *br_dev = netdev_master_upper_dev_get(dev); | ||
2522 | |||
2523 | if (!br_dev || !br_dev->netdev_ops->ndo_bridge_dellink) { | ||
2524 | err = -EOPNOTSUPP; | ||
2525 | goto out; | ||
2526 | } | ||
2527 | |||
2528 | err = br_dev->netdev_ops->ndo_bridge_dellink(dev, nlh); | ||
2529 | if (err) | ||
2530 | goto out; | ||
2531 | |||
2532 | flags &= ~BRIDGE_FLAGS_MASTER; | ||
2533 | } | ||
2534 | |||
2535 | if ((flags & BRIDGE_FLAGS_SELF)) { | ||
2536 | if (!dev->netdev_ops->ndo_bridge_dellink) | ||
2537 | err = -EOPNOTSUPP; | ||
2538 | else | ||
2539 | err = dev->netdev_ops->ndo_bridge_dellink(dev, nlh); | ||
2540 | |||
2541 | if (!err) | ||
2542 | flags &= ~BRIDGE_FLAGS_SELF; | ||
2543 | } | ||
2544 | |||
2545 | if (have_flags) | ||
2546 | memcpy(nla_data(attr), &flags, sizeof(flags)); | ||
2547 | /* Generate event to notify upper layer of bridge change */ | ||
2548 | if (!err) | ||
2549 | err = rtnl_bridge_notify(dev, oflags); | ||
2550 | out: | ||
2551 | return err; | ||
2552 | } | ||
2553 | |||
2471 | /* Protected by RTNL sempahore. */ | 2554 | /* Protected by RTNL sempahore. */ |
2472 | static struct rtattr **rta_buf; | 2555 | static struct rtattr **rta_buf; |
2473 | static int rtattr_max; | 2556 | static int rtattr_max; |
@@ -2651,6 +2734,7 @@ void __init rtnetlink_init(void) | |||
2651 | rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL); | 2734 | rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL); |
2652 | 2735 | ||
2653 | rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, NULL); | 2736 | rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, NULL); |
2737 | rtnl_register(PF_BRIDGE, RTM_DELLINK, rtnl_bridge_dellink, NULL, NULL); | ||
2654 | rtnl_register(PF_BRIDGE, RTM_SETLINK, rtnl_bridge_setlink, NULL, NULL); | 2738 | rtnl_register(PF_BRIDGE, RTM_SETLINK, rtnl_bridge_setlink, NULL, NULL); |
2655 | } | 2739 | } |
2656 | 2740 | ||