decnet: netdevice refcount leak
[safe/jmp/linux-2.6] / net / core / rtnetlink.c
index d6381c2..eb42873 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/security.h>
 #include <linux/mutex.h>
 #include <linux/if_addr.h>
-#include <linux/nsproxy.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -52,6 +51,7 @@
 #include <net/pkt_sched.h>
 #include <net/fib_rules.h>
 #include <net/rtnetlink.h>
+#include <net/net_namespace.h>
 
 struct rtnl_link
 {
@@ -455,8 +455,8 @@ int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid)
        return nlmsg_unicast(rtnl, skb, pid);
 }
 
-int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
-               struct nlmsghdr *nlh, gfp_t flags)
+void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
+                struct nlmsghdr *nlh, gfp_t flags)
 {
        struct sock *rtnl = net->rtnl;
        int report = 0;
@@ -464,7 +464,7 @@ int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
        if (nlh)
                report = nlmsg_report(nlh);
 
-       return nlmsg_notify(rtnl, skb, pid, group, report, flags);
+       nlmsg_notify(rtnl, skb, pid, group, report, flags);
 }
 
 void rtnl_set_sk_err(struct net *net, u32 group, int error)
@@ -551,7 +551,7 @@ static void set_operstate(struct net_device *dev, unsigned char transition)
 }
 
 static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
-                                struct net_device_stats *b)
+                                const struct net_device_stats *b)
 {
        a->rx_packets = b->rx_packets;
        a->tx_packets = b->tx_packets;
@@ -586,6 +586,7 @@ static inline size_t if_nlmsg_size(const struct net_device *dev)
 {
        return NLMSG_ALIGN(sizeof(struct ifinfomsg))
               + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
+              + nla_total_size(IFALIASZ) /* IFLA_IFALIAS */
               + nla_total_size(IFNAMSIZ) /* IFLA_QDISC */
               + nla_total_size(sizeof(struct rtnl_link_ifmap))
               + nla_total_size(sizeof(struct rtnl_link_stats))
@@ -605,10 +606,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                            int type, u32 pid, u32 seq, u32 change,
                            unsigned int flags)
 {
-       struct netdev_queue *txq;
        struct ifinfomsg *ifm;
        struct nlmsghdr *nlh;
-       struct net_device_stats *stats;
+       const struct net_device_stats *stats;
        struct nlattr *attr;
 
        nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
@@ -636,9 +636,11 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        if (dev->master)
                NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex);
 
-       txq = netdev_get_tx_queue(dev, 0);
-       if (txq->qdisc_sleeping)
-               NLA_PUT_STRING(skb, IFLA_QDISC, txq->qdisc_sleeping->ops->id);
+       if (dev->qdisc)
+               NLA_PUT_STRING(skb, IFLA_QDISC, dev->qdisc->ops->id);
+
+       if (dev->ifalias)
+               NLA_PUT_STRING(skb, IFLA_IFALIAS, dev->ifalias);
 
        if (1) {
                struct rtnl_link_ifmap map = {
@@ -662,7 +664,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        if (attr == NULL)
                goto nla_put_failure;
 
-       stats = dev->get_stats(dev);
+       stats = dev_get_stats(dev);
        copy_rtnl_link_stats(nla_data(attr), stats);
 
        if (dev->rtnl_link_ops) {
@@ -713,6 +715,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_IFALIAS]          = { .type = NLA_STRING, .len = IFALIASZ-1 },
 };
 
 static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
@@ -720,25 +723,6 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
        [IFLA_INFO_DATA]        = { .type = NLA_NESTED },
 };
 
-static struct net *get_net_ns_by_pid(pid_t pid)
-{
-       struct task_struct *tsk;
-       struct net *net;
-
-       /* Lookup the network namespace */
-       net = ERR_PTR(-ESRCH);
-       rcu_read_lock();
-       tsk = find_task_by_vpid(pid);
-       if (tsk) {
-               struct nsproxy *nsproxy;
-               nsproxy = task_nsproxy(tsk);
-               if (nsproxy)
-                       net = get_net(nsproxy->net_ns);
-       }
-       rcu_read_unlock();
-       return net;
-}
-
 static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
 {
        if (dev) {
@@ -757,6 +741,7 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
 static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                      struct nlattr **tb, char *ifname, int modified)
 {
+       const struct net_device_ops *ops = dev->netdev_ops;
        int send_addr_notify = 0;
        int err;
 
@@ -778,7 +763,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                struct rtnl_link_ifmap *u_map;
                struct ifmap k_map;
 
-               if (!dev->set_config) {
+               if (!ops->ndo_set_config) {
                        err = -EOPNOTSUPP;
                        goto errout;
                }
@@ -796,7 +781,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                k_map.dma = (unsigned char) u_map->dma;
                k_map.port = (unsigned char) u_map->port;
 
-               err = dev->set_config(dev, &k_map);
+               err = ops->ndo_set_config(dev, &k_map);
                if (err < 0)
                        goto errout;
 
@@ -807,7 +792,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                struct sockaddr *sa;
                int len;
 
-               if (!dev->set_mac_address) {
+               if (!ops->ndo_set_mac_address) {
                        err = -EOPNOTSUPP;
                        goto errout;
                }
@@ -826,7 +811,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                sa->sa_family = dev->type;
                memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
                       dev->addr_len);
-               err = dev->set_mac_address(dev, sa);
+               err = ops->ndo_set_mac_address(dev, sa);
                kfree(sa);
                if (err)
                        goto errout;
@@ -853,6 +838,14 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                modified = 1;
        }
 
+       if (tb[IFLA_IFALIAS]) {
+               err = dev_set_alias(dev, nla_data(tb[IFLA_IFALIAS]),
+                                   nla_len(tb[IFLA_IFALIAS]));
+               if (err < 0)
+                       goto errout;
+               modified = 1;
+       }
+
        if (tb[IFLA_BROADCAST]) {
                nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len);
                send_addr_notify = 1;
@@ -865,7 +858,9 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
                if (ifm->ifi_change)
                        flags = (flags & ifm->ifi_change) |
                                (dev->flags & ~ifm->ifi_change);
-               dev_change_flags(dev, flags);
+               err = dev_change_flags(dev, flags);
+               if (err < 0)
+                       goto errout;
        }
 
        if (tb[IFLA_TXQLEN])
@@ -977,12 +972,20 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname,
 {
        int err;
        struct net_device *dev;
+       unsigned int num_queues = 1;
+       unsigned int real_num_queues = 1;
 
+       if (ops->get_tx_queues) {
+               err = ops->get_tx_queues(net, tb, &num_queues, &real_num_queues);
+               if (err)
+                       goto err;
+       }
        err = -ENOMEM;
-       dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
+       dev = alloc_netdev_mq(ops->priv_size, ifname, ops->setup, num_queues);
        if (!dev)
                goto err;
 
+       dev->real_num_tx_queues = real_num_queues;
        if (strchr(dev->name, '%')) {
                err = dev_alloc_name(dev, dev->name);
                if (err < 0)
@@ -1027,7 +1030,7 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        struct nlattr *linkinfo[IFLA_INFO_MAX+1];
        int err;
 
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
 replay:
 #endif
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
@@ -1116,7 +1119,7 @@ replay:
                        return -EOPNOTSUPP;
 
                if (!ops) {
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
                        if (kind[0]) {
                                __rtnl_unlock();
                                request_module("rtnl-link-%s", kind);
@@ -1230,7 +1233,8 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+       rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_LINK, err);