GNU Linux-libre 5.13.14-gnu1
[releases.git] / tools / usb / usbip / src / usbip_network.c
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
23 int usbip_port = 3240;
24 char *usbip_port_string = "3240";
25
26 void 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
53 uint32_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         else
60                 i = ntohl(num);
61
62         return i;
63 }
64
65 uint16_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         else
72                 i = ntohs(num);
73
74         return i;
75 }
76
77 void 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
88 void 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
95 static 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
122 ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
123 {
124         return usbip_net_xmit(sockfd, buff, bufflen, 0);
125 }
126
127 ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
128 {
129         return usbip_net_xmit(sockfd, buff, bufflen, 1);
130 }
131
132 static 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
140 int 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
162 int 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;
206 err:
207         return -1;
208 }
209
210 int 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
222 int 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
234 int 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
246 int 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 Ready
260  */
261 int 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 }