diff options
Diffstat (limited to 'net/packet/af_packet.c')
| -rw-r--r-- | net/packet/af_packet.c | 33 | 
1 files changed, 20 insertions, 13 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 82a6f34d39d..2dbb32b988c 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1499,10 +1499,11 @@ retry:  	if (!skb) {  		size_t reserved = LL_RESERVED_SPACE(dev); +		int tlen = dev->needed_tailroom;  		unsigned int hhlen = dev->header_ops ? dev->hard_header_len : 0;  		rcu_read_unlock(); -		skb = sock_wmalloc(sk, len + reserved, 0, GFP_KERNEL); +		skb = sock_wmalloc(sk, len + reserved + tlen, 0, GFP_KERNEL);  		if (skb == NULL)  			return -ENOBUFS;  		/* FIXME: Save some space for broken drivers that write a hard @@ -1630,8 +1631,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,  	if (snaplen > res)  		snaplen = res; -	if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= -	    (unsigned)sk->sk_rcvbuf) +	if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)  		goto drop_n_acct;  	if (skb_shared(skb)) { @@ -1762,8 +1762,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,  	if (po->tp_version <= TPACKET_V2) {  		if (macoff + snaplen > po->rx_ring.frame_size) {  			if (po->copy_thresh && -				atomic_read(&sk->sk_rmem_alloc) + skb->truesize -				< (unsigned)sk->sk_rcvbuf) { +			    atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) {  				if (skb_shared(skb)) {  					copy_skb = skb_clone(skb, GFP_ATOMIC);  				} else { @@ -1944,7 +1943,7 @@ static void tpacket_destruct_skb(struct sk_buff *skb)  static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,  		void *frame, struct net_device *dev, int size_max, -		__be16 proto, unsigned char *addr) +		__be16 proto, unsigned char *addr, int hlen)  {  	union {  		struct tpacket_hdr *h1; @@ -1978,7 +1977,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,  		return -EMSGSIZE;  	} -	skb_reserve(skb, LL_RESERVED_SPACE(dev)); +	skb_reserve(skb, hlen);  	skb_reset_network_header(skb);  	data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll); @@ -2053,6 +2052,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)  	unsigned char *addr;  	int len_sum = 0;  	int status = 0; +	int hlen, tlen;  	mutex_lock(&po->pg_vec_lock); @@ -2101,16 +2101,17 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)  		}  		status = TP_STATUS_SEND_REQUEST; +		hlen = LL_RESERVED_SPACE(dev); +		tlen = dev->needed_tailroom;  		skb = sock_alloc_send_skb(&po->sk, -				LL_ALLOCATED_SPACE(dev) -				+ sizeof(struct sockaddr_ll), +				hlen + tlen + sizeof(struct sockaddr_ll),  				0, &err);  		if (unlikely(skb == NULL))  			goto out_status;  		tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto, -				addr); +				addr, hlen);  		if (unlikely(tp_len < 0)) {  			if (po->tp_loss) { @@ -2207,6 +2208,7 @@ static int packet_snd(struct socket *sock,  	int vnet_hdr_len;  	struct packet_sock *po = pkt_sk(sk);  	unsigned short gso_type = 0; +	int hlen, tlen;  	/*  	 *	Get and verify the address. @@ -2291,8 +2293,9 @@ static int packet_snd(struct socket *sock,  		goto out_unlock;  	err = -ENOBUFS; -	skb = packet_alloc_skb(sk, LL_ALLOCATED_SPACE(dev), -			       LL_RESERVED_SPACE(dev), len, vnet_hdr.hdr_len, +	hlen = LL_RESERVED_SPACE(dev); +	tlen = dev->needed_tailroom; +	skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, vnet_hdr.hdr_len,  			       msg->msg_flags & MSG_DONTWAIT, &err);  	if (skb == NULL)  		goto out_unlock; @@ -2450,8 +2453,12 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protoc  {  	struct packet_sock *po = pkt_sk(sk); -	if (po->fanout) +	if (po->fanout) { +		if (dev) +			dev_put(dev); +  		return -EINVAL; +	}  	lock_sock(sk);  |