18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
48c2ecf20Sopenharmony_ci *               2005-2007 Takahiro Hirofuchi
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <sys/socket.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <string.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <arpa/inet.h>
128c2ecf20Sopenharmony_ci#include <netdb.h>
138c2ecf20Sopenharmony_ci#include <netinet/tcp.h>
148c2ecf20Sopenharmony_ci#include <unistd.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#ifdef HAVE_LIBWRAP
178c2ecf20Sopenharmony_ci#include <tcpd.h>
188c2ecf20Sopenharmony_ci#endif
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "usbip_common.h"
218c2ecf20Sopenharmony_ci#include "usbip_network.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ciint usbip_port = 3240;
248c2ecf20Sopenharmony_cichar *usbip_port_string = "3240";
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_civoid usbip_setup_port_number(char *arg)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	dbg("parsing port arg '%s'", arg);
298c2ecf20Sopenharmony_ci	char *end;
308c2ecf20Sopenharmony_ci	unsigned long int port = strtoul(arg, &end, 10);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (end == arg) {
338c2ecf20Sopenharmony_ci		err("port: could not parse '%s' as a decimal integer", arg);
348c2ecf20Sopenharmony_ci		return;
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (*end != '\0') {
388c2ecf20Sopenharmony_ci		err("port: garbage at end of '%s'", arg);
398c2ecf20Sopenharmony_ci		return;
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	if (port > UINT16_MAX) {
438c2ecf20Sopenharmony_ci		err("port: %s too high (max=%d)",
448c2ecf20Sopenharmony_ci		    arg, UINT16_MAX);
458c2ecf20Sopenharmony_ci		return;
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	usbip_port = port;
498c2ecf20Sopenharmony_ci	usbip_port_string = arg;
508c2ecf20Sopenharmony_ci	info("using port %d (\"%s\")", usbip_port, usbip_port_string);
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ciuint32_t usbip_net_pack_uint32_t(int pack, uint32_t num)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	uint32_t i;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	if (pack)
588c2ecf20Sopenharmony_ci		i = htonl(num);
598c2ecf20Sopenharmony_ci	else
608c2ecf20Sopenharmony_ci		i = ntohl(num);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	return i;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ciuint16_t usbip_net_pack_uint16_t(int pack, uint16_t num)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	uint16_t i;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (pack)
708c2ecf20Sopenharmony_ci		i = htons(num);
718c2ecf20Sopenharmony_ci	else
728c2ecf20Sopenharmony_ci		i = ntohs(num);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	return i;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_civoid usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	udev->busnum = usbip_net_pack_uint32_t(pack, udev->busnum);
808c2ecf20Sopenharmony_ci	udev->devnum = usbip_net_pack_uint32_t(pack, udev->devnum);
818c2ecf20Sopenharmony_ci	udev->speed = usbip_net_pack_uint32_t(pack, udev->speed);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	udev->idVendor = usbip_net_pack_uint16_t(pack, udev->idVendor);
848c2ecf20Sopenharmony_ci	udev->idProduct = usbip_net_pack_uint16_t(pack, udev->idProduct);
858c2ecf20Sopenharmony_ci	udev->bcdDevice = usbip_net_pack_uint16_t(pack, udev->bcdDevice);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_civoid usbip_net_pack_usb_interface(int pack __attribute__((unused)),
898c2ecf20Sopenharmony_ci				  struct usbip_usb_interface *udev
908c2ecf20Sopenharmony_ci				  __attribute__((unused)))
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	/* uint8_t members need nothing */
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,
968c2ecf20Sopenharmony_ci			      int sending)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	ssize_t nbytes;
998c2ecf20Sopenharmony_ci	ssize_t total = 0;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (!bufflen)
1028c2ecf20Sopenharmony_ci		return 0;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	do {
1058c2ecf20Sopenharmony_ci		if (sending)
1068c2ecf20Sopenharmony_ci			nbytes = send(sockfd, buff, bufflen, 0);
1078c2ecf20Sopenharmony_ci		else
1088c2ecf20Sopenharmony_ci			nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci		if (nbytes <= 0)
1118c2ecf20Sopenharmony_ci			return -1;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		buff	 = (void *)((intptr_t) buff + nbytes);
1148c2ecf20Sopenharmony_ci		bufflen	-= nbytes;
1158c2ecf20Sopenharmony_ci		total	+= nbytes;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	} while (bufflen > 0);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return total;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cissize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	return usbip_net_xmit(sockfd, buff, bufflen, 0);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cissize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	return usbip_net_xmit(sockfd, buff, bufflen, 1);
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic inline void usbip_net_pack_op_common(int pack,
1338c2ecf20Sopenharmony_ci					    struct op_common *op_common)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	op_common->version = usbip_net_pack_uint16_t(pack, op_common->version);
1368c2ecf20Sopenharmony_ci	op_common->code = usbip_net_pack_uint16_t(pack, op_common->code);
1378c2ecf20Sopenharmony_ci	op_common->status = usbip_net_pack_uint32_t(pack, op_common->status);
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ciint usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct op_common op_common;
1438c2ecf20Sopenharmony_ci	int rc;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	memset(&op_common, 0, sizeof(op_common));
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	op_common.version = USBIP_VERSION;
1488c2ecf20Sopenharmony_ci	op_common.code    = code;
1498c2ecf20Sopenharmony_ci	op_common.status  = status;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	usbip_net_pack_op_common(1, &op_common);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	rc = usbip_net_send(sockfd, &op_common, sizeof(op_common));
1548c2ecf20Sopenharmony_ci	if (rc < 0) {
1558c2ecf20Sopenharmony_ci		dbg("usbip_net_send failed: %d", rc);
1568c2ecf20Sopenharmony_ci		return -1;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	return 0;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ciint usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct op_common op_common;
1658c2ecf20Sopenharmony_ci	int rc;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	memset(&op_common, 0, sizeof(op_common));
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));
1708c2ecf20Sopenharmony_ci	if (rc < 0) {
1718c2ecf20Sopenharmony_ci		dbg("usbip_net_recv failed: %d", rc);
1728c2ecf20Sopenharmony_ci		goto err;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	usbip_net_pack_op_common(0, &op_common);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (op_common.version != USBIP_VERSION) {
1788c2ecf20Sopenharmony_ci		err("USBIP Kernel and tool version mismatch: %d %d:",
1798c2ecf20Sopenharmony_ci		    op_common.version, USBIP_VERSION);
1808c2ecf20Sopenharmony_ci		goto err;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	switch (*code) {
1848c2ecf20Sopenharmony_ci	case OP_UNSPEC:
1858c2ecf20Sopenharmony_ci		break;
1868c2ecf20Sopenharmony_ci	default:
1878c2ecf20Sopenharmony_ci		if (op_common.code != *code) {
1888c2ecf20Sopenharmony_ci			dbg("unexpected pdu %#0x for %#0x", op_common.code,
1898c2ecf20Sopenharmony_ci			    *code);
1908c2ecf20Sopenharmony_ci			/* return error status */
1918c2ecf20Sopenharmony_ci			*status = ST_ERROR;
1928c2ecf20Sopenharmony_ci			goto err;
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	*status = op_common.status;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (op_common.status != ST_OK) {
1998c2ecf20Sopenharmony_ci		dbg("request failed at peer: %d", op_common.status);
2008c2ecf20Sopenharmony_ci		goto err;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	*code = op_common.code;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	return 0;
2068c2ecf20Sopenharmony_cierr:
2078c2ecf20Sopenharmony_ci	return -1;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ciint usbip_net_set_reuseaddr(int sockfd)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	const int val = 1;
2138c2ecf20Sopenharmony_ci	int ret;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
2168c2ecf20Sopenharmony_ci	if (ret < 0)
2178c2ecf20Sopenharmony_ci		dbg("setsockopt: SO_REUSEADDR");
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	return ret;
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ciint usbip_net_set_nodelay(int sockfd)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	const int val = 1;
2258c2ecf20Sopenharmony_ci	int ret;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
2288c2ecf20Sopenharmony_ci	if (ret < 0)
2298c2ecf20Sopenharmony_ci		dbg("setsockopt: TCP_NODELAY");
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return ret;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ciint usbip_net_set_keepalive(int sockfd)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	const int val = 1;
2378c2ecf20Sopenharmony_ci	int ret;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
2408c2ecf20Sopenharmony_ci	if (ret < 0)
2418c2ecf20Sopenharmony_ci		dbg("setsockopt: SO_KEEPALIVE");
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	return ret;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ciint usbip_net_set_v6only(int sockfd)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	const int val = 1;
2498c2ecf20Sopenharmony_ci	int ret;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
2528c2ecf20Sopenharmony_ci	if (ret < 0)
2538c2ecf20Sopenharmony_ci		dbg("setsockopt: IPV6_V6ONLY");
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return ret;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/*
2598c2ecf20Sopenharmony_ci * IPv6 Ready
2608c2ecf20Sopenharmony_ci */
2618c2ecf20Sopenharmony_ciint usbip_net_tcp_connect(char *hostname, char *service)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct addrinfo hints, *res, *rp;
2648c2ecf20Sopenharmony_ci	int sockfd;
2658c2ecf20Sopenharmony_ci	int ret;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	memset(&hints, 0, sizeof(hints));
2688c2ecf20Sopenharmony_ci	hints.ai_family = AF_UNSPEC;
2698c2ecf20Sopenharmony_ci	hints.ai_socktype = SOCK_STREAM;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/* get all possible addresses */
2728c2ecf20Sopenharmony_ci	ret = getaddrinfo(hostname, service, &hints, &res);
2738c2ecf20Sopenharmony_ci	if (ret < 0) {
2748c2ecf20Sopenharmony_ci		dbg("getaddrinfo: %s service %s: %s", hostname, service,
2758c2ecf20Sopenharmony_ci		    gai_strerror(ret));
2768c2ecf20Sopenharmony_ci		return ret;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* try the addresses */
2808c2ecf20Sopenharmony_ci	for (rp = res; rp; rp = rp->ai_next) {
2818c2ecf20Sopenharmony_ci		sockfd = socket(rp->ai_family, rp->ai_socktype,
2828c2ecf20Sopenharmony_ci				rp->ai_protocol);
2838c2ecf20Sopenharmony_ci		if (sockfd < 0)
2848c2ecf20Sopenharmony_ci			continue;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		/* should set TCP_NODELAY for usbip */
2878c2ecf20Sopenharmony_ci		usbip_net_set_nodelay(sockfd);
2888c2ecf20Sopenharmony_ci		/* TODO: write code for heartbeat */
2898c2ecf20Sopenharmony_ci		usbip_net_set_keepalive(sockfd);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci		if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
2928c2ecf20Sopenharmony_ci			break;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci		close(sockfd);
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	freeaddrinfo(res);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if (!rp)
3008c2ecf20Sopenharmony_ci		return EAI_SYSTEM;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	return sockfd;
3038c2ecf20Sopenharmony_ci}
304