10c2204a4SManivannan Sadhasivam // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
20c2204a4SManivannan Sadhasivam /*
30c2204a4SManivannan Sadhasivam * Copyright (c) 2015, Sony Mobile Communications Inc.
40c2204a4SManivannan Sadhasivam * Copyright (c) 2013, The Linux Foundation. All rights reserved.
50c2204a4SManivannan Sadhasivam * Copyright (c) 2020, Linaro Ltd.
60c2204a4SManivannan Sadhasivam */
70c2204a4SManivannan Sadhasivam
80c2204a4SManivannan Sadhasivam #include <linux/module.h>
90c2204a4SManivannan Sadhasivam #include <linux/qrtr.h>
100c2204a4SManivannan Sadhasivam #include <linux/workqueue.h>
110c2204a4SManivannan Sadhasivam #include <net/sock.h>
120c2204a4SManivannan Sadhasivam
130c2204a4SManivannan Sadhasivam #include "qrtr.h"
140c2204a4SManivannan Sadhasivam
1540e0b090SPeilin Ye #include <trace/events/sock.h>
16dfddb540SManivannan Sadhasivam #define CREATE_TRACE_POINTS
17dfddb540SManivannan Sadhasivam #include <trace/events/qrtr.h>
18dfddb540SManivannan Sadhasivam
19f26b32efSVignesh Viswanathan static DEFINE_XARRAY(nodes);
200c2204a4SManivannan Sadhasivam
210c2204a4SManivannan Sadhasivam static struct {
220c2204a4SManivannan Sadhasivam struct socket *sock;
230c2204a4SManivannan Sadhasivam struct sockaddr_qrtr bcast_sq;
240c2204a4SManivannan Sadhasivam struct list_head lookups;
250c2204a4SManivannan Sadhasivam struct workqueue_struct *workqueue;
260c2204a4SManivannan Sadhasivam struct work_struct work;
270c2204a4SManivannan Sadhasivam int local_node;
280c2204a4SManivannan Sadhasivam } qrtr_ns;
290c2204a4SManivannan Sadhasivam
300c2204a4SManivannan Sadhasivam static const char * const qrtr_ctrl_pkt_strings[] = {
310c2204a4SManivannan Sadhasivam [QRTR_TYPE_HELLO] = "hello",
320c2204a4SManivannan Sadhasivam [QRTR_TYPE_BYE] = "bye",
330c2204a4SManivannan Sadhasivam [QRTR_TYPE_NEW_SERVER] = "new-server",
340c2204a4SManivannan Sadhasivam [QRTR_TYPE_DEL_SERVER] = "del-server",
350c2204a4SManivannan Sadhasivam [QRTR_TYPE_DEL_CLIENT] = "del-client",
360c2204a4SManivannan Sadhasivam [QRTR_TYPE_RESUME_TX] = "resume-tx",
370c2204a4SManivannan Sadhasivam [QRTR_TYPE_EXIT] = "exit",
380c2204a4SManivannan Sadhasivam [QRTR_TYPE_PING] = "ping",
390c2204a4SManivannan Sadhasivam [QRTR_TYPE_NEW_LOOKUP] = "new-lookup",
400c2204a4SManivannan Sadhasivam [QRTR_TYPE_DEL_LOOKUP] = "del-lookup",
410c2204a4SManivannan Sadhasivam };
420c2204a4SManivannan Sadhasivam
430c2204a4SManivannan Sadhasivam struct qrtr_server_filter {
440c2204a4SManivannan Sadhasivam unsigned int service;
450c2204a4SManivannan Sadhasivam unsigned int instance;
460c2204a4SManivannan Sadhasivam unsigned int ifilter;
470c2204a4SManivannan Sadhasivam };
480c2204a4SManivannan Sadhasivam
490c2204a4SManivannan Sadhasivam struct qrtr_lookup {
500c2204a4SManivannan Sadhasivam unsigned int service;
510c2204a4SManivannan Sadhasivam unsigned int instance;
520c2204a4SManivannan Sadhasivam
530c2204a4SManivannan Sadhasivam struct sockaddr_qrtr sq;
540c2204a4SManivannan Sadhasivam struct list_head li;
550c2204a4SManivannan Sadhasivam };
560c2204a4SManivannan Sadhasivam
570c2204a4SManivannan Sadhasivam struct qrtr_server {
580c2204a4SManivannan Sadhasivam unsigned int service;
590c2204a4SManivannan Sadhasivam unsigned int instance;
600c2204a4SManivannan Sadhasivam
610c2204a4SManivannan Sadhasivam unsigned int node;
620c2204a4SManivannan Sadhasivam unsigned int port;
630c2204a4SManivannan Sadhasivam
640c2204a4SManivannan Sadhasivam struct list_head qli;
650c2204a4SManivannan Sadhasivam };
660c2204a4SManivannan Sadhasivam
670c2204a4SManivannan Sadhasivam struct qrtr_node {
680c2204a4SManivannan Sadhasivam unsigned int id;
69608a147aSVignesh Viswanathan struct xarray servers;
700c2204a4SManivannan Sadhasivam };
710c2204a4SManivannan Sadhasivam
node_get(unsigned int node_id)720c2204a4SManivannan Sadhasivam static struct qrtr_node *node_get(unsigned int node_id)
730c2204a4SManivannan Sadhasivam {
740c2204a4SManivannan Sadhasivam struct qrtr_node *node;
750c2204a4SManivannan Sadhasivam
76f26b32efSVignesh Viswanathan node = xa_load(&nodes, node_id);
770c2204a4SManivannan Sadhasivam if (node)
780c2204a4SManivannan Sadhasivam return node;
790c2204a4SManivannan Sadhasivam
800c2204a4SManivannan Sadhasivam /* If node didn't exist, allocate and insert it to the tree */
810c2204a4SManivannan Sadhasivam node = kzalloc(sizeof(*node), GFP_KERNEL);
820c2204a4SManivannan Sadhasivam if (!node)
839baeea50SDan Carpenter return NULL;
840c2204a4SManivannan Sadhasivam
850c2204a4SManivannan Sadhasivam node->id = node_id;
86608a147aSVignesh Viswanathan xa_init(&node->servers);
870c2204a4SManivannan Sadhasivam
88f26b32efSVignesh Viswanathan if (xa_store(&nodes, node_id, node, GFP_KERNEL)) {
8929de68c2SNatalia Petrova kfree(node);
9029de68c2SNatalia Petrova return NULL;
9129de68c2SNatalia Petrova }
920c2204a4SManivannan Sadhasivam
930c2204a4SManivannan Sadhasivam return node;
940c2204a4SManivannan Sadhasivam }
950c2204a4SManivannan Sadhasivam
server_match(const struct qrtr_server * srv,const struct qrtr_server_filter * f)960c2204a4SManivannan Sadhasivam static int server_match(const struct qrtr_server *srv,
970c2204a4SManivannan Sadhasivam const struct qrtr_server_filter *f)
980c2204a4SManivannan Sadhasivam {
990c2204a4SManivannan Sadhasivam unsigned int ifilter = f->ifilter;
1000c2204a4SManivannan Sadhasivam
1010c2204a4SManivannan Sadhasivam if (f->service != 0 && srv->service != f->service)
1020c2204a4SManivannan Sadhasivam return 0;
1030c2204a4SManivannan Sadhasivam if (!ifilter && f->instance)
1040c2204a4SManivannan Sadhasivam ifilter = ~0;
1050c2204a4SManivannan Sadhasivam
1060c2204a4SManivannan Sadhasivam return (srv->instance & ifilter) == f->instance;
1070c2204a4SManivannan Sadhasivam }
1080c2204a4SManivannan Sadhasivam
service_announce_new(struct sockaddr_qrtr * dest,struct qrtr_server * srv)1090c2204a4SManivannan Sadhasivam static int service_announce_new(struct sockaddr_qrtr *dest,
1100c2204a4SManivannan Sadhasivam struct qrtr_server *srv)
1110c2204a4SManivannan Sadhasivam {
1120c2204a4SManivannan Sadhasivam struct qrtr_ctrl_pkt pkt;
1130c2204a4SManivannan Sadhasivam struct msghdr msg = { };
1140c2204a4SManivannan Sadhasivam struct kvec iv;
1150c2204a4SManivannan Sadhasivam
116dfddb540SManivannan Sadhasivam trace_qrtr_ns_service_announce_new(srv->service, srv->instance,
117dfddb540SManivannan Sadhasivam srv->node, srv->port);
1180c2204a4SManivannan Sadhasivam
1190c2204a4SManivannan Sadhasivam iv.iov_base = &pkt;
1200c2204a4SManivannan Sadhasivam iv.iov_len = sizeof(pkt);
1210c2204a4SManivannan Sadhasivam
1220c2204a4SManivannan Sadhasivam memset(&pkt, 0, sizeof(pkt));
1230c2204a4SManivannan Sadhasivam pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_SERVER);
1240c2204a4SManivannan Sadhasivam pkt.server.service = cpu_to_le32(srv->service);
1250c2204a4SManivannan Sadhasivam pkt.server.instance = cpu_to_le32(srv->instance);
1260c2204a4SManivannan Sadhasivam pkt.server.node = cpu_to_le32(srv->node);
1270c2204a4SManivannan Sadhasivam pkt.server.port = cpu_to_le32(srv->port);
1280c2204a4SManivannan Sadhasivam
1290c2204a4SManivannan Sadhasivam msg.msg_name = (struct sockaddr *)dest;
1300c2204a4SManivannan Sadhasivam msg.msg_namelen = sizeof(*dest);
1310c2204a4SManivannan Sadhasivam
1320c2204a4SManivannan Sadhasivam return kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
1330c2204a4SManivannan Sadhasivam }
1340c2204a4SManivannan Sadhasivam
service_announce_del(struct sockaddr_qrtr * dest,struct qrtr_server * srv)1350c2204a4SManivannan Sadhasivam static int service_announce_del(struct sockaddr_qrtr *dest,
1360c2204a4SManivannan Sadhasivam struct qrtr_server *srv)
1370c2204a4SManivannan Sadhasivam {
1380c2204a4SManivannan Sadhasivam struct qrtr_ctrl_pkt pkt;
1390c2204a4SManivannan Sadhasivam struct msghdr msg = { };
1400c2204a4SManivannan Sadhasivam struct kvec iv;
1410c2204a4SManivannan Sadhasivam int ret;
1420c2204a4SManivannan Sadhasivam
143dfddb540SManivannan Sadhasivam trace_qrtr_ns_service_announce_del(srv->service, srv->instance,
144dfddb540SManivannan Sadhasivam srv->node, srv->port);
1450c2204a4SManivannan Sadhasivam
1460c2204a4SManivannan Sadhasivam iv.iov_base = &pkt;
1470c2204a4SManivannan Sadhasivam iv.iov_len = sizeof(pkt);
1480c2204a4SManivannan Sadhasivam
1490c2204a4SManivannan Sadhasivam memset(&pkt, 0, sizeof(pkt));
1500c2204a4SManivannan Sadhasivam pkt.cmd = cpu_to_le32(QRTR_TYPE_DEL_SERVER);
1510c2204a4SManivannan Sadhasivam pkt.server.service = cpu_to_le32(srv->service);
1520c2204a4SManivannan Sadhasivam pkt.server.instance = cpu_to_le32(srv->instance);
1530c2204a4SManivannan Sadhasivam pkt.server.node = cpu_to_le32(srv->node);
1540c2204a4SManivannan Sadhasivam pkt.server.port = cpu_to_le32(srv->port);
1550c2204a4SManivannan Sadhasivam
1560c2204a4SManivannan Sadhasivam msg.msg_name = (struct sockaddr *)dest;
1570c2204a4SManivannan Sadhasivam msg.msg_namelen = sizeof(*dest);
1580c2204a4SManivannan Sadhasivam
1590c2204a4SManivannan Sadhasivam ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
1600c2204a4SManivannan Sadhasivam if (ret < 0)
16113ef6ae8SColin Ian King pr_err("failed to announce del service\n");
1620c2204a4SManivannan Sadhasivam
1630c2204a4SManivannan Sadhasivam return ret;
1640c2204a4SManivannan Sadhasivam }
1650c2204a4SManivannan Sadhasivam
lookup_notify(struct sockaddr_qrtr * to,struct qrtr_server * srv,bool new)1660c2204a4SManivannan Sadhasivam static void lookup_notify(struct sockaddr_qrtr *to, struct qrtr_server *srv,
1670c2204a4SManivannan Sadhasivam bool new)
1680c2204a4SManivannan Sadhasivam {
1690c2204a4SManivannan Sadhasivam struct qrtr_ctrl_pkt pkt;
1700c2204a4SManivannan Sadhasivam struct msghdr msg = { };
1710c2204a4SManivannan Sadhasivam struct kvec iv;
1720c2204a4SManivannan Sadhasivam int ret;
1730c2204a4SManivannan Sadhasivam
1740c2204a4SManivannan Sadhasivam iv.iov_base = &pkt;
1750c2204a4SManivannan Sadhasivam iv.iov_len = sizeof(pkt);
1760c2204a4SManivannan Sadhasivam
1770c2204a4SManivannan Sadhasivam memset(&pkt, 0, sizeof(pkt));
1780c2204a4SManivannan Sadhasivam pkt.cmd = new ? cpu_to_le32(QRTR_TYPE_NEW_SERVER) :
1790c2204a4SManivannan Sadhasivam cpu_to_le32(QRTR_TYPE_DEL_SERVER);
1800c2204a4SManivannan Sadhasivam if (srv) {
1810c2204a4SManivannan Sadhasivam pkt.server.service = cpu_to_le32(srv->service);
1820c2204a4SManivannan Sadhasivam pkt.server.instance = cpu_to_le32(srv->instance);
1830c2204a4SManivannan Sadhasivam pkt.server.node = cpu_to_le32(srv->node);
1840c2204a4SManivannan Sadhasivam pkt.server.port = cpu_to_le32(srv->port);
1850c2204a4SManivannan Sadhasivam }
1860c2204a4SManivannan Sadhasivam
1870c2204a4SManivannan Sadhasivam msg.msg_name = (struct sockaddr *)to;
1880c2204a4SManivannan Sadhasivam msg.msg_namelen = sizeof(*to);
1890c2204a4SManivannan Sadhasivam
1900c2204a4SManivannan Sadhasivam ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
1910c2204a4SManivannan Sadhasivam if (ret < 0)
1920c2204a4SManivannan Sadhasivam pr_err("failed to send lookup notification\n");
1930c2204a4SManivannan Sadhasivam }
1940c2204a4SManivannan Sadhasivam
announce_servers(struct sockaddr_qrtr * sq)1950c2204a4SManivannan Sadhasivam static int announce_servers(struct sockaddr_qrtr *sq)
1960c2204a4SManivannan Sadhasivam {
1970c2204a4SManivannan Sadhasivam struct qrtr_server *srv;
1980c2204a4SManivannan Sadhasivam struct qrtr_node *node;
199608a147aSVignesh Viswanathan unsigned long index;
200082bb94fSManivannan Sadhasivam int ret;
2010c2204a4SManivannan Sadhasivam
2020c2204a4SManivannan Sadhasivam node = node_get(qrtr_ns.local_node);
2030c2204a4SManivannan Sadhasivam if (!node)
2040c2204a4SManivannan Sadhasivam return 0;
2050c2204a4SManivannan Sadhasivam
2060c2204a4SManivannan Sadhasivam /* Announce the list of servers registered in this node */
207608a147aSVignesh Viswanathan xa_for_each(&node->servers, index, srv) {
2080c2204a4SManivannan Sadhasivam ret = service_announce_new(sq, srv);
2090c2204a4SManivannan Sadhasivam if (ret < 0) {
2100c2204a4SManivannan Sadhasivam pr_err("failed to announce new service\n");
211082bb94fSManivannan Sadhasivam return ret;
2120c2204a4SManivannan Sadhasivam }
213082bb94fSManivannan Sadhasivam }
214082bb94fSManivannan Sadhasivam return 0;
2150c2204a4SManivannan Sadhasivam }
2160c2204a4SManivannan Sadhasivam
server_add(unsigned int service,unsigned int instance,unsigned int node_id,unsigned int port)2170c2204a4SManivannan Sadhasivam static struct qrtr_server *server_add(unsigned int service,
2180c2204a4SManivannan Sadhasivam unsigned int instance,
2190c2204a4SManivannan Sadhasivam unsigned int node_id,
2200c2204a4SManivannan Sadhasivam unsigned int port)
2210c2204a4SManivannan Sadhasivam {
2220c2204a4SManivannan Sadhasivam struct qrtr_server *srv;
2230c2204a4SManivannan Sadhasivam struct qrtr_server *old;
2240c2204a4SManivannan Sadhasivam struct qrtr_node *node;
2250c2204a4SManivannan Sadhasivam
2260c2204a4SManivannan Sadhasivam if (!service || !port)
2270c2204a4SManivannan Sadhasivam return NULL;
2280c2204a4SManivannan Sadhasivam
2290c2204a4SManivannan Sadhasivam srv = kzalloc(sizeof(*srv), GFP_KERNEL);
2300c2204a4SManivannan Sadhasivam if (!srv)
2319baeea50SDan Carpenter return NULL;
2320c2204a4SManivannan Sadhasivam
2330c2204a4SManivannan Sadhasivam srv->service = service;
2340c2204a4SManivannan Sadhasivam srv->instance = instance;
2350c2204a4SManivannan Sadhasivam srv->node = node_id;
2360c2204a4SManivannan Sadhasivam srv->port = port;
2370c2204a4SManivannan Sadhasivam
2380c2204a4SManivannan Sadhasivam node = node_get(node_id);
2390c2204a4SManivannan Sadhasivam if (!node)
2400c2204a4SManivannan Sadhasivam goto err;
2410c2204a4SManivannan Sadhasivam
2420c2204a4SManivannan Sadhasivam /* Delete the old server on the same port */
243608a147aSVignesh Viswanathan old = xa_store(&node->servers, port, srv, GFP_KERNEL);
2440c2204a4SManivannan Sadhasivam if (old) {
245608a147aSVignesh Viswanathan if (xa_is_err(old)) {
246608a147aSVignesh Viswanathan pr_err("failed to add server [0x%x:0x%x] ret:%d\n",
247608a147aSVignesh Viswanathan srv->service, srv->instance, xa_err(old));
248608a147aSVignesh Viswanathan goto err;
249608a147aSVignesh Viswanathan } else {
2500c2204a4SManivannan Sadhasivam kfree(old);
2510c2204a4SManivannan Sadhasivam }
252608a147aSVignesh Viswanathan }
2530c2204a4SManivannan Sadhasivam
254dfddb540SManivannan Sadhasivam trace_qrtr_ns_server_add(srv->service, srv->instance,
255dfddb540SManivannan Sadhasivam srv->node, srv->port);
2560c2204a4SManivannan Sadhasivam
2570c2204a4SManivannan Sadhasivam return srv;
2580c2204a4SManivannan Sadhasivam
2590c2204a4SManivannan Sadhasivam err:
2600c2204a4SManivannan Sadhasivam kfree(srv);
2610c2204a4SManivannan Sadhasivam return NULL;
2620c2204a4SManivannan Sadhasivam }
2630c2204a4SManivannan Sadhasivam
server_del(struct qrtr_node * node,unsigned int port,bool bcast)264839349d1SSricharan Ramabadhran static int server_del(struct qrtr_node *node, unsigned int port, bool bcast)
2650c2204a4SManivannan Sadhasivam {
2660c2204a4SManivannan Sadhasivam struct qrtr_lookup *lookup;
2670c2204a4SManivannan Sadhasivam struct qrtr_server *srv;
2680c2204a4SManivannan Sadhasivam struct list_head *li;
2690c2204a4SManivannan Sadhasivam
270608a147aSVignesh Viswanathan srv = xa_load(&node->servers, port);
2710c2204a4SManivannan Sadhasivam if (!srv)
2720c2204a4SManivannan Sadhasivam return -ENOENT;
2730c2204a4SManivannan Sadhasivam
274608a147aSVignesh Viswanathan xa_erase(&node->servers, port);
2750c2204a4SManivannan Sadhasivam
2760c2204a4SManivannan Sadhasivam /* Broadcast the removal of local servers */
277839349d1SSricharan Ramabadhran if (srv->node == qrtr_ns.local_node && bcast)
2780c2204a4SManivannan Sadhasivam service_announce_del(&qrtr_ns.bcast_sq, srv);
2790c2204a4SManivannan Sadhasivam
2800c2204a4SManivannan Sadhasivam /* Announce the service's disappearance to observers */
2810c2204a4SManivannan Sadhasivam list_for_each(li, &qrtr_ns.lookups) {
2820c2204a4SManivannan Sadhasivam lookup = container_of(li, struct qrtr_lookup, li);
2830c2204a4SManivannan Sadhasivam if (lookup->service && lookup->service != srv->service)
2840c2204a4SManivannan Sadhasivam continue;
2850c2204a4SManivannan Sadhasivam if (lookup->instance && lookup->instance != srv->instance)
2860c2204a4SManivannan Sadhasivam continue;
2870c2204a4SManivannan Sadhasivam
2880c2204a4SManivannan Sadhasivam lookup_notify(&lookup->sq, srv, false);
2890c2204a4SManivannan Sadhasivam }
2900c2204a4SManivannan Sadhasivam
2910c2204a4SManivannan Sadhasivam kfree(srv);
2920c2204a4SManivannan Sadhasivam
2930c2204a4SManivannan Sadhasivam return 0;
2940c2204a4SManivannan Sadhasivam }
2950c2204a4SManivannan Sadhasivam
say_hello(struct sockaddr_qrtr * dest)296a1dc1d6aSBjorn Andersson static int say_hello(struct sockaddr_qrtr *dest)
297a1dc1d6aSBjorn Andersson {
298a1dc1d6aSBjorn Andersson struct qrtr_ctrl_pkt pkt;
299a1dc1d6aSBjorn Andersson struct msghdr msg = { };
300a1dc1d6aSBjorn Andersson struct kvec iv;
301a1dc1d6aSBjorn Andersson int ret;
302a1dc1d6aSBjorn Andersson
303a1dc1d6aSBjorn Andersson iv.iov_base = &pkt;
304a1dc1d6aSBjorn Andersson iv.iov_len = sizeof(pkt);
305a1dc1d6aSBjorn Andersson
306a1dc1d6aSBjorn Andersson memset(&pkt, 0, sizeof(pkt));
307a1dc1d6aSBjorn Andersson pkt.cmd = cpu_to_le32(QRTR_TYPE_HELLO);
308a1dc1d6aSBjorn Andersson
309a1dc1d6aSBjorn Andersson msg.msg_name = (struct sockaddr *)dest;
310a1dc1d6aSBjorn Andersson msg.msg_namelen = sizeof(*dest);
311a1dc1d6aSBjorn Andersson
312a1dc1d6aSBjorn Andersson ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
313a1dc1d6aSBjorn Andersson if (ret < 0)
314a1dc1d6aSBjorn Andersson pr_err("failed to send hello msg\n");
315a1dc1d6aSBjorn Andersson
316a1dc1d6aSBjorn Andersson return ret;
317a1dc1d6aSBjorn Andersson }
318a1dc1d6aSBjorn Andersson
3190c2204a4SManivannan Sadhasivam /* Announce the list of servers registered on the local node */
ctrl_cmd_hello(struct sockaddr_qrtr * sq)3200c2204a4SManivannan Sadhasivam static int ctrl_cmd_hello(struct sockaddr_qrtr *sq)
3210c2204a4SManivannan Sadhasivam {
322a1dc1d6aSBjorn Andersson int ret;
323a1dc1d6aSBjorn Andersson
324a1dc1d6aSBjorn Andersson ret = say_hello(sq);
325a1dc1d6aSBjorn Andersson if (ret < 0)
326a1dc1d6aSBjorn Andersson return ret;
327a1dc1d6aSBjorn Andersson
3280c2204a4SManivannan Sadhasivam return announce_servers(sq);
3290c2204a4SManivannan Sadhasivam }
3300c2204a4SManivannan Sadhasivam
ctrl_cmd_bye(struct sockaddr_qrtr * from)3310c2204a4SManivannan Sadhasivam static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
3320c2204a4SManivannan Sadhasivam {
3330c2204a4SManivannan Sadhasivam struct qrtr_node *local_node;
3340c2204a4SManivannan Sadhasivam struct qrtr_ctrl_pkt pkt;
3350c2204a4SManivannan Sadhasivam struct qrtr_server *srv;
3360c2204a4SManivannan Sadhasivam struct sockaddr_qrtr sq;
3370c2204a4SManivannan Sadhasivam struct msghdr msg = { };
3380c2204a4SManivannan Sadhasivam struct qrtr_node *node;
339608a147aSVignesh Viswanathan unsigned long index;
3400c2204a4SManivannan Sadhasivam struct kvec iv;
341082bb94fSManivannan Sadhasivam int ret;
3420c2204a4SManivannan Sadhasivam
3430c2204a4SManivannan Sadhasivam iv.iov_base = &pkt;
3440c2204a4SManivannan Sadhasivam iv.iov_len = sizeof(pkt);
3450c2204a4SManivannan Sadhasivam
3460c2204a4SManivannan Sadhasivam node = node_get(from->sq_node);
3470c2204a4SManivannan Sadhasivam if (!node)
3480c2204a4SManivannan Sadhasivam return 0;
3490c2204a4SManivannan Sadhasivam
3500c2204a4SManivannan Sadhasivam /* Advertise removal of this client to all servers of remote node */
351608a147aSVignesh Viswanathan xa_for_each(&node->servers, index, srv)
352839349d1SSricharan Ramabadhran server_del(node, srv->port, true);
3530c2204a4SManivannan Sadhasivam
3540c2204a4SManivannan Sadhasivam /* Advertise the removal of this client to all local servers */
3550c2204a4SManivannan Sadhasivam local_node = node_get(qrtr_ns.local_node);
3560c2204a4SManivannan Sadhasivam if (!local_node)
3570c2204a4SManivannan Sadhasivam return 0;
3580c2204a4SManivannan Sadhasivam
3590c2204a4SManivannan Sadhasivam memset(&pkt, 0, sizeof(pkt));
3600c2204a4SManivannan Sadhasivam pkt.cmd = cpu_to_le32(QRTR_TYPE_BYE);
3610c2204a4SManivannan Sadhasivam pkt.client.node = cpu_to_le32(from->sq_node);
3620c2204a4SManivannan Sadhasivam
363608a147aSVignesh Viswanathan xa_for_each(&local_node->servers, index, srv) {
3640c2204a4SManivannan Sadhasivam sq.sq_family = AF_QIPCRTR;
3650c2204a4SManivannan Sadhasivam sq.sq_node = srv->node;
3660c2204a4SManivannan Sadhasivam sq.sq_port = srv->port;
3670c2204a4SManivannan Sadhasivam
3680c2204a4SManivannan Sadhasivam msg.msg_name = (struct sockaddr *)&sq;
3690c2204a4SManivannan Sadhasivam msg.msg_namelen = sizeof(sq);
3700c2204a4SManivannan Sadhasivam
3710c2204a4SManivannan Sadhasivam ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
3720c2204a4SManivannan Sadhasivam if (ret < 0) {
3730c2204a4SManivannan Sadhasivam pr_err("failed to send bye cmd\n");
374082bb94fSManivannan Sadhasivam return ret;
3750c2204a4SManivannan Sadhasivam }
3760c2204a4SManivannan Sadhasivam }
377082bb94fSManivannan Sadhasivam return 0;
3780c2204a4SManivannan Sadhasivam }
3790c2204a4SManivannan Sadhasivam
ctrl_cmd_del_client(struct sockaddr_qrtr * from,unsigned int node_id,unsigned int port)3800c2204a4SManivannan Sadhasivam static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
3810c2204a4SManivannan Sadhasivam unsigned int node_id, unsigned int port)
3820c2204a4SManivannan Sadhasivam {
3830c2204a4SManivannan Sadhasivam struct qrtr_node *local_node;
3840c2204a4SManivannan Sadhasivam struct qrtr_lookup *lookup;
3850c2204a4SManivannan Sadhasivam struct qrtr_ctrl_pkt pkt;
3860c2204a4SManivannan Sadhasivam struct msghdr msg = { };
3870c2204a4SManivannan Sadhasivam struct qrtr_server *srv;
3880c2204a4SManivannan Sadhasivam struct sockaddr_qrtr sq;
3890c2204a4SManivannan Sadhasivam struct qrtr_node *node;
3900c2204a4SManivannan Sadhasivam struct list_head *tmp;
3910c2204a4SManivannan Sadhasivam struct list_head *li;
392608a147aSVignesh Viswanathan unsigned long index;
3930c2204a4SManivannan Sadhasivam struct kvec iv;
394082bb94fSManivannan Sadhasivam int ret;
3950c2204a4SManivannan Sadhasivam
3960c2204a4SManivannan Sadhasivam iv.iov_base = &pkt;
3970c2204a4SManivannan Sadhasivam iv.iov_len = sizeof(pkt);
3980c2204a4SManivannan Sadhasivam
3990c2204a4SManivannan Sadhasivam /* Don't accept spoofed messages */
4000c2204a4SManivannan Sadhasivam if (from->sq_node != node_id)
4010c2204a4SManivannan Sadhasivam return -EINVAL;
4020c2204a4SManivannan Sadhasivam
4030c2204a4SManivannan Sadhasivam /* Local DEL_CLIENT messages comes from the port being closed */
4040c2204a4SManivannan Sadhasivam if (from->sq_node == qrtr_ns.local_node && from->sq_port != port)
4050c2204a4SManivannan Sadhasivam return -EINVAL;
4060c2204a4SManivannan Sadhasivam
4070c2204a4SManivannan Sadhasivam /* Remove any lookups by this client */
4080c2204a4SManivannan Sadhasivam list_for_each_safe(li, tmp, &qrtr_ns.lookups) {
4090c2204a4SManivannan Sadhasivam lookup = container_of(li, struct qrtr_lookup, li);
4100c2204a4SManivannan Sadhasivam if (lookup->sq.sq_node != node_id)
4110c2204a4SManivannan Sadhasivam continue;
4120c2204a4SManivannan Sadhasivam if (lookup->sq.sq_port != port)
4130c2204a4SManivannan Sadhasivam continue;
4140c2204a4SManivannan Sadhasivam
4150c2204a4SManivannan Sadhasivam list_del(&lookup->li);
4160c2204a4SManivannan Sadhasivam kfree(lookup);
4170c2204a4SManivannan Sadhasivam }
4180c2204a4SManivannan Sadhasivam
419839349d1SSricharan Ramabadhran /* Remove the server belonging to this port but don't broadcast
420839349d1SSricharan Ramabadhran * DEL_SERVER. Neighbours would've already removed the server belonging
421839349d1SSricharan Ramabadhran * to this port due to the DEL_CLIENT broadcast from qrtr_port_remove().
422839349d1SSricharan Ramabadhran */
4230c2204a4SManivannan Sadhasivam node = node_get(node_id);
4240c2204a4SManivannan Sadhasivam if (node)
425839349d1SSricharan Ramabadhran server_del(node, port, false);
4260c2204a4SManivannan Sadhasivam
4270c2204a4SManivannan Sadhasivam /* Advertise the removal of this client to all local servers */
4280c2204a4SManivannan Sadhasivam local_node = node_get(qrtr_ns.local_node);
4290c2204a4SManivannan Sadhasivam if (!local_node)
4300c2204a4SManivannan Sadhasivam return 0;
4310c2204a4SManivannan Sadhasivam
4320c2204a4SManivannan Sadhasivam memset(&pkt, 0, sizeof(pkt));
4330c2204a4SManivannan Sadhasivam pkt.cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT);
4340c2204a4SManivannan Sadhasivam pkt.client.node = cpu_to_le32(node_id);
4350c2204a4SManivannan Sadhasivam pkt.client.port = cpu_to_le32(port);
4360c2204a4SManivannan Sadhasivam
437608a147aSVignesh Viswanathan xa_for_each(&local_node->servers, index, srv) {
4380c2204a4SManivannan Sadhasivam sq.sq_family = AF_QIPCRTR;
4390c2204a4SManivannan Sadhasivam sq.sq_node = srv->node;
4400c2204a4SManivannan Sadhasivam sq.sq_port = srv->port;
4410c2204a4SManivannan Sadhasivam
4420c2204a4SManivannan Sadhasivam msg.msg_name = (struct sockaddr *)&sq;
4430c2204a4SManivannan Sadhasivam msg.msg_namelen = sizeof(sq);
4440c2204a4SManivannan Sadhasivam
4450c2204a4SManivannan Sadhasivam ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
4460c2204a4SManivannan Sadhasivam if (ret < 0) {
4470c2204a4SManivannan Sadhasivam pr_err("failed to send del client cmd\n");
448082bb94fSManivannan Sadhasivam return ret;
4490c2204a4SManivannan Sadhasivam }
4500c2204a4SManivannan Sadhasivam }
451082bb94fSManivannan Sadhasivam return 0;
4520c2204a4SManivannan Sadhasivam }
4530c2204a4SManivannan Sadhasivam
ctrl_cmd_new_server(struct sockaddr_qrtr * from,unsigned int service,unsigned int instance,unsigned int node_id,unsigned int port)4540c2204a4SManivannan Sadhasivam static int ctrl_cmd_new_server(struct sockaddr_qrtr *from,
4550c2204a4SManivannan Sadhasivam unsigned int service, unsigned int instance,
4560c2204a4SManivannan Sadhasivam unsigned int node_id, unsigned int port)
4570c2204a4SManivannan Sadhasivam {
4580c2204a4SManivannan Sadhasivam struct qrtr_lookup *lookup;
4590c2204a4SManivannan Sadhasivam struct qrtr_server *srv;
4600c2204a4SManivannan Sadhasivam struct list_head *li;
4610c2204a4SManivannan Sadhasivam int ret = 0;
4620c2204a4SManivannan Sadhasivam
4630c2204a4SManivannan Sadhasivam /* Ignore specified node and port for local servers */
4640c2204a4SManivannan Sadhasivam if (from->sq_node == qrtr_ns.local_node) {
4650c2204a4SManivannan Sadhasivam node_id = from->sq_node;
4660c2204a4SManivannan Sadhasivam port = from->sq_port;
4670c2204a4SManivannan Sadhasivam }
4680c2204a4SManivannan Sadhasivam
4690c2204a4SManivannan Sadhasivam srv = server_add(service, instance, node_id, port);
4700c2204a4SManivannan Sadhasivam if (!srv)
4710c2204a4SManivannan Sadhasivam return -EINVAL;
4720c2204a4SManivannan Sadhasivam
4730c2204a4SManivannan Sadhasivam if (srv->node == qrtr_ns.local_node) {
4740c2204a4SManivannan Sadhasivam ret = service_announce_new(&qrtr_ns.bcast_sq, srv);
4750c2204a4SManivannan Sadhasivam if (ret < 0) {
4760c2204a4SManivannan Sadhasivam pr_err("failed to announce new service\n");
4770c2204a4SManivannan Sadhasivam return ret;
4780c2204a4SManivannan Sadhasivam }
4790c2204a4SManivannan Sadhasivam }
4800c2204a4SManivannan Sadhasivam
4810c2204a4SManivannan Sadhasivam /* Notify any potential lookups about the new server */
4820c2204a4SManivannan Sadhasivam list_for_each(li, &qrtr_ns.lookups) {
4830c2204a4SManivannan Sadhasivam lookup = container_of(li, struct qrtr_lookup, li);
4840c2204a4SManivannan Sadhasivam if (lookup->service && lookup->service != service)
4850c2204a4SManivannan Sadhasivam continue;
4860c2204a4SManivannan Sadhasivam if (lookup->instance && lookup->instance != instance)
4870c2204a4SManivannan Sadhasivam continue;
4880c2204a4SManivannan Sadhasivam
4890c2204a4SManivannan Sadhasivam lookup_notify(&lookup->sq, srv, true);
4900c2204a4SManivannan Sadhasivam }
4910c2204a4SManivannan Sadhasivam
4920c2204a4SManivannan Sadhasivam return ret;
4930c2204a4SManivannan Sadhasivam }
4940c2204a4SManivannan Sadhasivam
ctrl_cmd_del_server(struct sockaddr_qrtr * from,unsigned int service,unsigned int instance,unsigned int node_id,unsigned int port)4950c2204a4SManivannan Sadhasivam static int ctrl_cmd_del_server(struct sockaddr_qrtr *from,
4960c2204a4SManivannan Sadhasivam unsigned int service, unsigned int instance,
4970c2204a4SManivannan Sadhasivam unsigned int node_id, unsigned int port)
4980c2204a4SManivannan Sadhasivam {
4990c2204a4SManivannan Sadhasivam struct qrtr_node *node;
5000c2204a4SManivannan Sadhasivam
5010c2204a4SManivannan Sadhasivam /* Ignore specified node and port for local servers*/
5020c2204a4SManivannan Sadhasivam if (from->sq_node == qrtr_ns.local_node) {
5030c2204a4SManivannan Sadhasivam node_id = from->sq_node;
5040c2204a4SManivannan Sadhasivam port = from->sq_port;
5050c2204a4SManivannan Sadhasivam }
5060c2204a4SManivannan Sadhasivam
5070c2204a4SManivannan Sadhasivam /* Local servers may only unregister themselves */
5080c2204a4SManivannan Sadhasivam if (from->sq_node == qrtr_ns.local_node && from->sq_port != port)
5090c2204a4SManivannan Sadhasivam return -EINVAL;
5100c2204a4SManivannan Sadhasivam
5110c2204a4SManivannan Sadhasivam node = node_get(node_id);
5120c2204a4SManivannan Sadhasivam if (!node)
5130c2204a4SManivannan Sadhasivam return -ENOENT;
5140c2204a4SManivannan Sadhasivam
5156a186b28SSarannya S server_del(node, port, true);
5166a186b28SSarannya S
5176a186b28SSarannya S return 0;
5180c2204a4SManivannan Sadhasivam }
5190c2204a4SManivannan Sadhasivam
ctrl_cmd_new_lookup(struct sockaddr_qrtr * from,unsigned int service,unsigned int instance)5200c2204a4SManivannan Sadhasivam static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
5210c2204a4SManivannan Sadhasivam unsigned int service, unsigned int instance)
5220c2204a4SManivannan Sadhasivam {
5230c2204a4SManivannan Sadhasivam struct qrtr_server_filter filter;
5240c2204a4SManivannan Sadhasivam struct qrtr_lookup *lookup;
525608a147aSVignesh Viswanathan struct qrtr_server *srv;
5260c2204a4SManivannan Sadhasivam struct qrtr_node *node;
527608a147aSVignesh Viswanathan unsigned long node_idx;
528608a147aSVignesh Viswanathan unsigned long srv_idx;
5290c2204a4SManivannan Sadhasivam
5300c2204a4SManivannan Sadhasivam /* Accept only local observers */
5310c2204a4SManivannan Sadhasivam if (from->sq_node != qrtr_ns.local_node)
5320c2204a4SManivannan Sadhasivam return -EINVAL;
5330c2204a4SManivannan Sadhasivam
5340c2204a4SManivannan Sadhasivam lookup = kzalloc(sizeof(*lookup), GFP_KERNEL);
5350c2204a4SManivannan Sadhasivam if (!lookup)
5360c2204a4SManivannan Sadhasivam return -ENOMEM;
5370c2204a4SManivannan Sadhasivam
5380c2204a4SManivannan Sadhasivam lookup->sq = *from;
5390c2204a4SManivannan Sadhasivam lookup->service = service;
5400c2204a4SManivannan Sadhasivam lookup->instance = instance;
5410c2204a4SManivannan Sadhasivam list_add_tail(&lookup->li, &qrtr_ns.lookups);
5420c2204a4SManivannan Sadhasivam
5430c2204a4SManivannan Sadhasivam memset(&filter, 0, sizeof(filter));
5440c2204a4SManivannan Sadhasivam filter.service = service;
5450c2204a4SManivannan Sadhasivam filter.instance = instance;
5460c2204a4SManivannan Sadhasivam
547608a147aSVignesh Viswanathan xa_for_each(&nodes, node_idx, node) {
548608a147aSVignesh Viswanathan xa_for_each(&node->servers, srv_idx, srv) {
5490c2204a4SManivannan Sadhasivam if (!server_match(srv, &filter))
5500c2204a4SManivannan Sadhasivam continue;
5510c2204a4SManivannan Sadhasivam
5520c2204a4SManivannan Sadhasivam lookup_notify(from, srv, true);
5530c2204a4SManivannan Sadhasivam }
5540c2204a4SManivannan Sadhasivam }
5550c2204a4SManivannan Sadhasivam
5560c2204a4SManivannan Sadhasivam /* Empty notification, to indicate end of listing */
5570c2204a4SManivannan Sadhasivam lookup_notify(from, NULL, true);
5580c2204a4SManivannan Sadhasivam
5590c2204a4SManivannan Sadhasivam return 0;
5600c2204a4SManivannan Sadhasivam }
5610c2204a4SManivannan Sadhasivam
ctrl_cmd_del_lookup(struct sockaddr_qrtr * from,unsigned int service,unsigned int instance)5620c2204a4SManivannan Sadhasivam static void ctrl_cmd_del_lookup(struct sockaddr_qrtr *from,
5630c2204a4SManivannan Sadhasivam unsigned int service, unsigned int instance)
5640c2204a4SManivannan Sadhasivam {
5650c2204a4SManivannan Sadhasivam struct qrtr_lookup *lookup;
5660c2204a4SManivannan Sadhasivam struct list_head *tmp;
5670c2204a4SManivannan Sadhasivam struct list_head *li;
5680c2204a4SManivannan Sadhasivam
5690c2204a4SManivannan Sadhasivam list_for_each_safe(li, tmp, &qrtr_ns.lookups) {
5700c2204a4SManivannan Sadhasivam lookup = container_of(li, struct qrtr_lookup, li);
5710c2204a4SManivannan Sadhasivam if (lookup->sq.sq_node != from->sq_node)
5720c2204a4SManivannan Sadhasivam continue;
5730c2204a4SManivannan Sadhasivam if (lookup->sq.sq_port != from->sq_port)
5740c2204a4SManivannan Sadhasivam continue;
5750c2204a4SManivannan Sadhasivam if (lookup->service != service)
5760c2204a4SManivannan Sadhasivam continue;
5770c2204a4SManivannan Sadhasivam if (lookup->instance && lookup->instance != instance)
5780c2204a4SManivannan Sadhasivam continue;
5790c2204a4SManivannan Sadhasivam
5800c2204a4SManivannan Sadhasivam list_del(&lookup->li);
5810c2204a4SManivannan Sadhasivam kfree(lookup);
5820c2204a4SManivannan Sadhasivam }
5830c2204a4SManivannan Sadhasivam }
5840c2204a4SManivannan Sadhasivam
qrtr_ns_worker(struct work_struct * work)5850c2204a4SManivannan Sadhasivam static void qrtr_ns_worker(struct work_struct *work)
5860c2204a4SManivannan Sadhasivam {
5870c2204a4SManivannan Sadhasivam const struct qrtr_ctrl_pkt *pkt;
5880c2204a4SManivannan Sadhasivam size_t recv_buf_size = 4096;
5890c2204a4SManivannan Sadhasivam struct sockaddr_qrtr sq;
5900c2204a4SManivannan Sadhasivam struct msghdr msg = { };
5910c2204a4SManivannan Sadhasivam unsigned int cmd;
5920c2204a4SManivannan Sadhasivam ssize_t msglen;
5930c2204a4SManivannan Sadhasivam void *recv_buf;
5940c2204a4SManivannan Sadhasivam struct kvec iv;
5950c2204a4SManivannan Sadhasivam int ret;
5960c2204a4SManivannan Sadhasivam
5970c2204a4SManivannan Sadhasivam msg.msg_name = (struct sockaddr *)&sq;
5980c2204a4SManivannan Sadhasivam msg.msg_namelen = sizeof(sq);
5990c2204a4SManivannan Sadhasivam
6000c2204a4SManivannan Sadhasivam recv_buf = kzalloc(recv_buf_size, GFP_KERNEL);
6010c2204a4SManivannan Sadhasivam if (!recv_buf)
6020c2204a4SManivannan Sadhasivam return;
6030c2204a4SManivannan Sadhasivam
6040c2204a4SManivannan Sadhasivam for (;;) {
6050c2204a4SManivannan Sadhasivam iv.iov_base = recv_buf;
6060c2204a4SManivannan Sadhasivam iv.iov_len = recv_buf_size;
6070c2204a4SManivannan Sadhasivam
6080c2204a4SManivannan Sadhasivam msglen = kernel_recvmsg(qrtr_ns.sock, &msg, &iv, 1,
6090c2204a4SManivannan Sadhasivam iv.iov_len, MSG_DONTWAIT);
6100c2204a4SManivannan Sadhasivam
6110c2204a4SManivannan Sadhasivam if (msglen == -EAGAIN)
6120c2204a4SManivannan Sadhasivam break;
6130c2204a4SManivannan Sadhasivam
6140c2204a4SManivannan Sadhasivam if (msglen < 0) {
6150c2204a4SManivannan Sadhasivam pr_err("error receiving packet: %zd\n", msglen);
6160c2204a4SManivannan Sadhasivam break;
6170c2204a4SManivannan Sadhasivam }
6180c2204a4SManivannan Sadhasivam
6190c2204a4SManivannan Sadhasivam pkt = recv_buf;
6200c2204a4SManivannan Sadhasivam cmd = le32_to_cpu(pkt->cmd);
6210c2204a4SManivannan Sadhasivam if (cmd < ARRAY_SIZE(qrtr_ctrl_pkt_strings) &&
6220c2204a4SManivannan Sadhasivam qrtr_ctrl_pkt_strings[cmd])
623dfddb540SManivannan Sadhasivam trace_qrtr_ns_message(qrtr_ctrl_pkt_strings[cmd],
624dfddb540SManivannan Sadhasivam sq.sq_node, sq.sq_port);
6250c2204a4SManivannan Sadhasivam
6260c2204a4SManivannan Sadhasivam ret = 0;
6270c2204a4SManivannan Sadhasivam switch (cmd) {
6280c2204a4SManivannan Sadhasivam case QRTR_TYPE_HELLO:
6290c2204a4SManivannan Sadhasivam ret = ctrl_cmd_hello(&sq);
6300c2204a4SManivannan Sadhasivam break;
6310c2204a4SManivannan Sadhasivam case QRTR_TYPE_BYE:
6320c2204a4SManivannan Sadhasivam ret = ctrl_cmd_bye(&sq);
6330c2204a4SManivannan Sadhasivam break;
6340c2204a4SManivannan Sadhasivam case QRTR_TYPE_DEL_CLIENT:
6350c2204a4SManivannan Sadhasivam ret = ctrl_cmd_del_client(&sq,
6360c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->client.node),
6370c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->client.port));
6380c2204a4SManivannan Sadhasivam break;
6390c2204a4SManivannan Sadhasivam case QRTR_TYPE_NEW_SERVER:
6400c2204a4SManivannan Sadhasivam ret = ctrl_cmd_new_server(&sq,
6410c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.service),
6420c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.instance),
6430c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.node),
6440c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.port));
6450c2204a4SManivannan Sadhasivam break;
6460c2204a4SManivannan Sadhasivam case QRTR_TYPE_DEL_SERVER:
6470c2204a4SManivannan Sadhasivam ret = ctrl_cmd_del_server(&sq,
6480c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.service),
6490c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.instance),
6500c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.node),
6510c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.port));
6520c2204a4SManivannan Sadhasivam break;
6530c2204a4SManivannan Sadhasivam case QRTR_TYPE_EXIT:
6540c2204a4SManivannan Sadhasivam case QRTR_TYPE_PING:
6550c2204a4SManivannan Sadhasivam case QRTR_TYPE_RESUME_TX:
6560c2204a4SManivannan Sadhasivam break;
6570c2204a4SManivannan Sadhasivam case QRTR_TYPE_NEW_LOOKUP:
6580c2204a4SManivannan Sadhasivam ret = ctrl_cmd_new_lookup(&sq,
6590c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.service),
6600c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.instance));
6610c2204a4SManivannan Sadhasivam break;
6620c2204a4SManivannan Sadhasivam case QRTR_TYPE_DEL_LOOKUP:
6630c2204a4SManivannan Sadhasivam ctrl_cmd_del_lookup(&sq,
6640c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.service),
6650c2204a4SManivannan Sadhasivam le32_to_cpu(pkt->server.instance));
6660c2204a4SManivannan Sadhasivam break;
6670c2204a4SManivannan Sadhasivam }
6680c2204a4SManivannan Sadhasivam
6690c2204a4SManivannan Sadhasivam if (ret < 0)
6700c2204a4SManivannan Sadhasivam pr_err("failed while handling packet from %d:%d",
6710c2204a4SManivannan Sadhasivam sq.sq_node, sq.sq_port);
6720c2204a4SManivannan Sadhasivam }
6730c2204a4SManivannan Sadhasivam
6740c2204a4SManivannan Sadhasivam kfree(recv_buf);
6750c2204a4SManivannan Sadhasivam }
6760c2204a4SManivannan Sadhasivam
qrtr_ns_data_ready(struct sock * sk)6770c2204a4SManivannan Sadhasivam static void qrtr_ns_data_ready(struct sock *sk)
6780c2204a4SManivannan Sadhasivam {
67940e0b090SPeilin Ye trace_sk_data_ready(sk);
68040e0b090SPeilin Ye
6810c2204a4SManivannan Sadhasivam queue_work(qrtr_ns.workqueue, &qrtr_ns.work);
6820c2204a4SManivannan Sadhasivam }
6830c2204a4SManivannan Sadhasivam
qrtr_ns_init(void)6844beb17e5SQinglang Miao int qrtr_ns_init(void)
6850c2204a4SManivannan Sadhasivam {
6860c2204a4SManivannan Sadhasivam struct sockaddr_qrtr sq;
6870c2204a4SManivannan Sadhasivam int ret;
6880c2204a4SManivannan Sadhasivam
6890c2204a4SManivannan Sadhasivam INIT_LIST_HEAD(&qrtr_ns.lookups);
6900c2204a4SManivannan Sadhasivam INIT_WORK(&qrtr_ns.work, qrtr_ns_worker);
6910c2204a4SManivannan Sadhasivam
6920c2204a4SManivannan Sadhasivam ret = sock_create_kern(&init_net, AF_QIPCRTR, SOCK_DGRAM,
6930c2204a4SManivannan Sadhasivam PF_QIPCRTR, &qrtr_ns.sock);
6940c2204a4SManivannan Sadhasivam if (ret < 0)
6954beb17e5SQinglang Miao return ret;
6960c2204a4SManivannan Sadhasivam
6970c2204a4SManivannan Sadhasivam ret = kernel_getsockname(qrtr_ns.sock, (struct sockaddr *)&sq);
6980c2204a4SManivannan Sadhasivam if (ret < 0) {
6990c2204a4SManivannan Sadhasivam pr_err("failed to get socket name\n");
7000c2204a4SManivannan Sadhasivam goto err_sock;
7010c2204a4SManivannan Sadhasivam }
7020c2204a4SManivannan Sadhasivam
703022acfa6STejun Heo qrtr_ns.workqueue = alloc_ordered_workqueue("qrtr_ns_handler", 0);
704a49e72b3SWei Yongjun if (!qrtr_ns.workqueue) {
705a49e72b3SWei Yongjun ret = -ENOMEM;
706c6e08d62SChris Lew goto err_sock;
707a49e72b3SWei Yongjun }
708c6e08d62SChris Lew
7090c2204a4SManivannan Sadhasivam qrtr_ns.sock->sk->sk_data_ready = qrtr_ns_data_ready;
7100c2204a4SManivannan Sadhasivam
7110c2204a4SManivannan Sadhasivam sq.sq_port = QRTR_PORT_CTRL;
7120c2204a4SManivannan Sadhasivam qrtr_ns.local_node = sq.sq_node;
7130c2204a4SManivannan Sadhasivam
7140c2204a4SManivannan Sadhasivam ret = kernel_bind(qrtr_ns.sock, (struct sockaddr *)&sq, sizeof(sq));
7150c2204a4SManivannan Sadhasivam if (ret < 0) {
7160c2204a4SManivannan Sadhasivam pr_err("failed to bind to socket\n");
717c6e08d62SChris Lew goto err_wq;
7180c2204a4SManivannan Sadhasivam }
7190c2204a4SManivannan Sadhasivam
7200c2204a4SManivannan Sadhasivam qrtr_ns.bcast_sq.sq_family = AF_QIPCRTR;
7210c2204a4SManivannan Sadhasivam qrtr_ns.bcast_sq.sq_node = QRTR_NODE_BCAST;
7220c2204a4SManivannan Sadhasivam qrtr_ns.bcast_sq.sq_port = QRTR_PORT_CTRL;
7230c2204a4SManivannan Sadhasivam
724a1dc1d6aSBjorn Andersson ret = say_hello(&qrtr_ns.bcast_sq);
7250c2204a4SManivannan Sadhasivam if (ret < 0)
7260c2204a4SManivannan Sadhasivam goto err_wq;
7270c2204a4SManivannan Sadhasivam
728*57fa96c0SChris Lew /* As the qrtr ns socket owner and creator is the same module, we have
729*57fa96c0SChris Lew * to decrease the qrtr module reference count to guarantee that it
730*57fa96c0SChris Lew * remains zero after the ns socket is created, otherwise, executing
731*57fa96c0SChris Lew * "rmmod" command is unable to make the qrtr module deleted after the
732*57fa96c0SChris Lew * qrtr module is inserted successfully.
733*57fa96c0SChris Lew *
734*57fa96c0SChris Lew * However, the reference count is increased twice in
735*57fa96c0SChris Lew * sock_create_kern(): one is to increase the reference count of owner
736*57fa96c0SChris Lew * of qrtr socket's proto_ops struct; another is to increment the
737*57fa96c0SChris Lew * reference count of owner of qrtr proto struct. Therefore, we must
738*57fa96c0SChris Lew * decrement the module reference count twice to ensure that it keeps
739*57fa96c0SChris Lew * zero after server's listening socket is created. Of course, we
740*57fa96c0SChris Lew * must bump the module reference count twice as well before the socket
741*57fa96c0SChris Lew * is closed.
742*57fa96c0SChris Lew */
743*57fa96c0SChris Lew module_put(qrtr_ns.sock->ops->owner);
744*57fa96c0SChris Lew module_put(qrtr_ns.sock->sk->sk_prot_creator->owner);
745*57fa96c0SChris Lew
7464beb17e5SQinglang Miao return 0;
7470c2204a4SManivannan Sadhasivam
7480c2204a4SManivannan Sadhasivam err_wq:
7490c2204a4SManivannan Sadhasivam destroy_workqueue(qrtr_ns.workqueue);
7500c2204a4SManivannan Sadhasivam err_sock:
7510c2204a4SManivannan Sadhasivam sock_release(qrtr_ns.sock);
7524beb17e5SQinglang Miao return ret;
7530c2204a4SManivannan Sadhasivam }
7540c2204a4SManivannan Sadhasivam EXPORT_SYMBOL_GPL(qrtr_ns_init);
7550c2204a4SManivannan Sadhasivam
qrtr_ns_remove(void)7560c2204a4SManivannan Sadhasivam void qrtr_ns_remove(void)
7570c2204a4SManivannan Sadhasivam {
7580c2204a4SManivannan Sadhasivam cancel_work_sync(&qrtr_ns.work);
7590c2204a4SManivannan Sadhasivam destroy_workqueue(qrtr_ns.workqueue);
760*57fa96c0SChris Lew
761*57fa96c0SChris Lew /* sock_release() expects the two references that were put during
762*57fa96c0SChris Lew * qrtr_ns_init(). This function is only called during module remove,
763*57fa96c0SChris Lew * so try_stop_module() has already set the refcnt to 0. Use
764*57fa96c0SChris Lew * __module_get() instead of try_module_get() to successfully take two
765*57fa96c0SChris Lew * references.
766*57fa96c0SChris Lew */
767*57fa96c0SChris Lew __module_get(qrtr_ns.sock->ops->owner);
768*57fa96c0SChris Lew __module_get(qrtr_ns.sock->sk->sk_prot_creator->owner);
7690c2204a4SManivannan Sadhasivam sock_release(qrtr_ns.sock);
7700c2204a4SManivannan Sadhasivam }
7710c2204a4SManivannan Sadhasivam EXPORT_SYMBOL_GPL(qrtr_ns_remove);
7720c2204a4SManivannan Sadhasivam
7730c2204a4SManivannan Sadhasivam MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
7740c2204a4SManivannan Sadhasivam MODULE_DESCRIPTION("Qualcomm IPC Router Nameservice");
7750c2204a4SManivannan Sadhasivam MODULE_LICENSE("Dual BSD/GPL");
776