|
@@ -359,7 +359,7 @@ static void tun_free_netdev(struct net_device *dev)
|
|
|
{
|
|
|
struct tun_struct *tun = netdev_priv(dev);
|
|
|
|
|
|
- sock_put(tun->socket.sk);
|
|
|
+ sk_release_kernel(tun->socket.sk);
|
|
|
}
|
|
|
|
|
|
/* Net device open. */
|
|
@@ -980,10 +980,18 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int tun_release(struct socket *sock)
|
|
|
+{
|
|
|
+ if (sock->sk)
|
|
|
+ sock_put(sock->sk);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* Ops structure to mimic raw sockets with tun */
|
|
|
static const struct proto_ops tun_socket_ops = {
|
|
|
.sendmsg = tun_sendmsg,
|
|
|
.recvmsg = tun_recvmsg,
|
|
|
+ .release = tun_release,
|
|
|
};
|
|
|
|
|
|
static struct proto tun_proto = {
|
|
@@ -1110,10 +1118,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
|
|
|
tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
|
|
|
|
|
|
err = -ENOMEM;
|
|
|
- sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto);
|
|
|
+ sk = sk_alloc(&init_net, AF_UNSPEC, GFP_KERNEL, &tun_proto);
|
|
|
if (!sk)
|
|
|
goto err_free_dev;
|
|
|
|
|
|
+ sk_change_net(sk, net);
|
|
|
tun->socket.wq = &tun->wq;
|
|
|
init_waitqueue_head(&tun->wq.wait);
|
|
|
tun->socket.ops = &tun_socket_ops;
|
|
@@ -1174,7 +1183,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
|
|
|
return 0;
|
|
|
|
|
|
err_free_sk:
|
|
|
- sock_put(sk);
|
|
|
+ tun_free_netdev(dev);
|
|
|
err_free_dev:
|
|
|
free_netdev(dev);
|
|
|
failed:
|