lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:   Mon, 13 Apr 2020 11:55:41 +0800 (GMT+08:00)
From:   王文虎 <wenhu.wang@...o.com>
To:     Bjorn Andersson <bjorn.andersson@...aro.org>
Cc:     akpm@...ux-foundation.org, "David S. Miller" <davem@...emloft.net>,
        Jakub Kicinski <kuba@...nel.org>,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
        Thomas Gleixner <tglx@...utronix.de>,
        Nicholas Mc Guire <hofrat@...dl.org>,
        Allison Randal <allison@...utok.net>,
        Johannes Berg <johannes.berg@...el.com>,
        Arnd Bergmann <arnd@...db.de>,
        Carl Huang <cjhuang@...eaurora.org>,
        linux-kernel@...r.kernel.org, netdev@...r.kernel.org,
        kernel@...o.com
Subject: Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route


From: Bjorn Andersson <bjorn.andersson@...aro.org>
Date: 2020-04-10 03:38:07
To:  Wang Wenhu <wenhu.wang@...o.com>
Cc:  akpm@...ux-foundation.org,"David S. Miller" <davem@...emloft.net>,Jakub Kicinski <kuba@...nel.org>,Greg Kroah-Hartman <gregkh@...uxfoundation.org>,Thomas Gleixner <tglx@...utronix.de>,Nicholas Mc Guire <hofrat@...dl.org>,Allison Randal <allison@...utok.net>,Johannes Berg <johannes.berg@...el.com>,Arnd Bergmann <arnd@...db.de>,Carl Huang <cjhuang@...eaurora.org>,linux-kernel@...r.kernel.org,netdev@...r.kernel.org,kernel@...o.com
Subject: Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route>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 <wenhu.wang@...o.com>
>
>Hi Wang,
>
>Isn't this implementing the same thing that was recently landed upstream
>as net/qrtr/ns.c?

>

Hi, Regards
I found the qmi-service-maintainence had been missing since QRTR was introduced
recently while I was busy working with another new driver which I would name
it RPMON(Remote Processor Monitor). I konw the maintainence is supported
in user level but did not find any opensource code.

As you mentioned ns,c, let me check it out first.

As for RPMON, I have sent it out to Greg KH.
https://lore.kernel.org/lkml/20200412112405.24116-1-wenhu.wang@vivo.com/

Thanks,
Wenhu

>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 <wenhu.wang@...o.com>
>> + *
>> + * 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 <linux/module.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/mutex.h>
>> +#include <linux/device.h>
>> +#include <linux/string.h>
>> +#include <linux/kobject.h>
>> +#include <linux/cdev.h>
>> +#include <linux/qrtr.h>
>> +#include <net/sock.h>
>> +
>> +#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
>> 


Powered by blists - more mailing lists