18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2015, Sony Mobile Communications Inc.
48c2ecf20Sopenharmony_ci * Copyright (c) 2013, The Linux Foundation. All rights reserved.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include <linux/module.h>
78c2ecf20Sopenharmony_ci#include <linux/netlink.h>
88c2ecf20Sopenharmony_ci#include <linux/qrtr.h>
98c2ecf20Sopenharmony_ci#include <linux/termios.h>	/* For TIOCINQ/OUTQ */
108c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
118c2ecf20Sopenharmony_ci#include <linux/wait.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <net/sock.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "qrtr.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define QRTR_PROTO_VER_1 1
188c2ecf20Sopenharmony_ci#define QRTR_PROTO_VER_2 3
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* auto-bind range */
218c2ecf20Sopenharmony_ci#define QRTR_MIN_EPH_SOCKET 0x4000
228c2ecf20Sopenharmony_ci#define QRTR_MAX_EPH_SOCKET 0x7fff
238c2ecf20Sopenharmony_ci#define QRTR_EPH_PORT_RANGE \
248c2ecf20Sopenharmony_ci		XA_LIMIT(QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/**
278c2ecf20Sopenharmony_ci * struct qrtr_hdr_v1 - (I|R)PCrouter packet header version 1
288c2ecf20Sopenharmony_ci * @version: protocol version
298c2ecf20Sopenharmony_ci * @type: packet type; one of QRTR_TYPE_*
308c2ecf20Sopenharmony_ci * @src_node_id: source node
318c2ecf20Sopenharmony_ci * @src_port_id: source port
328c2ecf20Sopenharmony_ci * @confirm_rx: boolean; whether a resume-tx packet should be send in reply
338c2ecf20Sopenharmony_ci * @size: length of packet, excluding this header
348c2ecf20Sopenharmony_ci * @dst_node_id: destination node
358c2ecf20Sopenharmony_ci * @dst_port_id: destination port
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_cistruct qrtr_hdr_v1 {
388c2ecf20Sopenharmony_ci	__le32 version;
398c2ecf20Sopenharmony_ci	__le32 type;
408c2ecf20Sopenharmony_ci	__le32 src_node_id;
418c2ecf20Sopenharmony_ci	__le32 src_port_id;
428c2ecf20Sopenharmony_ci	__le32 confirm_rx;
438c2ecf20Sopenharmony_ci	__le32 size;
448c2ecf20Sopenharmony_ci	__le32 dst_node_id;
458c2ecf20Sopenharmony_ci	__le32 dst_port_id;
468c2ecf20Sopenharmony_ci} __packed;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/**
498c2ecf20Sopenharmony_ci * struct qrtr_hdr_v2 - (I|R)PCrouter packet header later versions
508c2ecf20Sopenharmony_ci * @version: protocol version
518c2ecf20Sopenharmony_ci * @type: packet type; one of QRTR_TYPE_*
528c2ecf20Sopenharmony_ci * @flags: bitmask of QRTR_FLAGS_*
538c2ecf20Sopenharmony_ci * @optlen: length of optional header data
548c2ecf20Sopenharmony_ci * @size: length of packet, excluding this header and optlen
558c2ecf20Sopenharmony_ci * @src_node_id: source node
568c2ecf20Sopenharmony_ci * @src_port_id: source port
578c2ecf20Sopenharmony_ci * @dst_node_id: destination node
588c2ecf20Sopenharmony_ci * @dst_port_id: destination port
598c2ecf20Sopenharmony_ci */
608c2ecf20Sopenharmony_cistruct qrtr_hdr_v2 {
618c2ecf20Sopenharmony_ci	u8 version;
628c2ecf20Sopenharmony_ci	u8 type;
638c2ecf20Sopenharmony_ci	u8 flags;
648c2ecf20Sopenharmony_ci	u8 optlen;
658c2ecf20Sopenharmony_ci	__le32 size;
668c2ecf20Sopenharmony_ci	__le16 src_node_id;
678c2ecf20Sopenharmony_ci	__le16 src_port_id;
688c2ecf20Sopenharmony_ci	__le16 dst_node_id;
698c2ecf20Sopenharmony_ci	__le16 dst_port_id;
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci#define QRTR_FLAGS_CONFIRM_RX	BIT(0)
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistruct qrtr_cb {
758c2ecf20Sopenharmony_ci	u32 src_node;
768c2ecf20Sopenharmony_ci	u32 src_port;
778c2ecf20Sopenharmony_ci	u32 dst_node;
788c2ecf20Sopenharmony_ci	u32 dst_port;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	u8 type;
818c2ecf20Sopenharmony_ci	u8 confirm_rx;
828c2ecf20Sopenharmony_ci};
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#define QRTR_HDR_MAX_SIZE max_t(size_t, sizeof(struct qrtr_hdr_v1), \
858c2ecf20Sopenharmony_ci					sizeof(struct qrtr_hdr_v2))
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistruct qrtr_sock {
888c2ecf20Sopenharmony_ci	/* WARNING: sk must be the first member */
898c2ecf20Sopenharmony_ci	struct sock sk;
908c2ecf20Sopenharmony_ci	struct sockaddr_qrtr us;
918c2ecf20Sopenharmony_ci	struct sockaddr_qrtr peer;
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic inline struct qrtr_sock *qrtr_sk(struct sock *sk)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	BUILD_BUG_ON(offsetof(struct qrtr_sock, sk) != 0);
978c2ecf20Sopenharmony_ci	return container_of(sk, struct qrtr_sock, sk);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic unsigned int qrtr_local_nid = 1;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/* for node ids */
1038c2ecf20Sopenharmony_cistatic RADIX_TREE(qrtr_nodes, GFP_ATOMIC);
1048c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(qrtr_nodes_lock);
1058c2ecf20Sopenharmony_ci/* broadcast list */
1068c2ecf20Sopenharmony_cistatic LIST_HEAD(qrtr_all_nodes);
1078c2ecf20Sopenharmony_ci/* lock for qrtr_all_nodes and node reference */
1088c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(qrtr_node_lock);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci/* local port allocation management */
1118c2ecf20Sopenharmony_cistatic DEFINE_XARRAY_ALLOC(qrtr_ports);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/**
1148c2ecf20Sopenharmony_ci * struct qrtr_node - endpoint node
1158c2ecf20Sopenharmony_ci * @ep_lock: lock for endpoint management and callbacks
1168c2ecf20Sopenharmony_ci * @ep: endpoint
1178c2ecf20Sopenharmony_ci * @ref: reference count for node
1188c2ecf20Sopenharmony_ci * @nid: node id
1198c2ecf20Sopenharmony_ci * @qrtr_tx_flow: tree of qrtr_tx_flow, keyed by node << 32 | port
1208c2ecf20Sopenharmony_ci * @qrtr_tx_lock: lock for qrtr_tx_flow inserts
1218c2ecf20Sopenharmony_ci * @rx_queue: receive queue
1228c2ecf20Sopenharmony_ci * @item: list item for broadcast list
1238c2ecf20Sopenharmony_ci */
1248c2ecf20Sopenharmony_cistruct qrtr_node {
1258c2ecf20Sopenharmony_ci	struct mutex ep_lock;
1268c2ecf20Sopenharmony_ci	struct qrtr_endpoint *ep;
1278c2ecf20Sopenharmony_ci	struct kref ref;
1288c2ecf20Sopenharmony_ci	unsigned int nid;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	struct radix_tree_root qrtr_tx_flow;
1318c2ecf20Sopenharmony_ci	struct mutex qrtr_tx_lock; /* for qrtr_tx_flow */
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	struct sk_buff_head rx_queue;
1348c2ecf20Sopenharmony_ci	struct list_head item;
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/**
1388c2ecf20Sopenharmony_ci * struct qrtr_tx_flow - tx flow control
1398c2ecf20Sopenharmony_ci * @resume_tx: waiters for a resume tx from the remote
1408c2ecf20Sopenharmony_ci * @pending: number of waiting senders
1418c2ecf20Sopenharmony_ci * @tx_failed: indicates that a message with confirm_rx flag was lost
1428c2ecf20Sopenharmony_ci */
1438c2ecf20Sopenharmony_cistruct qrtr_tx_flow {
1448c2ecf20Sopenharmony_ci	struct wait_queue_head resume_tx;
1458c2ecf20Sopenharmony_ci	int pending;
1468c2ecf20Sopenharmony_ci	int tx_failed;
1478c2ecf20Sopenharmony_ci};
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci#define QRTR_TX_FLOW_HIGH	10
1508c2ecf20Sopenharmony_ci#define QRTR_TX_FLOW_LOW	5
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb,
1538c2ecf20Sopenharmony_ci			      int type, struct sockaddr_qrtr *from,
1548c2ecf20Sopenharmony_ci			      struct sockaddr_qrtr *to);
1558c2ecf20Sopenharmony_cistatic int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb,
1568c2ecf20Sopenharmony_ci			      int type, struct sockaddr_qrtr *from,
1578c2ecf20Sopenharmony_ci			      struct sockaddr_qrtr *to);
1588c2ecf20Sopenharmony_cistatic struct qrtr_sock *qrtr_port_lookup(int port);
1598c2ecf20Sopenharmony_cistatic void qrtr_port_put(struct qrtr_sock *ipc);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci/* Release node resources and free the node.
1628c2ecf20Sopenharmony_ci *
1638c2ecf20Sopenharmony_ci * Do not call directly, use qrtr_node_release.  To be used with
1648c2ecf20Sopenharmony_ci * kref_put_mutex.  As such, the node mutex is expected to be locked on call.
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_cistatic void __qrtr_node_release(struct kref *kref)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct qrtr_node *node = container_of(kref, struct qrtr_node, ref);
1698c2ecf20Sopenharmony_ci	struct radix_tree_iter iter;
1708c2ecf20Sopenharmony_ci	struct qrtr_tx_flow *flow;
1718c2ecf20Sopenharmony_ci	unsigned long flags;
1728c2ecf20Sopenharmony_ci	void __rcu **slot;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	spin_lock_irqsave(&qrtr_nodes_lock, flags);
1758c2ecf20Sopenharmony_ci	if (node->nid != QRTR_EP_NID_AUTO)
1768c2ecf20Sopenharmony_ci		radix_tree_delete(&qrtr_nodes, node->nid);
1778c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	list_del(&node->item);
1808c2ecf20Sopenharmony_ci	mutex_unlock(&qrtr_node_lock);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	skb_queue_purge(&node->rx_queue);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/* Free tx flow counters */
1858c2ecf20Sopenharmony_ci	radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
1868c2ecf20Sopenharmony_ci		flow = *slot;
1878c2ecf20Sopenharmony_ci		radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
1888c2ecf20Sopenharmony_ci		kfree(flow);
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci	kfree(node);
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci/* Increment reference to node. */
1948c2ecf20Sopenharmony_cistatic struct qrtr_node *qrtr_node_acquire(struct qrtr_node *node)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	if (node)
1978c2ecf20Sopenharmony_ci		kref_get(&node->ref);
1988c2ecf20Sopenharmony_ci	return node;
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/* Decrement reference to node and release as necessary. */
2028c2ecf20Sopenharmony_cistatic void qrtr_node_release(struct qrtr_node *node)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	if (!node)
2058c2ecf20Sopenharmony_ci		return;
2068c2ecf20Sopenharmony_ci	kref_put_mutex(&node->ref, __qrtr_node_release, &qrtr_node_lock);
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/**
2108c2ecf20Sopenharmony_ci * qrtr_tx_resume() - reset flow control counter
2118c2ecf20Sopenharmony_ci * @node:	qrtr_node that the QRTR_TYPE_RESUME_TX packet arrived on
2128c2ecf20Sopenharmony_ci * @skb:	resume_tx packet
2138c2ecf20Sopenharmony_ci */
2148c2ecf20Sopenharmony_cistatic void qrtr_tx_resume(struct qrtr_node *node, struct sk_buff *skb)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	struct qrtr_ctrl_pkt *pkt = (struct qrtr_ctrl_pkt *)skb->data;
2178c2ecf20Sopenharmony_ci	u64 remote_node = le32_to_cpu(pkt->client.node);
2188c2ecf20Sopenharmony_ci	u32 remote_port = le32_to_cpu(pkt->client.port);
2198c2ecf20Sopenharmony_ci	struct qrtr_tx_flow *flow;
2208c2ecf20Sopenharmony_ci	unsigned long key;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	key = remote_node << 32 | remote_port;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	rcu_read_lock();
2258c2ecf20Sopenharmony_ci	flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
2268c2ecf20Sopenharmony_ci	rcu_read_unlock();
2278c2ecf20Sopenharmony_ci	if (flow) {
2288c2ecf20Sopenharmony_ci		spin_lock(&flow->resume_tx.lock);
2298c2ecf20Sopenharmony_ci		flow->pending = 0;
2308c2ecf20Sopenharmony_ci		spin_unlock(&flow->resume_tx.lock);
2318c2ecf20Sopenharmony_ci		wake_up_interruptible_all(&flow->resume_tx);
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	consume_skb(skb);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci/**
2388c2ecf20Sopenharmony_ci * qrtr_tx_wait() - flow control for outgoing packets
2398c2ecf20Sopenharmony_ci * @node:	qrtr_node that the packet is to be send to
2408c2ecf20Sopenharmony_ci * @dest_node:	node id of the destination
2418c2ecf20Sopenharmony_ci * @dest_port:	port number of the destination
2428c2ecf20Sopenharmony_ci * @type:	type of message
2438c2ecf20Sopenharmony_ci *
2448c2ecf20Sopenharmony_ci * The flow control scheme is based around the low and high "watermarks". When
2458c2ecf20Sopenharmony_ci * the low watermark is passed the confirm_rx flag is set on the outgoing
2468c2ecf20Sopenharmony_ci * message, which will trigger the remote to send a control message of the type
2478c2ecf20Sopenharmony_ci * QRTR_TYPE_RESUME_TX to reset the counter. If the high watermark is hit
2488c2ecf20Sopenharmony_ci * further transmision should be paused.
2498c2ecf20Sopenharmony_ci *
2508c2ecf20Sopenharmony_ci * Return: 1 if confirm_rx should be set, 0 otherwise or errno failure
2518c2ecf20Sopenharmony_ci */
2528c2ecf20Sopenharmony_cistatic int qrtr_tx_wait(struct qrtr_node *node, int dest_node, int dest_port,
2538c2ecf20Sopenharmony_ci			int type)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	unsigned long key = (u64)dest_node << 32 | dest_port;
2568c2ecf20Sopenharmony_ci	struct qrtr_tx_flow *flow;
2578c2ecf20Sopenharmony_ci	int confirm_rx = 0;
2588c2ecf20Sopenharmony_ci	int ret;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/* Never set confirm_rx on non-data packets */
2618c2ecf20Sopenharmony_ci	if (type != QRTR_TYPE_DATA)
2628c2ecf20Sopenharmony_ci		return 0;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	mutex_lock(&node->qrtr_tx_lock);
2658c2ecf20Sopenharmony_ci	flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
2668c2ecf20Sopenharmony_ci	if (!flow) {
2678c2ecf20Sopenharmony_ci		flow = kzalloc(sizeof(*flow), GFP_KERNEL);
2688c2ecf20Sopenharmony_ci		if (flow) {
2698c2ecf20Sopenharmony_ci			init_waitqueue_head(&flow->resume_tx);
2708c2ecf20Sopenharmony_ci			if (radix_tree_insert(&node->qrtr_tx_flow, key, flow)) {
2718c2ecf20Sopenharmony_ci				kfree(flow);
2728c2ecf20Sopenharmony_ci				flow = NULL;
2738c2ecf20Sopenharmony_ci			}
2748c2ecf20Sopenharmony_ci		}
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci	mutex_unlock(&node->qrtr_tx_lock);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	/* Set confirm_rx if we where unable to find and allocate a flow */
2798c2ecf20Sopenharmony_ci	if (!flow)
2808c2ecf20Sopenharmony_ci		return 1;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	spin_lock_irq(&flow->resume_tx.lock);
2838c2ecf20Sopenharmony_ci	ret = wait_event_interruptible_locked_irq(flow->resume_tx,
2848c2ecf20Sopenharmony_ci						  flow->pending < QRTR_TX_FLOW_HIGH ||
2858c2ecf20Sopenharmony_ci						  flow->tx_failed ||
2868c2ecf20Sopenharmony_ci						  !node->ep);
2878c2ecf20Sopenharmony_ci	if (ret < 0) {
2888c2ecf20Sopenharmony_ci		confirm_rx = ret;
2898c2ecf20Sopenharmony_ci	} else if (!node->ep) {
2908c2ecf20Sopenharmony_ci		confirm_rx = -EPIPE;
2918c2ecf20Sopenharmony_ci	} else if (flow->tx_failed) {
2928c2ecf20Sopenharmony_ci		flow->tx_failed = 0;
2938c2ecf20Sopenharmony_ci		confirm_rx = 1;
2948c2ecf20Sopenharmony_ci	} else {
2958c2ecf20Sopenharmony_ci		flow->pending++;
2968c2ecf20Sopenharmony_ci		confirm_rx = flow->pending == QRTR_TX_FLOW_LOW;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci	spin_unlock_irq(&flow->resume_tx.lock);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return confirm_rx;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci/**
3048c2ecf20Sopenharmony_ci * qrtr_tx_flow_failed() - flag that tx of confirm_rx flagged messages failed
3058c2ecf20Sopenharmony_ci * @node:	qrtr_node that the packet is to be send to
3068c2ecf20Sopenharmony_ci * @dest_node:	node id of the destination
3078c2ecf20Sopenharmony_ci * @dest_port:	port number of the destination
3088c2ecf20Sopenharmony_ci *
3098c2ecf20Sopenharmony_ci * Signal that the transmission of a message with confirm_rx flag failed. The
3108c2ecf20Sopenharmony_ci * flow's "pending" counter will keep incrementing towards QRTR_TX_FLOW_HIGH,
3118c2ecf20Sopenharmony_ci * at which point transmission would stall forever waiting for the resume TX
3128c2ecf20Sopenharmony_ci * message associated with the dropped confirm_rx message.
3138c2ecf20Sopenharmony_ci * Work around this by marking the flow as having a failed transmission and
3148c2ecf20Sopenharmony_ci * cause the next transmission attempt to be sent with the confirm_rx.
3158c2ecf20Sopenharmony_ci */
3168c2ecf20Sopenharmony_cistatic void qrtr_tx_flow_failed(struct qrtr_node *node, int dest_node,
3178c2ecf20Sopenharmony_ci				int dest_port)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	unsigned long key = (u64)dest_node << 32 | dest_port;
3208c2ecf20Sopenharmony_ci	struct qrtr_tx_flow *flow;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	rcu_read_lock();
3238c2ecf20Sopenharmony_ci	flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
3248c2ecf20Sopenharmony_ci	rcu_read_unlock();
3258c2ecf20Sopenharmony_ci	if (flow) {
3268c2ecf20Sopenharmony_ci		spin_lock_irq(&flow->resume_tx.lock);
3278c2ecf20Sopenharmony_ci		flow->tx_failed = 1;
3288c2ecf20Sopenharmony_ci		spin_unlock_irq(&flow->resume_tx.lock);
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci/* Pass an outgoing packet socket buffer to the endpoint driver. */
3338c2ecf20Sopenharmony_cistatic int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb,
3348c2ecf20Sopenharmony_ci			     int type, struct sockaddr_qrtr *from,
3358c2ecf20Sopenharmony_ci			     struct sockaddr_qrtr *to)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	struct qrtr_hdr_v1 *hdr;
3388c2ecf20Sopenharmony_ci	size_t len = skb->len;
3398c2ecf20Sopenharmony_ci	int rc, confirm_rx;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	confirm_rx = qrtr_tx_wait(node, to->sq_node, to->sq_port, type);
3428c2ecf20Sopenharmony_ci	if (confirm_rx < 0) {
3438c2ecf20Sopenharmony_ci		kfree_skb(skb);
3448c2ecf20Sopenharmony_ci		return confirm_rx;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	hdr = skb_push(skb, sizeof(*hdr));
3488c2ecf20Sopenharmony_ci	hdr->version = cpu_to_le32(QRTR_PROTO_VER_1);
3498c2ecf20Sopenharmony_ci	hdr->type = cpu_to_le32(type);
3508c2ecf20Sopenharmony_ci	hdr->src_node_id = cpu_to_le32(from->sq_node);
3518c2ecf20Sopenharmony_ci	hdr->src_port_id = cpu_to_le32(from->sq_port);
3528c2ecf20Sopenharmony_ci	if (to->sq_port == QRTR_PORT_CTRL) {
3538c2ecf20Sopenharmony_ci		hdr->dst_node_id = cpu_to_le32(node->nid);
3548c2ecf20Sopenharmony_ci		hdr->dst_port_id = cpu_to_le32(QRTR_PORT_CTRL);
3558c2ecf20Sopenharmony_ci	} else {
3568c2ecf20Sopenharmony_ci		hdr->dst_node_id = cpu_to_le32(to->sq_node);
3578c2ecf20Sopenharmony_ci		hdr->dst_port_id = cpu_to_le32(to->sq_port);
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	hdr->size = cpu_to_le32(len);
3618c2ecf20Sopenharmony_ci	hdr->confirm_rx = !!confirm_rx;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	rc = skb_put_padto(skb, ALIGN(len, 4) + sizeof(*hdr));
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (!rc) {
3668c2ecf20Sopenharmony_ci		mutex_lock(&node->ep_lock);
3678c2ecf20Sopenharmony_ci		rc = -ENODEV;
3688c2ecf20Sopenharmony_ci		if (node->ep)
3698c2ecf20Sopenharmony_ci			rc = node->ep->xmit(node->ep, skb);
3708c2ecf20Sopenharmony_ci		else
3718c2ecf20Sopenharmony_ci			kfree_skb(skb);
3728c2ecf20Sopenharmony_ci		mutex_unlock(&node->ep_lock);
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci	/* Need to ensure that a subsequent message carries the otherwise lost
3758c2ecf20Sopenharmony_ci	 * confirm_rx flag if we dropped this one */
3768c2ecf20Sopenharmony_ci	if (rc && confirm_rx)
3778c2ecf20Sopenharmony_ci		qrtr_tx_flow_failed(node, to->sq_node, to->sq_port);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	return rc;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci/* Lookup node by id.
3838c2ecf20Sopenharmony_ci *
3848c2ecf20Sopenharmony_ci * callers must release with qrtr_node_release()
3858c2ecf20Sopenharmony_ci */
3868c2ecf20Sopenharmony_cistatic struct qrtr_node *qrtr_node_lookup(unsigned int nid)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	struct qrtr_node *node;
3898c2ecf20Sopenharmony_ci	unsigned long flags;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	mutex_lock(&qrtr_node_lock);
3928c2ecf20Sopenharmony_ci	spin_lock_irqsave(&qrtr_nodes_lock, flags);
3938c2ecf20Sopenharmony_ci	node = radix_tree_lookup(&qrtr_nodes, nid);
3948c2ecf20Sopenharmony_ci	node = qrtr_node_acquire(node);
3958c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
3968c2ecf20Sopenharmony_ci	mutex_unlock(&qrtr_node_lock);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	return node;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci/* Assign node id to node.
4028c2ecf20Sopenharmony_ci *
4038c2ecf20Sopenharmony_ci * This is mostly useful for automatic node id assignment, based on
4048c2ecf20Sopenharmony_ci * the source id in the incoming packet.
4058c2ecf20Sopenharmony_ci */
4068c2ecf20Sopenharmony_cistatic void qrtr_node_assign(struct qrtr_node *node, unsigned int nid)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	unsigned long flags;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	if (node->nid != QRTR_EP_NID_AUTO || nid == QRTR_EP_NID_AUTO)
4118c2ecf20Sopenharmony_ci		return;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	spin_lock_irqsave(&qrtr_nodes_lock, flags);
4148c2ecf20Sopenharmony_ci	radix_tree_insert(&qrtr_nodes, nid, node);
4158c2ecf20Sopenharmony_ci	node->nid = nid;
4168c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&qrtr_nodes_lock, flags);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci/**
4208c2ecf20Sopenharmony_ci * qrtr_endpoint_post() - post incoming data
4218c2ecf20Sopenharmony_ci * @ep: endpoint handle
4228c2ecf20Sopenharmony_ci * @data: data pointer
4238c2ecf20Sopenharmony_ci * @len: size of data in bytes
4248c2ecf20Sopenharmony_ci *
4258c2ecf20Sopenharmony_ci * Return: 0 on success; negative error code on failure
4268c2ecf20Sopenharmony_ci */
4278c2ecf20Sopenharmony_ciint qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	struct qrtr_node *node = ep->node;
4308c2ecf20Sopenharmony_ci	const struct qrtr_hdr_v1 *v1;
4318c2ecf20Sopenharmony_ci	const struct qrtr_hdr_v2 *v2;
4328c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc;
4338c2ecf20Sopenharmony_ci	struct sk_buff *skb;
4348c2ecf20Sopenharmony_ci	struct qrtr_cb *cb;
4358c2ecf20Sopenharmony_ci	size_t size;
4368c2ecf20Sopenharmony_ci	unsigned int ver;
4378c2ecf20Sopenharmony_ci	size_t hdrlen;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	if (len == 0 || len & 3)
4408c2ecf20Sopenharmony_ci		return -EINVAL;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	skb = __netdev_alloc_skb(NULL, len, GFP_ATOMIC | __GFP_NOWARN);
4438c2ecf20Sopenharmony_ci	if (!skb)
4448c2ecf20Sopenharmony_ci		return -ENOMEM;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	cb = (struct qrtr_cb *)skb->cb;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	/* Version field in v1 is little endian, so this works for both cases */
4498c2ecf20Sopenharmony_ci	ver = *(u8*)data;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	switch (ver) {
4528c2ecf20Sopenharmony_ci	case QRTR_PROTO_VER_1:
4538c2ecf20Sopenharmony_ci		if (len < sizeof(*v1))
4548c2ecf20Sopenharmony_ci			goto err;
4558c2ecf20Sopenharmony_ci		v1 = data;
4568c2ecf20Sopenharmony_ci		hdrlen = sizeof(*v1);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		cb->type = le32_to_cpu(v1->type);
4598c2ecf20Sopenharmony_ci		cb->src_node = le32_to_cpu(v1->src_node_id);
4608c2ecf20Sopenharmony_ci		cb->src_port = le32_to_cpu(v1->src_port_id);
4618c2ecf20Sopenharmony_ci		cb->confirm_rx = !!v1->confirm_rx;
4628c2ecf20Sopenharmony_ci		cb->dst_node = le32_to_cpu(v1->dst_node_id);
4638c2ecf20Sopenharmony_ci		cb->dst_port = le32_to_cpu(v1->dst_port_id);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		size = le32_to_cpu(v1->size);
4668c2ecf20Sopenharmony_ci		break;
4678c2ecf20Sopenharmony_ci	case QRTR_PROTO_VER_2:
4688c2ecf20Sopenharmony_ci		if (len < sizeof(*v2))
4698c2ecf20Sopenharmony_ci			goto err;
4708c2ecf20Sopenharmony_ci		v2 = data;
4718c2ecf20Sopenharmony_ci		hdrlen = sizeof(*v2) + v2->optlen;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci		cb->type = v2->type;
4748c2ecf20Sopenharmony_ci		cb->confirm_rx = !!(v2->flags & QRTR_FLAGS_CONFIRM_RX);
4758c2ecf20Sopenharmony_ci		cb->src_node = le16_to_cpu(v2->src_node_id);
4768c2ecf20Sopenharmony_ci		cb->src_port = le16_to_cpu(v2->src_port_id);
4778c2ecf20Sopenharmony_ci		cb->dst_node = le16_to_cpu(v2->dst_node_id);
4788c2ecf20Sopenharmony_ci		cb->dst_port = le16_to_cpu(v2->dst_port_id);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci		if (cb->src_port == (u16)QRTR_PORT_CTRL)
4818c2ecf20Sopenharmony_ci			cb->src_port = QRTR_PORT_CTRL;
4828c2ecf20Sopenharmony_ci		if (cb->dst_port == (u16)QRTR_PORT_CTRL)
4838c2ecf20Sopenharmony_ci			cb->dst_port = QRTR_PORT_CTRL;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci		size = le32_to_cpu(v2->size);
4868c2ecf20Sopenharmony_ci		break;
4878c2ecf20Sopenharmony_ci	default:
4888c2ecf20Sopenharmony_ci		pr_err("qrtr: Invalid version %d\n", ver);
4898c2ecf20Sopenharmony_ci		goto err;
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	if (!size || len != ALIGN(size, 4) + hdrlen)
4938c2ecf20Sopenharmony_ci		goto err;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if ((cb->type == QRTR_TYPE_NEW_SERVER ||
4968c2ecf20Sopenharmony_ci	     cb->type == QRTR_TYPE_RESUME_TX) &&
4978c2ecf20Sopenharmony_ci	    size < sizeof(struct qrtr_ctrl_pkt))
4988c2ecf20Sopenharmony_ci		goto err;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	if (cb->dst_port != QRTR_PORT_CTRL && cb->type != QRTR_TYPE_DATA &&
5018c2ecf20Sopenharmony_ci	    cb->type != QRTR_TYPE_RESUME_TX)
5028c2ecf20Sopenharmony_ci		goto err;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	skb_put_data(skb, data + hdrlen, size);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	qrtr_node_assign(node, cb->src_node);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	if (cb->type == QRTR_TYPE_NEW_SERVER) {
5098c2ecf20Sopenharmony_ci		/* Remote node endpoint can bridge other distant nodes */
5108c2ecf20Sopenharmony_ci		const struct qrtr_ctrl_pkt *pkt;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		pkt = data + hdrlen;
5138c2ecf20Sopenharmony_ci		qrtr_node_assign(node, le32_to_cpu(pkt->server.node));
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	if (cb->type == QRTR_TYPE_RESUME_TX) {
5178c2ecf20Sopenharmony_ci		qrtr_tx_resume(node, skb);
5188c2ecf20Sopenharmony_ci	} else {
5198c2ecf20Sopenharmony_ci		ipc = qrtr_port_lookup(cb->dst_port);
5208c2ecf20Sopenharmony_ci		if (!ipc)
5218c2ecf20Sopenharmony_ci			goto err;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci		if (sock_queue_rcv_skb(&ipc->sk, skb)) {
5248c2ecf20Sopenharmony_ci			qrtr_port_put(ipc);
5258c2ecf20Sopenharmony_ci			goto err;
5268c2ecf20Sopenharmony_ci		}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci		qrtr_port_put(ipc);
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	return 0;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_cierr:
5348c2ecf20Sopenharmony_ci	kfree_skb(skb);
5358c2ecf20Sopenharmony_ci	return -EINVAL;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qrtr_endpoint_post);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci/**
5418c2ecf20Sopenharmony_ci * qrtr_alloc_ctrl_packet() - allocate control packet skb
5428c2ecf20Sopenharmony_ci * @pkt: reference to qrtr_ctrl_pkt pointer
5438c2ecf20Sopenharmony_ci *
5448c2ecf20Sopenharmony_ci * Returns newly allocated sk_buff, or NULL on failure
5458c2ecf20Sopenharmony_ci *
5468c2ecf20Sopenharmony_ci * This function allocates a sk_buff large enough to carry a qrtr_ctrl_pkt and
5478c2ecf20Sopenharmony_ci * on success returns a reference to the control packet in @pkt.
5488c2ecf20Sopenharmony_ci */
5498c2ecf20Sopenharmony_cistatic struct sk_buff *qrtr_alloc_ctrl_packet(struct qrtr_ctrl_pkt **pkt)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	const int pkt_len = sizeof(struct qrtr_ctrl_pkt);
5528c2ecf20Sopenharmony_ci	struct sk_buff *skb;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	skb = alloc_skb(QRTR_HDR_MAX_SIZE + pkt_len, GFP_KERNEL);
5558c2ecf20Sopenharmony_ci	if (!skb)
5568c2ecf20Sopenharmony_ci		return NULL;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	skb_reserve(skb, QRTR_HDR_MAX_SIZE);
5598c2ecf20Sopenharmony_ci	*pkt = skb_put_zero(skb, pkt_len);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	return skb;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci/**
5658c2ecf20Sopenharmony_ci * qrtr_endpoint_register() - register a new endpoint
5668c2ecf20Sopenharmony_ci * @ep: endpoint to register
5678c2ecf20Sopenharmony_ci * @nid: desired node id; may be QRTR_EP_NID_AUTO for auto-assignment
5688c2ecf20Sopenharmony_ci * Return: 0 on success; negative error code on failure
5698c2ecf20Sopenharmony_ci *
5708c2ecf20Sopenharmony_ci * The specified endpoint must have the xmit function pointer set on call.
5718c2ecf20Sopenharmony_ci */
5728c2ecf20Sopenharmony_ciint qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	struct qrtr_node *node;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (!ep || !ep->xmit)
5778c2ecf20Sopenharmony_ci		return -EINVAL;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	node = kzalloc(sizeof(*node), GFP_KERNEL);
5808c2ecf20Sopenharmony_ci	if (!node)
5818c2ecf20Sopenharmony_ci		return -ENOMEM;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	kref_init(&node->ref);
5848c2ecf20Sopenharmony_ci	mutex_init(&node->ep_lock);
5858c2ecf20Sopenharmony_ci	skb_queue_head_init(&node->rx_queue);
5868c2ecf20Sopenharmony_ci	node->nid = QRTR_EP_NID_AUTO;
5878c2ecf20Sopenharmony_ci	node->ep = ep;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
5908c2ecf20Sopenharmony_ci	mutex_init(&node->qrtr_tx_lock);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	qrtr_node_assign(node, nid);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	mutex_lock(&qrtr_node_lock);
5958c2ecf20Sopenharmony_ci	list_add(&node->item, &qrtr_all_nodes);
5968c2ecf20Sopenharmony_ci	mutex_unlock(&qrtr_node_lock);
5978c2ecf20Sopenharmony_ci	ep->node = node;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	return 0;
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qrtr_endpoint_register);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci/**
6048c2ecf20Sopenharmony_ci * qrtr_endpoint_unregister - unregister endpoint
6058c2ecf20Sopenharmony_ci * @ep: endpoint to unregister
6068c2ecf20Sopenharmony_ci */
6078c2ecf20Sopenharmony_civoid qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	struct qrtr_node *node = ep->node;
6108c2ecf20Sopenharmony_ci	struct sockaddr_qrtr src = {AF_QIPCRTR, node->nid, QRTR_PORT_CTRL};
6118c2ecf20Sopenharmony_ci	struct sockaddr_qrtr dst = {AF_QIPCRTR, qrtr_local_nid, QRTR_PORT_CTRL};
6128c2ecf20Sopenharmony_ci	struct radix_tree_iter iter;
6138c2ecf20Sopenharmony_ci	struct qrtr_ctrl_pkt *pkt;
6148c2ecf20Sopenharmony_ci	struct qrtr_tx_flow *flow;
6158c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6168c2ecf20Sopenharmony_ci	void __rcu **slot;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	mutex_lock(&node->ep_lock);
6198c2ecf20Sopenharmony_ci	node->ep = NULL;
6208c2ecf20Sopenharmony_ci	mutex_unlock(&node->ep_lock);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	/* Notify the local controller about the event */
6238c2ecf20Sopenharmony_ci	skb = qrtr_alloc_ctrl_packet(&pkt);
6248c2ecf20Sopenharmony_ci	if (skb) {
6258c2ecf20Sopenharmony_ci		pkt->cmd = cpu_to_le32(QRTR_TYPE_BYE);
6268c2ecf20Sopenharmony_ci		qrtr_local_enqueue(NULL, skb, QRTR_TYPE_BYE, &src, &dst);
6278c2ecf20Sopenharmony_ci	}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	/* Wake up any transmitters waiting for resume-tx from the node */
6308c2ecf20Sopenharmony_ci	mutex_lock(&node->qrtr_tx_lock);
6318c2ecf20Sopenharmony_ci	radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
6328c2ecf20Sopenharmony_ci		flow = *slot;
6338c2ecf20Sopenharmony_ci		wake_up_interruptible_all(&flow->resume_tx);
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci	mutex_unlock(&node->qrtr_tx_lock);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	qrtr_node_release(node);
6388c2ecf20Sopenharmony_ci	ep->node = NULL;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qrtr_endpoint_unregister);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci/* Lookup socket by port.
6438c2ecf20Sopenharmony_ci *
6448c2ecf20Sopenharmony_ci * Callers must release with qrtr_port_put()
6458c2ecf20Sopenharmony_ci */
6468c2ecf20Sopenharmony_cistatic struct qrtr_sock *qrtr_port_lookup(int port)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (port == QRTR_PORT_CTRL)
6518c2ecf20Sopenharmony_ci		port = 0;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	rcu_read_lock();
6548c2ecf20Sopenharmony_ci	ipc = xa_load(&qrtr_ports, port);
6558c2ecf20Sopenharmony_ci	if (ipc)
6568c2ecf20Sopenharmony_ci		sock_hold(&ipc->sk);
6578c2ecf20Sopenharmony_ci	rcu_read_unlock();
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	return ipc;
6608c2ecf20Sopenharmony_ci}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci/* Release acquired socket. */
6638c2ecf20Sopenharmony_cistatic void qrtr_port_put(struct qrtr_sock *ipc)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	sock_put(&ipc->sk);
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci/* Remove port assignment. */
6698c2ecf20Sopenharmony_cistatic void qrtr_port_remove(struct qrtr_sock *ipc)
6708c2ecf20Sopenharmony_ci{
6718c2ecf20Sopenharmony_ci	struct qrtr_ctrl_pkt *pkt;
6728c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6738c2ecf20Sopenharmony_ci	int port = ipc->us.sq_port;
6748c2ecf20Sopenharmony_ci	struct sockaddr_qrtr to;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	to.sq_family = AF_QIPCRTR;
6778c2ecf20Sopenharmony_ci	to.sq_node = QRTR_NODE_BCAST;
6788c2ecf20Sopenharmony_ci	to.sq_port = QRTR_PORT_CTRL;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	skb = qrtr_alloc_ctrl_packet(&pkt);
6818c2ecf20Sopenharmony_ci	if (skb) {
6828c2ecf20Sopenharmony_ci		pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT);
6838c2ecf20Sopenharmony_ci		pkt->client.node = cpu_to_le32(ipc->us.sq_node);
6848c2ecf20Sopenharmony_ci		pkt->client.port = cpu_to_le32(ipc->us.sq_port);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci		skb_set_owner_w(skb, &ipc->sk);
6878c2ecf20Sopenharmony_ci		qrtr_bcast_enqueue(NULL, skb, QRTR_TYPE_DEL_CLIENT, &ipc->us,
6888c2ecf20Sopenharmony_ci				   &to);
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (port == QRTR_PORT_CTRL)
6928c2ecf20Sopenharmony_ci		port = 0;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	__sock_put(&ipc->sk);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	xa_erase(&qrtr_ports, port);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	/* Ensure that if qrtr_port_lookup() did enter the RCU read section we
6998c2ecf20Sopenharmony_ci	 * wait for it to up increment the refcount */
7008c2ecf20Sopenharmony_ci	synchronize_rcu();
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci/* Assign port number to socket.
7048c2ecf20Sopenharmony_ci *
7058c2ecf20Sopenharmony_ci * Specify port in the integer pointed to by port, and it will be adjusted
7068c2ecf20Sopenharmony_ci * on return as necesssary.
7078c2ecf20Sopenharmony_ci *
7088c2ecf20Sopenharmony_ci * Port may be:
7098c2ecf20Sopenharmony_ci *   0: Assign ephemeral port in [QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET]
7108c2ecf20Sopenharmony_ci *   <QRTR_MIN_EPH_SOCKET: Specified; requires CAP_NET_ADMIN
7118c2ecf20Sopenharmony_ci *   >QRTR_MIN_EPH_SOCKET: Specified; available to all
7128c2ecf20Sopenharmony_ci */
7138c2ecf20Sopenharmony_cistatic int qrtr_port_assign(struct qrtr_sock *ipc, int *port)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	int rc;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (!*port) {
7188c2ecf20Sopenharmony_ci		rc = xa_alloc(&qrtr_ports, port, ipc, QRTR_EPH_PORT_RANGE,
7198c2ecf20Sopenharmony_ci				GFP_KERNEL);
7208c2ecf20Sopenharmony_ci	} else if (*port < QRTR_MIN_EPH_SOCKET && !capable(CAP_NET_ADMIN)) {
7218c2ecf20Sopenharmony_ci		rc = -EACCES;
7228c2ecf20Sopenharmony_ci	} else if (*port == QRTR_PORT_CTRL) {
7238c2ecf20Sopenharmony_ci		rc = xa_insert(&qrtr_ports, 0, ipc, GFP_KERNEL);
7248c2ecf20Sopenharmony_ci	} else {
7258c2ecf20Sopenharmony_ci		rc = xa_insert(&qrtr_ports, *port, ipc, GFP_KERNEL);
7268c2ecf20Sopenharmony_ci	}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	if (rc == -EBUSY)
7298c2ecf20Sopenharmony_ci		return -EADDRINUSE;
7308c2ecf20Sopenharmony_ci	else if (rc < 0)
7318c2ecf20Sopenharmony_ci		return rc;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	sock_hold(&ipc->sk);
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	return 0;
7368c2ecf20Sopenharmony_ci}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci/* Reset all non-control ports */
7398c2ecf20Sopenharmony_cistatic void qrtr_reset_ports(void)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc;
7428c2ecf20Sopenharmony_ci	unsigned long index;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	rcu_read_lock();
7458c2ecf20Sopenharmony_ci	xa_for_each_start(&qrtr_ports, index, ipc, 1) {
7468c2ecf20Sopenharmony_ci		sock_hold(&ipc->sk);
7478c2ecf20Sopenharmony_ci		ipc->sk.sk_err = ENETRESET;
7488c2ecf20Sopenharmony_ci		ipc->sk.sk_error_report(&ipc->sk);
7498c2ecf20Sopenharmony_ci		sock_put(&ipc->sk);
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci	rcu_read_unlock();
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci/* Bind socket to address.
7558c2ecf20Sopenharmony_ci *
7568c2ecf20Sopenharmony_ci * Socket should be locked upon call.
7578c2ecf20Sopenharmony_ci */
7588c2ecf20Sopenharmony_cistatic int __qrtr_bind(struct socket *sock,
7598c2ecf20Sopenharmony_ci		       const struct sockaddr_qrtr *addr, int zapped)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc = qrtr_sk(sock->sk);
7628c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
7638c2ecf20Sopenharmony_ci	int port;
7648c2ecf20Sopenharmony_ci	int rc;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	/* rebinding ok */
7678c2ecf20Sopenharmony_ci	if (!zapped && addr->sq_port == ipc->us.sq_port)
7688c2ecf20Sopenharmony_ci		return 0;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	port = addr->sq_port;
7718c2ecf20Sopenharmony_ci	rc = qrtr_port_assign(ipc, &port);
7728c2ecf20Sopenharmony_ci	if (rc)
7738c2ecf20Sopenharmony_ci		return rc;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	/* unbind previous, if any */
7768c2ecf20Sopenharmony_ci	if (!zapped)
7778c2ecf20Sopenharmony_ci		qrtr_port_remove(ipc);
7788c2ecf20Sopenharmony_ci	ipc->us.sq_port = port;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	sock_reset_flag(sk, SOCK_ZAPPED);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	/* Notify all open ports about the new controller */
7838c2ecf20Sopenharmony_ci	if (port == QRTR_PORT_CTRL)
7848c2ecf20Sopenharmony_ci		qrtr_reset_ports();
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	return 0;
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci/* Auto bind to an ephemeral port. */
7908c2ecf20Sopenharmony_cistatic int qrtr_autobind(struct socket *sock)
7918c2ecf20Sopenharmony_ci{
7928c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
7938c2ecf20Sopenharmony_ci	struct sockaddr_qrtr addr;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	if (!sock_flag(sk, SOCK_ZAPPED))
7968c2ecf20Sopenharmony_ci		return 0;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	addr.sq_family = AF_QIPCRTR;
7998c2ecf20Sopenharmony_ci	addr.sq_node = qrtr_local_nid;
8008c2ecf20Sopenharmony_ci	addr.sq_port = 0;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	return __qrtr_bind(sock, &addr, 1);
8038c2ecf20Sopenharmony_ci}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci/* Bind socket to specified sockaddr. */
8068c2ecf20Sopenharmony_cistatic int qrtr_bind(struct socket *sock, struct sockaddr *saddr, int len)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, saddr);
8098c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc = qrtr_sk(sock->sk);
8108c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
8118c2ecf20Sopenharmony_ci	int rc;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	if (len < sizeof(*addr) || addr->sq_family != AF_QIPCRTR)
8148c2ecf20Sopenharmony_ci		return -EINVAL;
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	if (addr->sq_node != ipc->us.sq_node)
8178c2ecf20Sopenharmony_ci		return -EINVAL;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	lock_sock(sk);
8208c2ecf20Sopenharmony_ci	rc = __qrtr_bind(sock, addr, sock_flag(sk, SOCK_ZAPPED));
8218c2ecf20Sopenharmony_ci	release_sock(sk);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	return rc;
8248c2ecf20Sopenharmony_ci}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci/* Queue packet to local peer socket. */
8278c2ecf20Sopenharmony_cistatic int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb,
8288c2ecf20Sopenharmony_ci			      int type, struct sockaddr_qrtr *from,
8298c2ecf20Sopenharmony_ci			      struct sockaddr_qrtr *to)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc;
8328c2ecf20Sopenharmony_ci	struct qrtr_cb *cb;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	ipc = qrtr_port_lookup(to->sq_port);
8358c2ecf20Sopenharmony_ci	if (!ipc || &ipc->sk == skb->sk) { /* do not send to self */
8368c2ecf20Sopenharmony_ci		if (ipc)
8378c2ecf20Sopenharmony_ci			qrtr_port_put(ipc);
8388c2ecf20Sopenharmony_ci		kfree_skb(skb);
8398c2ecf20Sopenharmony_ci		return -ENODEV;
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	cb = (struct qrtr_cb *)skb->cb;
8438c2ecf20Sopenharmony_ci	cb->src_node = from->sq_node;
8448c2ecf20Sopenharmony_ci	cb->src_port = from->sq_port;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	if (sock_queue_rcv_skb(&ipc->sk, skb)) {
8478c2ecf20Sopenharmony_ci		qrtr_port_put(ipc);
8488c2ecf20Sopenharmony_ci		kfree_skb(skb);
8498c2ecf20Sopenharmony_ci		return -ENOSPC;
8508c2ecf20Sopenharmony_ci	}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	qrtr_port_put(ipc);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	return 0;
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci/* Queue packet for broadcast. */
8588c2ecf20Sopenharmony_cistatic int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb,
8598c2ecf20Sopenharmony_ci			      int type, struct sockaddr_qrtr *from,
8608c2ecf20Sopenharmony_ci			      struct sockaddr_qrtr *to)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	struct sk_buff *skbn;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	mutex_lock(&qrtr_node_lock);
8658c2ecf20Sopenharmony_ci	list_for_each_entry(node, &qrtr_all_nodes, item) {
8668c2ecf20Sopenharmony_ci		skbn = skb_clone(skb, GFP_KERNEL);
8678c2ecf20Sopenharmony_ci		if (!skbn)
8688c2ecf20Sopenharmony_ci			break;
8698c2ecf20Sopenharmony_ci		skb_set_owner_w(skbn, skb->sk);
8708c2ecf20Sopenharmony_ci		qrtr_node_enqueue(node, skbn, type, from, to);
8718c2ecf20Sopenharmony_ci	}
8728c2ecf20Sopenharmony_ci	mutex_unlock(&qrtr_node_lock);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	qrtr_local_enqueue(NULL, skb, type, from, to);
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	return 0;
8778c2ecf20Sopenharmony_ci}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_cistatic int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
8808c2ecf20Sopenharmony_ci{
8818c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name);
8828c2ecf20Sopenharmony_ci	int (*enqueue_fn)(struct qrtr_node *, struct sk_buff *, int,
8838c2ecf20Sopenharmony_ci			  struct sockaddr_qrtr *, struct sockaddr_qrtr *);
8848c2ecf20Sopenharmony_ci	__le32 qrtr_type = cpu_to_le32(QRTR_TYPE_DATA);
8858c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc = qrtr_sk(sock->sk);
8868c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
8878c2ecf20Sopenharmony_ci	struct qrtr_node *node;
8888c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8898c2ecf20Sopenharmony_ci	size_t plen;
8908c2ecf20Sopenharmony_ci	u32 type;
8918c2ecf20Sopenharmony_ci	int rc;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	if (msg->msg_flags & ~(MSG_DONTWAIT))
8948c2ecf20Sopenharmony_ci		return -EINVAL;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	if (len > 65535)
8978c2ecf20Sopenharmony_ci		return -EMSGSIZE;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	lock_sock(sk);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	if (addr) {
9028c2ecf20Sopenharmony_ci		if (msg->msg_namelen < sizeof(*addr)) {
9038c2ecf20Sopenharmony_ci			release_sock(sk);
9048c2ecf20Sopenharmony_ci			return -EINVAL;
9058c2ecf20Sopenharmony_ci		}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci		if (addr->sq_family != AF_QIPCRTR) {
9088c2ecf20Sopenharmony_ci			release_sock(sk);
9098c2ecf20Sopenharmony_ci			return -EINVAL;
9108c2ecf20Sopenharmony_ci		}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci		rc = qrtr_autobind(sock);
9138c2ecf20Sopenharmony_ci		if (rc) {
9148c2ecf20Sopenharmony_ci			release_sock(sk);
9158c2ecf20Sopenharmony_ci			return rc;
9168c2ecf20Sopenharmony_ci		}
9178c2ecf20Sopenharmony_ci	} else if (sk->sk_state == TCP_ESTABLISHED) {
9188c2ecf20Sopenharmony_ci		addr = &ipc->peer;
9198c2ecf20Sopenharmony_ci	} else {
9208c2ecf20Sopenharmony_ci		release_sock(sk);
9218c2ecf20Sopenharmony_ci		return -ENOTCONN;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	node = NULL;
9258c2ecf20Sopenharmony_ci	if (addr->sq_node == QRTR_NODE_BCAST) {
9268c2ecf20Sopenharmony_ci		if (addr->sq_port != QRTR_PORT_CTRL &&
9278c2ecf20Sopenharmony_ci		    qrtr_local_nid != QRTR_NODE_BCAST) {
9288c2ecf20Sopenharmony_ci			release_sock(sk);
9298c2ecf20Sopenharmony_ci			return -ENOTCONN;
9308c2ecf20Sopenharmony_ci		}
9318c2ecf20Sopenharmony_ci		enqueue_fn = qrtr_bcast_enqueue;
9328c2ecf20Sopenharmony_ci	} else if (addr->sq_node == ipc->us.sq_node) {
9338c2ecf20Sopenharmony_ci		enqueue_fn = qrtr_local_enqueue;
9348c2ecf20Sopenharmony_ci	} else {
9358c2ecf20Sopenharmony_ci		node = qrtr_node_lookup(addr->sq_node);
9368c2ecf20Sopenharmony_ci		if (!node) {
9378c2ecf20Sopenharmony_ci			release_sock(sk);
9388c2ecf20Sopenharmony_ci			return -ECONNRESET;
9398c2ecf20Sopenharmony_ci		}
9408c2ecf20Sopenharmony_ci		enqueue_fn = qrtr_node_enqueue;
9418c2ecf20Sopenharmony_ci	}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	plen = (len + 3) & ~3;
9448c2ecf20Sopenharmony_ci	skb = sock_alloc_send_skb(sk, plen + QRTR_HDR_MAX_SIZE,
9458c2ecf20Sopenharmony_ci				  msg->msg_flags & MSG_DONTWAIT, &rc);
9468c2ecf20Sopenharmony_ci	if (!skb) {
9478c2ecf20Sopenharmony_ci		rc = -ENOMEM;
9488c2ecf20Sopenharmony_ci		goto out_node;
9498c2ecf20Sopenharmony_ci	}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	skb_reserve(skb, QRTR_HDR_MAX_SIZE);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	rc = memcpy_from_msg(skb_put(skb, len), msg, len);
9548c2ecf20Sopenharmony_ci	if (rc) {
9558c2ecf20Sopenharmony_ci		kfree_skb(skb);
9568c2ecf20Sopenharmony_ci		goto out_node;
9578c2ecf20Sopenharmony_ci	}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	if (ipc->us.sq_port == QRTR_PORT_CTRL) {
9608c2ecf20Sopenharmony_ci		if (len < 4) {
9618c2ecf20Sopenharmony_ci			rc = -EINVAL;
9628c2ecf20Sopenharmony_ci			kfree_skb(skb);
9638c2ecf20Sopenharmony_ci			goto out_node;
9648c2ecf20Sopenharmony_ci		}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci		/* control messages already require the type as 'command' */
9678c2ecf20Sopenharmony_ci		skb_copy_bits(skb, 0, &qrtr_type, 4);
9688c2ecf20Sopenharmony_ci	}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	type = le32_to_cpu(qrtr_type);
9718c2ecf20Sopenharmony_ci	rc = enqueue_fn(node, skb, type, &ipc->us, addr);
9728c2ecf20Sopenharmony_ci	if (rc >= 0)
9738c2ecf20Sopenharmony_ci		rc = len;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ciout_node:
9768c2ecf20Sopenharmony_ci	qrtr_node_release(node);
9778c2ecf20Sopenharmony_ci	release_sock(sk);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	return rc;
9808c2ecf20Sopenharmony_ci}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_cistatic int qrtr_send_resume_tx(struct qrtr_cb *cb)
9838c2ecf20Sopenharmony_ci{
9848c2ecf20Sopenharmony_ci	struct sockaddr_qrtr remote = { AF_QIPCRTR, cb->src_node, cb->src_port };
9858c2ecf20Sopenharmony_ci	struct sockaddr_qrtr local = { AF_QIPCRTR, cb->dst_node, cb->dst_port };
9868c2ecf20Sopenharmony_ci	struct qrtr_ctrl_pkt *pkt;
9878c2ecf20Sopenharmony_ci	struct qrtr_node *node;
9888c2ecf20Sopenharmony_ci	struct sk_buff *skb;
9898c2ecf20Sopenharmony_ci	int ret;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	node = qrtr_node_lookup(remote.sq_node);
9928c2ecf20Sopenharmony_ci	if (!node)
9938c2ecf20Sopenharmony_ci		return -EINVAL;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	skb = qrtr_alloc_ctrl_packet(&pkt);
9968c2ecf20Sopenharmony_ci	if (!skb)
9978c2ecf20Sopenharmony_ci		return -ENOMEM;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	pkt->cmd = cpu_to_le32(QRTR_TYPE_RESUME_TX);
10008c2ecf20Sopenharmony_ci	pkt->client.node = cpu_to_le32(cb->dst_node);
10018c2ecf20Sopenharmony_ci	pkt->client.port = cpu_to_le32(cb->dst_port);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	ret = qrtr_node_enqueue(node, skb, QRTR_TYPE_RESUME_TX, &local, &remote);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	qrtr_node_release(node);
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	return ret;
10088c2ecf20Sopenharmony_ci}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_cistatic int qrtr_recvmsg(struct socket *sock, struct msghdr *msg,
10118c2ecf20Sopenharmony_ci			size_t size, int flags)
10128c2ecf20Sopenharmony_ci{
10138c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name);
10148c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
10158c2ecf20Sopenharmony_ci	struct sk_buff *skb;
10168c2ecf20Sopenharmony_ci	struct qrtr_cb *cb;
10178c2ecf20Sopenharmony_ci	int copied, rc;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	lock_sock(sk);
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	if (sock_flag(sk, SOCK_ZAPPED)) {
10228c2ecf20Sopenharmony_ci		release_sock(sk);
10238c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
10248c2ecf20Sopenharmony_ci	}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
10278c2ecf20Sopenharmony_ci				flags & MSG_DONTWAIT, &rc);
10288c2ecf20Sopenharmony_ci	if (!skb) {
10298c2ecf20Sopenharmony_ci		release_sock(sk);
10308c2ecf20Sopenharmony_ci		return rc;
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci	cb = (struct qrtr_cb *)skb->cb;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	copied = skb->len;
10358c2ecf20Sopenharmony_ci	if (copied > size) {
10368c2ecf20Sopenharmony_ci		copied = size;
10378c2ecf20Sopenharmony_ci		msg->msg_flags |= MSG_TRUNC;
10388c2ecf20Sopenharmony_ci	}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	rc = skb_copy_datagram_msg(skb, 0, msg, copied);
10418c2ecf20Sopenharmony_ci	if (rc < 0)
10428c2ecf20Sopenharmony_ci		goto out;
10438c2ecf20Sopenharmony_ci	rc = copied;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	if (addr) {
10468c2ecf20Sopenharmony_ci		/* There is an anonymous 2-byte hole after sq_family,
10478c2ecf20Sopenharmony_ci		 * make sure to clear it.
10488c2ecf20Sopenharmony_ci		 */
10498c2ecf20Sopenharmony_ci		memset(addr, 0, sizeof(*addr));
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci		addr->sq_family = AF_QIPCRTR;
10528c2ecf20Sopenharmony_ci		addr->sq_node = cb->src_node;
10538c2ecf20Sopenharmony_ci		addr->sq_port = cb->src_port;
10548c2ecf20Sopenharmony_ci		msg->msg_namelen = sizeof(*addr);
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ciout:
10588c2ecf20Sopenharmony_ci	if (cb->confirm_rx)
10598c2ecf20Sopenharmony_ci		qrtr_send_resume_tx(cb);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	skb_free_datagram(sk, skb);
10628c2ecf20Sopenharmony_ci	release_sock(sk);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	return rc;
10658c2ecf20Sopenharmony_ci}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_cistatic int qrtr_connect(struct socket *sock, struct sockaddr *saddr,
10688c2ecf20Sopenharmony_ci			int len, int flags)
10698c2ecf20Sopenharmony_ci{
10708c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, saddr);
10718c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc = qrtr_sk(sock->sk);
10728c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
10738c2ecf20Sopenharmony_ci	int rc;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	if (len < sizeof(*addr) || addr->sq_family != AF_QIPCRTR)
10768c2ecf20Sopenharmony_ci		return -EINVAL;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	lock_sock(sk);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	sk->sk_state = TCP_CLOSE;
10818c2ecf20Sopenharmony_ci	sock->state = SS_UNCONNECTED;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	rc = qrtr_autobind(sock);
10848c2ecf20Sopenharmony_ci	if (rc) {
10858c2ecf20Sopenharmony_ci		release_sock(sk);
10868c2ecf20Sopenharmony_ci		return rc;
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	ipc->peer = *addr;
10908c2ecf20Sopenharmony_ci	sock->state = SS_CONNECTED;
10918c2ecf20Sopenharmony_ci	sk->sk_state = TCP_ESTABLISHED;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	release_sock(sk);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	return 0;
10968c2ecf20Sopenharmony_ci}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_cistatic int qrtr_getname(struct socket *sock, struct sockaddr *saddr,
10998c2ecf20Sopenharmony_ci			int peer)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc = qrtr_sk(sock->sk);
11028c2ecf20Sopenharmony_ci	struct sockaddr_qrtr qaddr;
11038c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	lock_sock(sk);
11068c2ecf20Sopenharmony_ci	if (peer) {
11078c2ecf20Sopenharmony_ci		if (sk->sk_state != TCP_ESTABLISHED) {
11088c2ecf20Sopenharmony_ci			release_sock(sk);
11098c2ecf20Sopenharmony_ci			return -ENOTCONN;
11108c2ecf20Sopenharmony_ci		}
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci		qaddr = ipc->peer;
11138c2ecf20Sopenharmony_ci	} else {
11148c2ecf20Sopenharmony_ci		qaddr = ipc->us;
11158c2ecf20Sopenharmony_ci	}
11168c2ecf20Sopenharmony_ci	release_sock(sk);
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	qaddr.sq_family = AF_QIPCRTR;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	memcpy(saddr, &qaddr, sizeof(qaddr));
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	return sizeof(qaddr);
11238c2ecf20Sopenharmony_ci}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_cistatic int qrtr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
11268c2ecf20Sopenharmony_ci{
11278c2ecf20Sopenharmony_ci	void __user *argp = (void __user *)arg;
11288c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc = qrtr_sk(sock->sk);
11298c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
11308c2ecf20Sopenharmony_ci	struct sockaddr_qrtr *sq;
11318c2ecf20Sopenharmony_ci	struct sk_buff *skb;
11328c2ecf20Sopenharmony_ci	struct ifreq ifr;
11338c2ecf20Sopenharmony_ci	long len = 0;
11348c2ecf20Sopenharmony_ci	int rc = 0;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	lock_sock(sk);
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	switch (cmd) {
11398c2ecf20Sopenharmony_ci	case TIOCOUTQ:
11408c2ecf20Sopenharmony_ci		len = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
11418c2ecf20Sopenharmony_ci		if (len < 0)
11428c2ecf20Sopenharmony_ci			len = 0;
11438c2ecf20Sopenharmony_ci		rc = put_user(len, (int __user *)argp);
11448c2ecf20Sopenharmony_ci		break;
11458c2ecf20Sopenharmony_ci	case TIOCINQ:
11468c2ecf20Sopenharmony_ci		skb = skb_peek(&sk->sk_receive_queue);
11478c2ecf20Sopenharmony_ci		if (skb)
11488c2ecf20Sopenharmony_ci			len = skb->len;
11498c2ecf20Sopenharmony_ci		rc = put_user(len, (int __user *)argp);
11508c2ecf20Sopenharmony_ci		break;
11518c2ecf20Sopenharmony_ci	case SIOCGIFADDR:
11528c2ecf20Sopenharmony_ci		if (copy_from_user(&ifr, argp, sizeof(ifr))) {
11538c2ecf20Sopenharmony_ci			rc = -EFAULT;
11548c2ecf20Sopenharmony_ci			break;
11558c2ecf20Sopenharmony_ci		}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci		sq = (struct sockaddr_qrtr *)&ifr.ifr_addr;
11588c2ecf20Sopenharmony_ci		*sq = ipc->us;
11598c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &ifr, sizeof(ifr))) {
11608c2ecf20Sopenharmony_ci			rc = -EFAULT;
11618c2ecf20Sopenharmony_ci			break;
11628c2ecf20Sopenharmony_ci		}
11638c2ecf20Sopenharmony_ci		break;
11648c2ecf20Sopenharmony_ci	case SIOCADDRT:
11658c2ecf20Sopenharmony_ci	case SIOCDELRT:
11668c2ecf20Sopenharmony_ci	case SIOCSIFADDR:
11678c2ecf20Sopenharmony_ci	case SIOCGIFDSTADDR:
11688c2ecf20Sopenharmony_ci	case SIOCSIFDSTADDR:
11698c2ecf20Sopenharmony_ci	case SIOCGIFBRDADDR:
11708c2ecf20Sopenharmony_ci	case SIOCSIFBRDADDR:
11718c2ecf20Sopenharmony_ci	case SIOCGIFNETMASK:
11728c2ecf20Sopenharmony_ci	case SIOCSIFNETMASK:
11738c2ecf20Sopenharmony_ci		rc = -EINVAL;
11748c2ecf20Sopenharmony_ci		break;
11758c2ecf20Sopenharmony_ci	default:
11768c2ecf20Sopenharmony_ci		rc = -ENOIOCTLCMD;
11778c2ecf20Sopenharmony_ci		break;
11788c2ecf20Sopenharmony_ci	}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	release_sock(sk);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	return rc;
11838c2ecf20Sopenharmony_ci}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_cistatic int qrtr_release(struct socket *sock)
11868c2ecf20Sopenharmony_ci{
11878c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
11888c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	if (!sk)
11918c2ecf20Sopenharmony_ci		return 0;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	lock_sock(sk);
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	ipc = qrtr_sk(sk);
11968c2ecf20Sopenharmony_ci	sk->sk_shutdown = SHUTDOWN_MASK;
11978c2ecf20Sopenharmony_ci	if (!sock_flag(sk, SOCK_DEAD))
11988c2ecf20Sopenharmony_ci		sk->sk_state_change(sk);
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	sock_set_flag(sk, SOCK_DEAD);
12018c2ecf20Sopenharmony_ci	sock_orphan(sk);
12028c2ecf20Sopenharmony_ci	sock->sk = NULL;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	if (!sock_flag(sk, SOCK_ZAPPED))
12058c2ecf20Sopenharmony_ci		qrtr_port_remove(ipc);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	skb_queue_purge(&sk->sk_receive_queue);
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	release_sock(sk);
12108c2ecf20Sopenharmony_ci	sock_put(sk);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	return 0;
12138c2ecf20Sopenharmony_ci}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_cistatic const struct proto_ops qrtr_proto_ops = {
12168c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
12178c2ecf20Sopenharmony_ci	.family		= AF_QIPCRTR,
12188c2ecf20Sopenharmony_ci	.bind		= qrtr_bind,
12198c2ecf20Sopenharmony_ci	.connect	= qrtr_connect,
12208c2ecf20Sopenharmony_ci	.socketpair	= sock_no_socketpair,
12218c2ecf20Sopenharmony_ci	.accept		= sock_no_accept,
12228c2ecf20Sopenharmony_ci	.listen		= sock_no_listen,
12238c2ecf20Sopenharmony_ci	.sendmsg	= qrtr_sendmsg,
12248c2ecf20Sopenharmony_ci	.recvmsg	= qrtr_recvmsg,
12258c2ecf20Sopenharmony_ci	.getname	= qrtr_getname,
12268c2ecf20Sopenharmony_ci	.ioctl		= qrtr_ioctl,
12278c2ecf20Sopenharmony_ci	.gettstamp	= sock_gettstamp,
12288c2ecf20Sopenharmony_ci	.poll		= datagram_poll,
12298c2ecf20Sopenharmony_ci	.shutdown	= sock_no_shutdown,
12308c2ecf20Sopenharmony_ci	.release	= qrtr_release,
12318c2ecf20Sopenharmony_ci	.mmap		= sock_no_mmap,
12328c2ecf20Sopenharmony_ci	.sendpage	= sock_no_sendpage,
12338c2ecf20Sopenharmony_ci};
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_cistatic struct proto qrtr_proto = {
12368c2ecf20Sopenharmony_ci	.name		= "QIPCRTR",
12378c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
12388c2ecf20Sopenharmony_ci	.obj_size	= sizeof(struct qrtr_sock),
12398c2ecf20Sopenharmony_ci};
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_cistatic int qrtr_create(struct net *net, struct socket *sock,
12428c2ecf20Sopenharmony_ci		       int protocol, int kern)
12438c2ecf20Sopenharmony_ci{
12448c2ecf20Sopenharmony_ci	struct qrtr_sock *ipc;
12458c2ecf20Sopenharmony_ci	struct sock *sk;
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	if (sock->type != SOCK_DGRAM)
12488c2ecf20Sopenharmony_ci		return -EPROTOTYPE;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	sk = sk_alloc(net, AF_QIPCRTR, GFP_KERNEL, &qrtr_proto, kern);
12518c2ecf20Sopenharmony_ci	if (!sk)
12528c2ecf20Sopenharmony_ci		return -ENOMEM;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	sock_set_flag(sk, SOCK_ZAPPED);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	sock_init_data(sock, sk);
12578c2ecf20Sopenharmony_ci	sock->ops = &qrtr_proto_ops;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	ipc = qrtr_sk(sk);
12608c2ecf20Sopenharmony_ci	ipc->us.sq_family = AF_QIPCRTR;
12618c2ecf20Sopenharmony_ci	ipc->us.sq_node = qrtr_local_nid;
12628c2ecf20Sopenharmony_ci	ipc->us.sq_port = 0;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	return 0;
12658c2ecf20Sopenharmony_ci}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_cistatic const struct net_proto_family qrtr_family = {
12688c2ecf20Sopenharmony_ci	.owner	= THIS_MODULE,
12698c2ecf20Sopenharmony_ci	.family	= AF_QIPCRTR,
12708c2ecf20Sopenharmony_ci	.create	= qrtr_create,
12718c2ecf20Sopenharmony_ci};
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_cistatic int __init qrtr_proto_init(void)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	int rc;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	rc = proto_register(&qrtr_proto, 1);
12788c2ecf20Sopenharmony_ci	if (rc)
12798c2ecf20Sopenharmony_ci		return rc;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	rc = sock_register(&qrtr_family);
12828c2ecf20Sopenharmony_ci	if (rc) {
12838c2ecf20Sopenharmony_ci		proto_unregister(&qrtr_proto);
12848c2ecf20Sopenharmony_ci		return rc;
12858c2ecf20Sopenharmony_ci	}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	qrtr_ns_init();
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	return rc;
12908c2ecf20Sopenharmony_ci}
12918c2ecf20Sopenharmony_cipostcore_initcall(qrtr_proto_init);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_cistatic void __exit qrtr_proto_fini(void)
12948c2ecf20Sopenharmony_ci{
12958c2ecf20Sopenharmony_ci	qrtr_ns_remove();
12968c2ecf20Sopenharmony_ci	sock_unregister(qrtr_family.family);
12978c2ecf20Sopenharmony_ci	proto_unregister(&qrtr_proto);
12988c2ecf20Sopenharmony_ci}
12998c2ecf20Sopenharmony_cimodule_exit(qrtr_proto_fini);
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm IPC-router driver");
13028c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
13038c2ecf20Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_QIPCRTR);
1304