diff options
author | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-12-17 17:00:49 -0500 |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-12-17 17:00:49 -0500 |
commit | a4581b35e1bc80becf240238bc787a5ec2727db0 (patch) | |
tree | 34cbf36101639403a766e74deb36e7015d871b39 /net/ipv4 | |
parent | f940b88d3a57594289455ea99a93a8ddc5c4af06 (diff) | |
parent | 384703b8e6cd4c8ef08512e596024e028c91c339 (diff) |
Merge commit 'v3.2-rc6' into fbdev-next
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/ah4.c | 8 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 5 | ||||
-rw-r--r-- | net/ipv4/igmp.c | 3 | ||||
-rw-r--r-- | net/ipv4/inet_diag.c | 14 | ||||
-rw-r--r-- | net/ipv4/ip_forward.c | 2 | ||||
-rw-r--r-- | net/ipv4/ip_options.c | 4 | ||||
-rw-r--r-- | net/ipv4/ipip.c | 7 | ||||
-rw-r--r-- | net/ipv4/netfilter.c | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/Kconfig | 1 | ||||
-rw-r--r-- | net/ipv4/ping.c | 2 | ||||
-rw-r--r-- | net/ipv4/route.c | 196 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 1 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 2 | ||||
-rw-r--r-- | net/ipv4/udp.c | 15 |
14 files changed, 155 insertions, 108 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index c1f4154552fc..36d14406261e 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c | |||
@@ -136,8 +136,6 @@ static void ah_output_done(struct crypto_async_request *base, int err) | |||
136 | memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); | 136 | memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); |
137 | } | 137 | } |
138 | 138 | ||
139 | err = ah->nexthdr; | ||
140 | |||
141 | kfree(AH_SKB_CB(skb)->tmp); | 139 | kfree(AH_SKB_CB(skb)->tmp); |
142 | xfrm_output_resume(skb, err); | 140 | xfrm_output_resume(skb, err); |
143 | } | 141 | } |
@@ -264,12 +262,12 @@ static void ah_input_done(struct crypto_async_request *base, int err) | |||
264 | if (err) | 262 | if (err) |
265 | goto out; | 263 | goto out; |
266 | 264 | ||
265 | err = ah->nexthdr; | ||
266 | |||
267 | skb->network_header += ah_hlen; | 267 | skb->network_header += ah_hlen; |
268 | memcpy(skb_network_header(skb), work_iph, ihl); | 268 | memcpy(skb_network_header(skb), work_iph, ihl); |
269 | __skb_pull(skb, ah_hlen + ihl); | 269 | __skb_pull(skb, ah_hlen + ihl); |
270 | skb_set_transport_header(skb, -ihl); | 270 | skb_set_transport_header(skb, -ihl); |
271 | |||
272 | err = ah->nexthdr; | ||
273 | out: | 271 | out: |
274 | kfree(AH_SKB_CB(skb)->tmp); | 272 | kfree(AH_SKB_CB(skb)->tmp); |
275 | xfrm_input_resume(skb, err); | 273 | xfrm_input_resume(skb, err); |
@@ -371,8 +369,6 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) | |||
371 | if (err == -EINPROGRESS) | 369 | if (err == -EINPROGRESS) |
372 | goto out; | 370 | goto out; |
373 | 371 | ||
374 | if (err == -EBUSY) | ||
375 | err = NET_XMIT_DROP; | ||
376 | goto out_free; | 372 | goto out_free; |
377 | } | 373 | } |
378 | 374 | ||
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index c6b5092f29a1..65f01dc47565 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -1490,7 +1490,9 @@ static int devinet_conf_proc(ctl_table *ctl, int write, | |||
1490 | void __user *buffer, | 1490 | void __user *buffer, |
1491 | size_t *lenp, loff_t *ppos) | 1491 | size_t *lenp, loff_t *ppos) |
1492 | { | 1492 | { |
1493 | int old_value = *(int *)ctl->data; | ||
1493 | int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 1494 | int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
1495 | int new_value = *(int *)ctl->data; | ||
1494 | 1496 | ||
1495 | if (write) { | 1497 | if (write) { |
1496 | struct ipv4_devconf *cnf = ctl->extra1; | 1498 | struct ipv4_devconf *cnf = ctl->extra1; |
@@ -1501,6 +1503,9 @@ static int devinet_conf_proc(ctl_table *ctl, int write, | |||
1501 | 1503 | ||
1502 | if (cnf == net->ipv4.devconf_dflt) | 1504 | if (cnf == net->ipv4.devconf_dflt) |
1503 | devinet_copy_dflt_conf(net, i); | 1505 | devinet_copy_dflt_conf(net, i); |
1506 | if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1) | ||
1507 | if ((new_value == 0) && (old_value != 0)) | ||
1508 | rt_cache_flush(net, 0); | ||
1504 | } | 1509 | } |
1505 | 1510 | ||
1506 | return ret; | 1511 | return ret; |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index c7472eff2d51..b2ca095cb9da 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -1716,7 +1716,8 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, | |||
1716 | if (err) { | 1716 | if (err) { |
1717 | int j; | 1717 | int j; |
1718 | 1718 | ||
1719 | pmc->sfcount[sfmode]--; | 1719 | if (!delta) |
1720 | pmc->sfcount[sfmode]--; | ||
1720 | for (j=0; j<i; j++) | 1721 | for (j=0; j<i; j++) |
1721 | (void) ip_mc_del1_src(pmc, sfmode, &psfsrc[j]); | 1722 | (void) ip_mc_del1_src(pmc, sfmode, &psfsrc[j]); |
1722 | } else if (isexclude != (pmc->sfcount[MCAST_EXCLUDE] != 0)) { | 1723 | } else if (isexclude != (pmc->sfcount[MCAST_EXCLUDE] != 0)) { |
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index f5e2bdaef949..ccee270a9b65 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c | |||
@@ -108,9 +108,6 @@ static int inet_csk_diag_fill(struct sock *sk, | |||
108 | icsk->icsk_ca_ops->name); | 108 | icsk->icsk_ca_ops->name); |
109 | } | 109 | } |
110 | 110 | ||
111 | if ((ext & (1 << (INET_DIAG_TOS - 1))) && (sk->sk_family != AF_INET6)) | ||
112 | RTA_PUT_U8(skb, INET_DIAG_TOS, inet->tos); | ||
113 | |||
114 | r->idiag_family = sk->sk_family; | 111 | r->idiag_family = sk->sk_family; |
115 | r->idiag_state = sk->sk_state; | 112 | r->idiag_state = sk->sk_state; |
116 | r->idiag_timer = 0; | 113 | r->idiag_timer = 0; |
@@ -125,16 +122,23 @@ static int inet_csk_diag_fill(struct sock *sk, | |||
125 | r->id.idiag_src[0] = inet->inet_rcv_saddr; | 122 | r->id.idiag_src[0] = inet->inet_rcv_saddr; |
126 | r->id.idiag_dst[0] = inet->inet_daddr; | 123 | r->id.idiag_dst[0] = inet->inet_daddr; |
127 | 124 | ||
125 | /* IPv6 dual-stack sockets use inet->tos for IPv4 connections, | ||
126 | * hence this needs to be included regardless of socket family. | ||
127 | */ | ||
128 | if (ext & (1 << (INET_DIAG_TOS - 1))) | ||
129 | RTA_PUT_U8(skb, INET_DIAG_TOS, inet->tos); | ||
130 | |||
128 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | 131 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) |
129 | if (r->idiag_family == AF_INET6) { | 132 | if (r->idiag_family == AF_INET6) { |
130 | const struct ipv6_pinfo *np = inet6_sk(sk); | 133 | const struct ipv6_pinfo *np = inet6_sk(sk); |
131 | 134 | ||
135 | if (ext & (1 << (INET_DIAG_TCLASS - 1))) | ||
136 | RTA_PUT_U8(skb, INET_DIAG_TCLASS, np->tclass); | ||
137 | |||
132 | ipv6_addr_copy((struct in6_addr *)r->id.idiag_src, | 138 | ipv6_addr_copy((struct in6_addr *)r->id.idiag_src, |
133 | &np->rcv_saddr); | 139 | &np->rcv_saddr); |
134 | ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst, | 140 | ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst, |
135 | &np->daddr); | 141 | &np->daddr); |
136 | if (ext & (1 << (INET_DIAG_TOS - 1))) | ||
137 | RTA_PUT_U8(skb, INET_DIAG_TOS, np->tclass); | ||
138 | } | 142 | } |
139 | #endif | 143 | #endif |
140 | 144 | ||
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 3b34d1c86270..29a07b6c7168 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c | |||
@@ -84,7 +84,7 @@ int ip_forward(struct sk_buff *skb) | |||
84 | 84 | ||
85 | rt = skb_rtable(skb); | 85 | rt = skb_rtable(skb); |
86 | 86 | ||
87 | if (opt->is_strictroute && ip_hdr(skb)->daddr != rt->rt_gateway) | 87 | if (opt->is_strictroute && opt->nexthop != rt->rt_gateway) |
88 | goto sr_failed; | 88 | goto sr_failed; |
89 | 89 | ||
90 | if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) && | 90 | if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) && |
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index ec93335901dd..1e60f7679075 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c | |||
@@ -568,12 +568,13 @@ void ip_forward_options(struct sk_buff *skb) | |||
568 | ) { | 568 | ) { |
569 | if (srrptr + 3 > srrspace) | 569 | if (srrptr + 3 > srrspace) |
570 | break; | 570 | break; |
571 | if (memcmp(&ip_hdr(skb)->daddr, &optptr[srrptr-1], 4) == 0) | 571 | if (memcmp(&opt->nexthop, &optptr[srrptr-1], 4) == 0) |
572 | break; | 572 | break; |
573 | } | 573 | } |
574 | if (srrptr + 3 <= srrspace) { | 574 | if (srrptr + 3 <= srrspace) { |
575 | opt->is_changed = 1; | 575 | opt->is_changed = 1; |
576 | ip_rt_get_source(&optptr[srrptr-1], skb, rt); | 576 | ip_rt_get_source(&optptr[srrptr-1], skb, rt); |
577 | ip_hdr(skb)->daddr = opt->nexthop; | ||
577 | optptr[2] = srrptr+4; | 578 | optptr[2] = srrptr+4; |
578 | } else if (net_ratelimit()) | 579 | } else if (net_ratelimit()) |
579 | printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); | 580 | printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); |
@@ -640,6 +641,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) | |||
640 | } | 641 | } |
641 | if (srrptr <= srrspace) { | 642 | if (srrptr <= srrspace) { |
642 | opt->srr_is_hit = 1; | 643 | opt->srr_is_hit = 1; |
644 | opt->nexthop = nexthop; | ||
643 | opt->is_changed = 1; | 645 | opt->is_changed = 1; |
644 | } | 646 | } |
645 | return 0; | 647 | return 0; |
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 065effd8349a..0b2e7329abda 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -285,6 +285,8 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net, | |||
285 | if (register_netdevice(dev) < 0) | 285 | if (register_netdevice(dev) < 0) |
286 | goto failed_free; | 286 | goto failed_free; |
287 | 287 | ||
288 | strcpy(nt->parms.name, dev->name); | ||
289 | |||
288 | dev_hold(dev); | 290 | dev_hold(dev); |
289 | ipip_tunnel_link(ipn, nt); | 291 | ipip_tunnel_link(ipn, nt); |
290 | return nt; | 292 | return nt; |
@@ -759,7 +761,6 @@ static int ipip_tunnel_init(struct net_device *dev) | |||
759 | struct ip_tunnel *tunnel = netdev_priv(dev); | 761 | struct ip_tunnel *tunnel = netdev_priv(dev); |
760 | 762 | ||
761 | tunnel->dev = dev; | 763 | tunnel->dev = dev; |
762 | strcpy(tunnel->parms.name, dev->name); | ||
763 | 764 | ||
764 | memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); | 765 | memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); |
765 | memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); | 766 | memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); |
@@ -825,6 +826,7 @@ static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head) | |||
825 | static int __net_init ipip_init_net(struct net *net) | 826 | static int __net_init ipip_init_net(struct net *net) |
826 | { | 827 | { |
827 | struct ipip_net *ipn = net_generic(net, ipip_net_id); | 828 | struct ipip_net *ipn = net_generic(net, ipip_net_id); |
829 | struct ip_tunnel *t; | ||
828 | int err; | 830 | int err; |
829 | 831 | ||
830 | ipn->tunnels[0] = ipn->tunnels_wc; | 832 | ipn->tunnels[0] = ipn->tunnels_wc; |
@@ -848,6 +850,9 @@ static int __net_init ipip_init_net(struct net *net) | |||
848 | if ((err = register_netdev(ipn->fb_tunnel_dev))) | 850 | if ((err = register_netdev(ipn->fb_tunnel_dev))) |
849 | goto err_reg_dev; | 851 | goto err_reg_dev; |
850 | 852 | ||
853 | t = netdev_priv(ipn->fb_tunnel_dev); | ||
854 | |||
855 | strcpy(t->parms.name, ipn->fb_tunnel_dev->name); | ||
851 | return 0; | 856 | return 0; |
852 | 857 | ||
853 | err_reg_dev: | 858 | err_reg_dev: |
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 9899619ab9b8..4f47e064e262 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c | |||
@@ -64,7 +64,8 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) | |||
64 | /* Change in oif may mean change in hh_len. */ | 64 | /* Change in oif may mean change in hh_len. */ |
65 | hh_len = skb_dst(skb)->dev->hard_header_len; | 65 | hh_len = skb_dst(skb)->dev->hard_header_len; |
66 | if (skb_headroom(skb) < hh_len && | 66 | if (skb_headroom(skb) < hh_len && |
67 | pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC)) | 67 | pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)), |
68 | 0, GFP_ATOMIC)) | ||
68 | return -1; | 69 | return -1; |
69 | 70 | ||
70 | return 0; | 71 | return 0; |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 1dfc18a03fd4..f19f2182894c 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -325,7 +325,6 @@ config IP_NF_TARGET_TTL | |||
325 | # raw + specific targets | 325 | # raw + specific targets |
326 | config IP_NF_RAW | 326 | config IP_NF_RAW |
327 | tristate 'raw table support (required for NOTRACK/TRACE)' | 327 | tristate 'raw table support (required for NOTRACK/TRACE)' |
328 | depends on NETFILTER_ADVANCED | ||
329 | help | 328 | help |
330 | This option adds a `raw' table to iptables. This table is the very | 329 | This option adds a `raw' table to iptables. This table is the very |
331 | first in the netfilter framework and hooks in at the PREROUTING | 330 | first in the netfilter framework and hooks in at the PREROUTING |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index a06f73fdb3c0..43d4c3b22369 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
@@ -339,7 +339,6 @@ void ping_err(struct sk_buff *skb, u32 info) | |||
339 | sk = ping_v4_lookup(net, iph->daddr, iph->saddr, | 339 | sk = ping_v4_lookup(net, iph->daddr, iph->saddr, |
340 | ntohs(icmph->un.echo.id), skb->dev->ifindex); | 340 | ntohs(icmph->un.echo.id), skb->dev->ifindex); |
341 | if (sk == NULL) { | 341 | if (sk == NULL) { |
342 | ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS); | ||
343 | pr_debug("no socket, dropping\n"); | 342 | pr_debug("no socket, dropping\n"); |
344 | return; /* No socket for error */ | 343 | return; /* No socket for error */ |
345 | } | 344 | } |
@@ -679,7 +678,6 @@ static int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
679 | pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n", | 678 | pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n", |
680 | inet_sk(sk), inet_sk(sk)->inet_num, skb); | 679 | inet_sk(sk), inet_sk(sk)->inet_num, skb); |
681 | if (sock_queue_rcv_skb(sk, skb) < 0) { | 680 | if (sock_queue_rcv_skb(sk, skb) < 0) { |
682 | ICMP_INC_STATS_BH(sock_net(sk), ICMP_MIB_INERRORS); | ||
683 | kfree_skb(skb); | 681 | kfree_skb(skb); |
684 | pr_debug("ping_queue_rcv_skb -> failed\n"); | 682 | pr_debug("ping_queue_rcv_skb -> failed\n"); |
685 | return -1; | 683 | return -1; |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 155138d8ec8b..46af62363b8c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -112,7 +112,7 @@ | |||
112 | #include <net/secure_seq.h> | 112 | #include <net/secure_seq.h> |
113 | 113 | ||
114 | #define RT_FL_TOS(oldflp4) \ | 114 | #define RT_FL_TOS(oldflp4) \ |
115 | ((u32)(oldflp4->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))) | 115 | ((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK)) |
116 | 116 | ||
117 | #define IP_MAX_MTU 0xFFF0 | 117 | #define IP_MAX_MTU 0xFFF0 |
118 | 118 | ||
@@ -131,6 +131,7 @@ static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; | |||
131 | static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; | 131 | static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; |
132 | static int ip_rt_min_advmss __read_mostly = 256; | 132 | static int ip_rt_min_advmss __read_mostly = 256; |
133 | static int rt_chain_length_max __read_mostly = 20; | 133 | static int rt_chain_length_max __read_mostly = 20; |
134 | static int redirect_genid; | ||
134 | 135 | ||
135 | /* | 136 | /* |
136 | * Interface to generic destination cache. | 137 | * Interface to generic destination cache. |
@@ -138,7 +139,7 @@ static int rt_chain_length_max __read_mostly = 20; | |||
138 | 139 | ||
139 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); | 140 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); |
140 | static unsigned int ipv4_default_advmss(const struct dst_entry *dst); | 141 | static unsigned int ipv4_default_advmss(const struct dst_entry *dst); |
141 | static unsigned int ipv4_default_mtu(const struct dst_entry *dst); | 142 | static unsigned int ipv4_mtu(const struct dst_entry *dst); |
142 | static void ipv4_dst_destroy(struct dst_entry *dst); | 143 | static void ipv4_dst_destroy(struct dst_entry *dst); |
143 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); | 144 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); |
144 | static void ipv4_link_failure(struct sk_buff *skb); | 145 | static void ipv4_link_failure(struct sk_buff *skb); |
@@ -193,7 +194,7 @@ static struct dst_ops ipv4_dst_ops = { | |||
193 | .gc = rt_garbage_collect, | 194 | .gc = rt_garbage_collect, |
194 | .check = ipv4_dst_check, | 195 | .check = ipv4_dst_check, |
195 | .default_advmss = ipv4_default_advmss, | 196 | .default_advmss = ipv4_default_advmss, |
196 | .default_mtu = ipv4_default_mtu, | 197 | .mtu = ipv4_mtu, |
197 | .cow_metrics = ipv4_cow_metrics, | 198 | .cow_metrics = ipv4_cow_metrics, |
198 | .destroy = ipv4_dst_destroy, | 199 | .destroy = ipv4_dst_destroy, |
199 | .ifdown = ipv4_dst_ifdown, | 200 | .ifdown = ipv4_dst_ifdown, |
@@ -416,9 +417,13 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) | |||
416 | else { | 417 | else { |
417 | struct rtable *r = v; | 418 | struct rtable *r = v; |
418 | struct neighbour *n; | 419 | struct neighbour *n; |
419 | int len; | 420 | int len, HHUptod; |
420 | 421 | ||
422 | rcu_read_lock(); | ||
421 | n = dst_get_neighbour(&r->dst); | 423 | n = dst_get_neighbour(&r->dst); |
424 | HHUptod = (n && (n->nud_state & NUD_CONNECTED)) ? 1 : 0; | ||
425 | rcu_read_unlock(); | ||
426 | |||
422 | seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t" | 427 | seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t" |
423 | "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n", | 428 | "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n", |
424 | r->dst.dev ? r->dst.dev->name : "*", | 429 | r->dst.dev ? r->dst.dev->name : "*", |
@@ -432,7 +437,7 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) | |||
432 | dst_metric(&r->dst, RTAX_RTTVAR)), | 437 | dst_metric(&r->dst, RTAX_RTTVAR)), |
433 | r->rt_key_tos, | 438 | r->rt_key_tos, |
434 | -1, | 439 | -1, |
435 | (n && (n->nud_state & NUD_CONNECTED)) ? 1 : 0, | 440 | HHUptod, |
436 | r->rt_spec_dst, &len); | 441 | r->rt_spec_dst, &len); |
437 | 442 | ||
438 | seq_printf(seq, "%*s\n", 127 - len, ""); | 443 | seq_printf(seq, "%*s\n", 127 - len, ""); |
@@ -837,6 +842,7 @@ static void rt_cache_invalidate(struct net *net) | |||
837 | 842 | ||
838 | get_random_bytes(&shuffle, sizeof(shuffle)); | 843 | get_random_bytes(&shuffle, sizeof(shuffle)); |
839 | atomic_add(shuffle + 1U, &net->ipv4.rt_genid); | 844 | atomic_add(shuffle + 1U, &net->ipv4.rt_genid); |
845 | redirect_genid++; | ||
840 | } | 846 | } |
841 | 847 | ||
842 | /* | 848 | /* |
@@ -1304,16 +1310,40 @@ static void rt_del(unsigned hash, struct rtable *rt) | |||
1304 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1310 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1305 | } | 1311 | } |
1306 | 1312 | ||
1313 | static void check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) | ||
1314 | { | ||
1315 | struct rtable *rt = (struct rtable *) dst; | ||
1316 | __be32 orig_gw = rt->rt_gateway; | ||
1317 | struct neighbour *n, *old_n; | ||
1318 | |||
1319 | dst_confirm(&rt->dst); | ||
1320 | |||
1321 | rt->rt_gateway = peer->redirect_learned.a4; | ||
1322 | |||
1323 | n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway); | ||
1324 | if (IS_ERR(n)) { | ||
1325 | rt->rt_gateway = orig_gw; | ||
1326 | return; | ||
1327 | } | ||
1328 | old_n = xchg(&rt->dst._neighbour, n); | ||
1329 | if (old_n) | ||
1330 | neigh_release(old_n); | ||
1331 | if (!(n->nud_state & NUD_VALID)) { | ||
1332 | neigh_event_send(n, NULL); | ||
1333 | } else { | ||
1334 | rt->rt_flags |= RTCF_REDIRECTED; | ||
1335 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); | ||
1336 | } | ||
1337 | } | ||
1338 | |||
1307 | /* called in rcu_read_lock() section */ | 1339 | /* called in rcu_read_lock() section */ |
1308 | void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | 1340 | void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, |
1309 | __be32 saddr, struct net_device *dev) | 1341 | __be32 saddr, struct net_device *dev) |
1310 | { | 1342 | { |
1311 | int s, i; | 1343 | int s, i; |
1312 | struct in_device *in_dev = __in_dev_get_rcu(dev); | 1344 | struct in_device *in_dev = __in_dev_get_rcu(dev); |
1313 | struct rtable *rt; | ||
1314 | __be32 skeys[2] = { saddr, 0 }; | 1345 | __be32 skeys[2] = { saddr, 0 }; |
1315 | int ikeys[2] = { dev->ifindex, 0 }; | 1346 | int ikeys[2] = { dev->ifindex, 0 }; |
1316 | struct flowi4 fl4; | ||
1317 | struct inet_peer *peer; | 1347 | struct inet_peer *peer; |
1318 | struct net *net; | 1348 | struct net *net; |
1319 | 1349 | ||
@@ -1336,33 +1366,44 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1336 | goto reject_redirect; | 1366 | goto reject_redirect; |
1337 | } | 1367 | } |
1338 | 1368 | ||
1339 | memset(&fl4, 0, sizeof(fl4)); | ||
1340 | fl4.daddr = daddr; | ||
1341 | for (s = 0; s < 2; s++) { | 1369 | for (s = 0; s < 2; s++) { |
1342 | for (i = 0; i < 2; i++) { | 1370 | for (i = 0; i < 2; i++) { |
1343 | fl4.flowi4_oif = ikeys[i]; | 1371 | unsigned int hash; |
1344 | fl4.saddr = skeys[s]; | 1372 | struct rtable __rcu **rthp; |
1345 | rt = __ip_route_output_key(net, &fl4); | 1373 | struct rtable *rt; |
1346 | if (IS_ERR(rt)) | 1374 | |
1347 | continue; | 1375 | hash = rt_hash(daddr, skeys[s], ikeys[i], rt_genid(net)); |
1348 | 1376 | ||
1349 | if (rt->dst.error || rt->dst.dev != dev || | 1377 | rthp = &rt_hash_table[hash].chain; |
1350 | rt->rt_gateway != old_gw) { | 1378 | |
1351 | ip_rt_put(rt); | 1379 | while ((rt = rcu_dereference(*rthp)) != NULL) { |
1352 | continue; | 1380 | rthp = &rt->dst.rt_next; |
1353 | } | 1381 | |
1354 | 1382 | if (rt->rt_key_dst != daddr || | |
1355 | if (!rt->peer) | 1383 | rt->rt_key_src != skeys[s] || |
1356 | rt_bind_peer(rt, rt->rt_dst, 1); | 1384 | rt->rt_oif != ikeys[i] || |
1385 | rt_is_input_route(rt) || | ||
1386 | rt_is_expired(rt) || | ||
1387 | !net_eq(dev_net(rt->dst.dev), net) || | ||
1388 | rt->dst.error || | ||
1389 | rt->dst.dev != dev || | ||
1390 | rt->rt_gateway != old_gw) | ||
1391 | continue; | ||
1357 | 1392 | ||
1358 | peer = rt->peer; | 1393 | if (!rt->peer) |
1359 | if (peer) { | 1394 | rt_bind_peer(rt, rt->rt_dst, 1); |
1360 | peer->redirect_learned.a4 = new_gw; | 1395 | |
1361 | atomic_inc(&__rt_peer_genid); | 1396 | peer = rt->peer; |
1397 | if (peer) { | ||
1398 | if (peer->redirect_learned.a4 != new_gw || | ||
1399 | peer->redirect_genid != redirect_genid) { | ||
1400 | peer->redirect_learned.a4 = new_gw; | ||
1401 | peer->redirect_genid = redirect_genid; | ||
1402 | atomic_inc(&__rt_peer_genid); | ||
1403 | } | ||
1404 | check_peer_redir(&rt->dst, peer); | ||
1405 | } | ||
1362 | } | 1406 | } |
1363 | |||
1364 | ip_rt_put(rt); | ||
1365 | return; | ||
1366 | } | 1407 | } |
1367 | } | 1408 | } |
1368 | return; | 1409 | return; |
@@ -1649,40 +1690,9 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
1649 | } | 1690 | } |
1650 | } | 1691 | } |
1651 | 1692 | ||
1652 | static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) | ||
1653 | { | ||
1654 | struct rtable *rt = (struct rtable *) dst; | ||
1655 | __be32 orig_gw = rt->rt_gateway; | ||
1656 | struct neighbour *n, *old_n; | ||
1657 | |||
1658 | dst_confirm(&rt->dst); | ||
1659 | |||
1660 | rt->rt_gateway = peer->redirect_learned.a4; | ||
1661 | |||
1662 | n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway); | ||
1663 | if (IS_ERR(n)) | ||
1664 | return PTR_ERR(n); | ||
1665 | old_n = xchg(&rt->dst._neighbour, n); | ||
1666 | if (old_n) | ||
1667 | neigh_release(old_n); | ||
1668 | if (!n || !(n->nud_state & NUD_VALID)) { | ||
1669 | if (n) | ||
1670 | neigh_event_send(n, NULL); | ||
1671 | rt->rt_gateway = orig_gw; | ||
1672 | return -EAGAIN; | ||
1673 | } else { | ||
1674 | rt->rt_flags |= RTCF_REDIRECTED; | ||
1675 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); | ||
1676 | } | ||
1677 | return 0; | ||
1678 | } | ||
1679 | 1693 | ||
1680 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) | 1694 | static void ipv4_validate_peer(struct rtable *rt) |
1681 | { | 1695 | { |
1682 | struct rtable *rt = (struct rtable *) dst; | ||
1683 | |||
1684 | if (rt_is_expired(rt)) | ||
1685 | return NULL; | ||
1686 | if (rt->rt_peer_genid != rt_peer_genid()) { | 1696 | if (rt->rt_peer_genid != rt_peer_genid()) { |
1687 | struct inet_peer *peer; | 1697 | struct inet_peer *peer; |
1688 | 1698 | ||
@@ -1691,17 +1701,26 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) | |||
1691 | 1701 | ||
1692 | peer = rt->peer; | 1702 | peer = rt->peer; |
1693 | if (peer) { | 1703 | if (peer) { |
1694 | check_peer_pmtu(dst, peer); | 1704 | check_peer_pmtu(&rt->dst, peer); |
1695 | 1705 | ||
1706 | if (peer->redirect_genid != redirect_genid) | ||
1707 | peer->redirect_learned.a4 = 0; | ||
1696 | if (peer->redirect_learned.a4 && | 1708 | if (peer->redirect_learned.a4 && |
1697 | peer->redirect_learned.a4 != rt->rt_gateway) { | 1709 | peer->redirect_learned.a4 != rt->rt_gateway) |
1698 | if (check_peer_redir(dst, peer)) | 1710 | check_peer_redir(&rt->dst, peer); |
1699 | return NULL; | ||
1700 | } | ||
1701 | } | 1711 | } |
1702 | 1712 | ||
1703 | rt->rt_peer_genid = rt_peer_genid(); | 1713 | rt->rt_peer_genid = rt_peer_genid(); |
1704 | } | 1714 | } |
1715 | } | ||
1716 | |||
1717 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) | ||
1718 | { | ||
1719 | struct rtable *rt = (struct rtable *) dst; | ||
1720 | |||
1721 | if (rt_is_expired(rt)) | ||
1722 | return NULL; | ||
1723 | ipv4_validate_peer(rt); | ||
1705 | return dst; | 1724 | return dst; |
1706 | } | 1725 | } |
1707 | 1726 | ||
@@ -1806,12 +1825,17 @@ static unsigned int ipv4_default_advmss(const struct dst_entry *dst) | |||
1806 | return advmss; | 1825 | return advmss; |
1807 | } | 1826 | } |
1808 | 1827 | ||
1809 | static unsigned int ipv4_default_mtu(const struct dst_entry *dst) | 1828 | static unsigned int ipv4_mtu(const struct dst_entry *dst) |
1810 | { | 1829 | { |
1811 | unsigned int mtu = dst->dev->mtu; | 1830 | const struct rtable *rt = (const struct rtable *) dst; |
1831 | unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); | ||
1832 | |||
1833 | if (mtu && rt_is_output_route(rt)) | ||
1834 | return mtu; | ||
1835 | |||
1836 | mtu = dst->dev->mtu; | ||
1812 | 1837 | ||
1813 | if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { | 1838 | if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { |
1814 | const struct rtable *rt = (const struct rtable *) dst; | ||
1815 | 1839 | ||
1816 | if (rt->rt_gateway != rt->rt_dst && mtu > 576) | 1840 | if (rt->rt_gateway != rt->rt_dst && mtu > 576) |
1817 | mtu = 576; | 1841 | mtu = 576; |
@@ -1844,6 +1868,8 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4, | |||
1844 | dst_init_metrics(&rt->dst, peer->metrics, false); | 1868 | dst_init_metrics(&rt->dst, peer->metrics, false); |
1845 | 1869 | ||
1846 | check_peer_pmtu(&rt->dst, peer); | 1870 | check_peer_pmtu(&rt->dst, peer); |
1871 | if (peer->redirect_genid != redirect_genid) | ||
1872 | peer->redirect_learned.a4 = 0; | ||
1847 | if (peer->redirect_learned.a4 && | 1873 | if (peer->redirect_learned.a4 && |
1848 | peer->redirect_learned.a4 != rt->rt_gateway) { | 1874 | peer->redirect_learned.a4 != rt->rt_gateway) { |
1849 | rt->rt_gateway = peer->redirect_learned.a4; | 1875 | rt->rt_gateway = peer->redirect_learned.a4; |
@@ -2349,6 +2375,7 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
2349 | rth->rt_mark == skb->mark && | 2375 | rth->rt_mark == skb->mark && |
2350 | net_eq(dev_net(rth->dst.dev), net) && | 2376 | net_eq(dev_net(rth->dst.dev), net) && |
2351 | !rt_is_expired(rth)) { | 2377 | !rt_is_expired(rth)) { |
2378 | ipv4_validate_peer(rth); | ||
2352 | if (noref) { | 2379 | if (noref) { |
2353 | dst_use_noref(&rth->dst, jiffies); | 2380 | dst_use_noref(&rth->dst, jiffies); |
2354 | skb_dst_set_noref(skb, &rth->dst); | 2381 | skb_dst_set_noref(skb, &rth->dst); |
@@ -2407,11 +2434,11 @@ EXPORT_SYMBOL(ip_route_input_common); | |||
2407 | static struct rtable *__mkroute_output(const struct fib_result *res, | 2434 | static struct rtable *__mkroute_output(const struct fib_result *res, |
2408 | const struct flowi4 *fl4, | 2435 | const struct flowi4 *fl4, |
2409 | __be32 orig_daddr, __be32 orig_saddr, | 2436 | __be32 orig_daddr, __be32 orig_saddr, |
2410 | int orig_oif, struct net_device *dev_out, | 2437 | int orig_oif, __u8 orig_rtos, |
2438 | struct net_device *dev_out, | ||
2411 | unsigned int flags) | 2439 | unsigned int flags) |
2412 | { | 2440 | { |
2413 | struct fib_info *fi = res->fi; | 2441 | struct fib_info *fi = res->fi; |
2414 | u32 tos = RT_FL_TOS(fl4); | ||
2415 | struct in_device *in_dev; | 2442 | struct in_device *in_dev; |
2416 | u16 type = res->type; | 2443 | u16 type = res->type; |
2417 | struct rtable *rth; | 2444 | struct rtable *rth; |
@@ -2462,7 +2489,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | |||
2462 | rth->rt_genid = rt_genid(dev_net(dev_out)); | 2489 | rth->rt_genid = rt_genid(dev_net(dev_out)); |
2463 | rth->rt_flags = flags; | 2490 | rth->rt_flags = flags; |
2464 | rth->rt_type = type; | 2491 | rth->rt_type = type; |
2465 | rth->rt_key_tos = tos; | 2492 | rth->rt_key_tos = orig_rtos; |
2466 | rth->rt_dst = fl4->daddr; | 2493 | rth->rt_dst = fl4->daddr; |
2467 | rth->rt_src = fl4->saddr; | 2494 | rth->rt_src = fl4->saddr; |
2468 | rth->rt_route_iif = 0; | 2495 | rth->rt_route_iif = 0; |
@@ -2512,7 +2539,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | |||
2512 | static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4) | 2539 | static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4) |
2513 | { | 2540 | { |
2514 | struct net_device *dev_out = NULL; | 2541 | struct net_device *dev_out = NULL; |
2515 | u32 tos = RT_FL_TOS(fl4); | 2542 | __u8 tos = RT_FL_TOS(fl4); |
2516 | unsigned int flags = 0; | 2543 | unsigned int flags = 0; |
2517 | struct fib_result res; | 2544 | struct fib_result res; |
2518 | struct rtable *rth; | 2545 | struct rtable *rth; |
@@ -2688,7 +2715,7 @@ static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4) | |||
2688 | 2715 | ||
2689 | make_route: | 2716 | make_route: |
2690 | rth = __mkroute_output(&res, fl4, orig_daddr, orig_saddr, orig_oif, | 2717 | rth = __mkroute_output(&res, fl4, orig_daddr, orig_saddr, orig_oif, |
2691 | dev_out, flags); | 2718 | tos, dev_out, flags); |
2692 | if (!IS_ERR(rth)) { | 2719 | if (!IS_ERR(rth)) { |
2693 | unsigned int hash; | 2720 | unsigned int hash; |
2694 | 2721 | ||
@@ -2724,6 +2751,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp4) | |||
2724 | (IPTOS_RT_MASK | RTO_ONLINK)) && | 2751 | (IPTOS_RT_MASK | RTO_ONLINK)) && |
2725 | net_eq(dev_net(rth->dst.dev), net) && | 2752 | net_eq(dev_net(rth->dst.dev), net) && |
2726 | !rt_is_expired(rth)) { | 2753 | !rt_is_expired(rth)) { |
2754 | ipv4_validate_peer(rth); | ||
2727 | dst_use(&rth->dst, jiffies); | 2755 | dst_use(&rth->dst, jiffies); |
2728 | RT_CACHE_STAT_INC(out_hit); | 2756 | RT_CACHE_STAT_INC(out_hit); |
2729 | rcu_read_unlock_bh(); | 2757 | rcu_read_unlock_bh(); |
@@ -2747,9 +2775,11 @@ static struct dst_entry *ipv4_blackhole_dst_check(struct dst_entry *dst, u32 coo | |||
2747 | return NULL; | 2775 | return NULL; |
2748 | } | 2776 | } |
2749 | 2777 | ||
2750 | static unsigned int ipv4_blackhole_default_mtu(const struct dst_entry *dst) | 2778 | static unsigned int ipv4_blackhole_mtu(const struct dst_entry *dst) |
2751 | { | 2779 | { |
2752 | return 0; | 2780 | unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); |
2781 | |||
2782 | return mtu ? : dst->dev->mtu; | ||
2753 | } | 2783 | } |
2754 | 2784 | ||
2755 | static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) | 2785 | static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) |
@@ -2767,7 +2797,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { | |||
2767 | .protocol = cpu_to_be16(ETH_P_IP), | 2797 | .protocol = cpu_to_be16(ETH_P_IP), |
2768 | .destroy = ipv4_dst_destroy, | 2798 | .destroy = ipv4_dst_destroy, |
2769 | .check = ipv4_blackhole_dst_check, | 2799 | .check = ipv4_blackhole_dst_check, |
2770 | .default_mtu = ipv4_blackhole_default_mtu, | 2800 | .mtu = ipv4_blackhole_mtu, |
2771 | .default_advmss = ipv4_default_advmss, | 2801 | .default_advmss = ipv4_default_advmss, |
2772 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, | 2802 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, |
2773 | .cow_metrics = ipv4_rt_blackhole_cow_metrics, | 2803 | .cow_metrics = ipv4_rt_blackhole_cow_metrics, |
@@ -2845,7 +2875,7 @@ static int rt_fill_info(struct net *net, | |||
2845 | struct rtable *rt = skb_rtable(skb); | 2875 | struct rtable *rt = skb_rtable(skb); |
2846 | struct rtmsg *r; | 2876 | struct rtmsg *r; |
2847 | struct nlmsghdr *nlh; | 2877 | struct nlmsghdr *nlh; |
2848 | long expires = 0; | 2878 | unsigned long expires = 0; |
2849 | const struct inet_peer *peer = rt->peer; | 2879 | const struct inet_peer *peer = rt->peer; |
2850 | u32 id = 0, ts = 0, tsage = 0, error; | 2880 | u32 id = 0, ts = 0, tsage = 0, error; |
2851 | 2881 | ||
@@ -2902,8 +2932,12 @@ static int rt_fill_info(struct net *net, | |||
2902 | tsage = get_seconds() - peer->tcp_ts_stamp; | 2932 | tsage = get_seconds() - peer->tcp_ts_stamp; |
2903 | } | 2933 | } |
2904 | expires = ACCESS_ONCE(peer->pmtu_expires); | 2934 | expires = ACCESS_ONCE(peer->pmtu_expires); |
2905 | if (expires) | 2935 | if (expires) { |
2906 | expires -= jiffies; | 2936 | if (time_before(jiffies, expires)) |
2937 | expires -= jiffies; | ||
2938 | else | ||
2939 | expires = 0; | ||
2940 | } | ||
2907 | } | 2941 | } |
2908 | 2942 | ||
2909 | if (rt_is_input_route(rt)) { | 2943 | if (rt_is_input_route(rt)) { |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a7443159c400..a9db4b1a2215 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1510,6 +1510,7 @@ exit: | |||
1510 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | 1510 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); |
1511 | return NULL; | 1511 | return NULL; |
1512 | put_and_exit: | 1512 | put_and_exit: |
1513 | tcp_clear_xmit_timers(newsk); | ||
1513 | bh_unlock_sock(newsk); | 1514 | bh_unlock_sock(newsk); |
1514 | sock_put(newsk); | 1515 | sock_put(newsk); |
1515 | goto exit; | 1516 | goto exit; |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 980b98f6288c..63170e297540 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -1382,7 +1382,7 @@ static inline int tcp_minshall_check(const struct tcp_sock *tp) | |||
1382 | /* Return 0, if packet can be sent now without violation Nagle's rules: | 1382 | /* Return 0, if packet can be sent now without violation Nagle's rules: |
1383 | * 1. It is full sized. | 1383 | * 1. It is full sized. |
1384 | * 2. Or it contains FIN. (already checked by caller) | 1384 | * 2. Or it contains FIN. (already checked by caller) |
1385 | * 3. Or TCP_NODELAY was set. | 1385 | * 3. Or TCP_CORK is not set, and TCP_NODELAY is set. |
1386 | * 4. Or TCP_CORK is not set, and all sent packets are ACKed. | 1386 | * 4. Or TCP_CORK is not set, and all sent packets are ACKed. |
1387 | * With Minshall's modification: all sent small packets are ACKed. | 1387 | * With Minshall's modification: all sent small packets are ACKed. |
1388 | */ | 1388 | */ |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ab0966df1e2a..5a65eeac1d29 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1164,7 +1164,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1164 | struct inet_sock *inet = inet_sk(sk); | 1164 | struct inet_sock *inet = inet_sk(sk); |
1165 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | 1165 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; |
1166 | struct sk_buff *skb; | 1166 | struct sk_buff *skb; |
1167 | unsigned int ulen; | 1167 | unsigned int ulen, copied; |
1168 | int peeked; | 1168 | int peeked; |
1169 | int err; | 1169 | int err; |
1170 | int is_udplite = IS_UDPLITE(sk); | 1170 | int is_udplite = IS_UDPLITE(sk); |
@@ -1186,9 +1186,10 @@ try_again: | |||
1186 | goto out; | 1186 | goto out; |
1187 | 1187 | ||
1188 | ulen = skb->len - sizeof(struct udphdr); | 1188 | ulen = skb->len - sizeof(struct udphdr); |
1189 | if (len > ulen) | 1189 | copied = len; |
1190 | len = ulen; | 1190 | if (copied > ulen) |
1191 | else if (len < ulen) | 1191 | copied = ulen; |
1192 | else if (copied < ulen) | ||
1192 | msg->msg_flags |= MSG_TRUNC; | 1193 | msg->msg_flags |= MSG_TRUNC; |
1193 | 1194 | ||
1194 | /* | 1195 | /* |
@@ -1197,14 +1198,14 @@ try_again: | |||
1197 | * coverage checksum (UDP-Lite), do it before the copy. | 1198 | * coverage checksum (UDP-Lite), do it before the copy. |
1198 | */ | 1199 | */ |
1199 | 1200 | ||
1200 | if (len < ulen || UDP_SKB_CB(skb)->partial_cov) { | 1201 | if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { |
1201 | if (udp_lib_checksum_complete(skb)) | 1202 | if (udp_lib_checksum_complete(skb)) |
1202 | goto csum_copy_err; | 1203 | goto csum_copy_err; |
1203 | } | 1204 | } |
1204 | 1205 | ||
1205 | if (skb_csum_unnecessary(skb)) | 1206 | if (skb_csum_unnecessary(skb)) |
1206 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | 1207 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), |
1207 | msg->msg_iov, len); | 1208 | msg->msg_iov, copied); |
1208 | else { | 1209 | else { |
1209 | err = skb_copy_and_csum_datagram_iovec(skb, | 1210 | err = skb_copy_and_csum_datagram_iovec(skb, |
1210 | sizeof(struct udphdr), | 1211 | sizeof(struct udphdr), |
@@ -1233,7 +1234,7 @@ try_again: | |||
1233 | if (inet->cmsg_flags) | 1234 | if (inet->cmsg_flags) |
1234 | ip_cmsg_recv(msg, skb); | 1235 | ip_cmsg_recv(msg, skb); |
1235 | 1236 | ||
1236 | err = len; | 1237 | err = copied; |
1237 | if (flags & MSG_TRUNC) | 1238 | if (flags & MSG_TRUNC) |
1238 | err = ulen; | 1239 | err = ulen; |
1239 | 1240 | ||