diff options
Diffstat (limited to 'net/ipv4')
-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 | 5 | ||||
-rw-r--r-- | net/ipv4/netfilter.c | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/Kconfig | 1 | ||||
-rw-r--r-- | net/ipv4/route.c | 94 | ||||
-rw-r--r-- | net/ipv4/udp.c | 15 |
9 files changed, 88 insertions, 54 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index c6b5092f29a..65f01dc4756 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 c7472eff2d5..b2ca095cb9d 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 68e8ac51438..ccee270a9b6 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_TCLASS - 1))) | ||
137 | RTA_PUT_U8(skb, INET_DIAG_TCLASS, 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 3b34d1c8627..29a07b6c716 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 05d20cca9d6..1e60f767907 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,7 +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; |
643 | iph->daddr = nexthop; | 644 | opt->nexthop = nexthop; |
644 | opt->is_changed = 1; | 645 | opt->is_changed = 1; |
645 | } | 646 | } |
646 | return 0; | 647 | return 0; |
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 9899619ab9b..4f47e064e26 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 1dfc18a03fd..f19f2182894 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/route.c b/net/ipv4/route.c index 0c74da8a047..46af62363b8 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,7 +1310,7 @@ 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 | ||
1307 | static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) | 1313 | static void check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) |
1308 | { | 1314 | { |
1309 | struct rtable *rt = (struct rtable *) dst; | 1315 | struct rtable *rt = (struct rtable *) dst; |
1310 | __be32 orig_gw = rt->rt_gateway; | 1316 | __be32 orig_gw = rt->rt_gateway; |
@@ -1315,21 +1321,19 @@ static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) | |||
1315 | rt->rt_gateway = peer->redirect_learned.a4; | 1321 | rt->rt_gateway = peer->redirect_learned.a4; |
1316 | 1322 | ||
1317 | n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway); | 1323 | n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway); |
1318 | if (IS_ERR(n)) | 1324 | if (IS_ERR(n)) { |
1319 | return PTR_ERR(n); | 1325 | rt->rt_gateway = orig_gw; |
1326 | return; | ||
1327 | } | ||
1320 | old_n = xchg(&rt->dst._neighbour, n); | 1328 | old_n = xchg(&rt->dst._neighbour, n); |
1321 | if (old_n) | 1329 | if (old_n) |
1322 | neigh_release(old_n); | 1330 | neigh_release(old_n); |
1323 | if (!n || !(n->nud_state & NUD_VALID)) { | 1331 | if (!(n->nud_state & NUD_VALID)) { |
1324 | if (n) | 1332 | neigh_event_send(n, NULL); |
1325 | neigh_event_send(n, NULL); | ||
1326 | rt->rt_gateway = orig_gw; | ||
1327 | return -EAGAIN; | ||
1328 | } else { | 1333 | } else { |
1329 | rt->rt_flags |= RTCF_REDIRECTED; | 1334 | rt->rt_flags |= RTCF_REDIRECTED; |
1330 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); | 1335 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); |
1331 | } | 1336 | } |
1332 | return 0; | ||
1333 | } | 1337 | } |
1334 | 1338 | ||
1335 | /* called in rcu_read_lock() section */ | 1339 | /* called in rcu_read_lock() section */ |
@@ -1391,8 +1395,10 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1391 | 1395 | ||
1392 | peer = rt->peer; | 1396 | peer = rt->peer; |
1393 | if (peer) { | 1397 | if (peer) { |
1394 | if (peer->redirect_learned.a4 != new_gw) { | 1398 | if (peer->redirect_learned.a4 != new_gw || |
1399 | peer->redirect_genid != redirect_genid) { | ||
1395 | peer->redirect_learned.a4 = new_gw; | 1400 | peer->redirect_learned.a4 = new_gw; |
1401 | peer->redirect_genid = redirect_genid; | ||
1396 | atomic_inc(&__rt_peer_genid); | 1402 | atomic_inc(&__rt_peer_genid); |
1397 | } | 1403 | } |
1398 | check_peer_redir(&rt->dst, peer); | 1404 | check_peer_redir(&rt->dst, peer); |
@@ -1685,12 +1691,8 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
1685 | } | 1691 | } |
1686 | 1692 | ||
1687 | 1693 | ||
1688 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) | 1694 | static void ipv4_validate_peer(struct rtable *rt) |
1689 | { | 1695 | { |
1690 | struct rtable *rt = (struct rtable *) dst; | ||
1691 | |||
1692 | if (rt_is_expired(rt)) | ||
1693 | return NULL; | ||
1694 | if (rt->rt_peer_genid != rt_peer_genid()) { | 1696 | if (rt->rt_peer_genid != rt_peer_genid()) { |
1695 | struct inet_peer *peer; | 1697 | struct inet_peer *peer; |
1696 | 1698 | ||
@@ -1699,17 +1701,26 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) | |||
1699 | 1701 | ||
1700 | peer = rt->peer; | 1702 | peer = rt->peer; |
1701 | if (peer) { | 1703 | if (peer) { |
1702 | check_peer_pmtu(dst, peer); | 1704 | check_peer_pmtu(&rt->dst, peer); |
1703 | 1705 | ||
1706 | if (peer->redirect_genid != redirect_genid) | ||
1707 | peer->redirect_learned.a4 = 0; | ||
1704 | if (peer->redirect_learned.a4 && | 1708 | if (peer->redirect_learned.a4 && |
1705 | peer->redirect_learned.a4 != rt->rt_gateway) { | 1709 | peer->redirect_learned.a4 != rt->rt_gateway) |
1706 | if (check_peer_redir(dst, peer)) | 1710 | check_peer_redir(&rt->dst, peer); |
1707 | return NULL; | ||
1708 | } | ||
1709 | } | 1711 | } |
1710 | 1712 | ||
1711 | rt->rt_peer_genid = rt_peer_genid(); | 1713 | rt->rt_peer_genid = rt_peer_genid(); |
1712 | } | 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); | ||
1713 | return dst; | 1724 | return dst; |
1714 | } | 1725 | } |
1715 | 1726 | ||
@@ -1814,12 +1825,17 @@ static unsigned int ipv4_default_advmss(const struct dst_entry *dst) | |||
1814 | return advmss; | 1825 | return advmss; |
1815 | } | 1826 | } |
1816 | 1827 | ||
1817 | static unsigned int ipv4_default_mtu(const struct dst_entry *dst) | 1828 | static unsigned int ipv4_mtu(const struct dst_entry *dst) |
1818 | { | 1829 | { |
1819 | 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; | ||
1820 | 1837 | ||
1821 | if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { | 1838 | if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { |
1822 | const struct rtable *rt = (const struct rtable *) dst; | ||
1823 | 1839 | ||
1824 | if (rt->rt_gateway != rt->rt_dst && mtu > 576) | 1840 | if (rt->rt_gateway != rt->rt_dst && mtu > 576) |
1825 | mtu = 576; | 1841 | mtu = 576; |
@@ -1852,6 +1868,8 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4, | |||
1852 | dst_init_metrics(&rt->dst, peer->metrics, false); | 1868 | dst_init_metrics(&rt->dst, peer->metrics, false); |
1853 | 1869 | ||
1854 | 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; | ||
1855 | if (peer->redirect_learned.a4 && | 1873 | if (peer->redirect_learned.a4 && |
1856 | peer->redirect_learned.a4 != rt->rt_gateway) { | 1874 | peer->redirect_learned.a4 != rt->rt_gateway) { |
1857 | rt->rt_gateway = peer->redirect_learned.a4; | 1875 | rt->rt_gateway = peer->redirect_learned.a4; |
@@ -2357,6 +2375,7 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
2357 | rth->rt_mark == skb->mark && | 2375 | rth->rt_mark == skb->mark && |
2358 | net_eq(dev_net(rth->dst.dev), net) && | 2376 | net_eq(dev_net(rth->dst.dev), net) && |
2359 | !rt_is_expired(rth)) { | 2377 | !rt_is_expired(rth)) { |
2378 | ipv4_validate_peer(rth); | ||
2360 | if (noref) { | 2379 | if (noref) { |
2361 | dst_use_noref(&rth->dst, jiffies); | 2380 | dst_use_noref(&rth->dst, jiffies); |
2362 | skb_dst_set_noref(skb, &rth->dst); | 2381 | skb_dst_set_noref(skb, &rth->dst); |
@@ -2415,11 +2434,11 @@ EXPORT_SYMBOL(ip_route_input_common); | |||
2415 | static struct rtable *__mkroute_output(const struct fib_result *res, | 2434 | static struct rtable *__mkroute_output(const struct fib_result *res, |
2416 | const struct flowi4 *fl4, | 2435 | const struct flowi4 *fl4, |
2417 | __be32 orig_daddr, __be32 orig_saddr, | 2436 | __be32 orig_daddr, __be32 orig_saddr, |
2418 | int orig_oif, struct net_device *dev_out, | 2437 | int orig_oif, __u8 orig_rtos, |
2438 | struct net_device *dev_out, | ||
2419 | unsigned int flags) | 2439 | unsigned int flags) |
2420 | { | 2440 | { |
2421 | struct fib_info *fi = res->fi; | 2441 | struct fib_info *fi = res->fi; |
2422 | u32 tos = RT_FL_TOS(fl4); | ||
2423 | struct in_device *in_dev; | 2442 | struct in_device *in_dev; |
2424 | u16 type = res->type; | 2443 | u16 type = res->type; |
2425 | struct rtable *rth; | 2444 | struct rtable *rth; |
@@ -2470,7 +2489,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | |||
2470 | rth->rt_genid = rt_genid(dev_net(dev_out)); | 2489 | rth->rt_genid = rt_genid(dev_net(dev_out)); |
2471 | rth->rt_flags = flags; | 2490 | rth->rt_flags = flags; |
2472 | rth->rt_type = type; | 2491 | rth->rt_type = type; |
2473 | rth->rt_key_tos = tos; | 2492 | rth->rt_key_tos = orig_rtos; |
2474 | rth->rt_dst = fl4->daddr; | 2493 | rth->rt_dst = fl4->daddr; |
2475 | rth->rt_src = fl4->saddr; | 2494 | rth->rt_src = fl4->saddr; |
2476 | rth->rt_route_iif = 0; | 2495 | rth->rt_route_iif = 0; |
@@ -2520,7 +2539,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | |||
2520 | 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) |
2521 | { | 2540 | { |
2522 | struct net_device *dev_out = NULL; | 2541 | struct net_device *dev_out = NULL; |
2523 | u32 tos = RT_FL_TOS(fl4); | 2542 | __u8 tos = RT_FL_TOS(fl4); |
2524 | unsigned int flags = 0; | 2543 | unsigned int flags = 0; |
2525 | struct fib_result res; | 2544 | struct fib_result res; |
2526 | struct rtable *rth; | 2545 | struct rtable *rth; |
@@ -2696,7 +2715,7 @@ static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4) | |||
2696 | 2715 | ||
2697 | make_route: | 2716 | make_route: |
2698 | rth = __mkroute_output(&res, fl4, orig_daddr, orig_saddr, orig_oif, | 2717 | rth = __mkroute_output(&res, fl4, orig_daddr, orig_saddr, orig_oif, |
2699 | dev_out, flags); | 2718 | tos, dev_out, flags); |
2700 | if (!IS_ERR(rth)) { | 2719 | if (!IS_ERR(rth)) { |
2701 | unsigned int hash; | 2720 | unsigned int hash; |
2702 | 2721 | ||
@@ -2732,6 +2751,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp4) | |||
2732 | (IPTOS_RT_MASK | RTO_ONLINK)) && | 2751 | (IPTOS_RT_MASK | RTO_ONLINK)) && |
2733 | net_eq(dev_net(rth->dst.dev), net) && | 2752 | net_eq(dev_net(rth->dst.dev), net) && |
2734 | !rt_is_expired(rth)) { | 2753 | !rt_is_expired(rth)) { |
2754 | ipv4_validate_peer(rth); | ||
2735 | dst_use(&rth->dst, jiffies); | 2755 | dst_use(&rth->dst, jiffies); |
2736 | RT_CACHE_STAT_INC(out_hit); | 2756 | RT_CACHE_STAT_INC(out_hit); |
2737 | rcu_read_unlock_bh(); | 2757 | rcu_read_unlock_bh(); |
@@ -2755,9 +2775,11 @@ static struct dst_entry *ipv4_blackhole_dst_check(struct dst_entry *dst, u32 coo | |||
2755 | return NULL; | 2775 | return NULL; |
2756 | } | 2776 | } |
2757 | 2777 | ||
2758 | static unsigned int ipv4_blackhole_default_mtu(const struct dst_entry *dst) | 2778 | static unsigned int ipv4_blackhole_mtu(const struct dst_entry *dst) |
2759 | { | 2779 | { |
2760 | return 0; | 2780 | unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); |
2781 | |||
2782 | return mtu ? : dst->dev->mtu; | ||
2761 | } | 2783 | } |
2762 | 2784 | ||
2763 | 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) |
@@ -2775,7 +2797,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { | |||
2775 | .protocol = cpu_to_be16(ETH_P_IP), | 2797 | .protocol = cpu_to_be16(ETH_P_IP), |
2776 | .destroy = ipv4_dst_destroy, | 2798 | .destroy = ipv4_dst_destroy, |
2777 | .check = ipv4_blackhole_dst_check, | 2799 | .check = ipv4_blackhole_dst_check, |
2778 | .default_mtu = ipv4_blackhole_default_mtu, | 2800 | .mtu = ipv4_blackhole_mtu, |
2779 | .default_advmss = ipv4_default_advmss, | 2801 | .default_advmss = ipv4_default_advmss, |
2780 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, | 2802 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, |
2781 | .cow_metrics = ipv4_rt_blackhole_cow_metrics, | 2803 | .cow_metrics = ipv4_rt_blackhole_cow_metrics, |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ab0966df1e2..5a65eeac1d2 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 | ||