summaryrefslogtreecommitdiff
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/af_inet.c17
-rw-r--r--net/ipv4/igmp.c63
-rw-r--r--net/ipv4/inet_connection_sock.c7
-rw-r--r--net/ipv4/ip_sockglue.c4
-rw-r--r--net/ipv4/ip_vti.c3
-rw-r--r--net/ipv4/ipip.c3
-rw-r--r--net/ipv4/netfilter/nf_reject_ipv4.c2
-rw-r--r--net/ipv4/ping.c9
-rw-r--r--net/ipv4/raw.c6
-rw-r--r--net/ipv4/tcp.c5
-rw-r--r--net/ipv4/tcp_bpf.c17
-rw-r--r--net/ipv4/tcp_ipv4.c4
-rw-r--r--net/ipv4/tcp_output.c8
-rw-r--r--net/ipv4/udp.c9
-rw-r--r--net/ipv4/udp_bpf.c25
-rw-r--r--net/ipv4/udp_impl.h3
-rw-r--r--net/ipv4/udp_tunnel_nic.c2
17 files changed, 111 insertions, 76 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 3109c5ec38f3..4f105a0d0cfc 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -871,22 +871,17 @@ void inet_splice_eof(struct socket *sock)
EXPORT_SYMBOL_GPL(inet_splice_eof);
INDIRECT_CALLABLE_DECLARE(int udp_recvmsg(struct sock *, struct msghdr *,
- size_t, int, int *));
+ size_t, int));
int inet_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
int flags)
{
struct sock *sk = sock->sk;
- int addr_len = 0;
- int err;
if (likely(!(flags & MSG_ERRQUEUE)))
sock_rps_record_flow(sk);
- err = INDIRECT_CALL_2(sk->sk_prot->recvmsg, tcp_recvmsg, udp_recvmsg,
- sk, msg, size, flags, &addr_len);
- if (err >= 0)
- msg->msg_namelen = addr_len;
- return err;
+ return INDIRECT_CALL_2(sk->sk_prot->recvmsg, tcp_recvmsg, udp_recvmsg,
+ sk, msg, size, flags);
}
EXPORT_SYMBOL(inet_recvmsg);
@@ -1571,15 +1566,15 @@ __be32 inet_current_timestamp(void)
}
EXPORT_SYMBOL(inet_current_timestamp);
-int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
+int inet_recv_error(struct sock *sk, struct msghdr *msg, int len)
{
unsigned int family = READ_ONCE(sk->sk_family);
if (family == AF_INET)
- return ip_recv_error(sk, msg, len, addr_len);
+ return ip_recv_error(sk, msg, len);
#if IS_ENABLED(CONFIG_IPV6)
if (family == AF_INET6)
- return pingv6_ops.ipv6_recv_error(sk, msg, len, addr_len);
+ return pingv6_ops.ipv6_recv_error(sk, msg, len);
#endif
return -EINVAL;
}
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 449cb4ba6153..aca035eb5892 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -204,13 +204,18 @@ static void ip_sf_list_clear_all(struct ip_sf_list *psf)
static void igmp_stop_timer(struct ip_mc_list *im)
{
+ bool put = false;
+
spin_lock_bh(&im->lock);
if (timer_delete(&im->timer))
- refcount_dec(&im->refcnt);
- im->tm_running = 0;
- im->reporter = 0;
+ put = true;
+ WRITE_ONCE(im->tm_running, 0);
+ WRITE_ONCE(im->reporter, 0);
im->unsolicit_count = 0;
spin_unlock_bh(&im->lock);
+
+ if (put)
+ ip_ma_put(im);
}
/* It must be called with locked im->lock */
@@ -218,7 +223,7 @@ static void igmp_start_timer(struct ip_mc_list *im, int max_delay)
{
int tv = get_random_u32_below(max_delay);
- im->tm_running = 1;
+ WRITE_ONCE(im->tm_running, 1);
if (refcount_inc_not_zero(&im->refcnt)) {
if (mod_timer(&im->timer, jiffies + tv + 2))
ip_ma_put(im);
@@ -235,33 +240,42 @@ static void igmp_gq_start_timer(struct in_device *in_dev)
return;
in_dev->mr_gq_running = 1;
- if (!mod_timer(&in_dev->mr_gq_timer, exp))
- in_dev_hold(in_dev);
+ if (in_dev_hold_safe(in_dev)) {
+ if (mod_timer(&in_dev->mr_gq_timer, exp))
+ in_dev_put(in_dev);
+ }
}
static void igmp_ifc_start_timer(struct in_device *in_dev, int delay)
{
- int tv = get_random_u32_below(delay);
+ if (in_dev_hold_safe(in_dev)) {
+ int tv = get_random_u32_below(delay);
- if (!mod_timer(&in_dev->mr_ifc_timer, jiffies+tv+2))
- in_dev_hold(in_dev);
+ if (mod_timer(&in_dev->mr_ifc_timer, jiffies + tv + 2))
+ in_dev_put(in_dev);
+ }
}
static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
{
+ bool put = false;
+
spin_lock_bh(&im->lock);
im->unsolicit_count = 0;
if (timer_delete(&im->timer)) {
if ((long)(im->timer.expires-jiffies) < max_delay) {
add_timer(&im->timer);
- im->tm_running = 1;
+ WRITE_ONCE(im->tm_running, 1);
spin_unlock_bh(&im->lock);
return;
}
- refcount_dec(&im->refcnt);
+ put = true;
}
igmp_start_timer(im, max_delay);
spin_unlock_bh(&im->lock);
+
+ if (put)
+ ip_ma_put(im);
}
@@ -844,12 +858,12 @@ static void igmp_timer_expire(struct timer_list *t)
struct in_device *in_dev = im->interface;
spin_lock(&im->lock);
- im->tm_running = 0;
+ WRITE_ONCE(im->tm_running, 0);
if (im->unsolicit_count && --im->unsolicit_count)
igmp_start_timer(im, unsolicited_report_interval(in_dev));
- im->reporter = 1;
+ WRITE_ONCE(im->reporter, 1);
spin_unlock(&im->lock);
if (IGMP_V1_SEEN(in_dev))
@@ -1311,7 +1325,7 @@ static void __igmp_group_dropped(struct ip_mc_list *im, gfp_t gfp)
!READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
return;
- reporter = im->reporter;
+ reporter = READ_ONCE(im->reporter);
igmp_stop_timer(im);
if (!in_dev->dead) {
@@ -1527,7 +1541,7 @@ static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
}
if (im) {
- im->users++;
+ WRITE_ONCE(im->users, im->users + 1);
ip_mc_add_src(in_dev, &addr, mode, 0, NULL, 0);
goto out;
}
@@ -1536,7 +1550,7 @@ static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
if (!im)
goto out;
- im->users = 1;
+ WRITE_ONCE(im->users, 1);
im->interface = in_dev;
in_dev_hold(in_dev);
im->multiaddr = addr;
@@ -1770,7 +1784,10 @@ void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp)
(i = rtnl_dereference(*ip)) != NULL;
ip = &i->next_rcu) {
if (i->multiaddr == addr) {
- if (--i->users == 0) {
+ int new_users = i->users - 1;
+
+ WRITE_ONCE(i->users, new_users);
+ if (new_users == 0) {
ip_mc_hash_remove(in_dev, i);
*ip = i->next_rcu;
in_dev->mc_count--;
@@ -2946,6 +2963,7 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v)
struct ip_mc_list *im = v;
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
char *querier;
+ int tm_running;
long delta;
#ifdef CONFIG_IP_MULTICAST
@@ -2961,13 +2979,14 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v)
state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier);
}
- delta = im->timer.expires - jiffies;
+ tm_running = READ_ONCE(im->tm_running);
+ delta = READ_ONCE(im->timer.expires) - jiffies;
seq_printf(seq,
"\t\t\t\t%08X %5d %d:%08lX\t\t%d\n",
- im->multiaddr, im->users,
- im->tm_running,
- im->tm_running ? jiffies_delta_to_clock_t(delta) : 0,
- im->reporter);
+ im->multiaddr, READ_ONCE(im->users),
+ tm_running,
+ tm_running ? jiffies_delta_to_clock_t(delta) : 0,
+ READ_ONCE(im->reporter));
}
return 0;
}
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index c777895a720e..1679bfefa560 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -1163,6 +1163,9 @@ static bool reqsk_queue_hash_req(struct request_sock *req,
/* The timer needs to be setup after a successful insertion. */
timer_setup(&req->rsk_timer, reqsk_timer_handler, TIMER_PINNED);
+
+ preempt_disable_nested();
+
mod_timer(&req->rsk_timer, jiffies + timeout);
/* before letting lookups find us, make sure all req fields
@@ -1170,6 +1173,9 @@ static bool reqsk_queue_hash_req(struct request_sock *req,
*/
smp_wmb();
refcount_set(&req->rsk_refcnt, 2 + 1);
+
+ preempt_enable_nested();
+
return true;
}
@@ -1295,6 +1301,7 @@ EXPORT_SYMBOL(inet_csk_destroy_sock);
void inet_csk_prepare_for_destroy_sock(struct sock *sk)
{
/* The below has to be done to allow calling inet_csk_destroy_sock */
+ tcp_clear_sock_ops_cb_flags(sk);
sock_set_flag(sk, SOCK_DEAD);
tcp_orphan_count_inc();
}
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 6d9c5c20b1c4..7d4f1face2e7 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -520,7 +520,7 @@ static bool ipv4_datagram_support_cmsg(const struct sock *sk,
/*
* Handle MSG_ERRQUEUE
*/
-int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
+int ip_recv_error(struct sock *sk, struct msghdr *msg, int len)
{
struct sock_exterr_skb *serr;
struct sk_buff *skb;
@@ -557,7 +557,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
serr->addr_offset);
sin->sin_port = serr->port;
memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
- *addr_len = sizeof(*sin);
+ msg->msg_namelen = sizeof(*sin);
}
memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 95b6bb78fcd2..3b80929994a0 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -596,6 +596,9 @@ static int vti_changelink(struct net_device *dev, struct nlattr *tb[],
struct ip_tunnel_parm_kern p;
__u32 fwmark = t->fwmark;
+ if (!rtnl_dev_link_net_capable(dev, t->net))
+ return -EPERM;
+
vti_netlink_parms(data, &p, &fwmark);
return ip_tunnel_changelink(dev, tb, &p, fwmark);
}
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 3e03af073a1c..94e974c201f0 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -469,6 +469,9 @@ static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
bool collect_md;
__u32 fwmark = t->fwmark;
+ if (!rtnl_dev_link_net_capable(dev, t->net))
+ return -EPERM;
+
if (ip_tunnel_netlink_encap_parms(data, &ipencap)) {
int err = ip_tunnel_encap_setup(t, &ipencap);
diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c
index fae4aa4a5f09..c47d56576720 100644
--- a/net/ipv4/netfilter/nf_reject_ipv4.c
+++ b/net/ipv4/netfilter/nf_reject_ipv4.c
@@ -89,7 +89,7 @@ static bool nf_skb_is_icmp_unreach(const struct sk_buff *skb)
if (iph->protocol != IPPROTO_ICMP)
return false;
- thoff = skb_network_offset(skb) + sizeof(*iph);
+ thoff = skb_network_offset(skb) + ip_hdrlen(skb);
tp = skb_header_pointer(skb,
thoff + offsetof(struct icmphdr, type),
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 690f486173e0..7f32753a16f4 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -847,8 +847,7 @@ do_confirm:
goto out;
}
-int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
- int *addr_len)
+int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags)
{
struct inet_sock *isk = inet_sk(sk);
int family = sk->sk_family;
@@ -863,7 +862,7 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
goto out;
if (flags & MSG_ERRQUEUE)
- return inet_recv_error(sk, msg, len, addr_len);
+ return inet_recv_error(sk, msg, len);
skb = skb_recv_datagram(sk, flags, &err);
if (!skb)
@@ -891,7 +890,7 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
sin->sin_port = 0 /* skb->h.uh->source */;
sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- *addr_len = sizeof(*sin);
+ msg->msg_namelen = sizeof(*sin);
}
if (inet_cmsg_flags(isk))
@@ -912,7 +911,7 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
sin6->sin6_scope_id =
ipv6_iface_scope_id(&sin6->sin6_addr,
inet6_iif(skb));
- *addr_len = sizeof(*sin6);
+ msg->msg_namelen = sizeof(*sin6);
}
if (inet6_sk(sk)->rxopt.all)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index f79f4c29a043..26468a2ec63d 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -737,7 +737,7 @@ out:
*/
static int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
- int flags, int *addr_len)
+ int flags)
{
struct inet_sock *inet = inet_sk(sk);
size_t copied = 0;
@@ -749,7 +749,7 @@ static int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
goto out;
if (flags & MSG_ERRQUEUE) {
- err = ip_recv_error(sk, msg, len, addr_len);
+ err = ip_recv_error(sk, msg, len);
goto out;
}
@@ -775,7 +775,7 @@ static int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
sin->sin_port = 0;
memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
- *addr_len = sizeof(*sin);
+ msg->msg_namelen = sizeof(*sin);
}
if (inet_cmsg_flags(inet))
ip_cmsg_recv(msg, skb);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 6fc00b38695b..db80b81a74cb 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2909,14 +2909,13 @@ recv_sndq:
goto out;
}
-int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
- int *addr_len)
+int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags)
{
int cmsg_flags = 0, ret;
struct scm_timestamping_internal tss;
if (unlikely(flags & MSG_ERRQUEUE))
- return inet_recv_error(sk, msg, len, addr_len);
+ return inet_recv_error(sk, msg, len);
if (sk_can_busy_loop(sk) &&
skb_queue_empty_lockless(&sk->sk_receive_queue) &&
diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
index d3d6a47af527..7a3f0b244c8f 100644
--- a/net/ipv4/tcp_bpf.c
+++ b/net/ipv4/tcp_bpf.c
@@ -221,8 +221,7 @@ static bool is_next_msg_fin(struct sk_psock *psock)
static int tcp_bpf_recvmsg_parser(struct sock *sk,
struct msghdr *msg,
size_t len,
- int flags,
- int *addr_len)
+ int flags)
{
int peek = flags & MSG_PEEK;
struct sk_psock *psock;
@@ -232,14 +231,14 @@ static int tcp_bpf_recvmsg_parser(struct sock *sk,
u32 seq;
if (unlikely(flags & MSG_ERRQUEUE))
- return inet_recv_error(sk, msg, len, addr_len);
+ return inet_recv_error(sk, msg, len);
if (!len)
return 0;
psock = sk_psock_get(sk);
if (unlikely(!psock))
- return tcp_recvmsg(sk, msg, len, flags, addr_len);
+ return tcp_recvmsg(sk, msg, len, flags);
lock_sock(sk);
tcp = tcp_sk(sk);
@@ -352,24 +351,24 @@ static int tcp_bpf_ioctl(struct sock *sk, int cmd, int *karg)
}
static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
- int flags, int *addr_len)
+ int flags)
{
struct sk_psock *psock;
int copied, ret;
if (unlikely(flags & MSG_ERRQUEUE))
- return inet_recv_error(sk, msg, len, addr_len);
+ return inet_recv_error(sk, msg, len);
if (!len)
return 0;
psock = sk_psock_get(sk);
if (unlikely(!psock))
- return tcp_recvmsg(sk, msg, len, flags, addr_len);
+ return tcp_recvmsg(sk, msg, len, flags);
if (!skb_queue_empty(&sk->sk_receive_queue) &&
sk_psock_queue_empty(psock)) {
sk_psock_put(sk, psock);
- return tcp_recvmsg(sk, msg, len, flags, addr_len);
+ return tcp_recvmsg(sk, msg, len, flags);
}
lock_sock(sk);
msg_bytes_ready:
@@ -389,7 +388,7 @@ msg_bytes_ready:
goto msg_bytes_ready;
release_sock(sk);
sk_psock_put(sk, psock);
- return tcp_recvmsg(sk, msg, len, flags, addr_len);
+ return tcp_recvmsg(sk, msg, len, flags);
}
copied = -EAGAIN;
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 36206fc6aed2..f0106c2be1cf 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1505,9 +1505,9 @@ void tcp_clear_md5_list(struct sock *sk)
md5sig = rcu_dereference_protected(tp->md5sig_info, 1);
hlist_for_each_entry_safe(key, n, &md5sig->head, node) {
- hlist_del(&key->node);
+ hlist_del_rcu(&key->node);
atomic_sub(sizeof(*key), &sk->sk_omem_alloc);
- kfree(key);
+ kfree_rcu(key, rcu);
}
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 318d548b606e..479be2f24262 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -4263,9 +4263,13 @@ int tcp_connect(struct sock *sk)
if (needs_md5) {
tcp_ao_destroy_sock(sk, false);
} else if (needs_ao) {
+ struct tcp_md5sig_info *md5sig;
+
tcp_clear_md5_list(sk);
- kfree(rcu_replace_pointer(tp->md5sig_info, NULL,
- lockdep_sock_is_held(sk)));
+ md5sig = rcu_replace_pointer(tp->md5sig_info, NULL,
+ lockdep_sock_is_held(sk));
+ kfree_rcu(md5sig, rcu);
+ static_branch_slow_dec_deferred(&tcp_md5_needed);
}
}
#endif
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 4ac4a120fca8..2f5c91ba0ce9 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2059,8 +2059,7 @@ EXPORT_IPV6_MOD(udp_read_skb);
* return it, otherwise we block.
*/
-int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
- int *addr_len)
+int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags)
{
struct inet_sock *inet = inet_sk(sk);
DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
@@ -2071,7 +2070,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
bool checksum_valid = false;
if (flags & MSG_ERRQUEUE)
- return ip_recv_error(sk, msg, len, addr_len);
+ return ip_recv_error(sk, msg, len);
try_again:
off = sk_peek_offset(sk, flags);
@@ -2134,11 +2133,11 @@ try_again:
sin->sin_port = udp_hdr(skb)->source;
sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- *addr_len = sizeof(*sin);
+ msg->msg_namelen = sizeof(*sin);
BPF_CGROUP_RUN_PROG_UDP4_RECVMSG_LOCK(sk,
(struct sockaddr *)sin,
- addr_len);
+ &msg->msg_namelen);
}
if (udp_test_bit(GRO_ENABLED, sk))
diff --git a/net/ipv4/udp_bpf.c b/net/ipv4/udp_bpf.c
index 779a3a03762f..6987b8cf59eb 100644
--- a/net/ipv4/udp_bpf.c
+++ b/net/ipv4/udp_bpf.c
@@ -12,13 +12,13 @@
static struct proto *udpv6_prot_saved __read_mostly;
static int sk_udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
- int flags, int *addr_len)
+ int flags)
{
#if IS_ENABLED(CONFIG_IPV6)
if (sk->sk_family == AF_INET6)
- return udpv6_prot_saved->recvmsg(sk, msg, len, flags, addr_len);
+ return udpv6_prot_saved->recvmsg(sk, msg, len, flags);
#endif
- return udp_prot.recvmsg(sk, msg, len, flags, addr_len);
+ return udp_prot.recvmsg(sk, msg, len, flags);
}
static bool udp_sk_has_data(struct sock *sk)
@@ -52,7 +52,9 @@ static int udp_msg_wait_data(struct sock *sk, struct sk_psock *psock,
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
ret = udp_msg_has_data(sk, psock);
if (!ret) {
+ release_sock(sk);
wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
+ lock_sock(sk);
ret = udp_msg_has_data(sk, psock);
}
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
@@ -61,26 +63,27 @@ static int udp_msg_wait_data(struct sock *sk, struct sk_psock *psock,
}
static int udp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
- int flags, int *addr_len)
+ int flags)
{
struct sk_psock *psock;
int copied, ret;
if (unlikely(flags & MSG_ERRQUEUE))
- return inet_recv_error(sk, msg, len, addr_len);
+ return inet_recv_error(sk, msg, len);
if (!len)
return 0;
psock = sk_psock_get(sk);
if (unlikely(!psock))
- return sk_udp_recvmsg(sk, msg, len, flags, addr_len);
+ return sk_udp_recvmsg(sk, msg, len, flags);
if (!psock_has_data(psock)) {
- ret = sk_udp_recvmsg(sk, msg, len, flags, addr_len);
+ ret = sk_udp_recvmsg(sk, msg, len, flags);
goto out;
}
+ lock_sock(sk);
msg_bytes_ready:
copied = sk_msg_recvmsg(sk, psock, msg, len, flags);
if (!copied) {
@@ -92,11 +95,17 @@ msg_bytes_ready:
if (data) {
if (psock_has_data(psock))
goto msg_bytes_ready;
- ret = sk_udp_recvmsg(sk, msg, len, flags, addr_len);
+
+ release_sock(sk);
+
+ ret = sk_udp_recvmsg(sk, msg, len, flags);
goto out;
}
copied = -EAGAIN;
}
+
+ release_sock(sk);
+
ret = copied;
out:
sk_psock_put(sk, psock);
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h
index c7142213fc21..17a6fa8b1409 100644
--- a/net/ipv4/udp_impl.h
+++ b/net/ipv4/udp_impl.h
@@ -18,8 +18,7 @@ int udp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
int udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
-int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
- int *addr_len);
+int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags);
void udp_destroy_sock(struct sock *sk);
#ifdef CONFIG_PROC_FS
diff --git a/net/ipv4/udp_tunnel_nic.c b/net/ipv4/udp_tunnel_nic.c
index 944b3cf25468..b13e8f7092f4 100644
--- a/net/ipv4/udp_tunnel_nic.c
+++ b/net/ipv4/udp_tunnel_nic.c
@@ -301,7 +301,7 @@ __udp_tunnel_nic_device_sync(struct net_device *dev, struct udp_tunnel_nic *utn)
static void
udp_tunnel_nic_device_sync(struct net_device *dev, struct udp_tunnel_nic *utn)
{
- if (!utn->need_sync)
+ if (!utn->need_sync || utn->work_pending)
return;
queue_work(udp_tunnel_nic_workqueue, &utn->work);