brintos

brintos / linux-shallow public Read only

0
0
Text · 5.9 KiB · ed4dc8c Raw
304 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>4 *               2005-2007 Takahiro Hirofuchi5 */6 7#include <sys/socket.h>8 9#include <string.h>10 11#include <arpa/inet.h>12#include <netdb.h>13#include <netinet/tcp.h>14#include <unistd.h>15 16#ifdef HAVE_LIBWRAP17#include <tcpd.h>18#endif19 20#include "usbip_common.h"21#include "usbip_network.h"22 23int usbip_port = 3240;24char *usbip_port_string = "3240";25 26void usbip_setup_port_number(char *arg)27{28	dbg("parsing port arg '%s'", arg);29	char *end;30	unsigned long int port = strtoul(arg, &end, 10);31 32	if (end == arg) {33		err("port: could not parse '%s' as a decimal integer", arg);34		return;35	}36 37	if (*end != '\0') {38		err("port: garbage at end of '%s'", arg);39		return;40	}41 42	if (port > UINT16_MAX) {43		err("port: %s too high (max=%d)",44		    arg, UINT16_MAX);45		return;46	}47 48	usbip_port = port;49	usbip_port_string = arg;50	info("using port %d (\"%s\")", usbip_port, usbip_port_string);51}52 53uint32_t usbip_net_pack_uint32_t(int pack, uint32_t num)54{55	uint32_t i;56 57	if (pack)58		i = htonl(num);59	else60		i = ntohl(num);61 62	return i;63}64 65uint16_t usbip_net_pack_uint16_t(int pack, uint16_t num)66{67	uint16_t i;68 69	if (pack)70		i = htons(num);71	else72		i = ntohs(num);73 74	return i;75}76 77void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)78{79	udev->busnum = usbip_net_pack_uint32_t(pack, udev->busnum);80	udev->devnum = usbip_net_pack_uint32_t(pack, udev->devnum);81	udev->speed = usbip_net_pack_uint32_t(pack, udev->speed);82 83	udev->idVendor = usbip_net_pack_uint16_t(pack, udev->idVendor);84	udev->idProduct = usbip_net_pack_uint16_t(pack, udev->idProduct);85	udev->bcdDevice = usbip_net_pack_uint16_t(pack, udev->bcdDevice);86}87 88void usbip_net_pack_usb_interface(int pack __attribute__((unused)),89				  struct usbip_usb_interface *udev90				  __attribute__((unused)))91{92	/* uint8_t members need nothing */93}94 95static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,96			      int sending)97{98	ssize_t nbytes;99	ssize_t total = 0;100 101	if (!bufflen)102		return 0;103 104	do {105		if (sending)106			nbytes = send(sockfd, buff, bufflen, 0);107		else108			nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);109 110		if (nbytes <= 0)111			return -1;112 113		buff	 = (void *)((intptr_t) buff + nbytes);114		bufflen	-= nbytes;115		total	+= nbytes;116 117	} while (bufflen > 0);118 119	return total;120}121 122ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)123{124	return usbip_net_xmit(sockfd, buff, bufflen, 0);125}126 127ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)128{129	return usbip_net_xmit(sockfd, buff, bufflen, 1);130}131 132static inline void usbip_net_pack_op_common(int pack,133					    struct op_common *op_common)134{135	op_common->version = usbip_net_pack_uint16_t(pack, op_common->version);136	op_common->code = usbip_net_pack_uint16_t(pack, op_common->code);137	op_common->status = usbip_net_pack_uint32_t(pack, op_common->status);138}139 140int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)141{142	struct op_common op_common;143	int rc;144 145	memset(&op_common, 0, sizeof(op_common));146 147	op_common.version = USBIP_VERSION;148	op_common.code    = code;149	op_common.status  = status;150 151	usbip_net_pack_op_common(1, &op_common);152 153	rc = usbip_net_send(sockfd, &op_common, sizeof(op_common));154	if (rc < 0) {155		dbg("usbip_net_send failed: %d", rc);156		return -1;157	}158 159	return 0;160}161 162int usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status)163{164	struct op_common op_common;165	int rc;166 167	memset(&op_common, 0, sizeof(op_common));168 169	rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));170	if (rc < 0) {171		dbg("usbip_net_recv failed: %d", rc);172		goto err;173	}174 175	usbip_net_pack_op_common(0, &op_common);176 177	if (op_common.version != USBIP_VERSION) {178		err("USBIP Kernel and tool version mismatch: %d %d:",179		    op_common.version, USBIP_VERSION);180		goto err;181	}182 183	switch (*code) {184	case OP_UNSPEC:185		break;186	default:187		if (op_common.code != *code) {188			dbg("unexpected pdu %#0x for %#0x", op_common.code,189			    *code);190			/* return error status */191			*status = ST_ERROR;192			goto err;193		}194	}195 196	*status = op_common.status;197 198	if (op_common.status != ST_OK) {199		dbg("request failed at peer: %d", op_common.status);200		goto err;201	}202 203	*code = op_common.code;204 205	return 0;206err:207	return -1;208}209 210int usbip_net_set_reuseaddr(int sockfd)211{212	const int val = 1;213	int ret;214 215	ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));216	if (ret < 0)217		dbg("setsockopt: SO_REUSEADDR");218 219	return ret;220}221 222int usbip_net_set_nodelay(int sockfd)223{224	const int val = 1;225	int ret;226 227	ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));228	if (ret < 0)229		dbg("setsockopt: TCP_NODELAY");230 231	return ret;232}233 234int usbip_net_set_keepalive(int sockfd)235{236	const int val = 1;237	int ret;238 239	ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));240	if (ret < 0)241		dbg("setsockopt: SO_KEEPALIVE");242 243	return ret;244}245 246int usbip_net_set_v6only(int sockfd)247{248	const int val = 1;249	int ret;250 251	ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));252	if (ret < 0)253		dbg("setsockopt: IPV6_V6ONLY");254 255	return ret;256}257 258/*259 * IPv6 Ready260 */261int usbip_net_tcp_connect(char *hostname, char *service)262{263	struct addrinfo hints, *res, *rp;264	int sockfd;265	int ret;266 267	memset(&hints, 0, sizeof(hints));268	hints.ai_family = AF_UNSPEC;269	hints.ai_socktype = SOCK_STREAM;270 271	/* get all possible addresses */272	ret = getaddrinfo(hostname, service, &hints, &res);273	if (ret < 0) {274		dbg("getaddrinfo: %s service %s: %s", hostname, service,275		    gai_strerror(ret));276		return ret;277	}278 279	/* try the addresses */280	for (rp = res; rp; rp = rp->ai_next) {281		sockfd = socket(rp->ai_family, rp->ai_socktype,282				rp->ai_protocol);283		if (sockfd < 0)284			continue;285 286		/* should set TCP_NODELAY for usbip */287		usbip_net_set_nodelay(sockfd);288		/* TODO: write code for heartbeat */289		usbip_net_set_keepalive(sockfd);290 291		if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)292			break;293 294		close(sockfd);295	}296 297	freeaddrinfo(res);298 299	if (!rp)300		return EAI_SYSTEM;301 302	return sockfd;303}304