Commit c079fe24 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-qrtr-add-distant-node-support'

Loic Poulain says:

====================
net: qrtr: Add distant node support

QRTR protocol allows a node to communicate with an other non-immediate
node via an intermdediate immediate node acting as a 'bridge':

node-0 <=> node-1 <=> node-2

This is currently not supported in this upstream version and this
series aim to fix that.

This series is V2 because changes 1, 2 and 3 have already been submitted
separately on LKML.

Changes in v2:
- Add reviewed-by tags from Bjorn and Mani
- Fixing checkpatch issue reported by Jakub
====================

Link: https://lore.kernel.org/r/1604684010-24090-1-git-send-email-loic.poulain@linaro.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents a884915f 90829f07
...@@ -517,10 +517,6 @@ static int ctrl_cmd_new_server(struct sockaddr_qrtr *from, ...@@ -517,10 +517,6 @@ static int ctrl_cmd_new_server(struct sockaddr_qrtr *from,
port = from->sq_port; port = from->sq_port;
} }
/* Don't accept spoofed messages */
if (from->sq_node != node_id)
return -EINVAL;
srv = server_add(service, instance, node_id, port); srv = server_add(service, instance, node_id, port);
if (!srv) if (!srv)
return -EINVAL; return -EINVAL;
...@@ -559,10 +555,6 @@ static int ctrl_cmd_del_server(struct sockaddr_qrtr *from, ...@@ -559,10 +555,6 @@ static int ctrl_cmd_del_server(struct sockaddr_qrtr *from,
port = from->sq_port; port = from->sq_port;
} }
/* Don't accept spoofed messages */
if (from->sq_node != node_id)
return -EINVAL;
/* Local servers may only unregister themselves */ /* Local servers may only unregister themselves */
if (from->sq_node == qrtr_ns.local_node && from->sq_port != port) if (from->sq_node == qrtr_ns.local_node && from->sq_port != port)
return -EINVAL; return -EINVAL;
......
...@@ -171,8 +171,13 @@ static void __qrtr_node_release(struct kref *kref) ...@@ -171,8 +171,13 @@ static void __qrtr_node_release(struct kref *kref)
void __rcu **slot; void __rcu **slot;
spin_lock_irqsave(&qrtr_nodes_lock, flags); spin_lock_irqsave(&qrtr_nodes_lock, flags);
if (node->nid != QRTR_EP_NID_AUTO) /* If the node is a bridge for other nodes, there are possibly
radix_tree_delete(&qrtr_nodes, node->nid); * multiple entries pointing to our released node, delete them all.
*/
radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) {
if (*slot == node)
radix_tree_iter_delete(&qrtr_nodes, &iter, slot);
}
spin_unlock_irqrestore(&qrtr_nodes_lock, flags); spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
list_del(&node->item); list_del(&node->item);
...@@ -347,7 +352,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb, ...@@ -347,7 +352,7 @@ static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb,
hdr->src_port_id = cpu_to_le32(from->sq_port); hdr->src_port_id = cpu_to_le32(from->sq_port);
if (to->sq_port == QRTR_PORT_CTRL) { if (to->sq_port == QRTR_PORT_CTRL) {
hdr->dst_node_id = cpu_to_le32(node->nid); hdr->dst_node_id = cpu_to_le32(node->nid);
hdr->dst_port_id = cpu_to_le32(QRTR_NODE_BCAST); hdr->dst_port_id = cpu_to_le32(QRTR_PORT_CTRL);
} else { } else {
hdr->dst_node_id = cpu_to_le32(to->sq_node); hdr->dst_node_id = cpu_to_le32(to->sq_node);
hdr->dst_port_id = cpu_to_le32(to->sq_port); hdr->dst_port_id = cpu_to_le32(to->sq_port);
...@@ -401,12 +406,13 @@ static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid) ...@@ -401,12 +406,13 @@ static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid)
{ {
unsigned long flags; unsigned long flags;
if (node->nid != QRTR_EP_NID_AUTO || nid == QRTR_EP_NID_AUTO) if (nid == QRTR_EP_NID_AUTO)
return; return;
spin_lock_irqsave(&qrtr_nodes_lock, flags); spin_lock_irqsave(&qrtr_nodes_lock, flags);
radix_tree_insert(&qrtr_nodes, nid, node); radix_tree_insert(&qrtr_nodes, nid, node);
node->nid = nid; if (node->nid == QRTR_EP_NID_AUTO)
node->nid = nid;
spin_unlock_irqrestore(&qrtr_nodes_lock, flags); spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
} }
...@@ -494,6 +500,13 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) ...@@ -494,6 +500,13 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
qrtr_node_assign(node, cb->src_node); qrtr_node_assign(node, cb->src_node);
if (cb->type == QRTR_TYPE_NEW_SERVER) {
/* Remote node endpoint can bridge other distant nodes */
const struct qrtr_ctrl_pkt *pkt = data + hdrlen;
qrtr_node_assign(node, le32_to_cpu(pkt->server.node));
}
if (cb->type == QRTR_TYPE_RESUME_TX) { if (cb->type == QRTR_TYPE_RESUME_TX) {
qrtr_tx_resume(node, skb); qrtr_tx_resume(node, skb);
} else { } else {
...@@ -519,18 +532,20 @@ EXPORT_SYMBOL_GPL(qrtr_endpoint_post); ...@@ -519,18 +532,20 @@ EXPORT_SYMBOL_GPL(qrtr_endpoint_post);
/** /**
* qrtr_alloc_ctrl_packet() - allocate control packet skb * qrtr_alloc_ctrl_packet() - allocate control packet skb
* @pkt: reference to qrtr_ctrl_pkt pointer * @pkt: reference to qrtr_ctrl_pkt pointer
* @flags: the type of memory to allocate
* *
* Returns newly allocated sk_buff, or NULL on failure * Returns newly allocated sk_buff, or NULL on failure
* *
* This function allocates a sk_buff large enough to carry a qrtr_ctrl_pkt and * This function allocates a sk_buff large enough to carry a qrtr_ctrl_pkt and
* on success returns a reference to the control packet in @pkt. * on success returns a reference to the control packet in @pkt.
*/ */
static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt) static struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt,
gfp_t flags)
{ {
const int pkt_len = sizeof(struct qrtr_ctrl_pkt); const int pkt_len = sizeof(struct qrtr_ctrl_pkt);
struct sk_buff *skb; struct sk_buff *skb;
skb = alloc_skb(QRTR_HDR_MAX_SIZE + pkt_len, GFP_KERNEL); skb = alloc_skb(QRTR_HDR_MAX_SIZE + pkt_len, flags);
if (!skb) if (!skb)
return NULL; return NULL;
...@@ -592,6 +607,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep) ...@@ -592,6 +607,7 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
struct qrtr_ctrl_pkt *pkt; struct qrtr_ctrl_pkt *pkt;
struct qrtr_tx_flow *flow; struct qrtr_tx_flow *flow;
struct sk_buff *skb; struct sk_buff *skb;
unsigned long flags;
void __rcu **slot; void __rcu **slot;
mutex_lock(&node->ep_lock); mutex_lock(&node->ep_lock);
...@@ -599,11 +615,18 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep) ...@@ -599,11 +615,18 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
mutex_unlock(&node->ep_lock); mutex_unlock(&node->ep_lock);
/* Notify the local controller about the event */ /* Notify the local controller about the event */
skb = qrtr_alloc_ctrl_packet(&pkt); spin_lock_irqsave(&qrtr_nodes_lock, flags);
if (skb) { radix_tree_for_each_slot(slot, &qrtr_nodes, &iter, 0) {
pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE); if (*slot != node)
qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst); continue;
src.sq_node = iter.index;
skb = qrtr_alloc_ctrl_packet(&pkt, GFP_ATOMIC);
if (skb) {
pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE);
qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst);
}
} }
spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
/* Wake up any transmitters waiting for resume-tx from the node */ /* Wake up any transmitters waiting for resume-tx from the node */
mutex_lock(&node->qrtr_tx_lock); mutex_lock(&node->qrtr_tx_lock);
...@@ -656,7 +679,7 @@ static void qrtr_port_remove(struct qrtr_sock *ipc) ...@@ -656,7 +679,7 @@ static void qrtr_port_remove(struct qrtr_sock *ipc)
to.sq_node = QRTR_NODE_BCAST; to.sq_node = QRTR_NODE_BCAST;
to.sq_port = QRTR_PORT_CTRL; to.sq_port = QRTR_PORT_CTRL;
skb = qrtr_alloc_ctrl_packet(&pkt); skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
if (skb) { if (skb) {
pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT); pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT);
pkt->client.node = cpu_to_le32(ipc->us.sq_node); pkt->client.node = cpu_to_le32(ipc->us.sq_node);
...@@ -982,7 +1005,7 @@ static int qrtr_send_resume_tx(struct qrtr_cb *cb) ...@@ -982,7 +1005,7 @@ static int qrtr_send_resume_tx(struct qrtr_cb *cb)
if (!node) if (!node)
return -EINVAL; return -EINVAL;
skb = qrtr_alloc_ctrl_packet(&pkt); skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment