aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r--net/ipv4/udp.c47
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
574struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, 570struct 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
1241try_again: 1240try_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
1603static 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 */
1605static 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
1911void udp_v4_early_demux(struct sk_buff *skb) 1915void 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,