1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /* For accept4() */
8 #define _GNU_SOURCE 1
9
10 #define __packed __attribute__((__packed__))
11
12 #include <stdio.h>
13 #include <stdarg.h>
14 #include <stdbool.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25
26 /* Zephyr headers */
27 #include <zephyr/kernel.h>
28 #include <zephyr/usb/usb_device.h>
29
30 #include <posix_board_if.h>
31 #include "usb_dc_native_posix_adapt.h"
32
33 #define LOG_LEVEL CONFIG_USB_DRIVER_LOG_LEVEL
34 LOG_MODULE_REGISTER(native_posix_adapt);
35
36 #define USBIP_PORT 3240
37 #define USBIP_VERSION 273
38
39 #define VERBOSE_DEBUG
40
41 int connfd_global;
42 int seqnum_global;
43 int devid_global;
44
45 /* Helpers */
46
47 #ifdef VERBOSE_DEBUG
usbip_header_dump(struct usbip_header * hdr)48 static void usbip_header_dump(struct usbip_header *hdr)
49 {
50 LOG_DBG("cmd %x seq %u dir %u ep %x", ntohl(hdr->common.command),
51 ntohl(hdr->common.seqnum), ntohl(hdr->common.direction),
52 ntohl(hdr->common.ep));
53
54 switch (ntohl(hdr->common.command)) {
55 case USBIP_CMD_SUBMIT:
56 LOG_DBG("flags %x np %u int %u buflen %u",
57 ntohl(hdr->u.submit.transfer_flags),
58 ntohl(hdr->u.submit.number_of_packets),
59 ntohl(hdr->u.submit.interval),
60 ntohl(hdr->u.submit.transfer_buffer_length));
61 break;
62 case USBIP_CMD_UNLINK:
63 LOG_DBG("seq %d", ntohl(hdr->u.unlink.seqnum));
64 break;
65 default:
66 break;
67 }
68 }
69 #else
70 #define usbip_header_dump(x)
71 #endif
72
get_interface(uint8_t * descriptors)73 void get_interface(uint8_t *descriptors)
74 {
75 while (descriptors[0]) {
76 if (descriptors[1] == USB_DESC_INTERFACE) {
77 LOG_DBG("interface found");
78 }
79
80 /* skip to next descriptor */
81 descriptors += descriptors[0];
82 }
83 }
84
send_interfaces(const uint8_t * descriptors,int connfd)85 static int send_interfaces(const uint8_t *descriptors, int connfd)
86 {
87 struct devlist_interface {
88 uint8_t bInterfaceClass;
89 uint8_t bInterfaceSubClass;
90 uint8_t bInterfaceProtocol;
91 uint8_t padding; /* alignment */
92 } __packed iface;
93
94 while (descriptors[0]) {
95 if (descriptors[1] == USB_DESC_INTERFACE) {
96 struct usb_if_descriptor *desc = (void *)descriptors;
97
98 iface.bInterfaceClass = desc->bInterfaceClass;
99 iface.bInterfaceSubClass = desc->bInterfaceSubClass;
100 iface.bInterfaceProtocol = desc->bInterfaceProtocol;
101 iface.padding = 0U;
102
103 if (send(connfd, &iface, sizeof(iface), 0) !=
104 sizeof(iface)) {
105 LOG_ERR("send() failed: %s", strerror(errno));
106 return errno;
107 }
108 }
109
110 /* skip to next descriptor */
111 descriptors += descriptors[0];
112 }
113
114 return 0;
115 }
116
fill_device(struct devlist_device * dev,const uint8_t * desc)117 static void fill_device(struct devlist_device *dev, const uint8_t *desc)
118 {
119 struct usb_device_descriptor *dev_dsc = (void *)desc;
120 struct usb_cfg_descriptor *cfg =
121 (void *)(desc + sizeof(struct usb_device_descriptor));
122
123 memset(dev->path, 0, 256);
124 strcpy(dev->path, "/sys/devices/pci0000:00/0000:00:01.2/usb1/1-1");
125 memset(dev->busid, 0, 32);
126 strcpy(dev->busid, "1-1");
127
128 dev->busnum = htonl(1);
129 dev->devnum = htonl(2);
130 dev->speed = htonl(2);
131
132 dev->idVendor = htons(dev_dsc->idVendor);
133 dev->idProduct = htons(dev_dsc->idProduct);
134 dev->bcdDevice = htons(dev_dsc->bcdDevice);
135 dev->bDeviceClass = dev_dsc->bDeviceClass;
136 dev->bDeviceSubClass = dev_dsc->bDeviceSubClass;
137 dev->bDeviceProtocol = dev_dsc->bDeviceProtocol;
138
139 dev->bConfigurationValue = cfg->bConfigurationValue;
140 dev->bNumConfigurations = dev_dsc->bNumConfigurations;
141 dev->bNumInterfaces = cfg->bNumInterfaces;
142 }
143
send_device(const uint8_t * desc,int connfd)144 static int send_device(const uint8_t *desc, int connfd)
145 {
146 struct devlist_device dev;
147
148 fill_device(&dev, desc);
149
150 if (send(connfd, &dev, sizeof(dev), 0) != sizeof(dev)) {
151 LOG_ERR("send() device failed: %s", strerror(errno));
152 return errno;
153 }
154
155 return 0;
156 }
157
handle_device_list(const uint8_t * desc,int connfd)158 static int handle_device_list(const uint8_t *desc, int connfd)
159 {
160 struct op_common header = {
161 .version = htons(USBIP_VERSION),
162 .code = htons(OP_REP_DEVLIST),
163 .status = 0,
164 };
165
166 LOG_DBG("desc %p", desc);
167
168 if (send(connfd, &header, sizeof(header), 0) != sizeof(header)) {
169 LOG_ERR("send() header failed: %s", strerror(errno));
170 return errno;
171 }
172
173 /* Send number of devices */
174 uint32_t ndev = htonl(1);
175
176 if (send(connfd, &ndev, sizeof(ndev), 0) != sizeof(ndev)) {
177 LOG_ERR("send() ndev failed: %s", strerror(errno));
178 return errno;
179 }
180
181 send_device(desc, connfd);
182
183 send_interfaces(desc, connfd);
184
185 return 0;
186 }
187
handle_usbip_submit(int connfd,struct usbip_header * hdr)188 static void handle_usbip_submit(int connfd, struct usbip_header *hdr)
189 {
190 struct usbip_submit *req = &hdr->u.submit;
191 int read;
192
193 LOG_DBG("");
194
195 read = recv(connfd, req, sizeof(*req), 0);
196 if (read != sizeof(*req)) {
197 LOG_ERR("recv() failed: %s", strerror(errno));
198 return;
199 }
200
201 usbip_header_dump((void *)hdr);
202
203 if (ntohl(hdr->common.ep) == 0) {
204 handle_usb_control(hdr);
205 } else {
206 handle_usb_data(hdr);
207 }
208 }
209
handle_usbip_unlink(int connfd,struct usbip_header * hdr)210 static void handle_usbip_unlink(int connfd, struct usbip_header *hdr)
211 {
212 int read;
213
214 LOG_DBG("");
215
216 /* Need to read the whole structure */
217 read = recv(connfd, &hdr->u, sizeof(hdr->u), 0);
218 if (read != sizeof(hdr->u)) {
219 LOG_ERR("recv() failed: %s", strerror(errno));
220 return;
221 }
222
223 usbip_header_dump((void *)hdr);
224
225 /* TODO: unlink */
226 }
227
handle_import(const uint8_t * desc,int connfd)228 static int handle_import(const uint8_t *desc, int connfd)
229 {
230 struct op_common header = {
231 .version = htons(USBIP_VERSION),
232 .code = htons(OP_REP_IMPORT),
233 .status = 0,
234 };
235 char busid[32];
236
237 LOG_DBG("attach device");
238
239 if (recv(connfd, busid, 32, 0) != sizeof(busid)) {
240 LOG_ERR("recv() failed: %s", strerror(errno));
241 return errno;
242 }
243
244 if (send(connfd, &header, sizeof(header), 0) != sizeof(header)) {
245 LOG_ERR("send() header failed: %s", strerror(errno));
246 return errno;
247 }
248
249 send_device(desc, connfd);
250
251 return 0;
252 }
253
254 extern struct usb_desc_header __usb_descriptor_start[];
255
usbip_start(void)256 void usbip_start(void)
257 {
258 struct sockaddr_in srv;
259 unsigned char attached;
260 int listenfd, connfd;
261 const uint8_t *desc;
262 int reuse = 1;
263
264 LOG_DBG("Starting");
265
266 /*
267 * Do not use usb_get_device_descriptor();
268 * to prevent double string fixing
269 */
270 desc = (const uint8_t *)__usb_descriptor_start;
271 if (!desc) {
272 LOG_ERR("Descriptors are not set");
273 posix_exit(EXIT_FAILURE);
274 }
275
276 listenfd = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
277 if (listenfd < 0) {
278 LOG_ERR("socket() failed: %s", strerror(errno));
279 posix_exit(EXIT_FAILURE);
280 }
281
282 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
283 (const char *)&reuse, sizeof(reuse)) < 0) {
284 LOG_WRN("setsockopt() failed: %s", strerror(errno));
285 }
286
287 memset(&srv, 0, sizeof(srv));
288 srv.sin_family = AF_INET;
289 srv.sin_addr.s_addr = htonl(INADDR_ANY);
290 srv.sin_port = htons(USBIP_PORT);
291
292 if (bind(listenfd, (struct sockaddr *)&srv, sizeof(srv)) < 0) {
293 LOG_ERR("bind() failed: %s", strerror(errno));
294 posix_exit(EXIT_FAILURE);
295 }
296
297 if (listen(listenfd, SOMAXCONN) < 0) {
298 LOG_ERR("listen() failed: %s", strerror(errno));
299 posix_exit(EXIT_FAILURE);
300 }
301
302 while (true) {
303 struct sockaddr_in client_addr;
304 socklen_t client_addr_len = sizeof(client_addr);
305
306 connfd = accept4(listenfd, (struct sockaddr *)&client_addr,
307 &client_addr_len, SOCK_NONBLOCK);
308 if (connfd < 0) {
309 if (errno == EAGAIN || errno == EWOULDBLOCK) {
310 /* Non-blocking accept */
311 k_sleep(K_MSEC(100));
312
313 continue;
314 }
315
316 LOG_ERR("accept() failed: %s", strerror(errno));
317 posix_exit(EXIT_FAILURE);
318 }
319
320 connfd_global = connfd;
321
322 LOG_DBG("Connection: %s", inet_ntoa(client_addr.sin_addr));
323
324 /* Set attached 0 */
325 attached = 0U;
326
327 while (true) {
328 struct usbip_header cmd;
329 struct usbip_header_common *hdr = &cmd.common;
330 int read;
331
332 if (!attached) {
333 struct op_common req;
334
335 read = recv(connfd, &req, sizeof(req), 0);
336 if (read < 0) {
337 if (errno == EAGAIN ||
338 errno == EWOULDBLOCK) {
339 /* Non-blocking accept */
340 k_sleep(K_MSEC(100));
341
342 continue;
343 }
344 }
345
346 if (read != sizeof(req)) {
347 LOG_WRN("wrong length, %d", read);
348
349 /* Closing connection */
350 break;
351 }
352
353 LOG_HEXDUMP_DBG((uint8_t *)&req, sizeof(req),
354 "Got request");
355
356 LOG_DBG("Code: 0x%x", ntohs(req.code));
357
358 switch (ntohs(req.code)) {
359 case OP_REQ_DEVLIST:
360 handle_device_list(desc, connfd);
361 break;
362 case OP_REQ_IMPORT:
363 if (!handle_import(desc, connfd)) {
364 attached = 1U;
365 }
366 break;
367 default:
368 LOG_ERR("Unhandled code: 0x%x",
369 ntohs(req.code));
370 break;
371 }
372
373 continue;
374 }
375
376 /* Handle attached case */
377
378 read = recv(connfd, hdr, sizeof(*hdr), 0);
379 if (read < 0) {
380 if (errno == EAGAIN || errno == EWOULDBLOCK) {
381 /* Non-blocking accept */
382 k_sleep(K_MSEC(100));
383
384 continue;
385 }
386 }
387
388 LOG_HEXDUMP_DBG((uint8_t *)hdr, read, "Got cmd");
389
390 if (read != sizeof(*hdr)) {
391 LOG_ERR("recv wrong length: %d", read);
392
393 /* Closing connection */
394 break;
395 }
396
397 devid_global = ntohl(hdr->devid);
398 seqnum_global = ntohl(hdr->seqnum);
399
400 switch (ntohl(hdr->command)) {
401 case USBIP_CMD_SUBMIT:
402 handle_usbip_submit(connfd, &cmd);
403 break;
404 case USBIP_CMD_UNLINK:
405 handle_usbip_unlink(connfd, &cmd);
406 break;
407 default:
408 LOG_ERR("Unknown command: 0x%x",
409 ntohl(hdr->command));
410 close(connfd);
411 return;
412 }
413 }
414
415 LOG_DBG("Closing connection");
416 close(connfd);
417 }
418 }
419
usbip_recv(uint8_t * buf,size_t len)420 int usbip_recv(uint8_t *buf, size_t len)
421 {
422 return recv(connfd_global, buf, len, 0);
423 }
424
usbip_send(uint8_t ep,const uint8_t * data,size_t len)425 int usbip_send(uint8_t ep, const uint8_t *data, size_t len)
426 {
427 return send(connfd_global, data, len, 0);
428 }
429
usbip_send_common(uint8_t ep,uint32_t data_len)430 bool usbip_send_common(uint8_t ep, uint32_t data_len)
431 {
432 struct usbip_submit_rsp rsp;
433 uint32_t ep_dir = USB_EP_DIR_IS_IN(ep) ? USBIP_DIR_IN : USBIP_DIR_OUT;
434 uint32_t ep_idx = USB_EP_GET_IDX(ep);
435
436 rsp.common.command = htonl(USBIP_RET_SUBMIT);
437 rsp.common.seqnum = htonl(seqnum_global);
438 rsp.common.devid = htonl(0);
439 rsp.common.direction = htonl(ep_dir);
440 rsp.common.ep = htonl(ep_idx);
441
442 rsp.status = htonl(0);
443 rsp.actual_length = htonl(data_len);
444 rsp.start_frame = htonl(0);
445 rsp.number_of_packets = htonl(0);
446 rsp.error_count = htonl(0);
447
448 rsp.setup = htonl(0);
449
450 if (usbip_send(ep, (uint8_t *)&rsp, sizeof(rsp)) == sizeof(rsp)) {
451 return true;
452 }
453
454 return false;
455 }
456