diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index ef16b8ef9f1a..72e573aed1d0 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -757,7 +757,6 @@ static int qrtr_port_assign(struct qrtr_sock *ipc, int *port) { int rc; - mutex_lock(&qrtr_port_lock); if (!*port) { rc = idr_alloc_cyclic(&qrtr_ports, ipc, QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET + 1, GFP_ATOMIC); @@ -773,7 +772,6 @@ static int qrtr_port_assign(struct qrtr_sock *ipc, int *port) if (rc >= 0) *port = rc; } - mutex_unlock(&qrtr_port_lock); if (rc == -ENOSPC) return -EADDRINUSE; @@ -791,7 +789,6 @@ static void qrtr_reset_ports(void) struct qrtr_sock *ipc; int id; - mutex_lock(&qrtr_port_lock); idr_for_each_entry(&qrtr_ports, ipc, id) { /* Don't reset control port */ if (id == 0) @@ -802,7 +799,6 @@ static void qrtr_reset_ports(void) ipc->sk.sk_error_report(&ipc->sk); sock_put(&ipc->sk); } - mutex_unlock(&qrtr_port_lock); } /* Bind socket to address. @@ -821,22 +817,24 @@ static int __qrtr_bind(struct socket *sock, if (!zapped && addr->sq_port == ipc->us.sq_port) return 0; + mutex_lock(&qrtr_port_lock); port = addr->sq_port; rc = qrtr_port_assign(ipc, &port); - if (rc) + if (rc) { + mutex_unlock(&qrtr_port_lock); return rc; + } + /* Notify all open ports about the new controller */ + if (port == QRTR_PORT_CTRL) + qrtr_reset_ports(); + mutex_unlock(&qrtr_port_lock); /* unbind previous, if any */ if (!zapped) qrtr_port_remove(ipc); ipc->us.sq_port = port; - sock_reset_flag(sk, SOCK_ZAPPED); - /* Notify all open ports about the new controller */ - if (port == QRTR_PORT_CTRL) - qrtr_reset_ports(); - return 0; } @@ -884,12 +882,22 @@ static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb, { struct qrtr_sock *ipc; struct qrtr_cb *cb; + struct sock *sk = skb->sk; ipc = qrtr_port_lookup(to->sq_port); if (!ipc || &ipc->sk == skb->sk) { /* do not send to self */ kfree_skb(skb); return -ENODEV; } + /* Keep resetting NETRESET until socket is closed */ + if (sk && sk->sk_err == ENETRESET) { + sock_hold(sk); + sk->sk_err = ENETRESET; + sk->sk_error_report(sk); + sock_put(sk); + kfree_skb(skb); + return 0; + } cb = (struct qrtr_cb *)skb->cb; cb->src_node = from->sq_node;