diff options
Diffstat (limited to 'net/ipv4')
| -rw-r--r-- | net/ipv4/ah4.c | 18 | ||||
| -rw-r--r-- | net/ipv4/arp.c | 21 | ||||
| -rw-r--r-- | net/ipv4/datagram.c | 25 | ||||
| -rw-r--r-- | net/ipv4/devinet.c | 2 | ||||
| -rw-r--r-- | net/ipv4/esp4.c | 12 | ||||
| -rw-r--r-- | net/ipv4/ip_gre.c | 6 | ||||
| -rw-r--r-- | net/ipv4/ip_sockglue.c | 2 | ||||
| -rw-r--r-- | net/ipv4/ipcomp.c | 7 | ||||
| -rw-r--r-- | net/ipv4/ipconfig.c | 8 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ipt_REJECT.c | 1 | ||||
| -rw-r--r-- | net/ipv4/netfilter/iptable_nat.c | 15 | ||||
| -rw-r--r-- | net/ipv4/ping.c | 1 | ||||
| -rw-r--r-- | net/ipv4/raw.c | 1 | ||||
| -rw-r--r-- | net/ipv4/route.c | 54 | ||||
| -rw-r--r-- | net/ipv4/tcp.c | 15 | ||||
| -rw-r--r-- | net/ipv4/tcp_cong.c | 14 | ||||
| -rw-r--r-- | net/ipv4/tcp_input.c | 12 | ||||
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 15 | ||||
| -rw-r--r-- | net/ipv4/udp.c | 1 | 
19 files changed, 181 insertions, 49 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index a0d8392491c..a69b4e4a02b 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -269,7 +269,11 @@ static void ah_input_done(struct crypto_async_request *base, int err)  	skb->network_header += ah_hlen;  	memcpy(skb_network_header(skb), work_iph, ihl);  	__skb_pull(skb, ah_hlen + ihl); -	skb_set_transport_header(skb, -ihl); + +	if (x->props.mode == XFRM_MODE_TUNNEL) +		skb_reset_transport_header(skb); +	else +		skb_set_transport_header(skb, -ihl);  out:  	kfree(AH_SKB_CB(skb)->tmp);  	xfrm_input_resume(skb, err); @@ -381,7 +385,10 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)  	skb->network_header += ah_hlen;  	memcpy(skb_network_header(skb), work_iph, ihl);  	__skb_pull(skb, ah_hlen + ihl); -	skb_set_transport_header(skb, -ihl); +	if (x->props.mode == XFRM_MODE_TUNNEL) +		skb_reset_transport_header(skb); +	else +		skb_set_transport_header(skb, -ihl);  	err = nexthdr; @@ -413,9 +420,12 @@ static void ah4_err(struct sk_buff *skb, u32 info)  	if (!x)  		return; -	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) +	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) { +		atomic_inc(&flow_cache_genid); +		rt_genid_bump(net); +  		ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0); -	else +	} else  		ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0);  	xfrm_state_put(x);  } diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 9547a273b9e..ded146b217f 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -928,24 +928,25 @@ static void parp_redo(struct sk_buff *skb)  static int arp_rcv(struct sk_buff *skb, struct net_device *dev,  		   struct packet_type *pt, struct net_device *orig_dev)  { -	struct arphdr *arp; +	const struct arphdr *arp; + +	if (dev->flags & IFF_NOARP || +	    skb->pkt_type == PACKET_OTHERHOST || +	    skb->pkt_type == PACKET_LOOPBACK) +		goto freeskb; + +	skb = skb_share_check(skb, GFP_ATOMIC); +	if (!skb) +		goto out_of_mem;  	/* ARP header, plus 2 device addresses, plus 2 IP addresses.  */  	if (!pskb_may_pull(skb, arp_hdr_len(dev)))  		goto freeskb;  	arp = arp_hdr(skb); -	if (arp->ar_hln != dev->addr_len || -	    dev->flags & IFF_NOARP || -	    skb->pkt_type == PACKET_OTHERHOST || -	    skb->pkt_type == PACKET_LOOPBACK || -	    arp->ar_pln != 4) +	if (arp->ar_hln != dev->addr_len || arp->ar_pln != 4)  		goto freeskb; -	skb = skb_share_check(skb, GFP_ATOMIC); -	if (skb == NULL) -		goto out_of_mem; -  	memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));  	return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, skb, dev, NULL, arp_process); diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index 424fafbc8cb..b28e863fe0a 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c @@ -85,3 +85,28 @@ out:  	return err;  }  EXPORT_SYMBOL(ip4_datagram_connect); + +void ip4_datagram_release_cb(struct sock *sk) +{ +	const struct inet_sock *inet = inet_sk(sk); +	const struct ip_options_rcu *inet_opt; +	__be32 daddr = inet->inet_daddr; +	struct flowi4 fl4; +	struct rtable *rt; + +	if (! __sk_dst_get(sk) || __sk_dst_check(sk, 0)) +		return; + +	rcu_read_lock(); +	inet_opt = rcu_dereference(inet->inet_opt); +	if (inet_opt && inet_opt->opt.srr) +		daddr = inet_opt->opt.faddr; +	rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr, +				   inet->inet_saddr, inet->inet_dport, +				   inet->inet_sport, sk->sk_protocol, +				   RT_CONN_FLAGS(sk), sk->sk_bound_dev_if); +	if (!IS_ERR(rt)) +		__sk_dst_set(sk, &rt->dst); +	rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(ip4_datagram_release_cb); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index cc06a47f121..a8e4f2665d5 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -823,9 +823,9 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)  		if (!ifa) {  			ret = -ENOBUFS;  			ifa = inet_alloc_ifa(); -			INIT_HLIST_NODE(&ifa->hash);  			if (!ifa)  				break; +			INIT_HLIST_NODE(&ifa->hash);  			if (colon)  				memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);  			else diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index b61e9deb7c7..3b4f0cd2e63 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -346,7 +346,10 @@ static int esp_input_done2(struct sk_buff *skb, int err)  	pskb_trim(skb, skb->len - alen - padlen - 2);  	__skb_pull(skb, hlen); -	skb_set_transport_header(skb, -ihl); +	if (x->props.mode == XFRM_MODE_TUNNEL) +		skb_reset_transport_header(skb); +	else +		skb_set_transport_header(skb, -ihl);  	err = nexthdr[1]; @@ -499,9 +502,12 @@ static void esp4_err(struct sk_buff *skb, u32 info)  	if (!x)  		return; -	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) +	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) { +		atomic_inc(&flow_cache_genid); +		rt_genid_bump(net); +  		ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0); -	else +	} else  		ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0);  	xfrm_state_put(x);  } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 303012adf9e..e81b1caf2ea 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -963,8 +963,12 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev  			ptr--;  		}  		if (tunnel->parms.o_flags&GRE_CSUM) { +			int offset = skb_transport_offset(skb); +  			*ptr = 0; -			*(__sum16 *)ptr = ip_compute_csum((void *)(iph+1), skb->len - sizeof(struct iphdr)); +			*(__sum16 *)ptr = csum_fold(skb_checksum(skb, offset, +								 skb->len - offset, +								 0));  		}  	} diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 3c9d2088028..d9c4f113d70 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -590,7 +590,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,  	case IP_TTL:  		if (optlen < 1)  			goto e_inval; -		if (val != -1 && (val < 0 || val > 255)) +		if (val != -1 && (val < 1 || val > 255))  			goto e_inval;  		inet->uc_ttl = val;  		break; diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index d3ab47e19a8..9a46daed2f3 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -47,9 +47,12 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)  	if (!x)  		return; -	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) +	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) { +		atomic_inc(&flow_cache_genid); +		rt_genid_bump(net); +  		ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0); -	else +	} else  		ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0);  	xfrm_state_put(x);  } diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index d763701cff1..a2e50ae80b5 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -136,6 +136,8 @@ __be32 ic_myaddr = NONE;		/* My IP address */  static __be32 ic_netmask = NONE;	/* Netmask for local subnet */  __be32 ic_gateway = NONE;	/* Gateway IP address */ +__be32 ic_addrservaddr = NONE;	/* IP Address of the IP addresses'server */ +  __be32 ic_servaddr = NONE;	/* Boot server IP address */  __be32 root_server_addr = NONE;	/* Address of NFS server */ @@ -558,6 +560,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt  	if (ic_myaddr == NONE)  		ic_myaddr = tip;  	ic_servaddr = sip; +	ic_addrservaddr = sip;  	ic_got_reply = IC_RARP;  drop_unlock: @@ -1068,7 +1071,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str  				ic_servaddr = server_id;  #ifdef IPCONFIG_DEBUG  				printk("DHCP: Offered address %pI4 by server %pI4\n", -				       &ic_myaddr, &ic_servaddr); +				       &ic_myaddr, &b->iph.saddr);  #endif  				/* The DHCP indicated server address takes  				 * precedence over the bootp header one if @@ -1113,6 +1116,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str  	ic_dev = dev;  	ic_myaddr = b->your_ip;  	ic_servaddr = b->server_ip; +	ic_addrservaddr = b->iph.saddr;  	if (ic_gateway == NONE && b->relay_ip)  		ic_gateway = b->relay_ip;  	if (ic_nameservers[0] == NONE) @@ -1268,7 +1272,7 @@ static int __init ic_dynamic(void)  	printk("IP-Config: Got %s answer from %pI4, ",  		((ic_got_reply & IC_RARP) ? "RARP"  		 : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"), -	       &ic_servaddr); +	       &ic_addrservaddr);  	pr_cont("my address is %pI4\n", &ic_myaddr);  	return 0; diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 51f13f8ec72..04b18c1ac34 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -81,6 +81,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)  	niph->saddr	= oiph->daddr;  	niph->daddr	= oiph->saddr; +	skb_reset_transport_header(nskb);  	tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));  	memset(tcph, 0, sizeof(*tcph));  	tcph->source	= oth->dest; diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c index da2c8a368f6..eeaff7e4acb 100644 --- a/net/ipv4/netfilter/iptable_nat.c +++ b/net/ipv4/netfilter/iptable_nat.c @@ -124,23 +124,28 @@ nf_nat_ipv4_fn(unsigned int hooknum,  			ret = nf_nat_rule_find(skb, hooknum, in, out, ct);  			if (ret != NF_ACCEPT)  				return ret; -		} else +		} else {  			pr_debug("Already setup manip %s for ct %p\n",  				 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",  				 ct); +			if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) +				goto oif_changed; +		}  		break;  	default:  		/* ESTABLISHED */  		NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||  			     ctinfo == IP_CT_ESTABLISHED_REPLY); -		if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) { -			nf_ct_kill_acct(ct, ctinfo, skb); -			return NF_DROP; -		} +		if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) +			goto oif_changed;  	}  	return nf_nat_packet(ct, ctinfo, hooknum, skb); + +oif_changed: +	nf_ct_kill_acct(ct, ctinfo, skb); +	return NF_DROP;  }  static unsigned int diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 8f3d05424a3..6f9c07268cf 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -738,6 +738,7 @@ struct proto ping_prot = {  	.recvmsg =	ping_recvmsg,  	.bind =		ping_bind,  	.backlog_rcv =	ping_queue_rcv_skb, +	.release_cb =	ip4_datagram_release_cb,  	.hash =		ping_v4_hash,  	.unhash =	ping_v4_unhash,  	.get_port =	ping_v4_get_port, diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 73d1e4df4bf..6f08991409c 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -894,6 +894,7 @@ struct proto raw_prot = {  	.recvmsg	   = raw_recvmsg,  	.bind		   = raw_bind,  	.backlog_rcv	   = raw_rcv_skb, +	.release_cb	   = ip4_datagram_release_cb,  	.hash		   = raw_hash_sk,  	.unhash		   = raw_unhash_sk,  	.obj_size	   = sizeof(struct raw_sock), diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 844a9ef60db..a0fcc47fee7 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -912,6 +912,9 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)  	struct dst_entry *dst = &rt->dst;  	struct fib_result res; +	if (dst_metric_locked(dst, RTAX_MTU)) +		return; +  	if (dst->dev->mtu < mtu)  		return; @@ -962,7 +965,7 @@ void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,  }  EXPORT_SYMBOL_GPL(ipv4_update_pmtu); -void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) +static void __ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)  {  	const struct iphdr *iph = (const struct iphdr *) skb->data;  	struct flowi4 fl4; @@ -975,6 +978,53 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)  		ip_rt_put(rt);  	}  } + +void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) +{ +	const struct iphdr *iph = (const struct iphdr *) skb->data; +	struct flowi4 fl4; +	struct rtable *rt; +	struct dst_entry *dst; +	bool new = false; + +	bh_lock_sock(sk); +	rt = (struct rtable *) __sk_dst_get(sk); + +	if (sock_owned_by_user(sk) || !rt) { +		__ipv4_sk_update_pmtu(skb, sk, mtu); +		goto out; +	} + +	__build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); + +	if (!__sk_dst_check(sk, 0)) { +		rt = ip_route_output_flow(sock_net(sk), &fl4, sk); +		if (IS_ERR(rt)) +			goto out; + +		new = true; +	} + +	__ip_rt_update_pmtu((struct rtable *) rt->dst.path, &fl4, mtu); + +	dst = dst_check(&rt->dst, 0); +	if (!dst) { +		if (new) +			dst_release(&rt->dst); + +		rt = ip_route_output_flow(sock_net(sk), &fl4, sk); +		if (IS_ERR(rt)) +			goto out; + +		new = true; +	} + +	if (new) +		__sk_dst_set(sk, &rt->dst); + +out: +	bh_unlock_sock(sk); +}  EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu);  void ipv4_redirect(struct sk_buff *skb, struct net *net, @@ -1120,7 +1170,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)  	if (!mtu || time_after_eq(jiffies, rt->dst.expires))  		mtu = dst_metric_raw(dst, RTAX_MTU); -	if (mtu && rt_is_output_route(rt)) +	if (mtu)  		return mtu;  	mtu = dst->dev->mtu; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 1ca253635f7..2aa69c8ae60 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1428,12 +1428,12 @@ static void tcp_service_net_dma(struct sock *sk, bool wait)  }  #endif -static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) +static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)  {  	struct sk_buff *skb;  	u32 offset; -	skb_queue_walk(&sk->sk_receive_queue, skb) { +	while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) {  		offset = seq - TCP_SKB_CB(skb)->seq;  		if (tcp_hdr(skb)->syn)  			offset--; @@ -1441,6 +1441,11 @@ static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)  			*off = offset;  			return skb;  		} +		/* This looks weird, but this can happen if TCP collapsing +		 * splitted a fat GRO packet, while we released socket lock +		 * in skb_splice_bits() +		 */ +		sk_eat_skb(sk, skb, false);  	}  	return NULL;  } @@ -1482,7 +1487,7 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,  					break;  			}  			used = recv_actor(desc, skb, offset, len); -			if (used < 0) { +			if (used <= 0) {  				if (!copied)  					copied = used;  				break; @@ -1520,8 +1525,10 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,  	tcp_rcv_space_adjust(sk);  	/* Clean up data we have read: This will do ACK frames. */ -	if (copied > 0) +	if (copied > 0) { +		tcp_recv_skb(sk, seq, &offset);  		tcp_cleanup_rbuf(sk, copied); +	}  	return copied;  }  EXPORT_SYMBOL(tcp_read_sock); diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 291f2ed7cc3..cdf2e707bb1 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -310,6 +310,12 @@ void tcp_slow_start(struct tcp_sock *tp)  {  	int cnt; /* increase in packets */  	unsigned int delta = 0; +	u32 snd_cwnd = tp->snd_cwnd; + +	if (unlikely(!snd_cwnd)) { +		pr_err_once("snd_cwnd is nul, please report this bug.\n"); +		snd_cwnd = 1U; +	}  	/* RFC3465: ABC Slow start  	 * Increase only after a full MSS of bytes is acked @@ -324,7 +330,7 @@ void tcp_slow_start(struct tcp_sock *tp)  	if (sysctl_tcp_max_ssthresh > 0 && tp->snd_cwnd > sysctl_tcp_max_ssthresh)  		cnt = sysctl_tcp_max_ssthresh >> 1;	/* limited slow start */  	else -		cnt = tp->snd_cwnd;			/* exponential increase */ +		cnt = snd_cwnd;				/* exponential increase */  	/* RFC3465: ABC  	 * We MAY increase by 2 if discovered delayed ack @@ -334,11 +340,11 @@ void tcp_slow_start(struct tcp_sock *tp)  	tp->bytes_acked = 0;  	tp->snd_cwnd_cnt += cnt; -	while (tp->snd_cwnd_cnt >= tp->snd_cwnd) { -		tp->snd_cwnd_cnt -= tp->snd_cwnd; +	while (tp->snd_cwnd_cnt >= snd_cwnd) { +		tp->snd_cwnd_cnt -= snd_cwnd;  		delta++;  	} -	tp->snd_cwnd = min(tp->snd_cwnd + delta, tp->snd_cwnd_clamp); +	tp->snd_cwnd = min(snd_cwnd + delta, tp->snd_cwnd_clamp);  }  EXPORT_SYMBOL_GPL(tcp_slow_start); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index a28e4db8a95..ad70a962c20 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3504,6 +3504,11 @@ static bool tcp_process_frto(struct sock *sk, int flag)  		}  	} else {  		if (!(flag & FLAG_DATA_ACKED) && (tp->frto_counter == 1)) { +			if (!tcp_packets_in_flight(tp)) { +				tcp_enter_frto_loss(sk, 2, flag); +				return true; +			} +  			/* Prevent sending of new data. */  			tp->snd_cwnd = min(tp->snd_cwnd,  					   tcp_packets_in_flight(tp)); @@ -5543,7 +5548,7 @@ slow_path:  	if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))  		goto csum_error; -	if (!th->ack) +	if (!th->ack && !th->rst)  		goto discard;  	/* @@ -5649,8 +5654,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,  	 * the remote receives only the retransmitted (regular) SYNs: either  	 * the original SYN-data or the corresponding SYN-ACK is lost.  	 */ -	syn_drop = (cookie->len <= 0 && data && -		    inet_csk(sk)->icsk_retransmits); +	syn_drop = (cookie->len <= 0 && data && tp->total_retrans);  	tcp_fastopen_cache_set(sk, mss, cookie, syn_drop); @@ -5988,7 +5992,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,  			goto discard;  	} -	if (!th->ack) +	if (!th->ack && !th->rst)  		goto discard;  	if (!tcp_validate_incoming(sk, skb, th, 0)) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 54139fa514e..eadb693eef5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -369,11 +369,10 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)  	 * We do take care of PMTU discovery (RFC1191) special case :  	 * we can receive locally generated ICMP messages while socket is held.  	 */ -	if (sock_owned_by_user(sk) && -	    type != ICMP_DEST_UNREACH && -	    code != ICMP_FRAG_NEEDED) -		NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS); - +	if (sock_owned_by_user(sk)) { +		if (!(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)) +			NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS); +	}  	if (sk->sk_state == TCP_CLOSE)  		goto out; @@ -497,6 +496,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)  		 * errors returned from accept().  		 */  		inet_csk_reqsk_queue_drop(sk, req, prev); +		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);  		goto out;  	case TCP_SYN_SENT: @@ -1501,8 +1501,10 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)  	 * clogging syn queue with openreqs with exponentially increasing  	 * timeout.  	 */ -	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) +	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { +		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);  		goto drop; +	}  	req = inet_reqsk_alloc(&tcp_request_sock_ops);  	if (!req) @@ -1667,6 +1669,7 @@ drop_and_release:  drop_and_free:  	reqsk_free(req);  drop: +	NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);  	return 0;  }  EXPORT_SYMBOL(tcp_v4_conn_request); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 79c8dbe59b5..1f4d405eafb 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1952,6 +1952,7 @@ struct proto udp_prot = {  	.recvmsg	   = udp_recvmsg,  	.sendpage	   = udp_sendpage,  	.backlog_rcv	   = __udp_queue_rcv_skb, +	.release_cb	   = ip4_datagram_release_cb,  	.hash		   = udp_lib_hash,  	.unhash		   = udp_lib_unhash,  	.rehash		   = udp_v4_rehash,  |