Received: by 2002:a25:6193:0:0:0:0:0 with SMTP id v141csp1981798ybb; Thu, 9 Apr 2020 12:40:02 -0700 (PDT) X-Google-Smtp-Source: APiQypLvr2Rd2cmdfJF8pZCdRYKb7Jucsg5qK8dxYyfx52+Emt59N9VaojVQUMfI2cfnPtydAjYS X-Received: by 2002:a05:620a:307:: with SMTP id s7mr507929qkm.183.1586461202046; Thu, 09 Apr 2020 12:40:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1586461202; cv=none; d=google.com; s=arc-20160816; b=cW2B8S4FILaF8v3WUMIXjple67Qjk8r0PMO2YgEtKbPPgddh5EJQ3mYRg6wLxBHKej jN/eNHu139IF8zj4YWNH0MmCGqHvqI+3Nd26bPRv6Ayz5KqVTMb4TU2JuDx8SgSxCkGh nM3ThxP43vUDBQI2DjyAR3g27F1geKhf1LCFjjP0bRsvDj6hoMn53u0Pe4JYGJeuwNV9 48LkQMCqdra+fzHv27+whL/JzJkR+w89LM27Vf9mqfenD3l1QWm5p6OQn4GL2lA2Vl+m 6PZaun+qmqYS6XIfDqd+H4y3fkxIV/MNc8mD17nySMOlwyoF5MvA8zNfc1YM4ZtQVRI8 ZySA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:in-reply-to:content-disposition :mime-version:references:message-id:subject:cc:to:from:date :dkim-signature; bh=rwrF17Ae6YnNqVwxgTEj3Njtao+/qzrb7ZBwN0IGHPw=; b=AfR8DA4H5X9u9DL7IRpQ/YDyVIGRzaYkyov+/Mb5W9zrJUe3IL88zI4ql+0z1Gw4aJ m95G1uDAMc/k8JqS/XMedBrhztJnGyXLEiBUqmj6hOfsccv2djNenx00YvpgCBk1YIyO qcJp05DSLul7L93ClID1gSGnBcCox0VKod22LCH+lC7ISwgnF6//67MRd1lox+ZWJYh3 CX833D28iN7Ii0CnGESQgrNJ2UK1zA8lAvfEP97yrdRWeM/MJccpOjlvJf1058lVOSN8 DHwhZjhCm/OmPSL53fw6cOtzkE/pj1nJR218dLODoqQNRv9bA9T0MvkyKpp9WwLDT1Fq 6Vmg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=jDNxcFtW; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v8si5925435qtp.311.2020.04.09.12.39.46; Thu, 09 Apr 2020 12:40:02 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=jDNxcFtW; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726817AbgDITiE (ORCPT + 99 others); Thu, 9 Apr 2020 15:38:04 -0400 Received: from mail-pf1-f193.google.com ([209.85.210.193]:46331 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726699AbgDITiD (ORCPT ); Thu, 9 Apr 2020 15:38:03 -0400 Received: by mail-pf1-f193.google.com with SMTP id q3so4586928pff.13 for ; Thu, 09 Apr 2020 12:38:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=rwrF17Ae6YnNqVwxgTEj3Njtao+/qzrb7ZBwN0IGHPw=; b=jDNxcFtWcECXEF8ak/LGTcwXXU3Xd8f4b0c74FnJf9HA0BFqsj7troT7Dk2JuaiMPY ejsOHKWwvQwXmu5N3743EDDJz83eotOBW7gfvFC7pE0bZGzBMNAMhw+ZwXNuRObPBADs s8XAcFE6tWvlNIfYZ90+udMQ5aEufAbTcI/ogrUHhw/2hR5Ny64lSVg2G/+2K9VUYJdk WnXTw0ot4HoMXo0Scf0f32pCy0CNzVNiH3WyjYDZkk5RHNPEZ7EwHe0rKQnp2g+/QRQD SpJUiyIYSSifiDCHNZlRntPiAezfJjud5Z7f3Z1Lr8lAlIEb3hK9BLLO5n4NaNHGQAfi sTiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=rwrF17Ae6YnNqVwxgTEj3Njtao+/qzrb7ZBwN0IGHPw=; b=CWf4s5+GB6EtyOwhKfqTITwUGDl6iP2LuCnKtrOocce/3HO/MrE5fOMzcnlKh+epi8 mElyRALEtSlT6nXAoektgfwFHTBje3WUH5IRM0w2FwwbhlWELtDUx/6SYYan8dZ+GA+l 8bDgdD2Zjrs5S6mKlJdvr6tsXXjccHp+9peIbkPBkhg6r8aLugrnC0F6WLEFpekwIj3e W6ZKDcbKJkwhFsKh+qXatfgqaHv3OjwFRqzC0JS132GlpI/rQN097qBa7jetwGSL77GL gmPK2GYxwgxH1uWFT5/UM+z5u3TVxlvmEwmZXvE6YwUJnaKdFnHqE1zwfJkoEDV/B5fI 3VPw== X-Gm-Message-State: AGi0PubOdmxfBe8+1CcxsA3sK1EiYTmdgKWCYYuV7hGdcKURt20C46Ng Lj7VrZhzXklt4OxzFyaX1DjcGw== X-Received: by 2002:a63:9a11:: with SMTP id o17mr1017083pge.234.1586461079843; Thu, 09 Apr 2020 12:37:59 -0700 (PDT) Received: from builder.lan (104-188-17-28.lightspeed.sndgca.sbcglobal.net. [104.188.17.28]) by smtp.gmail.com with ESMTPSA id 80sm1364459pgb.45.2020.04.09.12.37.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Apr 2020 12:37:59 -0700 (PDT) Date: Thu, 9 Apr 2020 12:38:07 -0700 From: Bjorn Andersson To: Wang Wenhu Cc: akpm@linux-foundation.org, "David S. Miller" , Jakub Kicinski , Greg Kroah-Hartman , Thomas Gleixner , Nicholas Mc Guire , Allison Randal , Johannes Berg , Arnd Bergmann , Carl Huang , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, kernel@vivo.com Subject: Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route Message-ID: <20200409193807.GS20625@builder.lan> References: <20200408104833.6880-1-wenhu.wang@vivo.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20200408104833.6880-1-wenhu.wang@vivo.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed 08 Apr 03:46 PDT 2020, Wang Wenhu wrote: > QSR implements maintenance of qrtr services and lookups. It would > be helpful for developers to work with QRTR without the none-opensource > user-space implementation part of IPC Router. > > As we know, the extremely important point of IPC Router is the support > of services form different nodes. But QRTR was pushed into mainline > without route process support of services, and the router port process > is implemented in user-space as none-opensource codes, which is an > great unconvenience for developers. > > QSR also implements a interface via chardev and a set of sysfs class > files for the communication and debugging in user-space. We can get > service and lookup entries conveniently via sysfs file in /sys/class/qsr/. > Currently add-server, del-server, add-lookup and del-lookup control > packatets are processed and enhancements could be taken easily upon > currently implementation. > > Signed-off-by: Wang Wenhu Hi Wang, Isn't this implementing the same thing that was recently landed upstream as net/qrtr/ns.c? Regards, Bjorn > --- > Changelog: > This is a resent, but the first normal version of QSR support. > The former one sent out earlier contains only the patch of coding > style modification of qsr.c. > > Please do not be confused and take this patch as the NORMAL commit of QSR. > --- > net/qrtr/Kconfig | 8 + > net/qrtr/Makefile | 2 + > net/qrtr/qrtr.c | 5 + > net/qrtr/qrtr.h | 2 + > net/qrtr/qsr.c | 622 ++++++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 639 insertions(+) > create mode 100644 net/qrtr/qsr.c > > diff --git a/net/qrtr/Kconfig b/net/qrtr/Kconfig > index 63f89cc6e82c..d2ce8fb57278 100644 > --- a/net/qrtr/Kconfig > +++ b/net/qrtr/Kconfig > @@ -29,4 +29,12 @@ config QRTR_TUN > implement endpoints of QRTR, for purpose of tunneling data to other > hosts or testing purposes. > > +config QSR > + tristate "QRTR Service Router" > + help > + Say Y here to enable the kernel QRTR Service Router module. > + QSR support route processes of QRTR services and lookups. It would be > + helpful when develop with QRTR without user-space implementation of > + IPC Router support. > + > endif # QRTR > diff --git a/net/qrtr/Makefile b/net/qrtr/Makefile > index 1c6d6c120fb7..3882beaead29 100644 > --- a/net/qrtr/Makefile > +++ b/net/qrtr/Makefile > @@ -5,3 +5,5 @@ obj-$(CONFIG_QRTR_SMD) += qrtr-smd.o > qrtr-smd-y := smd.o > obj-$(CONFIG_QRTR_TUN) += qrtr-tun.o > qrtr-tun-y := tun.o > +obj-$(CONFIG_QSR) += qrtr-svc-router.o > +qrtr-svc-router-y := qsr.o > diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c > index 5a8e42ad1504..267f7d6c746f 100644 > --- a/net/qrtr/qrtr.c > +++ b/net/qrtr/qrtr.c > @@ -158,6 +158,11 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb, > static struct qrtr_sock *qrtr_port_lookup(int port); > static void qrtr_port_put(struct qrtr_sock *ipc); > > +unsigned int get_qrtr_local_nid(void) > +{ > + return qrtr_local_nid; > +} > + > /* Release node resources and free the node. > * > * Do not call directly, use qrtr_node_release. To be used with > diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h > index b81e6953c04b..872d98fd36c6 100644 > --- a/net/qrtr/qrtr.h > +++ b/net/qrtr/qrtr.h > @@ -29,4 +29,6 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep); > > int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len); > > +unsigned int get_qrtr_local_nid(void); > + > #endif > diff --git a/net/qrtr/qsr.c b/net/qrtr/qsr.c > new file mode 100644 > index 000000000000..906f5903ebad > --- /dev/null > +++ b/net/qrtr/qsr.c > @@ -0,0 +1,622 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +/* > + * Copyright (C) 2020 Vivo Communication Technology Co. Ltd. > + * Copyright (C) 2020 Wang Wenhu > + * > + * The QRTR Service Route module aims at providing maintenance > + * and route processes for qrtr service and lookup requests in > + * kernel. Also, it provides sysfs class interface to expose > + * the status of qrtr services and lookups. More could be done > + * through the character device /dev/qsr in user-space. > + * > + * Currently, only server add, server delete, lookup add and > + * lookup delete requests are processed. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "qrtr.h" > + > +#define QSR_NAME "qsr" > + > +/** > + * struct qsr_info - qrtr service route request information > + * @service: service identity > + * @instance: service instance > + * @server: server address > + * @client: client address > + * @node: qrtr node of server or client > + * @port: qrtr port of server or client > + * > + * When a control packet of new server request is received, the server > + * field should be reference for the server node address. For the opposite > + * situation, the client field should be referenced within a lookup request. > + */ > +struct qsr_info { > + __le32 service; > + __le32 instance; > + > + union { > + struct { > + __le32 node; > + __le32 port; > + } server; > + > + struct { > + __le32 node; > + __le32 port; > + } client; > + }; > + > + struct list_head list; > +}; > + > +/** > + * struct qsr - qrtr service route device structure > + * @dev: character device for user-space communication > + * @sk: socket to process messages > + * @sq: socket address to be binded > + * @ops: callbacks of different control package types > + * @qsr_lock: data buffer lock > + * @recv_buf: receive buffer > + * @recv_buf_size: receive buffer size > + * @wq: workqueue for message process worker > + * @work: work route to process queued messages > + * @lookups: pending lookup requests > + * @services: servers list to provide different kind of services > + */ > +struct qsr { > + struct device dev; > + struct socket *sk; > + struct sockaddr_qrtr sq; > + struct qsr_ops *ops; > + > + struct mutex qsr_lock; > + void *recv_buf; > + size_t recv_buf_size; > + > + struct workqueue_struct *wq; > + struct work_struct work; > + > + struct list_head lookups; > + struct list_head services; > +}; > + > +struct qsr_ops { > + int (*new_server)(struct qsr_info *svc); > + int (*new_lookup)(struct qsr_info *svc, u32 node, u32 port); > +}; > + > +static int qsr_major; > +static struct cdev *qsr_cdev; > +static struct qsr *qsr; > + > +static int qsr_new_server(struct qsr_info *new) > +{ > + struct qsr_info *lookup; > + struct qsr_ops *ops = qsr->ops; > + int ret; > + > + if (!ops->new_lookup) > + return 0; > + > + list_for_each_entry(lookup, &qsr->lookups, list) { > + if (lookup->service == new->service && > + lookup->instance == new->instance) { > + ret = ops->new_lookup(new, > + lookup->client.node, > + lookup->client.port); > + if (ret < 0) > + pr_err("Error to notice client of new server, %d\n", ret); > + else > + list_del(&lookup->list); > + return 0; > + } > + } > + > + return 0; > +} > + > +static int qsr_new_lookup(struct qsr_info *svc, u32 node, u32 port) > +{ > + struct qrtr_ctrl_pkt pkt; > + struct sockaddr_qrtr sq; > + struct msghdr msg = { }; > + struct kvec iv = { &pkt, sizeof(pkt) }; > + int ret = 0; > + > + memset(&pkt, 0, sizeof(pkt)); > + pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_SERVER); > + pkt.server.service = cpu_to_le32(svc->service); > + pkt.server.instance = cpu_to_le32(svc->instance); > + pkt.server.node = cpu_to_le32(svc->server.node); > + pkt.server.port = cpu_to_le32(svc->server.port); > + > + sq.sq_family = AF_QIPCRTR; > + sq.sq_node = node; > + sq.sq_port = port; > + > + msg.msg_name = &sq; > + msg.msg_namelen = sizeof(sq); > + > + mutex_lock(&qsr->qsr_lock); > + if (qsr->sk) { > + ret = kernel_sendmsg(qsr->sk, &msg, &iv, 1, sizeof(pkt)); > + if (ret < 0) > + pr_err("Error to send server info to client, %d\n", ret); > + } > + mutex_unlock(&qsr->qsr_lock); > + > + return ret; > +} > + > +static void qsr_recv_new_server(u32 service, > + u32 instance, > + u32 node, > + u32 port) > +{ > + struct qsr_ops *ops = qsr->ops; > + struct qsr_info *svc, *temp; > + int ret; > + > + if (!ops->new_server) > + return; > + > + if (!node && !port) > + return; > + > + list_for_each_entry(temp, &qsr->services, list) { > + if (temp->service == service && temp->instance == instance) { > + pr_err("Error server exists, service:0x%x instance:0x%x", > + service, instance); > + return; > + } > + } > + > + svc = kzalloc(sizeof(*svc), GFP_KERNEL); > + if (!svc) > + return; > + > + svc->service = service; > + svc->instance = instance; > + svc->server.node = node; > + svc->server.port = port; > + > + ret = ops->new_server(svc); > + if (ret < 0) > + kfree(svc); > + else > + list_add(&svc->list, &qsr->services); > +} > + > +static void qsr_recv_del_server(u32 service, u32 instance) > +{ > + struct qsr_info *svc; > + > + list_for_each_entry(svc, &qsr->lookups, list) { > + if (svc->service == service && svc->instance == instance) { > + list_del(&svc->list); > + return; > + } > + } > +} > + > +static void qsr_recv_new_lookup(u32 service, > + u32 instance, > + u32 node, > + u32 port) > +{ > + struct qsr_ops *ops = qsr->ops; > + struct qsr_info *svc, *temp; > + int ret; > + > + if (!ops->new_lookup) > + return; > + > + if (!node && !port) > + return; > + > + list_for_each_entry(temp, &qsr->lookups, list) { > + if (temp->service == service && > + temp->instance == instance && > + temp->client.node == node && > + temp->client.port == port) { > + pr_err("Error lookup exists, service:0x%x instance:0x%x node:%d port:%d", > + service, instance, node, port); > + return; > + } > + } > + > + list_for_each_entry(svc, &qsr->services, list) { > + if (svc->service == service && svc->instance == instance) { > + ret = ops->new_lookup(svc, node, port); > + if (ret < 0) > + pr_err("Error to send server info to client, %d", ret); > + return; > + } > + } > + > + /* Server does not exist. > + * Record the lookup information and add it to the pending list. > + */ > + > + svc = kzalloc(sizeof(*svc), GFP_KERNEL); > + if (!svc) > + return; > + > + svc->service = service; > + svc->instance = instance; > + svc->client.node = node; > + svc->client.port = port; > + > + list_add(&svc->list, &qsr->lookups); > +} > + > +static void qsr_recv_del_lookup(u32 service, > + u32 instance, > + u32 node, > + u32 port) > +{ > + struct qsr_info *lookup; > + > + if (!node && !port) > + return; > + > + list_for_each_entry(lookup, &qsr->lookups, list) { > + if (lookup->service == service && > + lookup->instance == instance && > + lookup->client.node == node && > + lookup->client.port == port) { > + list_del(&lookup->list); > + return; > + } > + } > +} > + > +static void qsr_recv_ctrl_pkt(struct sockaddr_qrtr *sq, > + const void *buf, > + size_t len) > +{ > + const struct qrtr_ctrl_pkt *pkt = buf; > + > + if (len < sizeof(struct qrtr_ctrl_pkt)) { > + pr_debug("ignoring short control packet\n"); > + return; > + } > + > + switch (le32_to_cpu(pkt->cmd)) { > + case QRTR_TYPE_NEW_SERVER: > + qsr_recv_new_server(le32_to_cpu(pkt->server.service), > + le32_to_cpu(pkt->server.instance), > + le32_to_cpu(pkt->server.node), > + le32_to_cpu(pkt->server.port)); > + break; > + > + case QRTR_TYPE_NEW_LOOKUP: > + qsr_recv_new_lookup(le32_to_cpu(pkt->server.service), > + le32_to_cpu(pkt->server.instance), > + sq->sq_node, > + sq->sq_port); > + break; > + > + case QRTR_TYPE_DEL_SERVER: > + qsr_recv_del_server(le32_to_cpu(pkt->server.service), > + le32_to_cpu(pkt->server.instance)); > + break; > + > + case QRTR_TYPE_DEL_LOOKUP: > + qsr_recv_del_lookup(le32_to_cpu(pkt->server.service), > + le32_to_cpu(pkt->server.instance), > + sq->sq_node, > + sq->sq_port); > + break; > + } > +} > + > +static void qsr_recv_work(struct work_struct *work) > +{ > + struct sockaddr_qrtr sq; > + struct msghdr msg = { .msg_name = &sq, .msg_namelen = sizeof(sq) }; > + struct kvec iv; > + ssize_t msglen; > + > + for (;;) { > + iv.iov_base = qsr->recv_buf; > + iv.iov_len = qsr->recv_buf_size; > + > + mutex_lock(&qsr->qsr_lock); > + if (qsr->sk) > + msglen = kernel_recvmsg(qsr->sk, &msg, &iv, 1, > + iv.iov_len, MSG_DONTWAIT); > + else > + msglen = -EPIPE; > + mutex_unlock(&qsr->qsr_lock); > + > + if (msglen == -EAGAIN) > + break; > + > + if (msglen < 0) { > + pr_err("qmi recvmsg failed: %zd\n", msglen); > + break; > + } > + > + qsr_recv_ctrl_pkt(&sq, qsr->recv_buf, msglen); > + } > +} > + > +static void qsr_data_ready(struct sock *sk) > +{ > + read_lock_bh(&sk->sk_callback_lock); > + queue_work(qsr->wq, &qsr->work); > + read_unlock_bh(&sk->sk_callback_lock); > +} > + > +static ssize_t name_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + int ret; > + > + mutex_lock(&qsr->qsr_lock); > + ret = sprintf(buf, "%s\n", QSR_NAME); > + mutex_unlock(&qsr->qsr_lock); > + > + return ret; > +} > +static DEVICE_ATTR_RO(name); > + > +static ssize_t lookups_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct qsr_info *lookup; > + int ret = 0; > + > + mutex_lock(&qsr->qsr_lock); > + list_for_each_entry(lookup, &qsr->lookups, list) { > + ret += sprintf(buf, "service:0x%04x instance:0x%04x node:%04d port:%04d\n", > + lookup->service, > + lookup->instance, > + lookup->server.node, > + lookup->server.port); > + } > + mutex_unlock(&qsr->qsr_lock); > + > + return ret; > +} > +static DEVICE_ATTR_RO(lookups); > + > +static ssize_t services_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct qsr_info *svc; > + int ret = 0; > + > + mutex_lock(&qsr->qsr_lock); > + list_for_each_entry(svc, &qsr->services, list) { > + ret += sprintf(buf, "service:0x%04x instance:0x%04x node:%04d port:%04d\n", > + svc->service, > + svc->instance, > + svc->server.node, > + svc->server.port); > + } > + mutex_unlock(&qsr->qsr_lock); > + > + return ret; > +} > +static DEVICE_ATTR_RO(services); > + > +static struct attribute *qsr_attrs[] = { > + &dev_attr_name.attr, > + &dev_attr_lookups.attr, > + &dev_attr_services.attr, > + NULL, > +}; > +ATTRIBUTE_GROUPS(qsr); > + > +/* Interface class infrastructure. */ > +static struct class qsr_class = { > + .name = QSR_NAME, > + .dev_groups = qsr_groups, > +}; > + > +static int qsr_dev_create(void) > +{ > + int ret = -ENOMEM; > + > + qsr = kzalloc(sizeof(*qsr), GFP_KERNEL); > + if (!qsr) > + goto out; > + > + INIT_LIST_HEAD(&qsr->lookups); > + INIT_LIST_HEAD(&qsr->services); > + > + INIT_WORK(&qsr->work, qsr_recv_work); > + > + qsr->recv_buf_size = sizeof(struct qrtr_ctrl_pkt); > + qsr->recv_buf = kzalloc(qsr->recv_buf_size, GFP_KERNEL); > + if (!qsr->recv_buf) > + goto out_qsr_free; > + > + qsr->wq = alloc_workqueue("qsr_wq", WQ_UNBOUND, 1); > + if (!qsr->wq) > + goto out_recv_buf_free; > + > + device_initialize(&qsr->dev); > + qsr->dev.devt = MKDEV(qsr_major, 0); > + qsr->dev.class = &qsr_class; > + dev_set_drvdata(&qsr->dev, qsr); > + > + ret = dev_set_name(&qsr->dev, QSR_NAME); > + if (ret) { > + pr_err("device name %s set failed, %d", QSR_NAME, ret); > + goto out_recv_buf_free; > + } > + > + mutex_init(&qsr->qsr_lock); > + > + ret = device_add(&qsr->dev); > + if (ret) > + goto out_wq_destroy; > + > + return ret; > + > +out_wq_destroy: > + destroy_workqueue(qsr->wq); > +out_recv_buf_free: > + kfree(qsr->recv_buf); > +out_qsr_free: > + kfree(qsr); > +out: > + return ret; > +} > + > +struct qsr_ops qsr_handle_ops = { > + .new_server = qsr_new_server, > + .new_lookup = qsr_new_lookup, > +}; > + > +static struct socket *qsr_sock_create(void) > +{ > + struct socket *sock; > + struct sockaddr addr; > + int ret; > + > + ret = sock_create_kern(&init_net, AF_QIPCRTR, SOCK_DGRAM, > + PF_QIPCRTR, &sock); > + > + if (ret < 0) > + return ERR_PTR(ret); > + > + qsr->sq.sq_family = AF_QIPCRTR; > + qsr->sq.sq_node = get_qrtr_local_nid(); > + qsr->sq.sq_port = QRTR_PORT_CTRL; > + qsr->ops = &qsr_handle_ops; > + > + if (sock->ops->bind) { > + memcpy(&addr, &qsr->sq, sizeof(qsr->sq)); > + ret = sock->ops->bind(sock, &addr, sizeof(addr)); > + if (ret) { > + pr_err("Failed to bind socket address node:0x%x port:0x%x.\n", > + qsr->sq.sq_node, qsr->sq.sq_port); > + goto err_bind; > + } > + pr_debug("qsr router port binded successfully.\n"); > + } > + > + sock->sk->sk_user_data = qsr; > + sock->sk->sk_data_ready = qsr_data_ready; > + sock->sk->sk_error_report = qsr_data_ready; > + sock->sk->sk_sndtimeo = HZ * 10; > + > + return sock; > + > +err_bind: > + sock_release(sock); > + return NULL; > +} > + > +static int qsr_release(void) > +{ > + sock_release(qsr->sk); > + > + kfree(qsr->recv_buf); > + > + destroy_workqueue(qsr->wq); > + > + kfree(qsr); > + > + return 0; > +} > + > +static const struct file_operations qsr_fops = { > + .owner = THIS_MODULE, > +}; > + > +static int __init qsr_init(void) > +{ > + int ret; > + static const char name[] = QSR_NAME; > + struct cdev *cdev = NULL; > + dev_t rtdev; > + > + /* 1. Allocate character device region. */ > + ret = alloc_chrdev_region(&rtdev, 0, 1, name); > + if (ret) { > + pr_err("failed to alloc chardev region\n"); > + goto out; > + } > + > + /* 2. Allocate, initiate and add cdev. */ > + ret = -ENOMEM; > + cdev = cdev_alloc(); > + if (!cdev) { > + pr_err("failed to alloc cdev\n"); > + goto out_unregister; > + } > + > + cdev->owner = THIS_MODULE; > + cdev->ops = &qsr_fops; > + kobject_set_name(&cdev->kobj, "%s", name); > + > + ret = cdev_add(cdev, rtdev, 1); > + if (ret) > + goto out_put; > + > + qsr_major = MAJOR(rtdev); > + qsr_cdev = cdev; > + > + /* 3. Register class. */ > + ret = class_register(&qsr_class); > + if (ret) { > + pr_err("class_register failed for qrtr route\n"); > + goto out_cdev_del; > + } > + > + /* 4. Create a qsr device. */ > + if (qsr_dev_create()) > + goto out_unregister_class; > + > + /* 5. Create a qrtr socket and bind it to Router port. */ > + qsr->sk = qsr_sock_create(); > + if (!qsr->sk) > + goto out_qsr_dev_del; > + > + return 0; > + > +out_qsr_dev_del: > + kfree(qsr); > +out_unregister_class: > + class_unregister(&qsr_class); > +out_cdev_del: > + cdev_del(qsr_cdev); > +out_put: > + kobject_put(&cdev->kobj); > +out_unregister: > + unregister_chrdev_region(rtdev, 1); > +out: > + return ret; > +} > +subsys_initcall(qsr_init); > + > +static void __exit qsr_exit(void) > +{ > + qsr_release(); > + unregister_chrdev_region(MKDEV(qsr_major, 0), 1); > + cdev_del(qsr_cdev); > + class_unregister(&qsr_class); > +} > +module_exit(qsr_exit); > + > +MODULE_AUTHOR("Wang Wenhu"); > +MODULE_ALIAS("QRTR:" QSR_NAME); > +MODULE_DESCRIPTION("Qualcomm IPC Router Service Route Support"); > +MODULE_LICENSE("GPL v2"); > -- > 2.17.1 >