diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/Kconfig | 2 | ||||
-rw-r--r-- | net/ipv4/datagram.c | 5 | ||||
-rw-r--r-- | net/ipv4/fib_frontend.c | 15 | ||||
-rw-r--r-- | net/ipv4/fib_trie.c | 8 | ||||
-rw-r--r-- | net/ipv4/igmp.c | 2 | ||||
-rw-r--r-- | net/ipv4/ip_sockglue.c | 3 | ||||
-rw-r--r-- | net/ipv4/route.c | 7 | ||||
-rw-r--r-- | net/ipv4/udp.c | 44 |
8 files changed, 78 insertions, 8 deletions
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 7c3a7d191249..571f8950ed06 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
@@ -46,7 +46,7 @@ config IP_ADVANCED_ROUTER | |||
46 | rp_filter on use: | 46 | rp_filter on use: |
47 | 47 | ||
48 | echo 1 > /proc/sys/net/ipv4/conf/<device>/rp_filter | 48 | echo 1 > /proc/sys/net/ipv4/conf/<device>/rp_filter |
49 | and | 49 | or |
50 | echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter | 50 | echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter |
51 | 51 | ||
52 | Note that some distributions enable it in startup scripts. | 52 | Note that some distributions enable it in startup scripts. |
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c index f0550941df7b..721a8a37b45c 100644 --- a/net/ipv4/datagram.c +++ b/net/ipv4/datagram.c | |||
@@ -62,8 +62,11 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
62 | } | 62 | } |
63 | if (!inet->inet_saddr) | 63 | if (!inet->inet_saddr) |
64 | inet->inet_saddr = rt->rt_src; /* Update source address */ | 64 | inet->inet_saddr = rt->rt_src; /* Update source address */ |
65 | if (!inet->inet_rcv_saddr) | 65 | if (!inet->inet_rcv_saddr) { |
66 | inet->inet_rcv_saddr = rt->rt_src; | 66 | inet->inet_rcv_saddr = rt->rt_src; |
67 | if (sk->sk_prot->rehash) | ||
68 | sk->sk_prot->rehash(sk); | ||
69 | } | ||
67 | inet->inet_daddr = rt->rt_dst; | 70 | inet->inet_daddr = rt->rt_dst; |
68 | inet->inet_dport = usin->sin_port; | 71 | inet->inet_dport = usin->sin_port; |
69 | sk->sk_state = TCP_ESTABLISHED; | 72 | sk->sk_state = TCP_ESTABLISHED; |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index a43968918350..7d02a9f999fa 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -246,6 +246,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, | |||
246 | 246 | ||
247 | struct fib_result res; | 247 | struct fib_result res; |
248 | int no_addr, rpf, accept_local; | 248 | int no_addr, rpf, accept_local; |
249 | bool dev_match; | ||
249 | int ret; | 250 | int ret; |
250 | struct net *net; | 251 | struct net *net; |
251 | 252 | ||
@@ -273,12 +274,22 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, | |||
273 | } | 274 | } |
274 | *spec_dst = FIB_RES_PREFSRC(res); | 275 | *spec_dst = FIB_RES_PREFSRC(res); |
275 | fib_combine_itag(itag, &res); | 276 | fib_combine_itag(itag, &res); |
277 | dev_match = false; | ||
278 | |||
276 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 279 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
277 | if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1) | 280 | for (ret = 0; ret < res.fi->fib_nhs; ret++) { |
281 | struct fib_nh *nh = &res.fi->fib_nh[ret]; | ||
282 | |||
283 | if (nh->nh_dev == dev) { | ||
284 | dev_match = true; | ||
285 | break; | ||
286 | } | ||
287 | } | ||
278 | #else | 288 | #else |
279 | if (FIB_RES_DEV(res) == dev) | 289 | if (FIB_RES_DEV(res) == dev) |
290 | dev_match = true; | ||
280 | #endif | 291 | #endif |
281 | { | 292 | if (dev_match) { |
282 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; | 293 | ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; |
283 | fib_res_put(&res); | 294 | fib_res_put(&res); |
284 | return ret; | 295 | return ret; |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 79d057a939ba..4a8e370862bc 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -186,7 +186,9 @@ static inline struct tnode *node_parent_rcu(struct node *node) | |||
186 | { | 186 | { |
187 | struct tnode *ret = node_parent(node); | 187 | struct tnode *ret = node_parent(node); |
188 | 188 | ||
189 | return rcu_dereference(ret); | 189 | return rcu_dereference_check(ret, |
190 | rcu_read_lock_held() || | ||
191 | lockdep_rtnl_is_held()); | ||
190 | } | 192 | } |
191 | 193 | ||
192 | /* Same as rcu_assign_pointer | 194 | /* Same as rcu_assign_pointer |
@@ -1753,7 +1755,9 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c) | |||
1753 | 1755 | ||
1754 | static struct leaf *trie_firstleaf(struct trie *t) | 1756 | static struct leaf *trie_firstleaf(struct trie *t) |
1755 | { | 1757 | { |
1756 | struct tnode *n = (struct tnode *) rcu_dereference(t->trie); | 1758 | struct tnode *n = (struct tnode *) rcu_dereference_check(t->trie, |
1759 | rcu_read_lock_held() || | ||
1760 | lockdep_rtnl_is_held()); | ||
1757 | 1761 | ||
1758 | if (!n) | 1762 | if (!n) |
1759 | return NULL; | 1763 | return NULL; |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a1ad0e7180d2..1fdcacd36ce7 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -834,7 +834,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | |||
834 | int mark = 0; | 834 | int mark = 0; |
835 | 835 | ||
836 | 836 | ||
837 | if (len == 8) { | 837 | if (len == 8 || IGMP_V2_SEEN(in_dev)) { |
838 | if (ih->code == 0) { | 838 | if (ih->code == 0) { |
839 | /* Alas, old v1 router presents here. */ | 839 | /* Alas, old v1 router presents here. */ |
840 | 840 | ||
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 6c40a8c46e79..64b70ad162e3 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -1129,6 +1129,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, | |||
1129 | case IP_HDRINCL: | 1129 | case IP_HDRINCL: |
1130 | val = inet->hdrincl; | 1130 | val = inet->hdrincl; |
1131 | break; | 1131 | break; |
1132 | case IP_NODEFRAG: | ||
1133 | val = inet->nodefrag; | ||
1134 | break; | ||
1132 | case IP_MTU_DISCOVER: | 1135 | case IP_MTU_DISCOVER: |
1133 | val = inet->pmtudisc; | 1136 | val = inet->pmtudisc; |
1134 | break; | 1137 | break; |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 3f56b6e6c6aa..6298f75d5e93 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2738,6 +2738,11 @@ slow_output: | |||
2738 | } | 2738 | } |
2739 | EXPORT_SYMBOL_GPL(__ip_route_output_key); | 2739 | EXPORT_SYMBOL_GPL(__ip_route_output_key); |
2740 | 2740 | ||
2741 | static struct dst_entry *ipv4_blackhole_dst_check(struct dst_entry *dst, u32 cookie) | ||
2742 | { | ||
2743 | return NULL; | ||
2744 | } | ||
2745 | |||
2741 | static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) | 2746 | static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) |
2742 | { | 2747 | { |
2743 | } | 2748 | } |
@@ -2746,7 +2751,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { | |||
2746 | .family = AF_INET, | 2751 | .family = AF_INET, |
2747 | .protocol = cpu_to_be16(ETH_P_IP), | 2752 | .protocol = cpu_to_be16(ETH_P_IP), |
2748 | .destroy = ipv4_dst_destroy, | 2753 | .destroy = ipv4_dst_destroy, |
2749 | .check = ipv4_dst_check, | 2754 | .check = ipv4_blackhole_dst_check, |
2750 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, | 2755 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, |
2751 | .entries = ATOMIC_INIT(0), | 2756 | .entries = ATOMIC_INIT(0), |
2752 | }; | 2757 | }; |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 32e0bef60d0a..fb23c2e63b52 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1260,6 +1260,49 @@ void udp_lib_unhash(struct sock *sk) | |||
1260 | } | 1260 | } |
1261 | EXPORT_SYMBOL(udp_lib_unhash); | 1261 | EXPORT_SYMBOL(udp_lib_unhash); |
1262 | 1262 | ||
1263 | /* | ||
1264 | * inet_rcv_saddr was changed, we must rehash secondary hash | ||
1265 | */ | ||
1266 | void udp_lib_rehash(struct sock *sk, u16 newhash) | ||
1267 | { | ||
1268 | if (sk_hashed(sk)) { | ||
1269 | struct udp_table *udptable = sk->sk_prot->h.udp_table; | ||
1270 | struct udp_hslot *hslot, *hslot2, *nhslot2; | ||
1271 | |||
1272 | hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); | ||
1273 | nhslot2 = udp_hashslot2(udptable, newhash); | ||
1274 | udp_sk(sk)->udp_portaddr_hash = newhash; | ||
1275 | if (hslot2 != nhslot2) { | ||
1276 | hslot = udp_hashslot(udptable, sock_net(sk), | ||
1277 | udp_sk(sk)->udp_port_hash); | ||
1278 | /* we must lock primary chain too */ | ||
1279 | spin_lock_bh(&hslot->lock); | ||
1280 | |||
1281 | spin_lock(&hslot2->lock); | ||
1282 | hlist_nulls_del_init_rcu(&udp_sk(sk)->udp_portaddr_node); | ||
1283 | hslot2->count--; | ||
1284 | spin_unlock(&hslot2->lock); | ||
1285 | |||
1286 | spin_lock(&nhslot2->lock); | ||
1287 | hlist_nulls_add_head_rcu(&udp_sk(sk)->udp_portaddr_node, | ||
1288 | &nhslot2->head); | ||
1289 | nhslot2->count++; | ||
1290 | spin_unlock(&nhslot2->lock); | ||
1291 | |||
1292 | spin_unlock_bh(&hslot->lock); | ||
1293 | } | ||
1294 | } | ||
1295 | } | ||
1296 | EXPORT_SYMBOL(udp_lib_rehash); | ||
1297 | |||
1298 | static void udp_v4_rehash(struct sock *sk) | ||
1299 | { | ||
1300 | u16 new_hash = udp4_portaddr_hash(sock_net(sk), | ||
1301 | inet_sk(sk)->inet_rcv_saddr, | ||
1302 | inet_sk(sk)->inet_num); | ||
1303 | udp_lib_rehash(sk, new_hash); | ||
1304 | } | ||
1305 | |||
1263 | static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | 1306 | static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) |
1264 | { | 1307 | { |
1265 | int rc; | 1308 | int rc; |
@@ -1843,6 +1886,7 @@ struct proto udp_prot = { | |||
1843 | .backlog_rcv = __udp_queue_rcv_skb, | 1886 | .backlog_rcv = __udp_queue_rcv_skb, |
1844 | .hash = udp_lib_hash, | 1887 | .hash = udp_lib_hash, |
1845 | .unhash = udp_lib_unhash, | 1888 | .unhash = udp_lib_unhash, |
1889 | .rehash = udp_v4_rehash, | ||
1846 | .get_port = udp_v4_get_port, | 1890 | .get_port = udp_v4_get_port, |
1847 | .memory_allocated = &udp_memory_allocated, | 1891 | .memory_allocated = &udp_memory_allocated, |
1848 | .sysctl_mem = sysctl_udp_mem, | 1892 | .sysctl_mem = sysctl_udp_mem, |