diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 47 |
1 files changed, 27 insertions, 20 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 5944d7d668dd..f140048334ce 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,16 @@ 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 xchg() 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 | dst_hold(dst); |
1608 | sk->sk_rx_dst = dst; | 1610 | old = xchg(&sk->sk_rx_dst, dst); |
1611 | dst_release(old); | ||
1609 | } | 1612 | } |
1610 | 1613 | ||
1611 | /* | 1614 | /* |
@@ -1736,15 +1739,16 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
1736 | if (udp4_csum_init(skb, uh, proto)) | 1739 | if (udp4_csum_init(skb, uh, proto)) |
1737 | goto csum_error; | 1740 | goto csum_error; |
1738 | 1741 | ||
1739 | if (skb->sk) { | 1742 | sk = skb_steal_sock(skb); |
1743 | if (sk) { | ||
1744 | struct dst_entry *dst = skb_dst(skb); | ||
1740 | int ret; | 1745 | int ret; |
1741 | sk = skb->sk; | ||
1742 | 1746 | ||
1743 | if (unlikely(sk->sk_rx_dst == NULL)) | 1747 | if (unlikely(sk->sk_rx_dst != dst)) |
1744 | udp_sk_rx_dst_set(sk, skb); | 1748 | udp_sk_rx_dst_set(sk, dst); |
1745 | 1749 | ||
1746 | ret = udp_queue_rcv_skb(sk, skb); | 1750 | ret = udp_queue_rcv_skb(sk, skb); |
1747 | 1751 | sock_put(sk); | |
1748 | /* a return value > 0 means to resubmit the input, but | 1752 | /* a return value > 0 means to resubmit the input, but |
1749 | * it wants the return to be -protocol, or 0 | 1753 | * it wants the return to be -protocol, or 0 |
1750 | */ | 1754 | */ |
@@ -1910,17 +1914,20 @@ static struct sock *__udp4_lib_demux_lookup(struct net *net, | |||
1910 | 1914 | ||
1911 | void udp_v4_early_demux(struct sk_buff *skb) | 1915 | void udp_v4_early_demux(struct sk_buff *skb) |
1912 | { | 1916 | { |
1913 | const struct iphdr *iph = ip_hdr(skb); | 1917 | struct net *net = dev_net(skb->dev); |
1914 | const struct udphdr *uh = udp_hdr(skb); | 1918 | const struct iphdr *iph; |
1919 | const struct udphdr *uh; | ||
1915 | struct sock *sk; | 1920 | struct sock *sk; |
1916 | struct dst_entry *dst; | 1921 | struct dst_entry *dst; |
1917 | struct net *net = dev_net(skb->dev); | ||
1918 | int dif = skb->dev->ifindex; | 1922 | int dif = skb->dev->ifindex; |
1919 | 1923 | ||
1920 | /* validate the packet */ | 1924 | /* validate the packet */ |
1921 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct udphdr))) | 1925 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct udphdr))) |
1922 | return; | 1926 | return; |
1923 | 1927 | ||
1928 | iph = ip_hdr(skb); | ||
1929 | uh = udp_hdr(skb); | ||
1930 | |||
1924 | if (skb->pkt_type == PACKET_BROADCAST || | 1931 | if (skb->pkt_type == PACKET_BROADCAST || |
1925 | skb->pkt_type == PACKET_MULTICAST) | 1932 | skb->pkt_type == PACKET_MULTICAST) |
1926 | sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr, | 1933 | sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr, |