• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define DEV_FORMAT "/dev/rndis"
11 
12 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_buf[4096];
13 
14 static struct usbh_rndis g_rndis_class;
15 
usbh_rndis_init_msg_transfer(struct usbh_rndis * rndis_class)16 static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
17 {
18     struct usb_setup_packet *setup = rndis_class->hport->setup;
19     int ret = 0;
20     rndis_initialize_msg_t *cmd;
21     rndis_initialize_cmplt_t *resp;
22 
23     cmd = (rndis_initialize_msg_t *)g_rndis_buf;
24 
25     cmd->MessageType = REMOTE_NDIS_INITIALIZE_MSG;
26     cmd->MessageLength = sizeof(rndis_initialize_msg_t);
27     cmd->RequestId = rndis_class->request_id++;
28     cmd->MajorVersion = 1;
29     cmd->MinorVersion = 0;
30     cmd->MaxTransferSize = 0x4000;
31 
32     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
33     setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
34     setup->wValue = 0;
35     setup->wIndex = 0;
36     setup->wLength = sizeof(rndis_initialize_msg_t);
37 
38     ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)cmd);
39     if (ret < 0) {
40         USB_LOG_ERR("rndis_initialize_msg_t send error, ret: %d\r\n", ret);
41         return ret;
42     }
43 
44     //ret = usbh_ep_intr_transfer()
45 
46     resp = (rndis_initialize_cmplt_t *)g_rndis_buf;
47 
48     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
49     setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
50     setup->wValue = 0;
51     setup->wIndex = 0;
52     setup->wLength = 4096;
53 
54     ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)resp);
55     if (ret < 0) {
56         USB_LOG_ERR("rndis_initialize_cmplt_t recv error, ret: %d\r\n", ret);
57         return ret;
58     }
59 
60     return ret;
61 }
62 
usbh_rndis_query_msg_transfer(struct usbh_rndis * rndis_class,uint32_t oid,uint32_t query_len,uint8_t * info,uint32_t * info_len)63 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)
64 {
65     struct usb_setup_packet *setup = rndis_class->hport->setup;
66     int ret = 0;
67     rndis_query_msg_t *cmd;
68     rndis_query_cmplt_t *resp;
69 
70     cmd = (rndis_query_msg_t *)g_rndis_buf;
71 
72     cmd->MessageType = REMOTE_NDIS_QUERY_MSG;
73     cmd->MessageLength = query_len + sizeof(rndis_query_msg_t);
74     cmd->RequestId = rndis_class->request_id++;
75     cmd->Oid = oid;
76     cmd->InformationBufferLength = query_len;
77     cmd->InformationBufferOffset = 20;
78     cmd->DeviceVcHandle = 0;
79 
80     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
81     setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
82     setup->wValue = 0;
83     setup->wIndex = 0;
84     setup->wLength = query_len + sizeof(rndis_query_msg_t);
85 
86     ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)cmd);
87     if (ret < 0) {
88         USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
89         return ret;
90     }
91 
92     //ret = usbh_ep_intr_transfer()
93 
94     resp = (rndis_query_cmplt_t *)g_rndis_buf;
95 
96     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
97     setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
98     setup->wValue = 0;
99     setup->wIndex = 0;
100     setup->wLength = 4096;
101 
102     ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)resp);
103     if (ret < 0) {
104         USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
105         return ret;
106     }
107 
108     memcpy(info, ((uint8_t *)resp + sizeof(rndis_query_cmplt_t)), resp->InformationBufferLength);
109     *info_len = resp->InformationBufferLength;
110 
111     return ret;
112 }
113 
usbh_rndis_set_msg_transfer(struct usbh_rndis * rndis_class,uint32_t oid,uint8_t * info,uint32_t info_len)114 static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint8_t *info, uint32_t info_len)
115 {
116     struct usb_setup_packet *setup = rndis_class->hport->setup;
117     int ret = 0;
118     rndis_set_msg_t *cmd;
119     rndis_set_cmplt_t *resp;
120 
121     cmd = (rndis_set_msg_t *)g_rndis_buf;
122 
123     cmd->MessageType = REMOTE_NDIS_SET_MSG;
124     cmd->MessageLength = info_len + sizeof(rndis_set_msg_t);
125     cmd->RequestId = rndis_class->request_id++;
126     cmd->Oid = oid;
127     cmd->InformationBufferLength = info_len;
128     cmd->InformationBufferOffset = 20;
129     cmd->DeviceVcHandle = 0;
130 
131     memcpy(((uint8_t *)cmd + sizeof(rndis_set_msg_t)), info, info_len);
132     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
133     setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
134     setup->wValue = 0;
135     setup->wIndex = 0;
136     setup->wLength = info_len + sizeof(rndis_set_msg_t);
137 
138     ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)cmd);
139     if (ret < 0) {
140         USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
141         return ret;
142     }
143 
144     //ret = usbh_ep_intr_transfer(rndis_class->hport->intin,buf,len,500);
145 
146     resp = (rndis_set_cmplt_t *)g_rndis_buf;
147 
148     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
149     setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
150     setup->wValue = 0;
151     setup->wIndex = 0;
152     setup->wLength = 4096;
153 
154     ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)resp);
155     if (ret < 0) {
156         USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
157         return ret;
158     }
159 
160     return ret;
161 }
162 
usbh_rndis_bulk_out_transfer(struct usbh_rndis * rndis_class,uint8_t * buffer,uint32_t buflen,uint32_t timeout)163 int usbh_rndis_bulk_out_transfer(struct usbh_rndis *rndis_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
164 {
165     int ret;
166     struct usbh_urb *urb = &rndis_class->bulkout_urb;
167     memset(urb, 0, sizeof(struct usbh_urb));
168 
169     usbh_bulk_urb_fill(urb, rndis_class->bulkout, buffer, buflen, timeout, NULL, NULL);
170     ret = usbh_submit_urb(urb);
171     if (ret == 0) {
172         ret = urb->actual_length;
173     }
174     return ret;
175 }
176 
usbh_rndis_bulk_in_transfer(struct usbh_rndis * rndis_class,uint8_t * buffer,uint32_t buflen,uint32_t timeout)177 int usbh_rndis_bulk_in_transfer(struct usbh_rndis *rndis_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
178 {
179     int ret;
180     struct usbh_urb *urb = &rndis_class->bulkin_urb;
181     memset(urb, 0, sizeof(struct usbh_urb));
182 
183     usbh_bulk_urb_fill(urb, rndis_class->bulkin, buffer, buflen, timeout, NULL, NULL);
184     ret = usbh_submit_urb(urb);
185     if (ret == 0) {
186         ret = urb->actual_length;
187     }
188     return ret;
189 }
190 
usbh_rndis_keepalive(struct usbh_rndis * rndis_class)191 int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
192 {
193     struct usb_setup_packet *setup = rndis_class->hport->setup;
194     int ret = 0;
195     rndis_keepalive_msg_t *cmd;
196     rndis_keepalive_cmplt_t *resp;
197 
198     cmd = (rndis_keepalive_msg_t *)g_rndis_buf;
199 
200     cmd->MessageType = REMOTE_NDIS_KEEPALIVE_MSG;
201     cmd->MessageLength = sizeof(rndis_keepalive_msg_t);
202     cmd->RequestId = rndis_class->request_id++;
203 
204     setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
205     setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
206     setup->wValue = 0;
207     setup->wIndex = 0;
208     setup->wLength = sizeof(rndis_keepalive_msg_t);
209 
210     ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)cmd);
211     if (ret < 0) {
212         USB_LOG_ERR("keepalive send error, ret: %d\r\n", ret);
213         return ret;
214     }
215 
216     //ret = usbh_ep_intr_transfer(rndis_class->hport->intin,buf,len,500);
217 
218     resp = (rndis_keepalive_cmplt_t *)g_rndis_buf;
219 
220     setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
221     setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
222     setup->wValue = 0;
223     setup->wIndex = 0;
224     setup->wLength = 4096;
225 
226     ret = usbh_control_transfer(rndis_class->hport->ep0, setup, (uint8_t *)resp);
227     if (ret < 0) {
228         USB_LOG_ERR("keepalive recv error, ret: %d\r\n", ret);
229         return ret;
230     }
231 
232     return ret;
233 }
234 
usbh_rndis_connect(struct usbh_hubport * hport,uint8_t intf)235 static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
236 {
237     struct usb_endpoint_descriptor *ep_desc;
238     int ret;
239     uint32_t *oid_support_list;
240     unsigned int oid = 0;
241     unsigned int oid_num = 0;
242     uint32_t data_len;
243     uint8_t tmp_buffer[512];
244     uint8_t data[32];
245 
246     struct usbh_rndis *rndis_class = &g_rndis_class;
247 
248     memset(rndis_class, 0, sizeof(struct usbh_rndis));
249 
250     rndis_class->hport = hport;
251     rndis_class->ctrl_intf = intf;
252     rndis_class->data_intf = intf + 1;
253 
254     hport->config.intf[intf].priv = rndis_class;
255     hport->config.intf[intf + 1].priv = NULL;
256 
257 #ifdef CONFIG_USBHOST_RNDIS_NOTIFY
258     ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
259     usbh_hport_activate_epx(&rndis_class->intin, hport, ep_desc);
260 #endif
261     for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
262         ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
263 
264         if (ep_desc->bEndpointAddress & 0x80) {
265             usbh_hport_activate_epx(&rndis_class->bulkin, hport, ep_desc);
266         } else {
267             usbh_hport_activate_epx(&rndis_class->bulkout, hport, ep_desc);
268         }
269     }
270 
271     ret = usbh_rndis_init_msg_transfer(rndis_class);
272     if (ret < 0) {
273         return ret;
274     }
275     USB_LOG_INFO("rndis init success\r\n");
276 
277     ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_SUPPORTED_LIST, 0, tmp_buffer, &data_len);
278     if (ret < 0) {
279         return ret;
280     }
281     oid_num = (data_len / 4);
282     USB_LOG_INFO("rndis query OID_GEN_SUPPORTED_LIST success,oid num :%d\r\n", oid_num);
283 
284     oid_support_list = (uint32_t *)tmp_buffer;
285 
286     for (uint8_t i = 0; i < oid_num; i++) {
287         oid = oid_support_list[i];
288         switch (oid) {
289             case OID_GEN_PHYSICAL_MEDIUM:
290                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_PHYSICAL_MEDIUM, 4, data, &data_len);
291                 if (ret < 0) {
292                     goto query_errorout;
293                 }
294                 break;
295             case OID_GEN_MAXIMUM_FRAME_SIZE:
296                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MAXIMUM_FRAME_SIZE, 4, data, &data_len);
297                 if (ret < 0) {
298                     goto query_errorout;
299                 }
300                 break;
301             case OID_GEN_LINK_SPEED:
302                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_LINK_SPEED, 4, data, &data_len);
303                 if (ret < 0) {
304                     goto query_errorout;
305                 }
306 
307                 memcpy(&rndis_class->link_speed, data, 4);
308                 break;
309             case OID_GEN_MEDIA_CONNECT_STATUS:
310                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, &data_len);
311                 if (ret < 0) {
312                     goto query_errorout;
313                 }
314                 if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
315                     rndis_class->link_status = true;
316                 } else {
317                     rndis_class->link_status = false;
318                 }
319                 break;
320             case OID_802_3_MAXIMUM_LIST_SIZE:
321                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_MAXIMUM_LIST_SIZE, 4, data, &data_len);
322                 if (ret < 0) {
323                     goto query_errorout;
324                 }
325                 break;
326             case OID_802_3_CURRENT_ADDRESS:
327                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_CURRENT_ADDRESS, 6, data, &data_len);
328                 if (ret < 0) {
329                     goto query_errorout;
330                 }
331 
332                 for (uint8_t j = 0; j < 6; j++) {
333                     rndis_class->mac[j] = data[j];
334                 }
335                 break;
336             case OID_802_3_PERMANENT_ADDRESS:
337                 ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_PERMANENT_ADDRESS, 6, data, &data_len);
338                 if (ret < 0) {
339                     goto query_errorout;
340                 }
341                 break;
342             default:
343                 USB_LOG_WRN("Ignore rndis query iod:%08x\r\n", oid);
344                 continue;
345         }
346         USB_LOG_INFO("rndis query iod:%08x success\r\n", oid);
347     }
348 
349     uint32_t packet_filter = 0x0f;
350     usbh_rndis_set_msg_transfer(rndis_class, OID_GEN_CURRENT_PACKET_FILTER, (uint8_t *)&packet_filter, 4);
351     if (ret < 0) {
352         return ret;
353     }
354     USB_LOG_INFO("rndis set OID_GEN_CURRENT_PACKET_FILTER success\r\n");
355 
356     uint8_t multicast_list[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x01 };
357     usbh_rndis_set_msg_transfer(rndis_class, OID_802_3_MULTICAST_LIST, multicast_list, 6);
358     if (ret < 0) {
359         return ret;
360     }
361     USB_LOG_INFO("rndis set OID_802_3_MULTICAST_LIST success\r\n");
362 
363     memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
364 
365     USB_LOG_INFO("Register RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
366     usbh_rndis_run(rndis_class);
367     return ret;
368 query_errorout:
369     USB_LOG_ERR("rndis query iod:%08x error\r\n", oid);
370     return ret;
371 }
372 
usbh_rndis_disconnect(struct usbh_hubport * hport,uint8_t intf)373 static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
374 {
375     int ret = 0;
376 
377     struct usbh_rndis *rndis_class = (struct usbh_rndis *)hport->config.intf[intf].priv;
378 
379     if (rndis_class) {
380         if (rndis_class->bulkin) {
381             usbh_pipe_free(rndis_class->bulkin);
382         }
383 
384         if (rndis_class->bulkout) {
385             usbh_pipe_free(rndis_class->bulkout);
386         }
387 
388         if (hport->config.intf[intf].devname[0] != '\0') {
389             USB_LOG_INFO("Unregister RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
390             usbh_rndis_stop(rndis_class);
391         }
392 
393         memset(rndis_class, 0, sizeof(struct usbh_rndis));
394     }
395 
396     return ret;
397 }
398 
usbh_rndis_run(struct usbh_rndis * rndis_class)399 __WEAK void usbh_rndis_run(struct usbh_rndis *rndis_class)
400 {
401 }
402 
usbh_rndis_stop(struct usbh_rndis * rndis_class)403 __WEAK void usbh_rndis_stop(struct usbh_rndis *rndis_class)
404 {
405 }
406 
407 static const struct usbh_class_driver rndis_class_driver = {
408     .driver_name = "rndis",
409     .connect = usbh_rndis_connect,
410     .disconnect = usbh_rndis_disconnect
411 };
412 
413 CLASS_INFO_DEFINE const struct usbh_class_info rndis_class_info = {
414     .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
415     .class = USB_DEVICE_CLASS_WIRELESS,
416     .subclass = 0x01,
417     .protocol = 0x03,
418     .vid = 0x00,
419     .pid = 0x00,
420     .class_driver = &rndis_class_driver
421 };
422