diff options
| author | Ingo Molnar <mingo@kernel.org> | 2013-12-17 09:27:08 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2013-12-17 09:27:08 -0500 |
| commit | bb799d3b980eb803ca2da4a4eefbd9308f8d988a (patch) | |
| tree | 69fbe0cd6d47b23a50f5e1d87bf7489532fae149 /net/ipv4 | |
| parent | 919fc6e34831d1c2b58bfb5ae261dc3facc9b269 (diff) | |
| parent | 319e2e3f63c348a9b66db4667efa73178e18b17d (diff) | |
Merge tag 'v3.13-rc4' into core/locking
Merge Linux 3.13-rc4, to refresh this rather old tree with the latest fixes.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'net/ipv4')
| -rw-r--r-- | net/ipv4/fib_rules.c | 5 | ||||
| -rw-r--r-- | net/ipv4/ip_sockglue.c | 3 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ipt_SYNPROXY.c | 1 | ||||
| -rw-r--r-- | net/ipv4/ping.c | 7 | ||||
| -rw-r--r-- | net/ipv4/protocol.c | 8 | ||||
| -rw-r--r-- | net/ipv4/raw.c | 2 | ||||
| -rw-r--r-- | net/ipv4/route.c | 8 | ||||
| -rw-r--r-- | net/ipv4/tcp.c | 4 | ||||
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 2 | ||||
| -rw-r--r-- | net/ipv4/tcp_memcontrol.c | 9 | ||||
| -rw-r--r-- | net/ipv4/tcp_offload.c | 31 | ||||
| -rw-r--r-- | net/ipv4/udp.c | 54 |
12 files changed, 69 insertions, 65 deletions
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 523be38e37de..f2e15738534d 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c | |||
| @@ -104,7 +104,10 @@ errout: | |||
| 104 | static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg) | 104 | static bool fib4_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg) |
| 105 | { | 105 | { |
| 106 | struct fib_result *result = (struct fib_result *) arg->result; | 106 | struct fib_result *result = (struct fib_result *) arg->result; |
| 107 | struct net_device *dev = result->fi->fib_dev; | 107 | struct net_device *dev = NULL; |
| 108 | |||
| 109 | if (result->fi) | ||
| 110 | dev = result->fi->fib_dev; | ||
| 108 | 111 | ||
| 109 | /* do not accept result if the route does | 112 | /* do not accept result if the route does |
| 110 | * not meet the required prefix length | 113 | * not meet the required prefix length |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 3f858266fa7e..ddf32a6bc415 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
| @@ -386,7 +386,7 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf | |||
| 386 | /* | 386 | /* |
| 387 | * Handle MSG_ERRQUEUE | 387 | * Handle MSG_ERRQUEUE |
| 388 | */ | 388 | */ |
| 389 | int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) | 389 | int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) |
| 390 | { | 390 | { |
| 391 | struct sock_exterr_skb *serr; | 391 | struct sock_exterr_skb *serr; |
| 392 | struct sk_buff *skb, *skb2; | 392 | struct sk_buff *skb, *skb2; |
| @@ -423,6 +423,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
| 423 | serr->addr_offset); | 423 | serr->addr_offset); |
| 424 | sin->sin_port = serr->port; | 424 | sin->sin_port = serr->port; |
| 425 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); | 425 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); |
| 426 | *addr_len = sizeof(*sin); | ||
| 426 | } | 427 | } |
| 427 | 428 | ||
| 428 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); | 429 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); |
diff --git a/net/ipv4/netfilter/ipt_SYNPROXY.c b/net/ipv4/netfilter/ipt_SYNPROXY.c index 01cffeaa0085..f13bd91d9a56 100644 --- a/net/ipv4/netfilter/ipt_SYNPROXY.c +++ b/net/ipv4/netfilter/ipt_SYNPROXY.c | |||
| @@ -244,6 +244,7 @@ synproxy_recv_client_ack(const struct synproxy_net *snet, | |||
| 244 | 244 | ||
| 245 | this_cpu_inc(snet->stats->cookie_valid); | 245 | this_cpu_inc(snet->stats->cookie_valid); |
| 246 | opts->mss = mss; | 246 | opts->mss = mss; |
| 247 | opts->options |= XT_SYNPROXY_OPT_MSS; | ||
| 247 | 248 | ||
| 248 | if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP) | 249 | if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP) |
| 249 | synproxy_check_timestamp_cookie(opts); | 250 | synproxy_check_timestamp_cookie(opts); |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 876c6ca2d8f9..242e7f4ed6f4 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
| @@ -772,7 +772,7 @@ int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 772 | err = PTR_ERR(rt); | 772 | err = PTR_ERR(rt); |
| 773 | rt = NULL; | 773 | rt = NULL; |
| 774 | if (err == -ENETUNREACH) | 774 | if (err == -ENETUNREACH) |
| 775 | IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); | 775 | IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); |
| 776 | goto out; | 776 | goto out; |
| 777 | } | 777 | } |
| 778 | 778 | ||
| @@ -841,10 +841,11 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 841 | 841 | ||
| 842 | if (flags & MSG_ERRQUEUE) { | 842 | if (flags & MSG_ERRQUEUE) { |
| 843 | if (family == AF_INET) { | 843 | if (family == AF_INET) { |
| 844 | return ip_recv_error(sk, msg, len); | 844 | return ip_recv_error(sk, msg, len, addr_len); |
| 845 | #if IS_ENABLED(CONFIG_IPV6) | 845 | #if IS_ENABLED(CONFIG_IPV6) |
| 846 | } else if (family == AF_INET6) { | 846 | } else if (family == AF_INET6) { |
| 847 | return pingv6_ops.ipv6_recv_error(sk, msg, len); | 847 | return pingv6_ops.ipv6_recv_error(sk, msg, len, |
| 848 | addr_len); | ||
| 848 | #endif | 849 | #endif |
| 849 | } | 850 | } |
| 850 | } | 851 | } |
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c index ce848461acbb..46d6a1c923a8 100644 --- a/net/ipv4/protocol.c +++ b/net/ipv4/protocol.c | |||
| @@ -31,10 +31,6 @@ | |||
| 31 | const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly; | 31 | const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly; |
| 32 | const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS] __read_mostly; | 32 | const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS] __read_mostly; |
| 33 | 33 | ||
| 34 | /* | ||
| 35 | * Add a protocol handler to the hash tables | ||
| 36 | */ | ||
| 37 | |||
| 38 | int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol) | 34 | int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol) |
| 39 | { | 35 | { |
| 40 | if (!prot->netns_ok) { | 36 | if (!prot->netns_ok) { |
| @@ -55,10 +51,6 @@ int inet_add_offload(const struct net_offload *prot, unsigned char protocol) | |||
| 55 | } | 51 | } |
| 56 | EXPORT_SYMBOL(inet_add_offload); | 52 | EXPORT_SYMBOL(inet_add_offload); |
| 57 | 53 | ||
| 58 | /* | ||
| 59 | * Remove a protocol from the hash tables. | ||
| 60 | */ | ||
| 61 | |||
| 62 | int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol) | 54 | int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol) |
| 63 | { | 55 | { |
| 64 | int ret; | 56 | int ret; |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 5cb8ddb505ee..23c3e5b5bb53 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
| @@ -697,7 +697,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 697 | goto out; | 697 | goto out; |
| 698 | 698 | ||
| 699 | if (flags & MSG_ERRQUEUE) { | 699 | if (flags & MSG_ERRQUEUE) { |
| 700 | err = ip_recv_error(sk, msg, len); | 700 | err = ip_recv_error(sk, msg, len, addr_len); |
| 701 | goto out; | 701 | goto out; |
| 702 | } | 702 | } |
| 703 | 703 | ||
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index f428935c50db..f8da28278014 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -1776,8 +1776,12 @@ local_input: | |||
| 1776 | rth->dst.error= -err; | 1776 | rth->dst.error= -err; |
| 1777 | rth->rt_flags &= ~RTCF_LOCAL; | 1777 | rth->rt_flags &= ~RTCF_LOCAL; |
| 1778 | } | 1778 | } |
| 1779 | if (do_cache) | 1779 | if (do_cache) { |
| 1780 | rt_cache_route(&FIB_RES_NH(res), rth); | 1780 | if (unlikely(!rt_cache_route(&FIB_RES_NH(res), rth))) { |
| 1781 | rth->dst.flags |= DST_NOCACHE; | ||
| 1782 | rt_add_uncached_list(rth); | ||
| 1783 | } | ||
| 1784 | } | ||
| 1781 | skb_dst_set(skb, &rth->dst); | 1785 | skb_dst_set(skb, &rth->dst); |
| 1782 | err = 0; | 1786 | err = 0; |
| 1783 | goto out; | 1787 | goto out; |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 3dc0c6cf02a8..c4638e6f0238 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
| @@ -1425,7 +1425,7 @@ static void tcp_service_net_dma(struct sock *sk, bool wait) | |||
| 1425 | do { | 1425 | do { |
| 1426 | if (dma_async_is_tx_complete(tp->ucopy.dma_chan, | 1426 | if (dma_async_is_tx_complete(tp->ucopy.dma_chan, |
| 1427 | last_issued, &done, | 1427 | last_issued, &done, |
| 1428 | &used) == DMA_SUCCESS) { | 1428 | &used) == DMA_COMPLETE) { |
| 1429 | /* Safe to free early-copied skbs now */ | 1429 | /* Safe to free early-copied skbs now */ |
| 1430 | __skb_queue_purge(&sk->sk_async_wait_queue); | 1430 | __skb_queue_purge(&sk->sk_async_wait_queue); |
| 1431 | break; | 1431 | break; |
| @@ -1433,7 +1433,7 @@ static void tcp_service_net_dma(struct sock *sk, bool wait) | |||
| 1433 | struct sk_buff *skb; | 1433 | struct sk_buff *skb; |
| 1434 | while ((skb = skb_peek(&sk->sk_async_wait_queue)) && | 1434 | while ((skb = skb_peek(&sk->sk_async_wait_queue)) && |
| 1435 | (dma_async_is_complete(skb->dma_cookie, done, | 1435 | (dma_async_is_complete(skb->dma_cookie, done, |
| 1436 | used) == DMA_SUCCESS)) { | 1436 | used) == DMA_COMPLETE)) { |
| 1437 | __skb_dequeue(&sk->sk_async_wait_queue); | 1437 | __skb_dequeue(&sk->sk_async_wait_queue); |
| 1438 | kfree_skb(skb); | 1438 | kfree_skb(skb); |
| 1439 | } | 1439 | } |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 59a6f8b90cd9..067213924751 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -177,7 +177,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 177 | if (IS_ERR(rt)) { | 177 | if (IS_ERR(rt)) { |
| 178 | err = PTR_ERR(rt); | 178 | err = PTR_ERR(rt); |
| 179 | if (err == -ENETUNREACH) | 179 | if (err == -ENETUNREACH) |
| 180 | IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 180 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); |
| 181 | return err; | 181 | return err; |
| 182 | } | 182 | } |
| 183 | 183 | ||
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c index 03e9154f7e68..f7e522c558ba 100644 --- a/net/ipv4/tcp_memcontrol.c +++ b/net/ipv4/tcp_memcontrol.c | |||
| @@ -6,13 +6,6 @@ | |||
| 6 | #include <linux/memcontrol.h> | 6 | #include <linux/memcontrol.h> |
| 7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
| 8 | 8 | ||
| 9 | static void memcg_tcp_enter_memory_pressure(struct sock *sk) | ||
| 10 | { | ||
| 11 | if (sk->sk_cgrp->memory_pressure) | ||
| 12 | sk->sk_cgrp->memory_pressure = 1; | ||
| 13 | } | ||
| 14 | EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure); | ||
| 15 | |||
| 16 | int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss) | 9 | int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss) |
| 17 | { | 10 | { |
| 18 | /* | 11 | /* |
| @@ -60,7 +53,6 @@ EXPORT_SYMBOL(tcp_destroy_cgroup); | |||
| 60 | static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) | 53 | static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) |
| 61 | { | 54 | { |
| 62 | struct cg_proto *cg_proto; | 55 | struct cg_proto *cg_proto; |
| 63 | u64 old_lim; | ||
| 64 | int i; | 56 | int i; |
| 65 | int ret; | 57 | int ret; |
| 66 | 58 | ||
| @@ -71,7 +63,6 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val) | |||
| 71 | if (val > RES_COUNTER_MAX) | 63 | if (val > RES_COUNTER_MAX) |
| 72 | val = RES_COUNTER_MAX; | 64 | val = RES_COUNTER_MAX; |
| 73 | 65 | ||
| 74 | old_lim = res_counter_read_u64(&cg_proto->memory_allocated, RES_LIMIT); | ||
| 75 | ret = res_counter_set_limit(&cg_proto->memory_allocated, val); | 66 | ret = res_counter_set_limit(&cg_proto->memory_allocated, val); |
| 76 | if (ret) | 67 | if (ret) |
| 77 | return ret; | 68 | return ret; |
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index a2b68a108eae..05606353c7e7 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c | |||
| @@ -274,33 +274,32 @@ static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff * | |||
| 274 | { | 274 | { |
| 275 | const struct iphdr *iph = skb_gro_network_header(skb); | 275 | const struct iphdr *iph = skb_gro_network_header(skb); |
| 276 | __wsum wsum; | 276 | __wsum wsum; |
| 277 | __sum16 sum; | 277 | |
| 278 | /* Don't bother verifying checksum if we're going to flush anyway. */ | ||
| 279 | if (NAPI_GRO_CB(skb)->flush) | ||
| 280 | goto skip_csum; | ||
| 281 | |||
| 282 | wsum = skb->csum; | ||
| 278 | 283 | ||
| 279 | switch (skb->ip_summed) { | 284 | switch (skb->ip_summed) { |
| 285 | case CHECKSUM_NONE: | ||
| 286 | wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb), | ||
| 287 | 0); | ||
| 288 | |||
| 289 | /* fall through */ | ||
| 290 | |||
| 280 | case CHECKSUM_COMPLETE: | 291 | case CHECKSUM_COMPLETE: |
| 281 | if (!tcp_v4_check(skb_gro_len(skb), iph->saddr, iph->daddr, | 292 | if (!tcp_v4_check(skb_gro_len(skb), iph->saddr, iph->daddr, |
| 282 | skb->csum)) { | 293 | wsum)) { |
| 283 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 294 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 284 | break; | 295 | break; |
| 285 | } | 296 | } |
| 286 | flush: | 297 | |
| 287 | NAPI_GRO_CB(skb)->flush = 1; | 298 | NAPI_GRO_CB(skb)->flush = 1; |
| 288 | return NULL; | 299 | return NULL; |
| 289 | |||
| 290 | case CHECKSUM_NONE: | ||
| 291 | wsum = csum_tcpudp_nofold(iph->saddr, iph->daddr, | ||
| 292 | skb_gro_len(skb), IPPROTO_TCP, 0); | ||
| 293 | sum = csum_fold(skb_checksum(skb, | ||
| 294 | skb_gro_offset(skb), | ||
| 295 | skb_gro_len(skb), | ||
| 296 | wsum)); | ||
| 297 | if (sum) | ||
| 298 | goto flush; | ||
| 299 | |||
| 300 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 301 | break; | ||
| 302 | } | 300 | } |
| 303 | 301 | ||
| 302 | skip_csum: | ||
| 304 | return tcp_gro_receive(head, skb); | 303 | return tcp_gro_receive(head, skb); |
| 305 | } | 304 | } |
| 306 | 305 | ||
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 5944d7d668dd..62c19fdd102d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
| @@ -560,15 +560,11 @@ static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, | |||
| 560 | __be16 sport, __be16 dport, | 560 | __be16 sport, __be16 dport, |
| 561 | struct udp_table *udptable) | 561 | struct udp_table *udptable) |
| 562 | { | 562 | { |
| 563 | struct sock *sk; | ||
| 564 | const struct iphdr *iph = ip_hdr(skb); | 563 | const struct iphdr *iph = ip_hdr(skb); |
| 565 | 564 | ||
| 566 | if (unlikely(sk = skb_steal_sock(skb))) | 565 | return __udp4_lib_lookup(dev_net(skb_dst(skb)->dev), iph->saddr, sport, |
| 567 | return sk; | 566 | iph->daddr, dport, inet_iif(skb), |
| 568 | else | 567 | udptable); |
| 569 | return __udp4_lib_lookup(dev_net(skb_dst(skb)->dev), iph->saddr, sport, | ||
| 570 | iph->daddr, dport, inet_iif(skb), | ||
| 571 | udptable); | ||
| 572 | } | 568 | } |
| 573 | 569 | ||
| 574 | struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, | 570 | struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, |
| @@ -999,7 +995,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 999 | err = PTR_ERR(rt); | 995 | err = PTR_ERR(rt); |
| 1000 | rt = NULL; | 996 | rt = NULL; |
| 1001 | if (err == -ENETUNREACH) | 997 | if (err == -ENETUNREACH) |
| 1002 | IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); | 998 | IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); |
| 1003 | goto out; | 999 | goto out; |
| 1004 | } | 1000 | } |
| 1005 | 1001 | ||
| @@ -1098,6 +1094,9 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset, | |||
| 1098 | struct udp_sock *up = udp_sk(sk); | 1094 | struct udp_sock *up = udp_sk(sk); |
| 1099 | int ret; | 1095 | int ret; |
| 1100 | 1096 | ||
| 1097 | if (flags & MSG_SENDPAGE_NOTLAST) | ||
| 1098 | flags |= MSG_MORE; | ||
| 1099 | |||
| 1101 | if (!up->pending) { | 1100 | if (!up->pending) { |
| 1102 | struct msghdr msg = { .msg_flags = flags|MSG_MORE }; | 1101 | struct msghdr msg = { .msg_flags = flags|MSG_MORE }; |
| 1103 | 1102 | ||
| @@ -1236,7 +1235,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 1236 | bool slow; | 1235 | bool slow; |
| 1237 | 1236 | ||
| 1238 | if (flags & MSG_ERRQUEUE) | 1237 | if (flags & MSG_ERRQUEUE) |
| 1239 | return ip_recv_error(sk, msg, len); | 1238 | return ip_recv_error(sk, msg, len, addr_len); |
| 1240 | 1239 | ||
| 1241 | try_again: | 1240 | try_again: |
| 1242 | skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), | 1241 | skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), |
| @@ -1600,12 +1599,21 @@ static void flush_stack(struct sock **stack, unsigned int count, | |||
| 1600 | kfree_skb(skb1); | 1599 | kfree_skb(skb1); |
| 1601 | } | 1600 | } |
| 1602 | 1601 | ||
| 1603 | static void udp_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) | 1602 | /* For TCP sockets, sk_rx_dst is protected by socket lock |
| 1603 | * For UDP, we use sk_dst_lock to guard against concurrent changes. | ||
| 1604 | */ | ||
| 1605 | static void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst) | ||
| 1604 | { | 1606 | { |
| 1605 | struct dst_entry *dst = skb_dst(skb); | 1607 | struct dst_entry *old; |
| 1606 | 1608 | ||
| 1607 | dst_hold(dst); | 1609 | spin_lock(&sk->sk_dst_lock); |
| 1608 | sk->sk_rx_dst = dst; | 1610 | old = sk->sk_rx_dst; |
| 1611 | if (likely(old != dst)) { | ||
| 1612 | dst_hold(dst); | ||
| 1613 | sk->sk_rx_dst = dst; | ||
| 1614 | dst_release(old); | ||
| 1615 | } | ||
| 1616 | spin_unlock(&sk->sk_dst_lock); | ||
| 1609 | } | 1617 | } |
| 1610 | 1618 | ||
| 1611 | /* | 1619 | /* |
| @@ -1736,15 +1744,16 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
| 1736 | if (udp4_csum_init(skb, uh, proto)) | 1744 | if (udp4_csum_init(skb, uh, proto)) |
| 1737 | goto csum_error; | 1745 | goto csum_error; |
| 1738 | 1746 | ||
| 1739 | if (skb->sk) { | 1747 | sk = skb_steal_sock(skb); |
| 1748 | if (sk) { | ||
| 1749 | struct dst_entry *dst = skb_dst(skb); | ||
| 1740 | int ret; | 1750 | int ret; |
| 1741 | sk = skb->sk; | ||
| 1742 | 1751 | ||
| 1743 | if (unlikely(sk->sk_rx_dst == NULL)) | 1752 | if (unlikely(sk->sk_rx_dst != dst)) |
| 1744 | udp_sk_rx_dst_set(sk, skb); | 1753 | udp_sk_rx_dst_set(sk, dst); |
| 1745 | 1754 | ||
| 1746 | ret = udp_queue_rcv_skb(sk, skb); | 1755 | ret = udp_queue_rcv_skb(sk, skb); |
| 1747 | 1756 | sock_put(sk); | |
| 1748 | /* a return value > 0 means to resubmit the input, but | 1757 | /* a return value > 0 means to resubmit the input, but |
| 1749 | * it wants the return to be -protocol, or 0 | 1758 | * it wants the return to be -protocol, or 0 |
| 1750 | */ | 1759 | */ |
| @@ -1910,17 +1919,20 @@ static struct sock *__udp4_lib_demux_lookup(struct net *net, | |||
| 1910 | 1919 | ||
| 1911 | void udp_v4_early_demux(struct sk_buff *skb) | 1920 | void udp_v4_early_demux(struct sk_buff *skb) |
| 1912 | { | 1921 | { |
| 1913 | const struct iphdr *iph = ip_hdr(skb); | 1922 | struct net *net = dev_net(skb->dev); |
| 1914 | const struct udphdr *uh = udp_hdr(skb); | 1923 | const struct iphdr *iph; |
| 1924 | const struct udphdr *uh; | ||
| 1915 | struct sock *sk; | 1925 | struct sock *sk; |
| 1916 | struct dst_entry *dst; | 1926 | struct dst_entry *dst; |
| 1917 | struct net *net = dev_net(skb->dev); | ||
| 1918 | int dif = skb->dev->ifindex; | 1927 | int dif = skb->dev->ifindex; |
| 1919 | 1928 | ||
| 1920 | /* validate the packet */ | 1929 | /* validate the packet */ |
| 1921 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct udphdr))) | 1930 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct udphdr))) |
| 1922 | return; | 1931 | return; |
| 1923 | 1932 | ||
| 1933 | iph = ip_hdr(skb); | ||
| 1934 | uh = udp_hdr(skb); | ||
| 1935 | |||
| 1924 | if (skb->pkt_type == PACKET_BROADCAST || | 1936 | if (skb->pkt_type == PACKET_BROADCAST || |
| 1925 | skb->pkt_type == PACKET_MULTICAST) | 1937 | skb->pkt_type == PACKET_MULTICAST) |
| 1926 | sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr, | 1938 | sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr, |
