Re: [PATCH v13 07/10] usbip: exporting devices: new application-side daemon

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 11/22/2016 07:48 AM, Nobuo Iwata wrote:
> This patch is the new application(vhci)-side daemon specific code.
> 
> The daemons are consisting three files.
> usbip.c : common code.
> usbip_dev.c: device(stub)-side specific code.
> usbip_app.c: application(vhci)-side specific code - this patch.
> 
> Here, device-side daemon is EXISTING-1 and application-side daemon is 
> NEW-1 in figure below.
> 
> EXISTING) - invites devices from application(vhci)-side
>          +------+                                 +------------------+
>  device--+ STUB |                                 | application/VHCI |
>          +------+                                 +------------------+
>  1) usbipd ... start daemon
>  = = =
>  2) usbip list --local
>  3) usbip bind
>                     <--- list bound devices ---   4) usbip list --remote
>                     <--- import a device ------   5) usbip attach
>  = = =
>                        X disconnected             6) usbip detach
>  7) usbip unbind
> 
> NEW) - dedicates devices from device(stb)-side
>          +------+                                 +------------------+
>  device--+ STUB |                                 | application/VHCI |
>          +------+                                 +------------------+
>                                               1) usbipa ... start daemon
>  = = =
>  2) usbip list --local
>  3) usbip connect     --- export a device ------>
>  = = =
>  4) usbip disconnect  --- un-export a device --->
> 
> Signed-off-by: Nobuo Iwata <nobuo.iwata@xxxxxxxxxxxxxxx>
> ---
>  tools/usb/usbip/libsrc/vhci_driver.c |  19 +++
>  tools/usb/usbip/libsrc/vhci_driver.h |   1 +
>  tools/usb/usbip/src/Makefile.am      |   7 +-
>  tools/usb/usbip/src/usbipd.c         |  12 +-
>  tools/usb/usbip/src/usbipd_app.c     | 242 +++++++++++++++++++++++++++
>  5 files changed, 279 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
> index d2221c5..3fe92ff 100644
> --- a/tools/usb/usbip/libsrc/vhci_driver.c
> +++ b/tools/usb/usbip/libsrc/vhci_driver.c
> @@ -314,6 +314,25 @@ int usbip_vhci_get_free_port(void)
>  	return -1;
>  }
>  
> +struct usbip_imported_device *usbip_vhci_find_device(char *host, char *busid)
> +{
> +	int ret;
> +	char rhost[NI_MAXHOST] = "unknown host";
> +	char rserv[NI_MAXSERV] = "unknown port";
> +	char rbusid[SYSFS_BUS_ID_SIZE];
> +
> +	for (int i = 0; i < vhci_driver->nports; i++) {
> +		ret = read_record(vhci_driver->idev[i].port, rhost, NI_MAXHOST,
> +				rserv, NI_MAXSERV, rbusid);

sizeof(rhist), sizeof(rserv)

BTW.
The read_record() function is really weird and probably it should be
also refactored. We pass 3 arrays but pass size only for 2 of them and
size of third argument is hard coded inside this function:(


> +		if (!ret &&
> +			!strncmp(host, rhost, NI_MAXHOST) &&
> +			!strncmp(busid, rbusid, SYSFS_BUS_ID_SIZE)) {
> +			return vhci_driver->idev + i;
> +		}

Is there any reason why you don't check port here?
I also thing that it's better to ensure that strings are \0 terminated
rather than using strncmp all the time.

> +	}
> +	return NULL;
> +}
> +

(...)

> +
> +static int import_device(int sockfd, struct usbip_usb_device *udev)
> +{
> +	int rc;
> +	int port;
> +
> +	dbg("Sockfd:%d", sockfd);
> +	port = usbip_vhci_get_free_port();
> +	if (port < 0) {
> +		err("no free port");
> +		return -1;
> +	}
> +
> +	dump_usb_device(udev);
> +	rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
> +					udev->devnum, udev->speed);
> +	if (rc < 0) {
> +		err("import device");
> +		return -1;
> +	}
> +
> +	return port;
> +}
> +
> +static int recv_request_export(int sockfd, char *host, char *port)
> +{
> +	struct op_export_request req;
> +	struct op_export_reply reply;
> +	int rhport = 0;
> +	int error = 0;
> +	int rc;
> +
> +	memset(&req, 0, sizeof(req));
> +	memset(&reply, 0, sizeof(reply));

As before. You don't need to memset() reply.

> +
> +	rc = usbip_net_recv(sockfd, &req, sizeof(req));
> +	if (rc < 0) {
> +		dbg("usbip_net_recv failed: export request");
> +		return -1;
> +	}
> +	PACK_OP_EXPORT_REQUEST(0, &req);
> +
> +	rhport = import_device(sockfd, &req.udev);
> +	if (rhport < 0) {
> +		dbg("export request busid %s: failed", req.udev.busid);
> +		error = 1;
> +	}
> +
> +	rc = usbip_net_send_op_common(sockfd, OP_REP_EXPORT,
> +				      (!error ? ST_OK : ST_NA));
> +	if (rc < 0) {
> +		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_EXPORT);
> +		return -1;
> +	}
> +
> +	if (!error)
> +		reply.returncode = 0;
> +	else
> +		reply.returncode = -1;

As I wrote in first patch. This may end up in compiler warning

> +
> +	PACK_OP_EXPORT_REPLY(0, &rep);
> +
> +	rc = usbip_net_send(sockfd, &reply, sizeof(reply));
> +	if (rc < 0) {
> +		dbg("usbip_net_send failed: export reply");
> +		return -1;
> +	}
> +
> +	rc = usbip_vhci_create_record(host, port, req.udev.busid, rhport);

This call should be moved to import_device() as we may endup with
inconsistent_state() if there is a comminication error.

> +	if (rc < 0) {
> +		err("record connection");
> +		return -1;
> +	}
> +
> +	dbg("export request busid %s: complete", req.udev.busid);
> +
> +	return 0;
> +}
> +
> +static int unimport_device(char *host, struct usbip_usb_device *udev)
> +{
> +	int rc;
> +	struct usbip_imported_device *idev;
> +
> +	idev = usbip_vhci_find_device(host, udev->busid);
> +	if (idev == NULL) {
> +		err("no imported port %s %s", host, udev->busid);
> +		return -1;
> +	}
> +
> +	rc = usbip_vhci_detach_device(idev->port);
> +	if (rc < 0) {
> +		err("no imported port %d %s %s", idev->port, host, udev->busid);
> +		return -1;
> +	}
> +	return idev->port;
> +}
> +
> +static int recv_request_unexport(int sockfd, char *host)
> +{
> +	struct op_unexport_request req;
> +	struct op_unexport_reply reply;
> +	int rhport = 0;
> +	int error = 0;
> +	int rc;
> +
> +	memset(&req, 0, sizeof(req));
> +	memset(&reply, 0, sizeof(reply));

As before. You don't need to memset() reply.

> +
> +	rc = usbip_net_recv(sockfd, &req, sizeof(req));
> +	if (rc < 0) {
> +		dbg("usbip_net_recv failed: unexport request");
> +		return -1;
> +	}
> +	PACK_OP_UNEXPORT_REQUEST(0, &req);
> +
> +	rhport = unimport_device(host, &req.udev);
> +	if (rhport < 0)
> +		error = 1;
> +
> +	rc = usbip_net_send_op_common(sockfd, OP_REP_UNEXPORT,
> +				      (!error ? ST_OK : ST_NA));
> +	if (rc < 0) {
> +		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_UNEXPORT);
> +		return -1;
> +	}
> +
> +	if (!error) {
> +		reply.returncode = 0;
> +	} else {
> +		reply.returncode = -1;

As I wrote in first patch. This may end up in compiler warning

> +		dbg("unexport request busid %s: failed", req.udev.busid);
> +		return -1;
> +	}
> +	PACK_OP_UNEXPORT_REPLY(0, &rep);
> +
> +	rc = usbip_net_send(sockfd, &reply, sizeof(reply));
> +	if (rc < 0) {
> +		dbg("usbip_net_send failed: unexport reply");
> +		return -1;
> +	}
> +
> +	usbip_vhci_delete_record(rhport);

I think that this function should be called from unimport_device()

Now this function can be ommited if there is some communication error
and we may endup in inconsistent state.

> +
> +	dbg("unexport request busid %s: complete", req.udev.busid);
> +
> +	return 0;
> +}
> +
> +int usbip_recv_pdu(int connfd, char *host, char *port)
> +{
> +	uint16_t code = OP_UNSPEC;
> +	int ret;
> +
> +	ret = usbip_net_recv_op_common(connfd, &code);
> +	if (ret < 0) {
> +		dbg("could not receive opcode: %#0x", code);
> +		return -1;
> +	}
> +
> +	ret = usbip_vhci_refresh_device_list();
> +	if (ret < 0) {
> +		dbg("could not refresh device list: %d", ret);
> +		return -1;
> +	}
> +
> +	info("received request: %#0x(%d)", code, connfd);
> +	switch (code) {
> +	case OP_REQ_EXPORT:
> +		ret = recv_request_export(connfd, host, port);
> +		break;
> +	case OP_REQ_UNEXPORT:
> +		ret = recv_request_unexport(connfd, host);
> +		break;
> +	default:
> +		err("received an unknown opcode: %#0x", code);
> +		ret = -1;
> +	}
> +
> +	if (ret == 0)
> +		info("request %#0x(%s:%s): complete", code, host, port);
> +	else
> +		info("request %#0x(%s:%s): failed", code, host, port);
> +
> +	return ret;
> +}
> 

This one is a copy-paste from usbip_recv_pdu() in usbipd_dev.c with only
values changed in switch. How about sharing this code and add only
callback which will be used based on received op_code?

Best regards,
-- 
Krzysztof Opasiak
Samsung R&D Institute Poland
Samsung Electronics
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux