Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
  4 *               2005-2007 Takahiro Hirofuchi
  5 */
  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_LIBWRAP
 17#include <tcpd.h>
 18#endif
 19
 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
 53void usbip_net_pack_uint32_t(int pack, uint32_t *num)
 54{
 55	uint32_t i;
 56
 57	if (pack)
 58		i = htonl(*num);
 59	else
 60		i = ntohl(*num);
 61
 62	*num = i;
 63}
 64
 65void usbip_net_pack_uint16_t(int pack, uint16_t *num)
 66{
 67	uint16_t i;
 68
 69	if (pack)
 70		i = htons(*num);
 71	else
 72		i = ntohs(*num);
 73
 74	*num = i;
 75}
 76
 77void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
 78{
 79	usbip_net_pack_uint32_t(pack, &udev->busnum);
 80	usbip_net_pack_uint32_t(pack, &udev->devnum);
 81	usbip_net_pack_uint32_t(pack, &udev->speed);
 82
 83	usbip_net_pack_uint16_t(pack, &udev->idVendor);
 84	usbip_net_pack_uint16_t(pack, &udev->idProduct);
 85	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 *udev
 90				  __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		else
108			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
132int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
133{
134	struct op_common op_common;
135	int rc;
136
137	memset(&op_common, 0, sizeof(op_common));
138
139	op_common.version = USBIP_VERSION;
140	op_common.code    = code;
141	op_common.status  = status;
142
143	PACK_OP_COMMON(1, &op_common);
144
145	rc = usbip_net_send(sockfd, &op_common, sizeof(op_common));
146	if (rc < 0) {
147		dbg("usbip_net_send failed: %d", rc);
148		return -1;
149	}
150
151	return 0;
152}
153
154int usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status)
155{
156	struct op_common op_common;
157	int rc;
158
159	memset(&op_common, 0, sizeof(op_common));
160
161	rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));
162	if (rc < 0) {
163		dbg("usbip_net_recv failed: %d", rc);
164		goto err;
165	}
166
167	PACK_OP_COMMON(0, &op_common);
168
169	if (op_common.version != USBIP_VERSION) {
170		err("USBIP Kernel and tool version mismatch: %d %d:",
171		    op_common.version, USBIP_VERSION);
172		goto err;
173	}
174
175	switch (*code) {
176	case OP_UNSPEC:
177		break;
178	default:
179		if (op_common.code != *code) {
180			dbg("unexpected pdu %#0x for %#0x", op_common.code,
181			    *code);
182			/* return error status */
183			*status = ST_ERROR;
184			goto err;
185		}
186	}
187
188	*status = op_common.status;
189
190	if (op_common.status != ST_OK) {
191		dbg("request failed at peer: %d", op_common.status);
192		goto err;
193	}
194
195	*code = op_common.code;
196
197	return 0;
198err:
199	return -1;
200}
201
202int usbip_net_set_reuseaddr(int sockfd)
203{
204	const int val = 1;
205	int ret;
206
207	ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
208	if (ret < 0)
209		dbg("setsockopt: SO_REUSEADDR");
210
211	return ret;
212}
213
214int usbip_net_set_nodelay(int sockfd)
215{
216	const int val = 1;
217	int ret;
218
219	ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
220	if (ret < 0)
221		dbg("setsockopt: TCP_NODELAY");
222
223	return ret;
224}
225
226int usbip_net_set_keepalive(int sockfd)
227{
228	const int val = 1;
229	int ret;
230
231	ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
232	if (ret < 0)
233		dbg("setsockopt: SO_KEEPALIVE");
234
235	return ret;
236}
237
238int usbip_net_set_v6only(int sockfd)
239{
240	const int val = 1;
241	int ret;
242
243	ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
244	if (ret < 0)
245		dbg("setsockopt: IPV6_V6ONLY");
246
247	return ret;
248}
249
250/*
251 * IPv6 Ready
252 */
253int usbip_net_tcp_connect(char *hostname, char *service)
254{
255	struct addrinfo hints, *res, *rp;
256	int sockfd;
257	int ret;
258
259	memset(&hints, 0, sizeof(hints));
260	hints.ai_family = AF_UNSPEC;
261	hints.ai_socktype = SOCK_STREAM;
262
263	/* get all possible addresses */
264	ret = getaddrinfo(hostname, service, &hints, &res);
265	if (ret < 0) {
266		dbg("getaddrinfo: %s service %s: %s", hostname, service,
267		    gai_strerror(ret));
268		return ret;
269	}
270
271	/* try the addresses */
272	for (rp = res; rp; rp = rp->ai_next) {
273		sockfd = socket(rp->ai_family, rp->ai_socktype,
274				rp->ai_protocol);
275		if (sockfd < 0)
276			continue;
277
278		/* should set TCP_NODELAY for usbip */
279		usbip_net_set_nodelay(sockfd);
280		/* TODO: write code for heartbeat */
281		usbip_net_set_keepalive(sockfd);
282
283		if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
284			break;
285
286		close(sockfd);
287	}
288
289	freeaddrinfo(res);
290
291	if (!rp)
292		return EAI_SYSTEM;
293
294	return sockfd;
295}