Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6-microblaze.git] / drivers / net / tun.c
index b52258c..d531954 100644 (file)
@@ -78,6 +78,7 @@
 #include <linux/mutex.h>
 
 #include <linux/uaccess.h>
+#include <linux/proc_fs.h>
 
 /* Uncomment to enable debugging */
 /* #define TUN_DEBUG 1 */
@@ -2286,11 +2287,67 @@ static int tun_validate(struct nlattr *tb[], struct nlattr *data[],
        return -EINVAL;
 }
 
+static size_t tun_get_size(const struct net_device *dev)
+{
+       BUILD_BUG_ON(sizeof(u32) != sizeof(uid_t));
+       BUILD_BUG_ON(sizeof(u32) != sizeof(gid_t));
+
+       return nla_total_size(sizeof(uid_t)) + /* OWNER */
+              nla_total_size(sizeof(gid_t)) + /* GROUP */
+              nla_total_size(sizeof(u8)) + /* TYPE */
+              nla_total_size(sizeof(u8)) + /* PI */
+              nla_total_size(sizeof(u8)) + /* VNET_HDR */
+              nla_total_size(sizeof(u8)) + /* PERSIST */
+              nla_total_size(sizeof(u8)) + /* MULTI_QUEUE */
+              nla_total_size(sizeof(u32)) + /* NUM_QUEUES */
+              nla_total_size(sizeof(u32)) + /* NUM_DISABLED_QUEUES */
+              0;
+}
+
+static int tun_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+       struct tun_struct *tun = netdev_priv(dev);
+
+       if (nla_put_u8(skb, IFLA_TUN_TYPE, tun->flags & TUN_TYPE_MASK))
+               goto nla_put_failure;
+       if (uid_valid(tun->owner) &&
+           nla_put_u32(skb, IFLA_TUN_OWNER,
+                       from_kuid_munged(current_user_ns(), tun->owner)))
+               goto nla_put_failure;
+       if (gid_valid(tun->group) &&
+           nla_put_u32(skb, IFLA_TUN_GROUP,
+                       from_kgid_munged(current_user_ns(), tun->group)))
+               goto nla_put_failure;
+       if (nla_put_u8(skb, IFLA_TUN_PI, !(tun->flags & IFF_NO_PI)))
+               goto nla_put_failure;
+       if (nla_put_u8(skb, IFLA_TUN_VNET_HDR, !!(tun->flags & IFF_VNET_HDR)))
+               goto nla_put_failure;
+       if (nla_put_u8(skb, IFLA_TUN_PERSIST, !!(tun->flags & IFF_PERSIST)))
+               goto nla_put_failure;
+       if (nla_put_u8(skb, IFLA_TUN_MULTI_QUEUE,
+                      !!(tun->flags & IFF_MULTI_QUEUE)))
+               goto nla_put_failure;
+       if (tun->flags & IFF_MULTI_QUEUE) {
+               if (nla_put_u32(skb, IFLA_TUN_NUM_QUEUES, tun->numqueues))
+                       goto nla_put_failure;
+               if (nla_put_u32(skb, IFLA_TUN_NUM_DISABLED_QUEUES,
+                               tun->numdisabled))
+                       goto nla_put_failure;
+       }
+
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
 static struct rtnl_link_ops tun_link_ops __read_mostly = {
        .kind           = DRV_NAME,
        .priv_size      = sizeof(struct tun_struct),
        .setup          = tun_setup,
        .validate       = tun_validate,
+       .get_size       = tun_get_size,
+       .fill_info      = tun_fill_info,
 };
 
 static void tun_sock_write_space(struct sock *sk)
@@ -2789,6 +2846,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        struct tun_struct *tun;
        void __user* argp = (void __user*)arg;
        struct ifreq ifr;
+       struct net *net;
        kuid_t owner;
        kgid_t group;
        int sndbuf;
@@ -2797,7 +2855,8 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        int le;
        int ret;
 
-       if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == SOCK_IOC_TYPE) {
+       if (cmd == TUNSETIFF || cmd == TUNSETQUEUE ||
+           (_IOC_TYPE(cmd) == SOCK_IOC_TYPE && cmd != SIOCGSKNS)) {
                if (copy_from_user(&ifr, argp, ifreq_len))
                        return -EFAULT;
        } else {
@@ -2817,6 +2876,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        rtnl_lock();
 
        tun = tun_get(tfile);
+       net = sock_net(&tfile->sk);
        if (cmd == TUNSETIFF) {
                ret = -EEXIST;
                if (tun)
@@ -2824,7 +2884,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 
                ifr.ifr_name[IFNAMSIZ-1] = '\0';
 
-               ret = tun_set_iff(sock_net(&tfile->sk), file, &ifr);
+               ret = tun_set_iff(net, file, &ifr);
 
                if (ret)
                        goto unlock;
@@ -2846,6 +2906,14 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
                tfile->ifindex = ifindex;
                goto unlock;
        }
+       if (cmd == SIOCGSKNS) {
+               ret = -EPERM;
+               if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+                       goto unlock;
+
+               ret = open_related_ns(&net->ns, get_net_ns);
+               goto unlock;
+       }
 
        ret = -EBADFD;
        if (!tun)