usbd_rndis.c
Go to the documentation of this file.
1 /**
2  * @file usbd_rndis.c
3  * @brief USB RNDIS class
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Pro.
10  *
11  * This software is provided under a commercial license. You may
12  * use this software under the conditions stated in the license
13  * terms. This source code cannot be redistributed.
14  *
15  * @author Oryx Embedded SARL (www.oryx-embedded.com)
16  * @version 1.9.0
17  **/
18 
19 //Switch to the appropriate trace level
20 #define TRACE_LEVEL TRACE_LEVEL_INFO
21 
22 //Dependencies
23 #include "usbd_ctlreq.h"
24 #include "usbd_desc.h"
25 #include "usbd_rndis.h"
26 #include "core/net.h"
27 #include "rndis.h"
28 #include "rndis_driver.h"
29 #include "rndis_debug.h"
30 #include "debug.h"
31 
32 //Debug macros
33 #if (TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
34  #undef TRACE_DEBUG
35  #define TRACE_DEBUG(...) fprintf(stderr, __VA_ARGS__)
36  #undef TRACE_DEBUG_ARRAY
37  #define TRACE_DEBUG_ARRAY(p, a, n) debugDisplayArray(stderr, p, a, n)
38 #endif
39 
40 
41 /**
42  * @brief RNDIS class callbacks
43  **/
44 
45 USBD_ClassTypeDef usbdRndisClass =
46 {
50  NULL,
54  NULL,
55  NULL,
56  NULL,
61 };
62 
63 
64 /**
65  * @brief RNDIS class initialization
66  * @param[in] pdev Pointer to a USBD_HandleTypeDef structure
67  * @param[in] cfgidx Configuration index
68  * @return Status code
69  **/
70 
71 uint8_t usbdRndisInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
72 {
73  //Check current speed
74  if(pdev->dev_speed == USBD_SPEED_HIGH)
75  {
76  //Open DATA IN endpoint
77  USBD_LL_OpenEP(pdev, RNDIS_DATA_IN_EP,
78  USBD_EP_TYPE_BULK, RNDIS_DATA_IN_EP_MPS_HS);
79 
80  //Open DATA OUT endpoint
81  USBD_LL_OpenEP(pdev, RNDIS_DATA_OUT_EP,
82  USBD_EP_TYPE_BULK, RNDIS_DATA_OUT_EP_MPS_HS);
83  }
84  else
85  {
86  //Open DATA IN endpoint
87  USBD_LL_OpenEP(pdev, RNDIS_DATA_IN_EP,
88  USBD_EP_TYPE_BULK, RNDIS_DATA_IN_EP_MPS_FS);
89 
90  //Open DATA OUT endpoint
91  USBD_LL_OpenEP(pdev, RNDIS_DATA_OUT_EP,
92  USBD_EP_TYPE_BULK, RNDIS_DATA_OUT_EP_MPS_FS);
93  }
94 
95  //Open notification endpoint
96  USBD_LL_OpenEP(pdev, RNDIS_NOTIFICATION_EP,
97  USBD_EP_TYPE_INTR, RNDIS_NOTIFICATION_EP_MPS);
98 
99  //Initialize RNDIS class context
100  rndisInit();
101 
102  //Link the RNDIS class context
103  pdev->pClassData = &rndisContext;
104 
105  //Debug message
106  TRACE_DEBUG("### usbdRndisReceivePacket 000 ###\r\n");
107 
108  //Prepare DATA OUT endpoint for reception
109  USBD_LL_PrepareReceive(pdev, RNDIS_DATA_OUT_EP,
111 
112  //Reception is active
114 
115  //Switch to the RNDIS_BUS_INITIALIZED state
117 
118  //Successful initialization
119  return USBD_OK;
120 }
121 
122 
123 /**
124  * @brief RNDIS class de-initialization
125  * @param[in] pdev Pointer to a USBD_HandleTypeDef structure
126  * @param[in] cfgidx Configuration index
127  * @return Status code
128  **/
129 
130 uint8_t usbdRndisDeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
131 {
132  //Close DATA IN endpoint
133  USBD_LL_CloseEP(pdev, RNDIS_DATA_IN_EP);
134  //Close DATA OUT endpoint
135  USBD_LL_CloseEP(pdev, RNDIS_DATA_OUT_EP);
136  //Close notification endpoint
137  USBD_LL_CloseEP(pdev, RNDIS_NOTIFICATION_EP);
138 
139  //Unlink the RNDIS class context
140  pdev->pClassData = NULL;
141 
142  //Switch to the RNDIS_UNINITIALIZED state
144 
145  //Successful processing
146  return USBD_OK;
147 }
148 
149 
150 /**
151  * @brief Process incoming setup request
152  * @param[in] pdev Pointer to a USBD_HandleTypeDef structure
153  * @param[in] req Pointer to the setup request
154  * @return Status code
155  **/
156 
157 uint8_t usbdRndisSetup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
158 {
159  //Debug message
160  TRACE_DEBUG("USB setup packet received...\r\n");
161  TRACE_DEBUG(" bmRequest = 0x%02" PRIX8 "\r\n", req->bmRequest);
162  TRACE_DEBUG(" bRequest = 0x%02" PRIX8 "\r\n", req->bRequest);
163  TRACE_DEBUG(" wValue = 0x%04" PRIX16 "\r\n", req->wValue);
164  TRACE_DEBUG(" wIndex = 0x%04" PRIX16 "\r\n", req->wIndex);
165  TRACE_DEBUG(" wLength = 0x%04" PRIX16 "\r\n", req->wLength);
166 
167  //Check request type
168  switch(req->bmRequest & USB_REQ_TYPE_MASK)
169  {
170  //Standard request?
171  case USB_REQ_TYPE_STANDARD:
172  //GET INTERFACE request?
173  if(req->bRequest == USB_REQ_GET_INTERFACE)
174  {
175  //A single alternate setting is supported
176  static uint8_t alternateSetting = 0;
177  //Return data back to the host
178  USBD_CtlSendData(pdev, &alternateSetting, 1);
179  }
180  //SET INTERFACE request
181  else if(req->bRequest == USB_REQ_SET_INTERFACE)
182  {
183  //The device only supports a single alternate setting
184  }
185  break;
186  //Class specific request?
187  case USB_REQ_TYPE_CLASS:
188  //Check direction
189  if(req->bmRequest & 0x80)
190  {
191  //GET ENCAPSULATED RESPONSE request?
192  if(req->bRequest == RNDIS_GET_ENCAPSULATED_RESPONSE)
193  {
194  //If for some reason the device receives a GET ENCAPSULATED RESPONSE
195  //and is unable to respond with a valid data on the Control endpoint,
196  //then it should return a one-byte packet set to 0x00, rather than
197  //stalling the Control endpoint
199  {
202  }
203 
204  //Debug message
205  TRACE_DEBUG("Sending encapsulated response (%" PRIuSIZE " bytes)...\r\n", rndisContext.encapsulatedRespLen);
207 
208  //Debug message
209  TRACE_DEBUG("Sending RNDIS message (%" PRIuSIZE " bytes)...\r\n", rndisContext.encapsulatedRespLen);
210  //Dump RNDIS message contents
212 
213  //Return data back to the host
215 
216  //Flush the response buffer
218  }
219  else
220  {
221  //Return data back to the host
222  USBD_CtlSendData(pdev, NULL, 0);
223  }
224  }
225  else
226  {
227  if(req->wLength != 0)
228  {
229  //Save request type
230  rndisContext.CmdOpCode = req->bRequest;
231  rndisContext.CmdLength = req->wLength;
232 
233  //Prepare receiving data on EP0
234  USBD_CtlPrepareRx(pdev, (uint8_t *) rndisContext.data, req->wLength);
235  }
236  }
237  break;
238  //Unknown request?
239  default:
240  break;
241  }
242 
243  //Successful processing
244  return USBD_OK;
245 }
246 
247 
248 /**
249  * @brief Handle data stage (control endpoint)
250  * @param[in] pdev Pointer to a USBD_HandleTypeDef structure
251  * @return Status code
252  **/
253 
254 uint8_t usbdRndisEp0RxReady(USBD_HandleTypeDef *pdev)
255 {
256  //Debug message
257  TRACE_DEBUG(" Data (opcode=0x%02" PRIX8 ", length=%u)\r\n", rndisContext.CmdOpCode, rndisContext.CmdLength);
259 
260  if(rndisContext.CmdOpCode != 0xFF)
261  {
262  //Process RNDIS message
264 
265  rndisContext.CmdOpCode = 0xFF;
266  }
267 
268  //Successful processing
269  return USBD_OK;
270 }
271 
272 
273 /**
274  * @brief DATA IN callback
275  * @param[in] pdev Pointer to a USBD_HandleTypeDef structure
276  * @param[in] epnum Endpoint number
277  * @return Status code
278  **/
279 
280 uint8_t usbdRndisDataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
281 {
282  //DATA IN endpoint?
283  if((epnum & 0x7F) == (RNDIS_DATA_IN_EP & 0x7F))
284  {
285  //Debug message
286  TRACE_DEBUG("########## USB DATA IN EP sent #############\r\n");
287 
288  //The current buffer has been transmitted and is now available for writing
290 
291  //Increment index and wrap around if necessary
293  rndisTxReadIndex = 0;
294 
295  //Check whether the next buffer is ready
297  {
298  //Start transmitting data
299  USBD_LL_Transmit(pdev, RNDIS_DATA_IN_EP,
302  }
303  else
304  {
305  //Suspend transmission
307  }
308 
309  //The transmitter can accept another packet
311  }
312 
313  //Successful processing
314  return USBD_OK;
315 }
316 
317 
318 /**
319  * @brief DATA OUT callback
320  * @param[in] pdev Pointer to a USBD_HandleTypeDef structure
321  * @param[in] epnum Endpoint number
322  * @return Status code
323  **/
324 
325 uint8_t usbdRndisDataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
326 {
327  size_t length;
328  RndisRxBufferDesc *rxBufferDesc;
329 
330  //DATA OUT endpoint?
331  if((epnum & 0x7F) == (RNDIS_DATA_OUT_EP & 0x7F))
332  {
333  //Retrieve the length of the packet
334  length = USBD_LL_GetRxDataSize(pdev, epnum);
335 
336  //Debug message
337  TRACE_DEBUG("Data received on DATA OUT endpoint (%" PRIuSIZE " bytes)\r\n", length);
338 
339  //Make sure the total length is acceptable
341  {
342  //Point to the current buffer descriptor
343  rxBufferDesc = &rndisRxBuffer[rndisRxWriteIndex];
344 
345  //Copy data
346  memcpy(rxBufferDesc->data + rndisContext.rxBufferLen,
348 
349  //Update the length of the RX buffer
351 
352  //Last packet?
354  {
355  //Debug message
356  TRACE_DEBUG("RNDIS Packet message received (%" PRIuSIZE " bytes)...\r\n",
357  rxBufferDesc->length);
358  //Dump RNDIS Packet message contents
359  rndisDumpMsg((RndisMsg *) rxBufferDesc->data, rxBufferDesc->length);
360 
361  //Store the length of the message
362  rxBufferDesc->length = rndisContext.rxBufferLen;
363  //The current buffer is available for reading
364  rxBufferDesc->ready = TRUE;
365 
366  //Increment index and wrap around if necessary
368  rndisRxWriteIndex = 0;
369 
370  //Suspend reception
372 
373  //Set event flag
374  rndisDriverInterface->nicEvent = TRUE;
375  //Notify the TCP/IP stack of the event
377 
378  //Flush RX buffer
380  }
381  else
382  {
383  //Debug message
384  TRACE_DEBUG("### usbdRndisReceivePacket 222 ###\r\n");
385 
386  //Prepare DATA OUT endpoint for reception
387  USBD_LL_PrepareReceive(&USBD_Device, RNDIS_DATA_OUT_EP,
389  }
390  }
391  else
392  {
393  //Flush RX buffer
395 
396  //Debug message
397  TRACE_DEBUG("### usbdRndisReceivePacket 333 ###\r\n");
398 
399  //Prepare DATA OUT endpoint for reception
400  USBD_LL_PrepareReceive(&USBD_Device, RNDIS_DATA_OUT_EP,
402  }
403  }
404 
405  //Successful processing
406  return USBD_OK;
407 }
408 
409 
410 /**
411  * @brief Retrieve configuration descriptor (high speed)
412  * @param[out] length Length of the descriptor, in bytes
413  * @return Pointer to the descriptor
414  **/
415 
417 {
418  //Not implemented
419  *length = 0;
420  return NULL;
421 }
422 
423 
424 /**
425  * @brief Retrieve configuration descriptor (full speed)
426  * @param[out] length Length of the descriptor, in bytes
427  * @return Pointer to the descriptor
428  **/
429 
431 {
432  //Not implemented
433  *length = sizeof(usbdConfigDescriptors);
434  return (uint8_t *) &usbdConfigDescriptors;
435 }
436 
437 
438 /**
439  * @brief Retrieve configuration descriptor (other speed)
440  * @param[out] length Length of the descriptor, in bytes
441  * @return Pointer to the descriptor
442  **/
443 
445 {
446  //Not implemented
447  *length = 0;
448  return NULL;
449 }
450 
451 
452 /**
453  * @brief Retrieve device qualifier descriptor
454  * @param[out] length Length of the descriptor, in bytes
455  * @return Pointer to the descriptor
456  **/
457 
459 {
460  //Not implemented
461  *length = 0;
462  return NULL;
463 }
RNDIS (Remote Network Driver Interface Specification)
const UsbConfigDescriptors usbdConfigDescriptors
USB configuration descriptors.
Definition: usbd_desc.c:87
uint_t rndisTxReadIndex
Definition: rndis_driver.c:40
error_t rndisProcessMsg(const RndisMsg *message, size_t length)
Process incoming RNDIS message.
Definition: rndis.c:99
RX buffer descriptor.
Definition: rndis_driver.h:70
Generic RNDIS message.
Definition: rndis.h:196
bool_t rxState
Definition: rndis.h:459
TCP/IP stack core.
Debugging facilities.
uint8_t usbdRndisDataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
DATA OUT callback.
Definition: usbd_rndis.c:325
USBD_ClassTypeDef usbdRndisClass
RNDIS class callbacks.
Definition: usbd_rndis.c:45
RndisTxBufferDesc rndisTxBuffer[RNDIS_TX_BUFFER_COUNT]
Definition: rndis_driver.c:35
void rndisChangeState(RndisState newState)
Update RNDIS state.
Definition: rndis.c:699
USBD_HandleTypeDef USBD_Device
USB RNDIS class.
NetInterface * rndisDriverInterface
Definition: rndis_driver.c:32
uint8_t CmdOpCode
Definition: rndis.h:467
#define TRUE
Definition: os_port.h:48
uint8_t * usbdRndisGetFullSpeedConfigDesc(uint16_t *length)
Retrieve configuration descriptor (full speed)
Definition: usbd_rndis.c:430
#define RNDIS_DATA_IN_EP_MPS_FS
Definition: usbd_rndis.h:32
uint8_t * usbdRndisGetOtherSpeedConfigDesc(uint16_t *length)
Retrieve configuration descriptor (other speed)
Definition: usbd_rndis.c:444
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: usbd_rndis.c:37
#define RNDIS_GET_ENCAPSULATED_RESPONSE
Definition: usbd_rndis.h:39
uint_t rndisRxWriteIndex
Definition: rndis_driver.c:41
uint8_t encapsulatedResp[RNDIS_MAX_TRANSFER_SIZE]
Definition: rndis.h:463
#define RNDIS_DATA_OUT_EP_MPS_HS
Definition: usbd_rndis.h:35
uint8_t usbdRndisInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
RNDIS class initialization.
Definition: usbd_rndis.c:71
RNDIS driver.
RndisRxBufferDesc rndisRxBuffer[RNDIS_RX_BUFFER_COUNT]
Definition: rndis_driver.c:36
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
#define RNDIS_TX_BUFFER_COUNT
Definition: rndis_driver.h:27
#define RNDIS_DATA_OUT_EP
Definition: usbd_rndis.h:28
RNDIS (Remote Network Driver Interface Specification)
uint8_t usbdRndisEp0RxReady(USBD_HandleTypeDef *pdev)
Handle data stage (control endpoint)
Definition: usbd_rndis.c:254
uint8_t * usbdRndisGetDeviceQualifierDesc(uint16_t *length)
Retrieve device qualifier descriptor.
Definition: usbd_rndis.c:458
uint8_t * usbdRndisGetHighSpeedConfigDesc(uint16_t *length)
Retrieve configuration descriptor (high speed)
Definition: usbd_rndis.c:416
#define RNDIS_MAX_TRANSFER_SIZE
Definition: rndis.h:41
size_t rxBufferLen
Definition: rndis.h:462
#define RNDIS_DATA_OUT_EP_MPS_FS
Definition: usbd_rndis.h:33
uint8_t data[RNDIS_RX_BUFFER_SIZE]
Definition: rndis_driver.h:74
OsEvent netEvent
Definition: net.c:72
uint8_t data[]
Definition: dtls_misc.h:167
#define PRIuSIZE
Definition: compiler_port.h:72
error_t rndisDumpMsg(const RndisMsg *message, size_t length)
Dump RNDIS message for debugging purpose.
Definition: rndis_debug.c:112
#define TRACE_DEBUG(...)
Definition: usbd_rndis.c:35
uint8_t CmdLength
Definition: rndis.h:468
#define RNDIS_RX_BUFFER_COUNT
Definition: rndis_driver.h:41
#define RNDIS_DATA_IN_EP
Definition: usbd_rndis.h:27
uint32_t data[512/4]
Definition: rndis.h:466
uint8_t usbdRndisDataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
DATA IN callback.
Definition: usbd_rndis.c:280
#define RNDIS_NOTIFICATION_EP
Definition: usbd_rndis.h:26
size_t encapsulatedRespLen
Definition: rndis.h:464
void rndisInit(void)
RNDIS core initialization.
Definition: rndis.c:77
RndisContext rndisContext
Definition: rndis.c:42
uint8_t rxBuffer[RNDIS_MAX_TRANSFER_SIZE]
Definition: rndis.h:461
uint8_t usbdRndisDeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
RNDIS class de-initialization.
Definition: usbd_rndis.c:130
uint8_t length
Definition: dtls_misc.h:140
#define RNDIS_NOTIFICATION_EP_MPS
Definition: usbd_rndis.h:31
bool_t txState
Definition: rndis.h:458
#define FALSE
Definition: os_port.h:44
#define RNDIS_DATA_IN_EP_MPS_HS
Definition: usbd_rndis.h:34
uint8_t usbdRndisSetup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
Process incoming setup request.
Definition: usbd_rndis.c:157
USB descriptors.