diff options
Diffstat (limited to 'quicktun.c')
-rw-r--r-- | quicktun.c | 41 |
1 files changed, 33 insertions, 8 deletions
@@ -43,7 +43,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 err; + goto drop; vec.iov_base = skb->data; vec.iov_len = skb->len; @@ -55,24 +55,31 @@ static netdev_tx_t quicktun_net_xmit(struct sk_buff *skb, struct net_device *dev msg.msg_flags = MSG_DONTWAIT; kernel_sendmsg(tun->sock, &msg, &vec, 1, skb->len); + + tun->dev->stats.tx_packets++; + tun->dev->stats.tx_bytes += skb->len; } + else + goto drop; consume_skb(skb); return NETDEV_TX_OK; - err: + drop: kfree_skb(skb); + tun->dev->stats.tx_dropped++; return NETDEV_TX_OK; } static void quicktun_udp_data_ready(struct sock *sk, int bytes) { - int err; struct sk_buff *skb; + unsigned int len; struct quicktun_struct *tun = sk->sk_user_data; - struct iphdr *iphdr; + int err; + skb = skb_recv_datagram(sk, 0, 1, &err); if (!skb) { @@ -86,27 +93,45 @@ static void quicktun_udp_data_ready(struct sock *sk, int bytes) err = skb_linearize(skb); if (err < 0) - goto err; + goto drop; __skb_pull(skb, sizeof(struct udphdr)); + len = skb->len; + switch (tun->flags & QUICKTUN_MODE_MASK) { case QUICKTUN_MODE_ETHERNET: skb->protocol = eth_type_trans(skb, tun->dev); break; + case QUICKTUN_MODE_IP: __skb_tunnel_rx(skb, tun->dev); skb_reset_network_header(skb); - iphdr = (struct iphdr*)skb->data; - skb->protocol = htons((iphdr->version == 6) ? ETH_P_IPV6 : ETH_P_IP); + switch (skb->data[0] & 0xf0) { + case 0x40: + skb->protocol = htons(ETH_P_IP); + break; + case 0x60: + skb->protocol = htons(ETH_P_IPV6); + break; + default: + goto drop; + } break; + + default: + goto drop; } netif_rx_ni(skb); + + tun->dev->stats.rx_packets++; + tun->dev->stats.rx_bytes += len; return; - err: + drop: + tun->dev->stats.rx_dropped++; kfree_skb(skb); } |