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