Loading net/qrtr/qrtr.c +100 −29 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/qrtr.h> #include <linux/termios.h> /* For TIOCINQ/OUTQ */ #include <linux/wait.h> #include <linux/rwsem.h> #include <net/sock.h> Loading @@ -28,6 +29,10 @@ #define QRTR_MIN_EPH_SOCKET 0x4000 #define QRTR_MAX_EPH_SOCKET 0x7fff /* qrtr socket states */ #define QRTR_STATE_MULTI -2 #define QRTR_STATE_INIT -1 /** * struct qrtr_hdr_v1 - (I|R)PCrouter packet header version 1 * @version: protocol version Loading Loading @@ -94,6 +99,8 @@ struct qrtr_sock { struct sock sk; struct sockaddr_qrtr us; struct sockaddr_qrtr peer; int state; }; static inline struct qrtr_sock *qrtr_sk(struct sock *sk) Loading @@ -109,7 +116,7 @@ static RADIX_TREE(qrtr_nodes, GFP_KERNEL); /* broadcast list */ static LIST_HEAD(qrtr_all_epts); /* lock for qrtr_nodes, qrtr_all_epts and node reference */ static DEFINE_MUTEX(qrtr_node_lock); static DECLARE_RWSEM(qrtr_node_lock); /* local port allocation management */ static DEFINE_IDR(qrtr_ports); Loading Loading @@ -157,6 +164,32 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, int type, struct sockaddr_qrtr *from, struct sockaddr_qrtr *to); static bool refcount_dec_and_rwsem_lock(refcount_t *r, struct rw_semaphore *sem) { if (refcount_dec_not_one(r)) return false; down_write(sem); if (!refcount_dec_and_test(r)) { up_write(sem); return false; } return true; } static inline int kref_put_rwsem_lock(struct kref *kref, void (*release)(struct kref *kref), struct rw_semaphore *sem) { if (refcount_dec_and_rwsem_lock(&kref->refcount, sem)) { release(kref); return 1; } return 0; } /* Release node resources and free the node. * * Do not call directly, use qrtr_node_release. To be used with Loading @@ -176,7 +209,7 @@ static void __qrtr_node_release(struct kref *kref) } list_del(&node->item); mutex_unlock(&qrtr_node_lock); up_write(&qrtr_node_lock); /* Free tx flow counters */ radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) { Loading @@ -184,6 +217,7 @@ static void __qrtr_node_release(struct kref *kref) kfree(*slot); } flush_work(&node->work); skb_queue_purge(&node->rx_queue); kfree(node); } Loading @@ -201,7 +235,7 @@ static void qrtr_node_release(struct qrtr_node *node) { if (!node) return; kref_put_mutex(&node->ref, __qrtr_node_release, &qrtr_node_lock); kref_put_rwsem_lock(&node->ref, __qrtr_node_release, &qrtr_node_lock); } /** Loading Loading @@ -314,8 +348,13 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, hdr->type = cpu_to_le32(type); hdr->src_node_id = cpu_to_le32(from->sq_node); hdr->src_port_id = cpu_to_le32(from->sq_port); if (to->sq_port == QRTR_PORT_CTRL) { hdr->dst_node_id = cpu_to_le32(node->nid); hdr->dst_port_id = cpu_to_le32(QRTR_NODE_BCAST); } else { hdr->dst_node_id = cpu_to_le32(to->sq_node); hdr->dst_port_id = cpu_to_le32(to->sq_port); } hdr->size = cpu_to_le32(len); hdr->confirm_rx = !!confirm_rx; Loading @@ -340,10 +379,10 @@ static struct qrtr_node *qrtr_node_lookup(unsigned int nid) { struct qrtr_node *node; mutex_lock(&qrtr_node_lock); down_read(&qrtr_node_lock); node = radix_tree_lookup(&qrtr_nodes, nid); node = qrtr_node_acquire(node); mutex_unlock(&qrtr_node_lock); up_read(&qrtr_node_lock); return node; } Loading @@ -358,13 +397,13 @@ static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid) if (nid == QRTR_EP_NID_AUTO) return; mutex_lock(&qrtr_node_lock); down_write(&qrtr_node_lock); if (!radix_tree_lookup(&qrtr_nodes, nid)) radix_tree_insert(&qrtr_nodes, nid, node); if (node->nid == QRTR_EP_NID_AUTO) node->nid = nid; mutex_unlock(&qrtr_node_lock); up_write(&qrtr_node_lock); } /** Loading Loading @@ -548,9 +587,9 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid) qrtr_node_assign(node, nid); mutex_lock(&qrtr_node_lock); down_write(&qrtr_node_lock); list_add(&node->item, &qrtr_all_epts); mutex_unlock(&qrtr_node_lock); up_write(&qrtr_node_lock); ep->node = node; return 0; Loading Loading @@ -614,29 +653,59 @@ static void qrtr_port_put(struct qrtr_sock *ipc) sock_put(&ipc->sk); } /* Remove port assignment. */ static void qrtr_port_remove(struct qrtr_sock *ipc) static void qrtr_send_del_client(struct qrtr_sock *ipc) { struct qrtr_ctrl_pkt *pkt; struct sk_buff *skb; int port = ipc->us.sq_port; struct sockaddr_qrtr to; struct qrtr_node *node; struct sk_buff *skbn; struct sk_buff *skb; int type = QRTR_TYPE_DEL_CLIENT; skb = qrtr_alloc_ctrl_packet(&pkt); if (!skb) return; to.sq_family = AF_QIPCRTR; to.sq_node = QRTR_NODE_BCAST; to.sq_port = QRTR_PORT_CTRL; skb = qrtr_alloc_ctrl_packet(&pkt); if (skb) { pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT); pkt->client.node = cpu_to_le32(ipc->us.sq_node); pkt->client.port = cpu_to_le32(ipc->us.sq_port); skb_set_owner_w(skb, &ipc->sk); qrtr_bcast_enqueue(NULL, skb, QRTR_TYPE_DEL_CLIENT, &ipc->us, &to); if (ipc->state == QRTR_STATE_MULTI) { qrtr_bcast_enqueue(NULL, skb, type, &ipc->us, &to); return; } if (ipc->state > QRTR_STATE_INIT) { node = qrtr_node_lookup(ipc->state); if (!node) goto exit; skbn = skb_clone(skb, GFP_KERNEL); if (!skbn) { qrtr_node_release(node); goto exit; } skb_set_owner_w(skbn, &ipc->sk); qrtr_node_enqueue(node, skbn, type, &ipc->us, &to); qrtr_node_release(node); } exit: qrtr_local_enqueue(NULL, skb, type, &ipc->us, &to); } /* Remove port assignment. */ static void qrtr_port_remove(struct qrtr_sock *ipc) { int port = ipc->us.sq_port; qrtr_send_del_client(ipc); if (port == QRTR_PORT_CTRL) port = 0; Loading Loading @@ -821,7 +890,7 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, { struct sk_buff *skbn; mutex_lock(&qrtr_node_lock); down_read(&qrtr_node_lock); list_for_each_entry(node, &qrtr_all_epts, item) { if (node->nid == QRTR_EP_NID_AUTO) continue; Loading @@ -829,14 +898,10 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, if (!skbn) break; skb_set_owner_w(skbn, skb->sk); to->sq_node = cpu_to_le32(node->nid); to->sq_port = QRTR_NODE_BCAST; qrtr_node_enqueue(node, skbn, type, from, to); } mutex_unlock(&qrtr_node_lock); up_read(&qrtr_node_lock); to->sq_node = QRTR_NODE_BCAST; to->sq_port = QRTR_PORT_CTRL; qrtr_local_enqueue(node, skb, type, from, to); return 0; Loading Loading @@ -902,6 +967,11 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) release_sock(sk); return -ECONNRESET; } if (ipc->state > QRTR_STATE_INIT && ipc->state != node->nid) ipc->state = QRTR_STATE_MULTI; else if (ipc->state == QRTR_STATE_INIT) ipc->state = node->nid; } plen = (len + 3) & ~3; Loading Loading @@ -1223,6 +1293,7 @@ static int qrtr_create(struct net *net, struct socket *sock, ipc->us.sq_family = AF_QIPCRTR; ipc->us.sq_node = qrtr_local_nid; ipc->us.sq_port = 0; ipc->state = QRTR_STATE_INIT; return 0; } Loading Loading
net/qrtr/qrtr.c +100 −29 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <linux/qrtr.h> #include <linux/termios.h> /* For TIOCINQ/OUTQ */ #include <linux/wait.h> #include <linux/rwsem.h> #include <net/sock.h> Loading @@ -28,6 +29,10 @@ #define QRTR_MIN_EPH_SOCKET 0x4000 #define QRTR_MAX_EPH_SOCKET 0x7fff /* qrtr socket states */ #define QRTR_STATE_MULTI -2 #define QRTR_STATE_INIT -1 /** * struct qrtr_hdr_v1 - (I|R)PCrouter packet header version 1 * @version: protocol version Loading Loading @@ -94,6 +99,8 @@ struct qrtr_sock { struct sock sk; struct sockaddr_qrtr us; struct sockaddr_qrtr peer; int state; }; static inline struct qrtr_sock *qrtr_sk(struct sock *sk) Loading @@ -109,7 +116,7 @@ static RADIX_TREE(qrtr_nodes, GFP_KERNEL); /* broadcast list */ static LIST_HEAD(qrtr_all_epts); /* lock for qrtr_nodes, qrtr_all_epts and node reference */ static DEFINE_MUTEX(qrtr_node_lock); static DECLARE_RWSEM(qrtr_node_lock); /* local port allocation management */ static DEFINE_IDR(qrtr_ports); Loading Loading @@ -157,6 +164,32 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, int type, struct sockaddr_qrtr *from, struct sockaddr_qrtr *to); static bool refcount_dec_and_rwsem_lock(refcount_t *r, struct rw_semaphore *sem) { if (refcount_dec_not_one(r)) return false; down_write(sem); if (!refcount_dec_and_test(r)) { up_write(sem); return false; } return true; } static inline int kref_put_rwsem_lock(struct kref *kref, void (*release)(struct kref *kref), struct rw_semaphore *sem) { if (refcount_dec_and_rwsem_lock(&kref->refcount, sem)) { release(kref); return 1; } return 0; } /* Release node resources and free the node. * * Do not call directly, use qrtr_node_release. To be used with Loading @@ -176,7 +209,7 @@ static void __qrtr_node_release(struct kref *kref) } list_del(&node->item); mutex_unlock(&qrtr_node_lock); up_write(&qrtr_node_lock); /* Free tx flow counters */ radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) { Loading @@ -184,6 +217,7 @@ static void __qrtr_node_release(struct kref *kref) kfree(*slot); } flush_work(&node->work); skb_queue_purge(&node->rx_queue); kfree(node); } Loading @@ -201,7 +235,7 @@ static void qrtr_node_release(struct qrtr_node *node) { if (!node) return; kref_put_mutex(&node->ref, __qrtr_node_release, &qrtr_node_lock); kref_put_rwsem_lock(&node->ref, __qrtr_node_release, &qrtr_node_lock); } /** Loading Loading @@ -314,8 +348,13 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, hdr->type = cpu_to_le32(type); hdr->src_node_id = cpu_to_le32(from->sq_node); hdr->src_port_id = cpu_to_le32(from->sq_port); if (to->sq_port == QRTR_PORT_CTRL) { hdr->dst_node_id = cpu_to_le32(node->nid); hdr->dst_port_id = cpu_to_le32(QRTR_NODE_BCAST); } else { hdr->dst_node_id = cpu_to_le32(to->sq_node); hdr->dst_port_id = cpu_to_le32(to->sq_port); } hdr->size = cpu_to_le32(len); hdr->confirm_rx = !!confirm_rx; Loading @@ -340,10 +379,10 @@ static struct qrtr_node *qrtr_node_lookup(unsigned int nid) { struct qrtr_node *node; mutex_lock(&qrtr_node_lock); down_read(&qrtr_node_lock); node = radix_tree_lookup(&qrtr_nodes, nid); node = qrtr_node_acquire(node); mutex_unlock(&qrtr_node_lock); up_read(&qrtr_node_lock); return node; } Loading @@ -358,13 +397,13 @@ static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid) if (nid == QRTR_EP_NID_AUTO) return; mutex_lock(&qrtr_node_lock); down_write(&qrtr_node_lock); if (!radix_tree_lookup(&qrtr_nodes, nid)) radix_tree_insert(&qrtr_nodes, nid, node); if (node->nid == QRTR_EP_NID_AUTO) node->nid = nid; mutex_unlock(&qrtr_node_lock); up_write(&qrtr_node_lock); } /** Loading Loading @@ -548,9 +587,9 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid) qrtr_node_assign(node, nid); mutex_lock(&qrtr_node_lock); down_write(&qrtr_node_lock); list_add(&node->item, &qrtr_all_epts); mutex_unlock(&qrtr_node_lock); up_write(&qrtr_node_lock); ep->node = node; return 0; Loading Loading @@ -614,29 +653,59 @@ static void qrtr_port_put(struct qrtr_sock *ipc) sock_put(&ipc->sk); } /* Remove port assignment. */ static void qrtr_port_remove(struct qrtr_sock *ipc) static void qrtr_send_del_client(struct qrtr_sock *ipc) { struct qrtr_ctrl_pkt *pkt; struct sk_buff *skb; int port = ipc->us.sq_port; struct sockaddr_qrtr to; struct qrtr_node *node; struct sk_buff *skbn; struct sk_buff *skb; int type = QRTR_TYPE_DEL_CLIENT; skb = qrtr_alloc_ctrl_packet(&pkt); if (!skb) return; to.sq_family = AF_QIPCRTR; to.sq_node = QRTR_NODE_BCAST; to.sq_port = QRTR_PORT_CTRL; skb = qrtr_alloc_ctrl_packet(&pkt); if (skb) { pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT); pkt->client.node = cpu_to_le32(ipc->us.sq_node); pkt->client.port = cpu_to_le32(ipc->us.sq_port); skb_set_owner_w(skb, &ipc->sk); qrtr_bcast_enqueue(NULL, skb, QRTR_TYPE_DEL_CLIENT, &ipc->us, &to); if (ipc->state == QRTR_STATE_MULTI) { qrtr_bcast_enqueue(NULL, skb, type, &ipc->us, &to); return; } if (ipc->state > QRTR_STATE_INIT) { node = qrtr_node_lookup(ipc->state); if (!node) goto exit; skbn = skb_clone(skb, GFP_KERNEL); if (!skbn) { qrtr_node_release(node); goto exit; } skb_set_owner_w(skbn, &ipc->sk); qrtr_node_enqueue(node, skbn, type, &ipc->us, &to); qrtr_node_release(node); } exit: qrtr_local_enqueue(NULL, skb, type, &ipc->us, &to); } /* Remove port assignment. */ static void qrtr_port_remove(struct qrtr_sock *ipc) { int port = ipc->us.sq_port; qrtr_send_del_client(ipc); if (port == QRTR_PORT_CTRL) port = 0; Loading Loading @@ -821,7 +890,7 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, { struct sk_buff *skbn; mutex_lock(&qrtr_node_lock); down_read(&qrtr_node_lock); list_for_each_entry(node, &qrtr_all_epts, item) { if (node->nid == QRTR_EP_NID_AUTO) continue; Loading @@ -829,14 +898,10 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, if (!skbn) break; skb_set_owner_w(skbn, skb->sk); to->sq_node = cpu_to_le32(node->nid); to->sq_port = QRTR_NODE_BCAST; qrtr_node_enqueue(node, skbn, type, from, to); } mutex_unlock(&qrtr_node_lock); up_read(&qrtr_node_lock); to->sq_node = QRTR_NODE_BCAST; to->sq_port = QRTR_PORT_CTRL; qrtr_local_enqueue(node, skb, type, from, to); return 0; Loading Loading @@ -902,6 +967,11 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) release_sock(sk); return -ECONNRESET; } if (ipc->state > QRTR_STATE_INIT && ipc->state != node->nid) ipc->state = QRTR_STATE_MULTI; else if (ipc->state == QRTR_STATE_INIT) ipc->state = node->nid; } plen = (len + 3) & ~3; Loading Loading @@ -1223,6 +1293,7 @@ static int qrtr_create(struct net *net, struct socket *sock, ipc->us.sq_family = AF_QIPCRTR; ipc->us.sq_node = qrtr_local_nid; ipc->us.sq_port = 0; ipc->state = QRTR_STATE_INIT; return 0; } Loading