[NETNS]: Pass namespace through ip_rt_ioctl.
[safe/jmp/linux-2.6] / net / ipv4 / fib_frontend.c
index 7fe54a3..15909a9 100644 (file)
@@ -49,8 +49,6 @@
 
 #define FFprint(a...) printk(KERN_DEBUG a)
 
-static struct sock *fibnl;
-
 #ifndef CONFIG_IP_MULTIPLE_TABLES
 
 static int __net_init fib4_rules_init(struct net *net)
@@ -307,14 +305,14 @@ static int put_rtax(struct nlattr *mx, int len, int type, u32 value)
        return len + nla_total_size(4);
 }
 
-static int rtentry_to_fib_config(int cmd, struct rtentry *rt,
+static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
                                 struct fib_config *cfg)
 {
        __be32 addr;
        int plen;
 
        memset(cfg, 0, sizeof(*cfg));
-       cfg->fc_nlinfo.nl_net = &init_net;
+       cfg->fc_nlinfo.nl_net = net;
 
        if (rt->rt_dst.sa_family != AF_INET)
                return -EAFNOSUPPORT;
@@ -375,7 +373,7 @@ static int rtentry_to_fib_config(int cmd, struct rtentry *rt,
                colon = strchr(devname, ':');
                if (colon)
                        *colon = 0;
-               dev = __dev_get_by_name(&init_net, devname);
+               dev = __dev_get_by_name(net, devname);
                if (!dev)
                        return -ENODEV;
                cfg->fc_oif = dev->ifindex;
@@ -398,7 +396,7 @@ static int rtentry_to_fib_config(int cmd, struct rtentry *rt,
        if (rt->rt_gateway.sa_family == AF_INET && addr) {
                cfg->fc_gw = addr;
                if (rt->rt_flags & RTF_GATEWAY &&
-                   inet_addr_type(&init_net, addr) == RTN_UNICAST)
+                   inet_addr_type(net, addr) == RTN_UNICAST)
                        cfg->fc_scope = RT_SCOPE_UNIVERSE;
        }
 
@@ -439,7 +437,7 @@ static int rtentry_to_fib_config(int cmd, struct rtentry *rt,
  *     Handle IP routing ioctl calls. These are used to manipulate the routing tables
  */
 
-int ip_rt_ioctl(unsigned int cmd, void __user *arg)
+int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
 {
        struct fib_config cfg;
        struct rtentry rt;
@@ -455,18 +453,18 @@ int ip_rt_ioctl(unsigned int cmd, void __user *arg)
                        return -EFAULT;
 
                rtnl_lock();
-               err = rtentry_to_fib_config(cmd, &rt, &cfg);
+               err = rtentry_to_fib_config(net, cmd, &rt, &cfg);
                if (err == 0) {
                        struct fib_table *tb;
 
                        if (cmd == SIOCDELRT) {
-                               tb = fib_get_table(&init_net, cfg.fc_table);
+                               tb = fib_get_table(net, cfg.fc_table);
                                if (tb)
                                        err = tb->tb_delete(tb, &cfg);
                                else
                                        err = -ESRCH;
                        } else {
-                               tb = fib_new_table(&init_net, cfg.fc_table);
+                               tb = fib_new_table(net, cfg.fc_table);
                                if (tb)
                                        err = tb->tb_insert(tb, &cfg);
                                else
@@ -496,8 +494,8 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX+1] = {
        [RTA_FLOW]              = { .type = NLA_U32 },
 };
 
-static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
-                            struct fib_config *cfg)
+static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
+                           struct nlmsghdr *nlh, struct fib_config *cfg)
 {
        struct nlattr *attr;
        int err, remaining;
@@ -521,7 +519,7 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
        cfg->fc_nlinfo.nlh = nlh;
-       cfg->fc_nlinfo.nl_net = &init_net;
+       cfg->fc_nlinfo.nl_net = net;
 
        if (cfg->fc_type > RTN_MAX) {
                err = -EINVAL;
@@ -577,7 +575,7 @@ static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *ar
        if (net != &init_net)
                return -EINVAL;
 
-       err = rtm_to_fib_config(skb, nlh, &cfg);
+       err = rtm_to_fib_config(net, skb, nlh, &cfg);
        if (err < 0)
                goto errout;
 
@@ -602,7 +600,7 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *ar
        if (net != &init_net)
                return -EINVAL;
 
-       err = rtm_to_fib_config(skb, nlh, &cfg);
+       err = rtm_to_fib_config(net, skb, nlh, &cfg);
        if (err < 0)
                goto errout;
 
@@ -669,6 +667,7 @@ out:
 
 static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
 {
+       struct net *net = ifa->ifa_dev->dev->nd_net;
        struct fib_table *tb;
        struct fib_config cfg = {
                .fc_protocol = RTPROT_KERNEL,
@@ -679,14 +678,14 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad
                .fc_oif = ifa->ifa_dev->dev->ifindex,
                .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND,
                .fc_nlinfo = {
-                       .nl_net = &init_net,
+                       .nl_net = net,
                },
        };
 
        if (type == RTN_UNICAST)
-               tb = fib_new_table(&init_net, RT_TABLE_MAIN);
+               tb = fib_new_table(net, RT_TABLE_MAIN);
        else
-               tb = fib_new_table(&init_net, RT_TABLE_LOCAL);
+               tb = fib_new_table(net, RT_TABLE_LOCAL);
 
        if (tb == NULL)
                return;
@@ -845,11 +844,13 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
 
 static void nl_fib_input(struct sk_buff *skb)
 {
+       struct net *net;
        struct fib_result_nl *frn;
        struct nlmsghdr *nlh;
        struct fib_table *tb;
        u32 pid;
 
+       net = skb->sk->sk_net;
        nlh = nlmsg_hdr(skb);
        if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
            nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn)))
@@ -861,28 +862,36 @@ static void nl_fib_input(struct sk_buff *skb)
        nlh = nlmsg_hdr(skb);
 
        frn = (struct fib_result_nl *) NLMSG_DATA(nlh);
-       tb = fib_get_table(&init_net, frn->tb_id_in);
+       tb = fib_get_table(net, frn->tb_id_in);
 
        nl_fib_lookup(frn, tb);
 
        pid = NETLINK_CB(skb).pid;       /* pid of sending process */
        NETLINK_CB(skb).pid = 0;         /* from kernel */
        NETLINK_CB(skb).dst_group = 0;  /* unicast */
-       netlink_unicast(fibnl, skb, pid, MSG_DONTWAIT);
+       netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT);
 }
 
 static int nl_fib_lookup_init(struct net *net)
 {
-       fibnl = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0,
-                                     nl_fib_input, NULL, THIS_MODULE);
-       if (fibnl == NULL)
+       struct sock *sk;
+       sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0,
+                                  nl_fib_input, NULL, THIS_MODULE);
+       if (sk == NULL)
                return -EAFNOSUPPORT;
+       /* Don't hold an extra reference on the namespace */
+       put_net(sk->sk_net);
+       net->ipv4.fibnl = sk;
        return 0;
 }
 
 static void nl_fib_lookup_exit(struct net *net)
 {
-       sock_put(fibnl);
+       /* At the last minute lie and say this is a socket for the
+        * initial network namespace. So the socket will  be safe to free.
+        */
+       net->ipv4.fibnl->sk_net = get_net(&init_net);
+       sock_put(net->ipv4.fibnl);
 }
 
 static void fib_disable_ip(struct net_device *dev, int force)