]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/core/rtnetlink.c
Merge branch 'sysdev' into release
[mv-sheeva.git] / net / core / rtnetlink.c
index 2d65c6bb24c10e8734d7e0ee93644c2cd3298b45..49f7ea5b4c7510ca9caeb9d494486fea71c04c9d 100644 (file)
@@ -868,6 +868,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                   netif_running(dev) ? dev->operstate : IF_OPER_DOWN);
        NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode);
        NLA_PUT_U32(skb, IFLA_MTU, dev->mtu);
+       NLA_PUT_U32(skb, IFLA_GROUP, dev->group);
 
        if (dev->ifindex != dev->iflink)
                NLA_PUT_U32(skb, IFLA_LINK, dev->iflink);
@@ -1035,6 +1036,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
        [IFLA_MTU]              = { .type = NLA_U32 },
        [IFLA_LINK]             = { .type = NLA_U32 },
+       [IFLA_MASTER]           = { .type = NLA_U32 },
        [IFLA_TXQLEN]           = { .type = NLA_U32 },
        [IFLA_WEIGHT]           = { .type = NLA_U32 },
        [IFLA_OPERSTATE]        = { .type = NLA_U8 },
@@ -1177,6 +1179,41 @@ static int do_setvfinfo(struct net_device *dev, struct nlattr *attr)
        return err;
 }
 
+static int do_set_master(struct net_device *dev, int ifindex)
+{
+       struct net_device *master_dev;
+       const struct net_device_ops *ops;
+       int err;
+
+       if (dev->master) {
+               if (dev->master->ifindex == ifindex)
+                       return 0;
+               ops = dev->master->netdev_ops;
+               if (ops->ndo_del_slave) {
+                       err = ops->ndo_del_slave(dev->master, dev);
+                       if (err)
+                               return err;
+               } else {
+                       return -EOPNOTSUPP;
+               }
+       }
+
+       if (ifindex) {
+               master_dev = __dev_get_by_index(dev_net(dev), ifindex);
+               if (!master_dev)
+                       return -EINVAL;
+               ops = master_dev->netdev_ops;
+               if (ops->ndo_add_slave) {
+                       err = ops->ndo_add_slave(master_dev, dev);
+                       if (err)
+                               return err;
+               } else {
+                       return -EOPNOTSUPP;
+               }
+       }
+       return 0;
+}
+
 static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                      struct nlattr **tb, char *ifname, int modified)
 {
@@ -1264,6 +1301,11 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                modified = 1;
        }
 
+       if (tb[IFLA_GROUP]) {
+               dev_set_group(dev, nla_get_u32(tb[IFLA_GROUP]));
+               modified = 1;
+       }
+
        /*
         * Interface selected by interface index but interface
         * name provided implies that a name change has been
@@ -1295,6 +1337,13 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                        goto errout;
        }
 
+       if (tb[IFLA_MASTER]) {
+               err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]));
+               if (err)
+                       goto errout;
+               modified = 1;
+       }
+
        if (tb[IFLA_TXQLEN])
                dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
 
@@ -1541,6 +1590,8 @@ struct net_device *rtnl_create_link(struct net *src_net, struct net *net,
                set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
        if (tb[IFLA_LINKMODE])
                dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
+       if (tb[IFLA_GROUP])
+               dev_set_group(dev, nla_get_u32(tb[IFLA_GROUP]));
 
        return dev;
 
@@ -1551,6 +1602,24 @@ err:
 }
 EXPORT_SYMBOL(rtnl_create_link);
 
+static int rtnl_group_changelink(struct net *net, int group,
+               struct ifinfomsg *ifm,
+               struct nlattr **tb)
+{
+       struct net_device *dev;
+       int err;
+
+       for_each_netdev(net, dev) {
+               if (dev->group == group) {
+                       err = do_setlink(dev, ifm, tb, NULL, 0);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
 static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
        struct net *net = sock_net(skb->sk);
@@ -1578,10 +1647,12 @@ replay:
        ifm = nlmsg_data(nlh);
        if (ifm->ifi_index > 0)
                dev = __dev_get_by_index(net, ifm->ifi_index);
-       else if (ifname[0])
-               dev = __dev_get_by_name(net, ifname);
-       else
-               dev = NULL;
+       else {
+               if (ifname[0])
+                       dev = __dev_get_by_name(net, ifname);
+               else
+                       dev = NULL;
+       }
 
        err = validate_linkmsg(dev, tb);
        if (err < 0)
@@ -1645,8 +1716,13 @@ replay:
                        return do_setlink(dev, ifm, tb, ifname, modified);
                }
 
-               if (!(nlh->nlmsg_flags & NLM_F_CREATE))
+               if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
+                       if (ifm->ifi_index == 0 && tb[IFLA_GROUP])
+                               return rtnl_group_changelink(net,
+                                               nla_get_u32(tb[IFLA_GROUP]),
+                                               ifm, tb);
                        return -ENODEV;
+               }
 
                if (ifm->ifi_index)
                        return -EOPNOTSUPP;