tuntap: correctly handle error in tun_set_iff()
[firefly-linux-kernel-4.4.55.git] / drivers / net / tun.c
index 2dddb1bc82c90bae632de357a95227b4a2af6684..807815fc996839d14efd18625fb300a2f48d2577 100644 (file)
@@ -749,15 +749,17 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
                          >= dev->tx_queue_len / tun->numqueues)
                goto drop;
 
+       if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
+               goto drop;
+
        if (skb->sk) {
                sock_tx_timestamp(skb->sk, &skb_shinfo(skb)->tx_flags);
                sw_tx_timestamp(skb);
        }
 
        /* Orphan the skb - required as we might hang on to it
-        * for indefinite time. */
-       if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
-               goto drop;
+        * for indefinite time.
+        */
        skb_orphan(skb);
 
        nf_reset(skb);
@@ -1639,11 +1641,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                INIT_LIST_HEAD(&tun->disabled);
                err = tun_attach(tun, file, false);
                if (err < 0)
-                       goto err_free_dev;
+                       goto err_free_flow;
 
                err = register_netdevice(tun->dev);
                if (err < 0)
-                       goto err_free_dev;
+                       goto err_detach;
 
                if (device_create_file(&tun->dev->dev, &dev_attr_tun_flags) ||
                    device_create_file(&tun->dev->dev, &dev_attr_owner) ||
@@ -1687,7 +1689,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
        strcpy(ifr->ifr_name, tun->dev->name);
        return 0;
 
- err_free_dev:
+err_detach:
+       tun_detach_all(dev);
+err_free_flow:
+       tun_flow_uninit(tun);
+       security_tun_dev_free_security(tun->security);
+err_free_dev:
        free_netdev(dev);
        return err;
 }