diff options
Diffstat (limited to 'quicktun.c')
-rw-r--r-- | quicktun.c | 27 |
1 files changed, 18 insertions, 9 deletions
@@ -50,7 +50,7 @@ static netdev_tx_t quicktun_net_xmit(struct sk_buff *skb, struct net_device *dev if (tun->remote_address.sin_addr.s_addr) { err = skb_linearize(skb); if (err < 0) - goto drop; + goto error; vec.iov_base = skb->data; vec.iov_len = skb->len; @@ -67,16 +67,16 @@ static netdev_tx_t quicktun_net_xmit(struct sk_buff *skb, struct net_device *dev tun->dev->stats.tx_bytes += skb->len; } else - goto drop; + goto error; consume_skb(skb); return NETDEV_TX_OK; - drop: +error: kfree_skb(skb); - tun->dev->stats.tx_dropped++; + tun->dev->stats.tx_errors++; return NETDEV_TX_OK; } @@ -88,8 +88,11 @@ static void quicktun_udp_data_ready(struct sock *sk, int bytes) int err; + read_lock(&sk->sk_callback_lock); + skb = skb_recv_datagram(sk, 0, 1, &err); if (!skb) { + read_unlock(&sk->sk_callback_lock); if (err == -EAGAIN) return; pr_info("Quicktun: UDP socket error %d", err); @@ -138,13 +141,17 @@ static void quicktun_udp_data_ready(struct sock *sk, int bytes) goto drop; } + read_unlock(&sk->sk_callback_lock); + netif_rx_ni(skb); tun->dev->stats.rx_packets++; tun->dev->stats.rx_bytes += len; return; - drop: +drop: + read_unlock(&sk->sk_callback_lock); + tun->dev->stats.rx_dropped++; kfree_skb(skb); } @@ -259,7 +266,7 @@ static int quicktun_socket_init(struct net_device *dev) goto error; return 0; - error: +error: sock_release(tun->sock); return err; } @@ -347,11 +354,11 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf return 0; - err_free_sk: +err_free_sk: rtnl_unlock(); sock_release(tun->sock); - err_free_dev: +err_free_dev: free_netdev(dev); return err; } @@ -361,6 +368,8 @@ static void __quicktun_delete_device(struct net_device *dev) { struct quicktun_struct *tun = netdev_priv(dev); struct socket *sock = tun->sock; + kernel_sock_shutdown(sock, SHUT_RD); + list_del(&tun->list); unregister_netdevice(dev); @@ -401,7 +410,7 @@ static int quicktun_cmd_delete_device(struct sk_buff *skb, struct genl_info *inf return 0; - err_unlock: +err_unlock: rtnl_unlock(); return err; |