1 /*
2  * Copyright (c) 2022, sakumisu
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "usbh_core.h"
7 #include "usbh_rndis.h"
8 #include "rndis_protocol.h"
9 
10 #undef USB_DBG_TAG
11 #define USB_DBG_TAG "usbh_rndis"
12 #include "usb_log.h"
13 
14 #define DEV_FORMAT "/dev/rndis"
15 
16 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_buf[512];
17 
18 #define CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE 1514
19 #define CONFIG_USBHOST_RNDIS_ETH_MSG_SIZE       (CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE + 44)
20 
21 static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE, CONFIG_USB_ALIGN_SIZE)];
22 static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[USB_ALIGN_UP(CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE, CONFIG_USB_ALIGN_SIZE)];
23 // static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_inttx_buffer[USB_ALIGN_UP(16, CONFIG_USB_ALIGN_SIZE)];
24 
25 static struct usbh_rndis g_rndis_class;
26 
usbh_rndis_get_notification(struct usbh_rndis * rndis_class)27 static int usbh_rndis_get_notification(struct usbh_rndis *rndis_class)
28 {
29     (void)rndis_class;
30     // int ret;
31     // struct usbh_urb *urb = &rndis_class->intin_urb;
32 
33     // usbh_int_urb_fill(urb, rndis_class->hport, rndis_class->intin, g_rndis_inttx_buffer, rndis_class->intin->wMaxPacketSize, USB_OSAL_WAITING_FOREVER, NULL, NULL);
34     // ret = usbh_submit_urb(urb);
35     // if (ret == 0) {
36     //     ret = urb->actual_length;
37     // }
38     // return ret;
39     return 0;
40 }
41 
usbh_rndis_init_msg_transfer(struct usbh_rndis * rndis_class)42 static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
43 {
44     struct usb_setup_packet *setup;
45     int ret = 0;
46     rndis_initialize_msg_t *cmd;
47     rndis_initialize_cmplt_t *resp;
48 
49     if (!rndis_class || !rndis_class->hport) {
50         return -USB_ERR_INVAL;
51     }
52     setup = rndis_class->hport->setup;
53 
54     cmd = (rndis_initialize_msg_t *)g_rndis_buf;
55 
56     cmd->MessageType = REMOTE_NDIS_INITIALIZE_MSG;
57     cmd->MessageLength = sizeof(rndis_initialize_msg_t);
58     cmd->RequestId = rndis_class->request_id++;
59     cmd->MajorVersion = 1;
60     cmd->MinorVersion = 0;
61     cmd->MaxTransferSize = 0x4000;
62 
63     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
64     setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
65     setup->wValue = 0;
66     setup->wIndex = 0;
67     setup->wLength = sizeof(rndis_initialize_msg_t);
68 
69     ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
70     if (ret < 0) {
71         USB_LOG_ERR("init send error, ret: %d\r\n", ret);
72         return ret;
73     }
74 
75     usbh_rndis_get_notification(rndis_class);
76 
77     resp = (rndis_initialize_cmplt_t *)g_rndis_buf;
78 
79     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
80     setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
81     setup->wValue = 0;
82     setup->wIndex = 0;
83     setup->wLength = sizeof(g_rndis_buf);
84 
85     ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
86     if (ret < 0) {
87         USB_LOG_ERR("init recv error, ret: %d\r\n", ret);
88         return ret;
89     }
90 
91     rndis_class->max_transfer_pkts = resp->MaxPacketsPerTransfer;
92     rndis_class->max_transfer_size = resp->MaxTransferSize;
93     USB_LOG_INFO("MaxPacketsPerTransfer: %u\r\n", (unsigned int)resp->MaxPacketsPerTransfer);
94     USB_LOG_INFO("MaxTransferSize: %u\r\n", (unsigned int)resp->MaxTransferSize);
95 
96     return ret;
97 }
98 
usbh_rndis_query_msg_transfer(struct usbh_rndis * rndis_class,uint32_t oid,uint32_t query_len,uint8_t * info,uint32_t * info_len)99 int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint32_t query_len, uint8_t *info, uint32_t *info_len)
100 {
101     struct usb_setup_packet *setup;
102     int ret = 0;
103     rndis_query_msg_t *cmd;
104     rndis_query_cmplt_t *resp;
105 
106     if (!rndis_class || !rndis_class->hport) {
107         return -USB_ERR_INVAL;
108     }
109     setup = rndis_class->hport->setup;
110 
111     cmd = (rndis_query_msg_t *)g_rndis_buf;
112 
113     cmd->MessageType = REMOTE_NDIS_QUERY_MSG;
114     cmd->MessageLength = query_len + sizeof(rndis_query_msg_t);
115     cmd->RequestId = rndis_class->request_id++;
116     cmd->Oid = oid;
117     cmd->InformationBufferLength = query_len;
118     cmd->InformationBufferOffset = 20;
119     cmd->DeviceVcHandle = 0;
120 
121     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
122     setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
123     setup->wValue = 0;
124     setup->wIndex = 0;
125     setup->wLength = query_len + sizeof(rndis_query_msg_t);
126 
127     ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
128     if (ret < 0) {
129         USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
130         return ret;
131     }
132 
133     usbh_rndis_get_notification(rndis_class);
134 
135     resp = (rndis_query_cmplt_t *)g_rndis_buf;
136 
137     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
138     setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
139     setup->wValue = 0;
140     setup->wIndex = 0;
141     setup->wLength = sizeof(g_rndis_buf);
142 
143     ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
144     if (ret < 0) {
145         USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
146         return ret;
147     }
148 
149     memcpy(info, ((uint8_t *)resp + sizeof(rndis_query_cmplt_t)), resp->InformationBufferLength);
150     *info_len = resp->InformationBufferLength;
151 
152     return ret;
153 }
154 
usbh_rndis_set_msg_transfer(struct usbh_rndis * rndis_class,uint32_t oid,uint8_t * info,uint32_t info_len)155 static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint8_t *info, uint32_t info_len)
156 {
157     struct usb_setup_packet *setup;
158     int ret = 0;
159     rndis_set_msg_t *cmd;
160     rndis_set_cmplt_t *resp;
161 
162     if (!rndis_class || !rndis_class->hport) {
163         return -USB_ERR_INVAL;
164     }
165     setup = rndis_class->hport->setup;
166 
167     cmd = (rndis_set_msg_t *)g_rndis_buf;
168 
169     cmd->MessageType = REMOTE_NDIS_SET_MSG;
170     cmd->MessageLength = info_len + sizeof(rndis_set_msg_t);
171     cmd->RequestId = rndis_class->request_id++;
172     cmd->Oid = oid;
173     cmd->InformationBufferLength = info_len;
174     cmd->InformationBufferOffset = 20;
175     cmd->DeviceVcHandle = 0;
176 
177     memcpy(((uint8_t *)cmd + sizeof(rndis_set_msg_t)), info, info_len);
178     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
179     setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
180     setup->wValue = 0;
181     setup->wIndex = 0;
182     setup->wLength = info_len + sizeof(rndis_set_msg_t);
183 
184     ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
185     if (ret < 0) {
186         USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
187         return ret;
188     }
189 
190     usbh_rndis_get_notification(rndis_class);
191 
192     resp = (rndis_set_cmplt_t *)g_rndis_buf;
193 
194     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
195     setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
196     setup->wValue = 0;
197     setup->wIndex = 0;
198     setup->wLength = sizeof(g_rndis_buf);
199 
200     ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
201     if (ret < 0) {
202         USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
203         return ret;
204     }
205 
206     return ret;
207 }
208 
usbh_rndis_get_connect_status(struct usbh_rndis * rndis_class)209 int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class)
210 {
211     int ret;
212     uint8_t data[32];
213     uint32_t data_len;
214 
215     ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, &data_len);
216     if (ret < 0) {
217         return ret;
218     }
219     if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
220         rndis_class->connect_status = true;
221     } else {
222         rndis_class->connect_status = false;
223     }
224     return 0;
225 }
226 
usbh_rndis_keepalive(struct usbh_rndis * rndis_class)227 int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
228 {
229     struct usb_setup_packet *setup;
230     int ret = 0;
231     rndis_keepalive_msg_t *cmd;
232     rndis_keepalive_cmplt_t *resp;
233 
234     if (!rndis_class || !rndis_class->hport) {
235         return -USB_ERR_INVAL;
236     }
237     setup = rndis_class->hport->setup;
238 
239     cmd = (rndis_keepalive_msg_t *)g_rndis_buf;
240 
241     cmd->MessageType = REMOTE_NDIS_KEEPALIVE_MSG;
242     cmd->MessageLength = sizeof(rndis_keepalive_msg_t);
243     cmd->RequestId = rndis_class->request_id++;
244 
245     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
246     setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
247     setup->wValue = 0;
248     setup->wIndex = 0;
249     setup->wLength = sizeof(rndis_keepalive_msg_t);
250 
251     ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
252     if (ret < 0) {
253         USB_LOG_ERR("keepalive send error, ret: %d\r\n", ret);
254         return ret;
255     }
256 
257     usbh_rndis_get_notification(rndis_class);
258 
259     resp = (rndis_keepalive_cmplt_t *)g_rndis_buf;
260 
261     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
262     setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
263     setup->wValue = 0;
264     setup->wIndex = 0;
265     setup->wLength = sizeof(g_rndis_buf);
266 
267     ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
268     if (ret < 0) {
269         USB_LOG_ERR("keepalive recv error, ret: %d\r\n", ret);
270         return ret;
271     }
272 
273     return ret;
274 }
275 
usbh_rndis_connect(struct usbh_hubport * hport,uint8_t intf)276 static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
277 {
278     struct usb_endpoint_descriptor *ep_desc;
279     int ret;
280     uint32_t *oid_support_list;
281     uint32_t oid = 0;
282     uint32_t oid_num = 0;
283     uint32_t data_len;
284     uint8_t tmp_buffer[512];
285     uint8_t data[32];
286 
287     struct usbh_rndis *rndis_class = &g_rndis_class;
288 
289     memset(rndis_class, 0, sizeof(struct usbh_rndis));
290 
291     rndis_class->hport = hport;
292     rndis_class->ctrl_intf = intf;
293     rndis_class->data_intf = intf + 1;
294 
295     hport->config.intf[intf].priv = rndis_class;
296     hport->config.intf[intf + 1].priv = NULL;
297 
298     // ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
299     // USBH_EP_INIT(rndis_class->intin, ep_desc);
300 
301     for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
302         ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
303 
304         if (ep_desc->bEndpointAddress & 0x80) {
305             USBH_EP_INIT(rndis_class->bulkin, ep_desc);
306         } else {
307             USBH_EP_INIT(rndis_class->bulkout, ep_desc);
308         }
309     }
310 
311     ret = usbh_rndis_init_msg_transfer(rndis_class);
312     if (ret < 0) {
313         return ret;
314     }
315 
316     ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_SUPPORTED_LIST, 0, tmp_buffer, &data_len);
317     if (ret < 0) {
318         return ret;
319     }
320     oid_num = (data_len / 4);
321     USB_LOG_INFO("rndis query OID_GEN_SUPPORTED_LIST success,oid num: %u\r\n", (unsigned int)oid_num);
322 
323     oid_support_list = (uint32_t *)tmp_buffer;
324 
325     for (uint8_t i = 0; i < oid_num; i++) {
326         oid = oid_support_list[i];
327         switch (oid) {
328             case OID_GEN_PHYSICAL_MEDIUM:
329                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_PHYSICAL_MEDIUM, 4, data, &data_len);
330                 if (ret < 0) {
331                     goto query_errorout;
332                 }
333                 break;
334             case OID_GEN_MAXIMUM_FRAME_SIZE:
335                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MAXIMUM_FRAME_SIZE, 4, data, &data_len);
336                 if (ret < 0) {
337                     goto query_errorout;
338                 }
339                 break;
340             case OID_GEN_LINK_SPEED:
341                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_LINK_SPEED, 4, data, &data_len);
342                 if (ret < 0) {
343                     goto query_errorout;
344                 }
345 
346                 memcpy(&rndis_class->link_speed, data, 4);
347                 break;
348             case OID_GEN_MEDIA_CONNECT_STATUS:
349                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, &data_len);
350                 if (ret < 0) {
351                     goto query_errorout;
352                 }
353                 if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
354                     rndis_class->connect_status = true;
355                 } else {
356                     rndis_class->connect_status = false;
357                 }
358                 break;
359             case OID_802_3_MAXIMUM_LIST_SIZE:
360                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_MAXIMUM_LIST_SIZE, 4, data, &data_len);
361                 if (ret < 0) {
362                     goto query_errorout;
363                 }
364                 break;
365             case OID_802_3_CURRENT_ADDRESS:
366                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_CURRENT_ADDRESS, 6, data, &data_len);
367                 if (ret < 0) {
368                     goto query_errorout;
369                 }
370 
371                 for (uint8_t j = 0; j < 6; j++) {
372                     rndis_class->mac[j] = data[j];
373                 }
374                 break;
375             case OID_802_3_PERMANENT_ADDRESS:
376                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_PERMANENT_ADDRESS, 6, data, &data_len);
377                 if (ret < 0) {
378                     goto query_errorout;
379                 }
380                 break;
381             default:
382                 break;
383         }
384     }
385 
386     uint32_t packet_filter = 0x0f;
387     ret = usbh_rndis_set_msg_transfer(rndis_class, OID_GEN_CURRENT_PACKET_FILTER, (uint8_t *)&packet_filter, 4);
388     if (ret < 0) {
389         return ret;
390     }
391 
392     uint8_t multicast_list[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x01 };
393     ret = usbh_rndis_set_msg_transfer(rndis_class, OID_802_3_MULTICAST_LIST, multicast_list, 6);
394     if (ret < 0) {
395         return ret;
396     }
397 
398     USB_LOG_INFO("rndis MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
399                  rndis_class->mac[0],
400                  rndis_class->mac[1],
401                  rndis_class->mac[2],
402                  rndis_class->mac[3],
403                  rndis_class->mac[4],
404                  rndis_class->mac[5]);
405 
406     strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
407 
408     USB_LOG_INFO("Register RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
409     usbh_rndis_run(rndis_class);
410     return ret;
411 query_errorout:
412     USB_LOG_ERR("rndis query iod:%08x error\r\n", (unsigned int)oid);
413     return ret;
414 }
415 
usbh_rndis_disconnect(struct usbh_hubport * hport,uint8_t intf)416 static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
417 {
418     int ret = 0;
419 
420     struct usbh_rndis *rndis_class = (struct usbh_rndis *)hport->config.intf[intf].priv;
421 
422     if (rndis_class) {
423         if (rndis_class->bulkin) {
424             usbh_kill_urb(&rndis_class->bulkin_urb);
425         }
426 
427         if (rndis_class->bulkout) {
428             usbh_kill_urb(&rndis_class->bulkout_urb);
429         }
430 
431         // if (rndis_class->intin) {
432         //     usbh_kill_urb(&rndis_class->intin_urb);
433         // }
434 
435         if (hport->config.intf[intf].devname[0] != '\0') {
436             usb_osal_thread_schedule_other();
437             USB_LOG_INFO("Unregister RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
438             usbh_rndis_stop(rndis_class);
439         }
440 
441         memset(rndis_class, 0, sizeof(struct usbh_rndis));
442     }
443 
444     return ret;
445 }
446 
usbh_rndis_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)447 void usbh_rndis_rx_thread(CONFIG_USB_OSAL_THREAD_SET_ARGV)
448 {
449     uint32_t g_rndis_rx_length;
450     int ret;
451     uint32_t pmg_offset;
452     rndis_data_packet_t *pmsg;
453     rndis_data_packet_t temp;
454 #if CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE <= (16 * 1024)
455     uint32_t transfer_size = CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE;
456 #else
457     uint32_t transfer_size = (16 * 1024);
458 #endif
459 
460     (void)CONFIG_USB_OSAL_THREAD_GET_ARGV;
461 
462     USB_LOG_INFO("Create rndis rx thread\r\n");
463     // clang-format off
464 find_class:
465     // clang-format on
466     g_rndis_class.connect_status = false;
467     if (usbh_find_class_instance("/dev/rndis") == NULL) {
468         goto delete;
469     }
470 
471     while (g_rndis_class.connect_status == false) {
472         ret = usbh_rndis_get_connect_status(&g_rndis_class);
473         if (ret < 0) {
474             usb_osal_msleep(100);
475             goto find_class;
476         }
477         usb_osal_msleep(128);
478     }
479 
480     g_rndis_rx_length = 0;
481     while (1) {
482         usbh_bulk_urb_fill(&g_rndis_class.bulkin_urb, g_rndis_class.hport, g_rndis_class.bulkin, &g_rndis_rx_buffer[g_rndis_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
483         ret = usbh_submit_urb(&g_rndis_class.bulkin_urb);
484         if (ret < 0) {
485             break;
486         }
487 
488         g_rndis_rx_length += g_rndis_class.bulkin_urb.actual_length;
489 
490         /* A transfer is complete because last packet is a short packet.
491          * Short packet is not zero, match g_rndis_rx_length % USB_GET_MAXPACKETSIZE(g_rndis_class.bulkin->wMaxPacketSize).
492          * Short packet cannot be zero.
493         */
494         if (g_rndis_rx_length % USB_GET_MAXPACKETSIZE(g_rndis_class.bulkin->wMaxPacketSize)) {
495             pmg_offset = 0;
496 
497             uint32_t total_len = g_rndis_rx_length;
498 
499             while (g_rndis_rx_length > 0) {
500                 USB_LOG_DBG("rxlen:%u\r\n", (unsigned int)g_rndis_rx_length);
501 
502                 pmsg = (rndis_data_packet_t *)(g_rndis_rx_buffer + pmg_offset);
503 
504                 /* Not word-aligned case */
505                 if (pmg_offset & 0x3) {
506                     usb_memcpy(&temp, pmsg, sizeof(rndis_data_packet_t));
507                     pmsg = &temp;
508                 }
509 
510                 if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
511                     uint8_t *buf = (uint8_t *)(g_rndis_rx_buffer + pmg_offset + sizeof(rndis_generic_msg_t) + pmsg->DataOffset);
512 
513                     usbh_rndis_eth_input(buf, pmsg->DataLength);
514                     pmg_offset += pmsg->MessageLength;
515                     g_rndis_rx_length -= pmsg->MessageLength;
516 
517                     /* drop the last dummy byte, it is a short packet to tell us we have received a multiple of wMaxPacketSize */
518                     if (g_rndis_rx_length < 4) {
519                         g_rndis_rx_length = 0;
520                     }
521                 } else {
522                     USB_LOG_ERR("offset:%u,remain:%u,total:%u\r\n", (unsigned int)pmg_offset, (unsigned int)g_rndis_rx_length, (unsigned int)total_len);
523                     g_rndis_rx_length = 0;
524                     USB_LOG_ERR("Error rndis packet message\r\n");
525                 }
526             }
527         } else {
528 #if CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE <= (16 * 1024)
529             if (g_rndis_rx_length == CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE) {
530 #else
531             if ((g_rndis_rx_length + (16 * 1024)) > CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE) {
532 #endif
533                 USB_LOG_ERR("Rx packet is overflow, please reduce tcp window size or increase CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE\r\n");
534                 while (1) {
535                 }
536             }
537         }
538     }
539 
540     // clang-format off
541 delete:
542     USB_LOG_INFO("Delete rndis rx thread\r\n");
543     usb_osal_thread_delete(NULL);
544     // clang-format on
545 }
546 
547 uint8_t *usbh_rndis_get_eth_txbuf(void)
548 {
549     return (g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
550 }
551 
552 int usbh_rndis_eth_output(uint32_t buflen)
553 {
554     rndis_data_packet_t *hdr;
555     uint32_t len;
556 
557     if (g_rndis_class.connect_status == false) {
558         return -USB_ERR_NOTCONN;
559     }
560 
561     hdr = (rndis_data_packet_t *)g_rndis_tx_buffer;
562     memset(hdr, 0, sizeof(rndis_data_packet_t));
563 
564     hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
565     hdr->MessageLength = sizeof(rndis_data_packet_t) + buflen;
566     hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
567     hdr->DataLength = buflen;
568 
569     len = hdr->MessageLength;
570     /* if message length is the multiple of wMaxPacketSize, we should add a short packet to tell device transfer is over. */
571     if (!(len % g_rndis_class.bulkout->wMaxPacketSize)) {
572         len += 1;
573     }
574 
575     USB_LOG_DBG("txlen:%d\r\n", len);
576 
577     usbh_bulk_urb_fill(&g_rndis_class.bulkout_urb, g_rndis_class.hport, g_rndis_class.bulkout, g_rndis_tx_buffer, len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
578     return usbh_submit_urb(&g_rndis_class.bulkout_urb);
579 }
580 
581 __WEAK void usbh_rndis_run(struct usbh_rndis *rndis_class)
582 {
583     (void)rndis_class;
584 }
585 
586 __WEAK void usbh_rndis_stop(struct usbh_rndis *rndis_class)
587 {
588     (void)rndis_class;
589 }
590 
591 static const struct usbh_class_driver rndis_class_driver = {
592     .driver_name = "rndis",
593     .connect = usbh_rndis_connect,
594     .disconnect = usbh_rndis_disconnect
595 };
596 
597 CLASS_INFO_DEFINE const struct usbh_class_info rndis_class_info = {
598     .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
599     .bInterfaceClass = USB_DEVICE_CLASS_WIRELESS,
600     .bInterfaceSubClass = 0x01,
601     .bInterfaceProtocol = 0x03,
602     .id_table = NULL,
603     .class_driver = &rndis_class_driver
604 };
605