Merge git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/linux-2.6-nsfd
[cascardo/linux.git] / net / core / rtnetlink.c
index d2ba259..abd936d 100644 (file)
@@ -850,6 +850,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        struct nlattr *attr, *af_spec;
        struct rtnl_af_ops *af_ops;
 
+       ASSERT_RTNL();
        nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
        if (nlh == NULL)
                return -EMSGSIZE;
@@ -1045,6 +1046,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_LINKMODE]         = { .type = NLA_U8 },
        [IFLA_LINKINFO]         = { .type = NLA_NESTED },
        [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
+       [IFLA_NET_NS_FD]        = { .type = NLA_U32 },
        [IFLA_IFALIAS]          = { .type = NLA_STRING, .len = IFALIASZ-1 },
        [IFLA_VFINFO_LIST]      = {. type = NLA_NESTED },
        [IFLA_VF_PORTS]         = { .type = NLA_NESTED },
@@ -1093,6 +1095,8 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
         */
        if (tb[IFLA_NET_NS_PID])
                net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID]));
+       else if (tb[IFLA_NET_NS_FD])
+               net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD]));
        else
                net = get_net(src_net);
        return net;
@@ -1223,7 +1227,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
        int send_addr_notify = 0;
        int err;
 
-       if (tb[IFLA_NET_NS_PID]) {
+       if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) {
                struct net *net = rtnl_link_get_net(dev_net(dev), tb);
                if (IS_ERR(net)) {
                        err = PTR_ERR(net);
@@ -1876,6 +1880,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        int min_len;
        int family;
        int type;
+       int err;
 
        type = nlh->nlmsg_type;
        if (type > RTM_MAX)
@@ -1902,8 +1907,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                if (dumpit == NULL)
                        return -EOPNOTSUPP;
 
+               __rtnl_unlock();
                rtnl = net->rtnl;
-               return netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
+               err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
+               rtnl_lock();
+               return err;
        }
 
        memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
@@ -1956,6 +1964,8 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
        case NETDEV_GOING_DOWN:
        case NETDEV_UNREGISTER:
        case NETDEV_UNREGISTER_BATCH:
+       case NETDEV_RELEASE:
+       case NETDEV_JOIN:
                break;
        default:
                rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
@@ -1973,7 +1983,7 @@ static int __net_init rtnetlink_net_init(struct net *net)
 {
        struct sock *sk;
        sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
-                                  rtnetlink_rcv, NULL, THIS_MODULE);
+                                  rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
        if (!sk)
                return -ENOMEM;
        net->rtnl = sk;