diff options
Diffstat (limited to 'net/ipv6/udp.c')
| -rw-r--r-- | net/ipv6/udp.c | 27 | 
1 files changed, 20 insertions, 7 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 16c176e7c69a..91e795bb9ade 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -616,8 +616,11 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  	}  	/* Tunnels don't have an application socket: don't pass errors back */ -	if (tunnel) +	if (tunnel) { +		if (udp_sk(sk)->encap_err_rcv) +			udp_sk(sk)->encap_err_rcv(sk, skb, offset);  		goto out; +	}  	if (!np->recverr) {  		if (!harderr || sk->sk_state != TCP_ESTABLISHED) @@ -647,16 +650,20 @@ static int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)  	rc = __udp_enqueue_schedule_skb(sk, skb);  	if (rc < 0) {  		int is_udplite = IS_UDPLITE(sk); +		enum skb_drop_reason drop_reason;  		/* Note that an ENOMEM error is charged twice */ -		if (rc == -ENOMEM) +		if (rc == -ENOMEM) {  			UDP6_INC_STATS(sock_net(sk),  					 UDP_MIB_RCVBUFERRORS, is_udplite); -		else +			drop_reason = SKB_DROP_REASON_SOCKET_RCVBUFF; +		} else {  			UDP6_INC_STATS(sock_net(sk),  				       UDP_MIB_MEMERRORS, is_udplite); +			drop_reason = SKB_DROP_REASON_PROTO_MEM; +		}  		UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); -		kfree_skb(skb); +		kfree_skb_reason(skb, drop_reason);  		return -1;  	} @@ -672,11 +679,14 @@ static __inline__ int udpv6_err(struct sk_buff *skb,  static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)  { +	enum skb_drop_reason drop_reason = SKB_DROP_REASON_NOT_SPECIFIED;  	struct udp_sock *up = udp_sk(sk);  	int is_udplite = IS_UDPLITE(sk); -	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) +	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { +		drop_reason = SKB_DROP_REASON_XFRM_POLICY;  		goto drop; +	}  	if (static_branch_unlikely(&udpv6_encap_needed_key) && up->encap_type) {  		int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); @@ -735,8 +745,10 @@ static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)  	    udp_lib_checksum_complete(skb))  		goto csum_error; -	if (sk_filter_trim_cap(sk, skb, sizeof(struct udphdr))) +	if (sk_filter_trim_cap(sk, skb, sizeof(struct udphdr))) { +		drop_reason = SKB_DROP_REASON_SOCKET_FILTER;  		goto drop; +	}  	udp_csum_pull_header(skb); @@ -745,11 +757,12 @@ static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb)  	return __udpv6_queue_rcv_skb(sk, skb);  csum_error: +	drop_reason = SKB_DROP_REASON_UDP_CSUM;  	__UDP6_INC_STATS(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite);  drop:  	__UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite);  	atomic_inc(&sk->sk_drops); -	kfree_skb(skb); +	kfree_skb_reason(skb, drop_reason);  	return -1;  }  |