]> Pileus Git - ~andy/linux/blobdiff - net/core/rtnetlink.c
[NETNS]: DST cleanup routines should be called inside namespace.
[~andy/linux] / net / core / rtnetlink.c
index 9efaf35934f4078552f8c6a39260a3832865ef68..2bd9c5f7627dd84b450ec3f105263979adda77e3 100644 (file)
@@ -82,32 +82,6 @@ int rtnl_trylock(void)
        return mutex_trylock(&rtnl_mutex);
 }
 
-int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
-{
-       memset(tb, 0, sizeof(struct rtattr*)*maxattr);
-
-       while (RTA_OK(rta, len)) {
-               unsigned flavor = rta->rta_type;
-               if (flavor && flavor <= maxattr)
-                       tb[flavor-1] = rta;
-               rta = RTA_NEXT(rta, len);
-       }
-       return 0;
-}
-
-int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr,
-                                struct rtattr *rta, int len)
-{
-       if (RTA_PAYLOAD(rta) < len)
-               return -1;
-       if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
-               rta = RTA_DATA(rta) + RTA_ALIGN(len);
-               return rtattr_parse_nested(tb, maxattr, rta);
-       }
-       memset(tb, 0, sizeof(struct rtattr *) * maxattr);
-       return 0;
-}
-
 static struct rtnl_link *rtnl_msg_handlers[NPROTO];
 
 static inline int rtm_msgindex(int msgtype)
@@ -442,21 +416,6 @@ void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data
        memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size);
 }
 
-size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size)
-{
-       size_t ret = RTA_PAYLOAD(rta);
-       char *src = RTA_DATA(rta);
-
-       if (ret > 0 && src[ret - 1] == '\0')
-               ret--;
-       if (size > 0) {
-               size_t len = (ret >= size) ? size - 1 : ret;
-               memset(dest, 0, size);
-               memcpy(dest, src, len);
-       }
-       return ret;
-}
-
 int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, int echo)
 {
        struct sock *rtnl = net->rtnl;
@@ -708,9 +667,6 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        int s_idx = cb->args[0];
        struct net_device *dev;
 
-       if (net != &init_net)
-               return 0;
-
        idx = 0;
        for_each_netdev(net, dev) {
                if (idx < s_idx)
@@ -733,10 +689,12 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_BROADCAST]        = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
        [IFLA_MAP]              = { .len = sizeof(struct rtnl_link_ifmap) },
        [IFLA_MTU]              = { .type = NLA_U32 },
+       [IFLA_LINK]             = { .type = NLA_U32 },
        [IFLA_TXQLEN]           = { .type = NLA_U32 },
        [IFLA_WEIGHT]           = { .type = NLA_U32 },
        [IFLA_OPERSTATE]        = { .type = NLA_U8 },
        [IFLA_LINKMODE]         = { .type = NLA_U8 },
+       [IFLA_LINKINFO]         = { .type = NLA_NESTED },
        [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
 };
 
@@ -764,6 +722,21 @@ static struct net *get_net_ns_by_pid(pid_t pid)
        return net;
 }
 
+static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
+{
+       if (dev) {
+               if (tb[IFLA_ADDRESS] &&
+                   nla_len(tb[IFLA_ADDRESS]) < dev->addr_len)
+                       return -EINVAL;
+
+               if (tb[IFLA_BROADCAST] &&
+                   nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                      struct nlattr **tb, char *ifname, int modified)
 {
@@ -913,9 +886,6 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        struct nlattr *tb[IFLA_MAX+1];
        char ifname[IFNAMSIZ];
 
-       if (net != &init_net)
-               return -EINVAL;
-
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
        if (err < 0)
                goto errout;
@@ -939,12 +909,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                goto errout;
        }
 
-       if (tb[IFLA_ADDRESS] &&
-           nla_len(tb[IFLA_ADDRESS]) < dev->addr_len)
-               goto errout_dev;
-
-       if (tb[IFLA_BROADCAST] &&
-           nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
+       if ((err = validate_linkmsg(dev, tb)) < 0)
                goto errout_dev;
 
        err = do_setlink(dev, ifm, tb, ifname, 0);
@@ -964,9 +929,6 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        struct nlattr *tb[IFLA_MAX+1];
        int err;
 
-       if (net != &init_net)
-               return -EINVAL;
-
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
        if (err < 0)
                return err;
@@ -1048,9 +1010,6 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        struct nlattr *linkinfo[IFLA_INFO_MAX+1];
        int err;
 
-       if (net != &init_net)
-               return -EINVAL;
-
 #ifdef CONFIG_KMOD
 replay:
 #endif
@@ -1071,6 +1030,9 @@ replay:
        else
                dev = NULL;
 
+       if ((err = validate_linkmsg(dev, tb)) < 0)
+               return err;
+
        if (tb[IFLA_LINKINFO]) {
                err = nla_parse_nested(linkinfo, IFLA_INFO_MAX,
                                       tb[IFLA_LINKINFO], ifla_info_policy);
@@ -1177,9 +1139,6 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
        struct sk_buff *nskb;
        int err;
 
-       if (net != &init_net)
-               return -EINVAL;
-
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
        if (err < 0)
                return err;
@@ -1215,13 +1174,9 @@ errout:
 
 static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct net *net = skb->sk->sk_net;
        int idx;
        int s_idx = cb->family;
 
-       if (net != &init_net)
-               return 0;
-
        if (s_idx == 0)
                s_idx = 1;
        for (idx=1; idx<NPROTO; idx++) {
@@ -1243,6 +1198,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
 
 void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
 {
+       struct net *net = dev->nd_net;
        struct sk_buff *skb;
        int err = -ENOBUFS;
 
@@ -1257,10 +1213,10 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+       err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
 errout:
        if (err < 0)
-               rtnl_set_sk_err(&init_net, RTNLGRP_LINK, err);
+               rtnl_set_sk_err(net, RTNLGRP_LINK, err);
 }
 
 /* Protected by RTNL sempahore.  */
@@ -1353,9 +1309,6 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
 {
        struct net_device *dev = ptr;
 
-       if (dev->nd_net != &init_net)
-               return NOTIFY_DONE;
-
        switch (event) {
        case NETDEV_UNREGISTER:
                rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
@@ -1389,25 +1342,14 @@ static int rtnetlink_net_init(struct net *net)
                                   rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
        if (!sk)
                return -ENOMEM;
-
-       /* Don't hold an extra reference on the namespace */
-       put_net(sk->sk_net);
        net->rtnl = sk;
        return 0;
 }
 
 static void rtnetlink_net_exit(struct net *net)
 {
-       struct sock *sk = net->rtnl;
-       if (sk) {
-               /* At the last minute lie and say this is a socket for the
-                * initial network namespace.  So the socket will be safe to
-                * free.
-                */
-               sk->sk_net = get_net(&init_net);
-               sock_put(sk);
-               net->rtnl = NULL;
-       }
+       netlink_kernel_release(net->rtnl);
+       net->rtnl = NULL;
 }
 
 static struct pernet_operations rtnetlink_net_ops = {
@@ -1443,9 +1385,6 @@ void __init rtnetlink_init(void)
 }
 
 EXPORT_SYMBOL(__rta_fill);
-EXPORT_SYMBOL(rtattr_strlcpy);
-EXPORT_SYMBOL(rtattr_parse);
-EXPORT_SYMBOL(__rtattr_parse_nested_compat);
 EXPORT_SYMBOL(rtnetlink_put_metrics);
 EXPORT_SYMBOL(rtnl_lock);
 EXPORT_SYMBOL(rtnl_trylock);