1/****************************************************************************
2 * drivers/usbdev/rndis.c
3 *
4 *   Copyright (C) 2011-2017 Gregory Nutt. All rights reserved.
5 *   Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
6 *   Authors: Sakari Kapanen <sakari.m.kapanen@gmail.com>,
7 *            Petteri Aimonen <jpa@git.mail.kapsi.fi>
8 *
9 * References:
10 *   [MS-RNDIS]:
11 *     Remote Network Driver Interface Specification (RNDIS) Protocol
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in
21 *    the documentation and/or other materials provided with the
22 *    distribution.
23 * 3. Neither the name NuttX nor the names of its contributors may be
24 *    used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
34 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
35 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 ****************************************************************************/
41/****************************************************************************
42 * Notice of Export Control Law
43 * ===============================================
44 * Huawei LiteOS may be subject to applicable export control laws and regulations,
45 * which might include those applicable to Huawei LiteOS of U.S. and the country in
46 * which you are located.
47 * Import, export and usage of Huawei LiteOS in any manner by you shall be in
48 * compliance with such applicable export control laws and regulations.
49 ****************************************************************************/
50
51/****************************************************************************
52 * Included Files
53 ****************************************************************************/
54
55#include <errno.h>
56#include <string.h>
57#include <stdlib.h>
58#include <stdio.h>
59#include <securec.h>
60
61#include <lwip/netifapi.h>
62#include "rndis_std.h"
63#include "gadget/rndis.h"
64#include "gadget/f_ether.h"
65#include "gadget/composite.h"
66
67/****************************************************************************
68 * Pre-processor definitions
69 ****************************************************************************/
70
71#ifdef LOSCFG_DRIVERS_USB3_DEVICE_CONTROLLER
72#define FRNDIS_MAX_PACKET_SIZE   0x0400
73#else
74#define FRNDIS_MAX_PACKET_SIZE   0x0200
75#endif
76
77#define WORK_AVAILABLE(work) ((work)->work_status == 0)
78typedef uint32_t irqstate_t;
79#define UINFO PRINT_INFO
80
81SPIN_LOCK_INIT(g_rndis_spinlock);
82static inline irqstate_t enter_critical_section(void)
83{
84  irqstate_t flags;
85
86  LOS_SpinLockSave(&g_rndis_spinlock, &flags);
87
88  return flags;
89}
90
91static inline void leave_critical_section(irqstate_t flags)
92{
93  LOS_SpinUnlockRestore(&g_rndis_spinlock, flags);
94}
95
96static pthread_mutex_t rndis_mtx = PTHREAD_MUTEX_INITIALIZER;
97#define NET_LOCK()   (void)pthread_mutex_lock(&rndis_mtx)
98#define NET_UNLOCK() (void)pthread_mutex_unlock(&rndis_mtx)
99
100#define LINK_STATUS_EVENT_MASK    (1)
101
102#define CONFIG_NET_ETH_MTU      (2048)
103#define CONFIG_RNDIS_BULKIN_REQLEN (CONFIG_NET_ETH_MTU + RNDIS_PACKET_HDR_SIZE)
104#define CONFIG_RNDIS_BULKOUT_REQLEN CONFIG_RNDIS_BULKIN_REQLEN
105
106#define RNDIS_CONFIGID          (1)
107#define RNDIS_CONFIGIDNONE      (0)
108
109#define RNDIS_BUFFER_SIZE       CONFIG_NET_ETH_MTU
110
111/****************************************************************************
112 * Private Types
113 ****************************************************************************/
114
115/* This structure describes the internal state of the driver */
116
117struct rndis_dev_s
118{
119  struct los_eth_driver   netdev;        /* Network driver structure */
120  FAR struct usbdev_s     *usbdev;       /* usbdev driver pointer */
121  FAR struct usbdev_ep_s  *epintin;      /* Interrupt IN endpoint structure */
122  FAR struct usbdev_ep_s  *epbulkin;     /* Bulk IN endpoint structure */
123  FAR struct usbdev_ep_s  *epbulkout;    /* Bulk OUT endpoint structure */
124  FAR struct usbdev_req_s *ctrlreq;      /* Pointer to preallocated control request */
125  FAR struct usbdev_req_s *epintin_req;  /* Pointer to preallocated interrupt in endpoint request */
126  FAR struct usbdev_req_s *rdreq;        /* Pointer to Preallocated control endpoint read request */
127  struct list_head reqlist;              /* List of free write request containers */
128
129  void *resp_buf;                        /* Used to store response messages */
130
131  bool epintin_enable;                   /* Interrupt endpoint enable flag */
132  bool epbulkin_enable;                  /* IN endpoint enable flag */
133  bool epbulkout_enable;                 /* OUT endpoint enable flag */
134  struct workqueue_struct *wq;           /* Workqueue for TX and RX */
135  struct work_struct rxwork;             /* Worker for dispatching RX packets */
136  struct work_struct pollwork;           /* TX poll worker */
137
138  uint8_t config;                        /* USB Configuration number */
139  FAR struct usbdev_req_s *net_req;      /* Pointer to request whose buffer is assigned to network */
140  FAR struct usbdev_req_s *rx_req;       /* Pointer request container that holds RX buffer */
141  size_t current_rx_received;            /* Number of bytes of current RX datagram received over USB */
142  size_t current_rx_datagram_size;       /* Total number of bytes of the current RX datagram */
143  size_t current_rx_datagram_offset;     /* Offset of current RX datagram */
144  size_t current_rx_msglen;              /* Length of the entire message to be received */
145  bool rdreq_submitted;                  /* Indicates if the read request is submitted */
146  bool rx_blocked;                       /* Indicates if we can receive packets on bulk in endpoint */
147  bool ctrlreq_has_encap_response;       /* Indicates if ctrlreq buffer holds a response */
148  bool connected;                        /* Connection status indicator */
149  uint32_t rndis_packet_filter;          /* RNDIS packet filter value */
150  uint32_t rndis_host_tx_count;          /* TX packet counter */
151  uint32_t rndis_host_rx_count;          /* RX packet counter */
152  uint8_t host_mac_address[6];           /* Host side MAC address */
153  EVENT_CB_S link_status_event;          /* Network connection event */
154  pthread_t task_id;                     /* Network connection status processing task */
155  atomic_t tx_transferring;              /* Tx transmission flag */
156};
157
158/* The internal version of the class driver */
159
160struct rndis_driver_s
161{
162  struct usbdevclass_driver_s drvr;
163  FAR struct rndis_dev_s      *dev;
164};
165
166/* This is what is allocated */
167
168struct rndis_alloc_s
169{
170  struct rndis_dev_s    dev;
171  struct rndis_driver_s drvr;
172};
173
174/* RNDIS object ID - value pair structure */
175
176struct rndis_oid_value_s
177{
178  uint32_t objid;
179  uint32_t length;
180  uint32_t value;
181  FAR const void *data; /* Data pointer overrides value if non-NULL. */
182};
183
184/****************************************************************************
185 * Private Function Prototypes
186 ****************************************************************************/
187
188/* Netdev driver callbacks */
189
190static int rndis_txavail(FAR struct rndis_dev_s *dev);
191static int rndis_transmit(FAR struct rndis_dev_s *priv);
192static int rndis_txpoll(FAR struct rndis_dev_s *priv);
193
194/* usbclass callbacks */
195
196static int  usbclass_setup(FAR struct usbdevclass_driver_s *driver,
197                           FAR struct usbdev_s *dev,
198                           FAR const struct usb_device_request *ctrl,
199                           FAR uint8_t *dataout, size_t outlen);
200static int  usbclass_bind(FAR struct usbdevclass_driver_s *driver,
201                          FAR struct usbdev_s *dev);
202static int usbclass_unbind(FAR struct usbdevclass_driver_s *driver,
203                           FAR struct usbdev_s *dev);
204static void usbclass_disconnect(FAR struct usbdevclass_driver_s *driver,
205                                FAR struct usbdev_s *dev);
206static int  usbclass_setconfig(FAR struct rndis_dev_s *priv, uint8_t config);
207static void usbclass_resetconfig(FAR struct rndis_dev_s *priv);
208static FAR struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep,
209                                                  uint16_t len);
210static void usbclass_freereq(FAR struct usbdev_ep_s *ep,
211                             FAR struct usbdev_req_s *req);
212
213/****************************************************************************
214 * Private Data
215 ****************************************************************************/
216
217/* USB driver operations */
218
219const struct usbdevclass_driverops_s g_eth_driverops =
220{
221  usbclass_bind,
222  usbclass_unbind,
223  usbclass_setup,
224  usbclass_disconnect,
225  NULL,
226  NULL
227};
228
229struct rndis_hs_function_descriptor g_rndis_hs_func_desc =
230{
231  {
232    .bLength           = sizeof(struct usb_interface_assoc_descriptor),
233    .bDescriptorType   = 0x0b,
234    .bInterfaceCount   = 0x02,
235    .bFunctionClass    = 0x02,
236    .bFunctionSubClass = 0x06,
237    .bFunctionProtocol = 0,
238    .iFunction         = 6,
239  },
240  {
241    .bLength            = sizeof(struct usb_interface_descriptor),
242    .bDescriptorType    = UDESC_INTERFACE,
243    .bAlternateSetting  = 0,
244    .bNumEndpoints      = 1,    /* Endpoints Num */
245    .bInterfaceClass    = UDCLASS_COMM,
246    .bInterfaceSubClass = UICLASS_CDC,
247    .bInterfaceProtocol = UIPROTO_DATA_VENDOR,
248    .iInterface         = 0x04
249  },
250  {
251    .bLength            = sizeof(struct usb_cdc_header_desc),
252    .bDescriptorType    = 0x24,
253    .bDescriptorSubType = 0,
254    HSETW(.bcdCDC, 0x0110),
255  },
256  {
257    .bLength            = sizeof(struct usb_cdc_call_mgmt_descriptor),
258    .bDescriptorType    = 0x24,
259    .bDescriptorSubType = 0x01,
260    .bmCapabilities     = 0,
261    .bDataInterface     = 0x01, /* data-interfac */
262  },
263  {
264    .bLength            = sizeof(struct usb_cdc_acm_descriptor),
265    .bDescriptorType    = 0x24,
266    .bDescriptorSubType = 0x02,
267    .bmCapabilities     = 0,
268  },
269  {
270    .bLength            = sizeof(struct usb_cdc_union_desc),
271    .bDescriptorType    = 0x24,
272    .bDescriptorSubType = 0x06,
273  },
274  {
275    .bLength            = sizeof(struct usb_endpoint_descriptor),
276    .bDescriptorType    = UDESC_ENDPOINT,
277    .bEndpointAddress   = UE_DIR_IN,
278    .bmAttributes       = UE_INTERRUPT,
279    HSETW(.wMaxPacketSize, 0x0008),
280    .bInterval          = 9,
281  },
282#ifdef LOSCFG_DRIVERS_USB3_DEVICE_CONTROLLER
283  {
284    .bLength         = 6,
285    .bDescriptorType = 0x30,
286    .bMaxBurst       = 0,
287    .bmAttributes    = 0,
288    HSETW(.wBytesPerInterval, 0x0008),
289  },
290#endif
291  {
292    .bLength             = sizeof(struct usb_interface_descriptor),
293    .bDescriptorType     = UDESC_INTERFACE,
294    .bAlternateSetting   = 0,
295    .bNumEndpoints       = 2,   /* Endpoints Num */
296    .bInterfaceClass     = UICLASS_CDC_DATA,
297    .bInterfaceSubClass  = 0,   /* interface subclass */
298    .bInterfaceProtocol  = 0,   /* interface protocol */
299    .iInterface          = 5,
300  },
301  {
302    .bLength          = sizeof(struct usb_endpoint_descriptor),
303    .bDescriptorType  = UDESC_ENDPOINT,
304    .bEndpointAddress = UE_DIR_IN,
305    .bmAttributes     = UE_BULK,
306    HSETW(.wMaxPacketSize, FRNDIS_MAX_PACKET_SIZE),
307    .bInterval        = 0,
308  },
309#ifdef LOSCFG_DRIVERS_USB3_DEVICE_CONTROLLER
310  {
311    .bLength            = 6,
312    .bDescriptorType    = 0x30,
313    .bMaxBurst          = 0,
314    .bmAttributes       = 0,
315    .wBytesPerInterval  = {0x00}
316  },
317#endif
318  {
319    .bLength             = sizeof(struct usb_endpoint_descriptor),
320    .bDescriptorType     = UDESC_ENDPOINT,
321    .bEndpointAddress    = UE_DIR_OUT,
322    .bmAttributes        = UE_BULK,
323    HSETW(.wMaxPacketSize, FRNDIS_MAX_PACKET_SIZE),
324    .bInterval           = 0,
325  },
326#ifdef LOSCFG_DRIVERS_USB3_DEVICE_CONTROLLER
327  {
328    .bLength            = 6,
329    .bDescriptorType    = 0x30,
330    .bMaxBurst          = 0,
331    .bmAttributes       = 0,
332    .wBytesPerInterval  = {0x00}
333  },
334#endif
335};
336
337struct usb_config_descriptor g_rndis_hs_config_desc =
338{
339  .bLength             = USB_CONFIG_DESC_SIZE,
340  .bDescriptorType     = UDESC_CONFIG,
341  HSETW(.wTotalLength, USB_CONFIG_DESC_SIZE + sizeof(g_rndis_hs_func_desc)),
342  .bNumInterface       = 2,
343  .bConfigurationValue = 1,
344  .iConfiguration      = 0,
345  .bmAttributes        = UC_SELF_POWERED | UC_BUS_POWERED,
346  .bMaxPower           = 1, /* max power */
347};
348
349struct rndis_hs_descriptor g_rndis_hs_desc =
350{
351  .rndis_config = &g_rndis_hs_config_desc,
352  .rndis_func   = &g_rndis_hs_func_desc
353};
354
355/* These lists give dummy responses to be returned to PC. The values are
356 * chosen so that Windows is happy - other operating systems don't really care
357 * much.
358 */
359
360static const uint32_t g_rndis_supported_oids[] =
361{
362  RNDIS_OID_GEN_SUPPORTED_LIST,
363  RNDIS_OID_GEN_HARDWARE_STATUS,
364  RNDIS_OID_GEN_MEDIA_SUPPORTED,
365  RNDIS_OID_GEN_MEDIA_IN_USE,
366  RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
367  RNDIS_OID_GEN_LINK_SPEED,
368  RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE,
369  RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE,
370  RNDIS_OID_GEN_VENDOR_ID,
371  RNDIS_OID_GEN_VENDOR_DESCRIPTION,
372  RNDIS_OID_GEN_VENDOR_DRIVER_VERSION,
373  RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
374  RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE,
375  RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
376  RNDIS_OID_GEN_PHYSICAL_MEDIUM,
377  RNDIS_OID_GEN_XMIT_OK,
378  RNDIS_OID_GEN_RCV_OK,
379  RNDIS_OID_GEN_XMIT_ERROR,
380  RNDIS_OID_GEN_RCV_ERROR,
381  RNDIS_OID_GEN_RCV_NO_BUFFER,
382  RNDIS_OID_802_3_PERMANENT_ADDRESS,
383  RNDIS_OID_802_3_CURRENT_ADDRESS,
384  RNDIS_OID_802_3_MULTICAST_LIST,
385  RNDIS_OID_802_3_MAC_OPTIONS,
386  RNDIS_OID_802_3_MAXIMUM_LIST_SIZE,
387  RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT,
388  RNDIS_OID_802_3_XMIT_ONE_COLLISION,
389  RNDIS_OID_802_3_XMIT_MORE_COLLISION,
390};
391
392static const struct rndis_oid_value_s g_rndis_oid_values[] =
393{
394  {RNDIS_OID_GEN_SUPPORTED_LIST, sizeof(g_rndis_supported_oids), 0, g_rndis_supported_oids},
395  {RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,    4, CONFIG_NET_ETH_MTU,  NULL},
396#ifdef CONFIG_USBDEV_DUALSPEED
397  {RNDIS_OID_GEN_LINK_SPEED,            4, 100000,              NULL},
398#else
399  {RNDIS_OID_GEN_LINK_SPEED,            4, 2000000,             NULL},
400#endif
401  {RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE,   4, CONFIG_NET_ETH_MTU,  NULL},
402  {RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE,    4, CONFIG_NET_ETH_MTU,  NULL},
403  {RNDIS_OID_GEN_VENDOR_ID,             4, 0x00FFFFFF,          NULL},
404  {RNDIS_OID_GEN_VENDOR_DESCRIPTION,    6, 0,                   "RNDIS"},
405  {RNDIS_OID_GEN_CURRENT_PACKET_FILTER, 4, 0,                   NULL},
406  {RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE,    4, 2048,                NULL},
407  {RNDIS_OID_GEN_XMIT_OK,               4, 0,                   NULL},
408  {RNDIS_OID_GEN_RCV_OK,                4, 0,                   NULL},
409  {RNDIS_OID_802_3_PERMANENT_ADDRESS,   6, 0,                   NULL},
410  {RNDIS_OID_802_3_CURRENT_ADDRESS,     6, 0,                   NULL},
411  {RNDIS_OID_802_3_MULTICAST_LIST,      4, 0xE0000000,          NULL},
412  {RNDIS_OID_802_3_MAXIMUM_LIST_SIZE,   4, 1,                   NULL},
413  {0x0,                                 4, 0,                   NULL}, /* Default fallback */
414};
415
416/****************************************************************************
417 * Private Data
418 ****************************************************************************/
419
420static void link_status_check_func(struct rndis_dev_s *dev)
421{
422  int link_status;
423  struct netif *netif = &dev->netdev.ac_if;
424
425  link_status = dev->connected;
426  if (netif_is_up(netif) && !link_status)
427    {
428      (void)netifapi_netif_set_link_down(netif);
429      (void)netifapi_netif_set_down(netif);
430      dprintf("set usb rndis network link down!\n");
431    }
432  else if (!netif_is_up(netif) && link_status)
433    {
434      (void)netifapi_netif_set_link_up(netif);
435      (void)netifapi_netif_set_up(netif);
436      dprintf("set usb rndis network link up!\n");
437    }
438}
439
440static void link_status_check_thread(UINTPTR para)
441{
442  struct rndis_dev_s *dev = (struct rndis_dev_s *)para;
443
444  for (;;)
445    {
446      (void)LOS_EventRead(&dev->link_status_event, LINK_STATUS_EVENT_MASK, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
447
448      link_status_check_func(dev);
449    }
450}
451
452static void link_status_check_init(struct rndis_dev_s *dev)
453{
454#define LINK_STATUS_TASK_PRI  10
455  uint32_t ret;
456
457  (void)LOS_EventInit(&dev->link_status_event);
458  ret = usb_os_task_creat(&dev->task_id, (TSK_ENTRY_FUNC)link_status_check_thread, LINK_STATUS_TASK_PRI, "USB_Status_Task", (UINTPTR)(dev));
459  if (ret)
460    {
461      (void)LOS_EventDestroy(&dev->link_status_event);
462      return;
463    }
464}
465
466static void link_status_check_deinit(struct rndis_dev_s *dev)
467{
468  (void)usb_os_task_delete(dev->task_id);
469  (void)LOS_EventDestroy(&dev->link_status_event);
470}
471
472static void link_status_change(struct rndis_dev_s *dev)
473{
474  (void)LOS_EventWrite(&dev->link_status_event, LINK_STATUS_EVENT_MASK);
475}
476
477/****************************************************************************
478 * Buffering of data is implemented in the following manner:
479 *
480 * RNDIS driver holds a number of preallocated bulk IN endpoint write
481 * requests along with buffers large enough to hold an Ethernet packet and
482 * the corresponding RNDIS header.
483 *
484 * One of these is always reserved for packet reception - when data arrives
485 * on the bulk OUT endpoint, it is copied to the reserved request buffer.
486 * When the reception of an Ethernet packet is complete, a worker to process
487 * the packet is scheduled and bulk OUT endpoint is set to NAK.
488 *
489 * The processing worker passes the buffer to the network. When the network is
490 * done processing the packet, the buffer might contain data to be sent.
491 * If so, the corresponding write request is queued on the bulk IN endpoint.
492 * The NAK state on bulk OUT endpoint is cleared to allow new packets to
493 * arrive. If there's no data to send, the request is returned to the list of
494 * free requests.
495 *
496 * When a bulk IN write operation is complete, the request is added to the
497 * list of free requests.
498 *
499 ****************************************************************************/
500
501/****************************************************************************
502 * Name: rndis_submit_rdreq
503 *
504 * Description:
505 *   Submits the bulk OUT read request. Takes care not to submit the request
506 *   when the RX packet buffer is already in use.
507 *
508 * Input Parameters:
509 *   priv: pointer to RNDIS device driver structure
510 *
511 * Returned Value:
512 *   The return value of the EP_SUBMIT operation
513 *
514 ****************************************************************************/
515
516static int rndis_submit_rdreq(FAR struct rndis_dev_s *priv)
517{
518  int ret = OK;
519
520  if (!priv->rdreq_submitted && !priv->rx_blocked)
521    {
522      priv->rdreq->len            = CONFIG_RNDIS_BULKOUT_REQLEN;
523      priv->epbulkout->handle_req = priv->rdreq;
524
525      ret = EP_SUBMIT(priv->epbulkout, priv->rdreq);
526      if (ret != OK)
527        {
528          usb_err("%s %d, len:%u\n", __FUNCTION__, __LINE__, priv->rdreq->len);
529        }
530      else
531        {
532          priv->rdreq_submitted = true;
533        }
534    }
535
536  return ret;
537}
538
539/****************************************************************************
540 * Name: rndis_cancel_rdreq
541 *
542 * Description:
543 *   Cancels the bulk OUT endpoint read request.
544 *
545 * Input Parameters:
546 *   priv: pointer to RNDIS device driver structure
547 *
548 ****************************************************************************/
549
550static void rndis_cancel_rdreq(FAR struct rndis_dev_s *priv)
551{
552  if (priv->rdreq_submitted)
553    {
554      EP_CANCEL(priv->epbulkout, priv->rdreq);
555      priv->rdreq_submitted = false;
556    }
557}
558
559/****************************************************************************
560 * Name: rndis_block_rx
561 *
562 * Description:
563 *   Blocks reception of further bulk OUT endpoint data.
564 *
565 * Input Parameters:
566 *   priv: pointer to RNDIS device driver structure
567 *
568 ****************************************************************************/
569
570static void rndis_block_rx(FAR struct rndis_dev_s *priv)
571{
572  priv->rx_blocked = true;
573  rndis_cancel_rdreq(priv);
574}
575
576/****************************************************************************
577 * Name: rndis_unblock_rx
578 *
579 * Description:
580 *   Unblocks reception of bulk OUT endpoint data.
581 *
582 * Input Parameters:
583 *   priv: pointer to RNDIS device driver structure
584 *
585 * Assumptions:
586 *   Called from critical section
587 *
588 ****************************************************************************/
589
590static void rndis_unblock_rx(FAR struct rndis_dev_s *priv)
591{
592  priv->rx_blocked = false;
593}
594
595/****************************************************************************
596 * Name: rndis_allocwrreq
597 *
598 * Description:
599 *   Allocates a bulk IN endpoint request from the list of free request
600 *   buffers.
601 *
602 * Input Parameters:
603 *   priv: pointer to RNDIS device driver structure
604 *
605 * Returned Value:
606 *   NULL if allocation failed; pointer to allocated request if succeeded
607 *
608 * Assumptions:
609 *   Called from critical section
610 *
611 ****************************************************************************/
612
613static FAR struct usbdev_req_s *rndis_allocwrreq(FAR struct rndis_dev_s *priv)
614{
615  struct usbdev_req_s *req;
616
617  req = usbclass_allocreq(priv->epbulkin, CONFIG_RNDIS_BULKIN_REQLEN);
618  if (req == NULL)
619    {
620      return NULL;
621    }
622
623  return req;
624}
625
626/****************************************************************************
627 * Name: rndis_hasfreereqs
628 *
629 * Description:
630 *   Checks if there are free requests usable for TX data.
631 *
632 * Input Parameters:
633 *   priv: pointer to RNDIS device driver structure
634 *
635 * Returned Value:
636 *   true if requests available; false if no requests available
637 *
638 * Assumptions:
639 *   Called from critical section
640 *
641 ****************************************************************************/
642
643static bool rndis_hasfreereqs(FAR struct rndis_dev_s *priv)
644{
645  return list_empty(&priv->reqlist) ? true : false;
646}
647
648/****************************************************************************
649 * Name: rndis_freewrreq
650 *
651 * Description:
652 *   Returns a bulk IN endpoint write requests to the list of free requests.
653 *
654 * Input Parameters:
655 *   priv: pointer to RNDIS device driver structure
656 *   req: pointer to the request
657 *
658 * Assumptions:
659 *   Called with interrupts disabled.
660 *
661 ****************************************************************************/
662
663static void rndis_freewrreq(FAR struct rndis_dev_s *priv,
664                            FAR struct usbdev_req_s *req)
665{
666  DEBUGASSERT(req != NULL);
667
668  usbclass_freereq(priv->epbulkin, req);
669  rndis_submit_rdreq(priv);
670}
671
672/****************************************************************************
673 * Name: rndis_allocnetreq
674 *
675 * Description:
676 *   Allocates a request buffer to be used on the network.
677 *
678 * Input Parameters:
679 *   priv: pointer to RNDIS device driver structure
680 *
681 * Returned Value:
682 *   true if succeeded; false if failed
683 *
684 * Assumptions:
685 *   Caller holds the network lock
686 *
687 ****************************************************************************/
688
689static bool rndis_allocnetreq(FAR struct rndis_dev_s *priv)
690{
691  irqstate_t flags = enter_critical_section();
692
693  if (rndis_hasfreereqs(priv))
694    {
695      leave_critical_section(flags);
696      return false;
697    }
698
699  if (atomic_read(&priv->tx_transferring))
700    {
701      leave_critical_section(flags);
702      return false;
703    }
704
705  priv->net_req = list_first_entry(&priv->reqlist, struct usbdev_req_s, list);
706  list_del_init(&priv->net_req->list);
707
708  atomic_set(&priv->tx_transferring, 1);
709  leave_critical_section(flags);
710  return priv->net_req != NULL;
711}
712
713/****************************************************************************
714 * Name: rndis_sendnetreq
715 *
716 * Description:
717 *   Submits the request buffer held by the network.
718 *
719 * Input Parameters:
720 *   priv: pointer to RNDIS device driver structure
721 *
722 * Assumptions:
723 *   Caller holds the network lock
724 *
725 ****************************************************************************/
726
727static void rndis_sendnetreq(FAR struct rndis_dev_s *priv)
728{
729  irqstate_t flags = enter_critical_section();
730
731  DEBUGASSERT(priv->net_req != NULL);
732
733  priv->net_req->priv = priv->net_req;
734  priv->epbulkin->handle_req = priv->net_req;
735  EP_SUBMIT(priv->epbulkin, priv->net_req);
736
737  priv->net_req = NULL;
738
739  leave_critical_section(flags);
740}
741
742/****************************************************************************
743 * Name: rndis_freenetreq
744 *
745 * Description:
746 *   Frees the request buffer held by the network.
747 *
748 * Input Parameters:
749 *   priv: pointer to RNDIS device driver structure
750 *
751 * Assumptions:
752 *   Caller holds the network lock
753 *
754 ****************************************************************************/
755
756static void rndis_freenetreq(FAR struct rndis_dev_s *priv)
757{
758  irqstate_t flags = enter_critical_section();
759
760  rndis_freewrreq(priv, priv->net_req);
761  priv->net_req = NULL;
762
763  leave_critical_section(flags);
764}
765
766/****************************************************************************
767 * Name: rndis_allocrxreq
768 *
769 * Description:
770 *   Allocates a buffer for packet reception if there already isn't one.
771 *
772 * Input Parameters:
773 *   priv: pointer to RNDIS device driver structure
774 *
775 * Returned Value:
776 *   true if succeeded; false if failed
777 *
778 * Assumptions:
779 *   Called from critical section
780 *
781 ****************************************************************************/
782
783static bool rndis_allocrxreq(FAR struct rndis_dev_s *priv)
784{
785  if (priv->rx_req != NULL)
786    {
787      return true;
788    }
789
790  priv->rx_req = rndis_allocwrreq(priv);
791  return priv->rx_req != NULL;
792}
793
794/****************************************************************************
795 * Name: rndis_giverxreq
796 *
797 * Description:
798 *   Passes the RX packet buffer to the network
799 *
800 * Input Parameters:
801 *   priv: pointer to RNDIS device driver structure
802 *
803 * Assumptions:
804 *   Caller holds the network lock
805 *
806 ****************************************************************************/
807
808static void rndis_giverxreq(FAR struct rndis_dev_s *priv)
809{
810  DEBUGASSERT(priv->rx_req != NULL);
811  DEBUGASSERT(priv->net_req == NULL);
812
813  priv->net_req = priv->rx_req;
814  priv->rx_req  = NULL;
815}
816
817/****************************************************************************
818 * Name: rndis_fillrequest
819 *
820 * Description:
821 *   Fills the RNDIS header to the request buffer
822 *
823 * Input Parameters:
824 *   priv: pointer to RNDIS device driver structure
825 *   req: the request whose buffer we should fill
826 *
827 * Returned Value:
828 *   The total length of the request data
829 *
830 * Assumptions:
831 *   Caller holds the network lock
832 *
833 ****************************************************************************/
834
835static uint16_t rndis_fillrequest(FAR struct rndis_dev_s *priv,
836                                  FAR struct usbdev_req_s *req)
837{
838  size_t datalen = req->len - RNDIS_PACKET_HDR_SIZE;
839
840  if (datalen > 0)
841    {
842      /* Send the required headers */
843
844      FAR struct rndis_packet_msg *msg = (FAR struct rndis_packet_msg *)req->buf;
845      (void)memset_s(msg, RNDIS_PACKET_HDR_SIZE, 0, RNDIS_PACKET_HDR_SIZE);
846
847      msg->msgtype    = RNDIS_PACKET_MSG;
848      msg->msglen     = RNDIS_PACKET_HDR_SIZE + datalen;
849      msg->dataoffset = RNDIS_PACKET_HDR_SIZE - 8;
850      msg->datalen    = datalen;
851
852      req->flags      = USBDEV_REQFLAGS_NULLPKT;
853    }
854
855  return req->len;
856}
857
858/****************************************************************************
859 * Name: rndis_rxdispatch
860 *
861 * Description:
862 *   Processes the received Ethernet packet. Called from work queue.
863 *
864 * Input Parameters:
865 *   arg: pointer to RNDIS device driver structure
866 *
867 ****************************************************************************/
868
869static void rndis_rxdispatch(FAR struct work_struct *arg)
870{
871  FAR struct rndis_dev_s *priv = (FAR struct rndis_dev_s *)arg->data;
872  irqstate_t flags;
873
874  NET_LOCK();
875  flags = enter_critical_section();
876  rndis_giverxreq(priv);
877  leave_critical_section(flags);
878
879  if (priv->net_req == NULL)
880    {
881      return;
882    }
883
884  eth_rx(&priv->netdev, priv->net_req);
885
886  priv->current_rx_datagram_size = 0;
887  rndis_unblock_rx(priv);
888
889  rndis_freenetreq(priv);
890  NET_UNLOCK();
891}
892
893/****************************************************************************
894 * Name: rndis_txpoll
895 *
896 * Description:
897 *   Sends the packet that is stored in the network packet buffer. Called
898 *   from work queue by e.g. txavail and txpoll callbacks.
899 *
900 * Input Parameters:
901 *   dev: pointer to network driver structure
902 *
903 * Assumptions:
904 *   Caller holds the network lock
905 *
906 ****************************************************************************/
907
908static int rndis_txpoll(FAR struct rndis_dev_s *priv)
909{
910  int ret = OK;
911
912  if (!priv->connected)
913    {
914      return -EBUSY;
915    }
916
917  if (priv->net_req->len > 0)
918    {
919      ret = rndis_transmit(priv);
920    }
921
922  /* If zero is returned, the polling will continue until all connections have
923   * been examined.
924   */
925
926  return ret;
927}
928
929/****************************************************************************
930 * Name: rndis_transmit
931 *
932 * Description:
933 *   Start hardware transmission.
934 *
935 ****************************************************************************/
936
937static int rndis_transmit(FAR struct rndis_dev_s *priv)
938{
939  /* Queue the packet */
940
941  rndis_fillrequest(priv, priv->net_req);
942  rndis_sendnetreq(priv);
943
944  return OK;
945}
946
947/****************************************************************************
948 * Name: rndis_txavail_work
949 *
950 * Description:
951 *   txavail worker function
952 *
953 ****************************************************************************/
954
955static void rndis_txavail_work(FAR struct work_struct *arg)
956{
957  FAR struct rndis_dev_s *priv = (FAR struct rndis_dev_s *)arg->data;
958
959  NET_LOCK();
960
961  if (rndis_allocnetreq(priv))
962    {
963      rndis_txpoll(priv);
964    }
965
966  NET_UNLOCK();
967}
968
969/****************************************************************************
970 * Name: rndis_txavail
971 *
972 * Description:
973 *   Network txavail callback that's called when there are buffers available
974 *   for sending data. May be called from an interrupt, so we must queue a
975 *   worker to do the actual processing.
976 *
977 ****************************************************************************/
978
979static int rndis_txavail(FAR struct rndis_dev_s *priv)
980{
981  bool ret;
982
983  if (WORK_AVAILABLE(&priv->pollwork))
984    {
985      ret = queue_work(priv->wq, &priv->pollwork);
986      if (ret == false) {
987          usb_err("queue work failed!\n");
988      }
989    }
990
991  return OK;
992}
993
994/************************************************************************************
995 * Name: rndis_recvpacket
996 *
997 * Description:
998 *   Handles a USB packet arriving on the data bulk out endpoint.
999 *
1000 * Assumptions:
1001 *   Called from the USB interrupt handler with interrupts disabled.
1002 *
1003 ************************************************************************************/
1004
1005static inline int rndis_recvpacket(FAR struct rndis_dev_s *priv,
1006                                   FAR uint8_t *reqbuf, uint16_t reqlen)
1007{
1008  int ret;
1009
1010  if (!rndis_allocrxreq(priv))
1011    {
1012      return -ENOMEM;
1013    }
1014
1015  if (!priv->connected)
1016    {
1017      return -EBUSY;
1018    }
1019
1020  if (!priv->current_rx_datagram_size)
1021    {
1022      if (reqlen < 16)
1023        {
1024          /* Packet too small to contain a message header */
1025        }
1026      else
1027        {
1028          /* The packet contains a RNDIS packet message header */
1029
1030          FAR struct rndis_packet_msg *msg = (FAR struct rndis_packet_msg *)reqbuf;
1031          if (msg->msgtype == RNDIS_PACKET_MSG)
1032            {
1033              priv->current_rx_received      = reqlen;
1034              priv->current_rx_datagram_size = msg->datalen;
1035              priv->current_rx_msglen        = msg->msglen;
1036
1037              /* According to RNDIS-over-USB send, if the message length is a
1038               * multiple of endpoint max packet size, the host must send an
1039               * additional single-byte zero packet. Take that in account here.
1040               */
1041
1042              if ((priv->current_rx_msglen % priv->epbulkout->maxpacket) == 0)
1043                {
1044                  priv->current_rx_msglen += 1;
1045                }
1046
1047              /* Data offset is defined as an offset from the beginning of the
1048               * offset field itself
1049               */
1050
1051              priv->current_rx_datagram_offset = msg->dataoffset + 8;
1052              if (priv->current_rx_datagram_offset < reqlen)
1053                {
1054                  ret = memcpy_s(&priv->rx_req->buf[RNDIS_PACKET_HDR_SIZE],
1055                                 CONFIG_RNDIS_BULKIN_REQLEN - RNDIS_PACKET_HDR_SIZE,
1056                                 &reqbuf[priv->current_rx_datagram_offset],
1057                                 reqlen - priv->current_rx_datagram_offset);
1058                  if (ret != EOK)
1059                    {
1060                      usb_err("memcpy failed!\n");
1061                      return -ENOMEM;
1062                    }
1063                }
1064            }
1065          else
1066            {
1067              usb_err("Unknown RNDIS message type %u\n", msg->msgtype);
1068            }
1069        }
1070    }
1071  else
1072    {
1073      if (priv->current_rx_received >= priv->current_rx_datagram_offset &&
1074          priv->current_rx_received <= priv->current_rx_datagram_size +
1075          priv->current_rx_datagram_offset)
1076        {
1077          size_t index = priv->current_rx_received - priv->current_rx_datagram_offset;
1078          size_t copysize = min(reqlen, priv->current_rx_datagram_size - index);
1079
1080          /* Check if the received packet exceeds request buffer */
1081
1082          if ((RNDIS_PACKET_HDR_SIZE + index + copysize) <= CONFIG_NET_ETH_MTU)
1083            {
1084              ret = memcpy_s(&priv->rx_req->buf[RNDIS_PACKET_HDR_SIZE + index],
1085                             CONFIG_RNDIS_BULKIN_REQLEN - RNDIS_PACKET_HDR_SIZE - index,
1086                             reqbuf, copysize);
1087              if (ret != EOK)
1088                {
1089                  usb_err("memcpy failed!\n");
1090                  return -ENOMEM;
1091                }
1092            }
1093          else
1094            {
1095              usb_err("The packet exceeds request buffer (reqlen=%u) \n", reqlen);
1096            }
1097        }
1098      priv->current_rx_received += reqlen;
1099    }
1100
1101  if (priv->current_rx_received >= priv->current_rx_msglen)
1102    {
1103      /* Check for a usable packet length (4 added for the CRC) */
1104
1105      if (priv->current_rx_datagram_size > (CONFIG_NET_ETH_MTU + 4) ||
1106          priv->current_rx_datagram_size <= (sizeof(struct eth_hdr) + 4))
1107        {
1108          priv->current_rx_datagram_size = 0;
1109        }
1110      else
1111        {
1112          priv->rx_req->xfrd = priv->current_rx_received;
1113
1114          ret = queue_work(priv->wq, &priv->rxwork);
1115          DEBUGASSERT(ret == 0);
1116          UNUSED(ret);
1117
1118          rndis_block_rx(priv);
1119          priv->rndis_host_tx_count++;
1120          return -EBUSY;
1121        }
1122    }
1123
1124  return OK;
1125}
1126
1127/****************************************************************************
1128 * Name: rndis_prepare_response
1129 *
1130 * Description:
1131 *   Passes the RX packet buffer to the network
1132 *
1133 * Input Parameters:
1134 *   priv: pointer to RNDIS device driver structure
1135 *
1136 * Assumptions:
1137 *   Called from critical section
1138 *
1139 ****************************************************************************/
1140
1141static bool rndis_prepare_response(FAR struct rndis_dev_s *priv, size_t size,
1142                                   FAR struct rndis_command_header *request_hdr)
1143{
1144  FAR struct rndis_response_header *hdr;
1145  priv->resp_buf = malloc(size);
1146  if (!priv->resp_buf)
1147    {
1148      usb_err("malloc fail!\n");
1149      return false;
1150    }
1151
1152  hdr = (FAR struct rndis_response_header *)priv->resp_buf;
1153
1154  hdr->msgtype = request_hdr->msgtype | RNDIS_MSG_COMPLETE;
1155  hdr->msglen  = size;
1156  hdr->reqid   = request_hdr->reqid;
1157  hdr->status  = RNDIS_STATUS_SUCCESS;
1158
1159  priv->ctrlreq_has_encap_response = true;
1160
1161  return true;
1162}
1163
1164/****************************************************************************
1165 * Name: rndis_send_encapsulated_response
1166 *
1167 * Description:
1168 *   Give a notification to the host that there is an encapsulated response
1169 *   available.
1170 *
1171 * Input Parameters:
1172 *   priv: pointer to RNDIS device driver structure
1173 *
1174 * Assumptions:
1175 *   Called from critical section
1176 *
1177 ****************************************************************************/
1178
1179static int rndis_send_encapsulated_response(FAR struct rndis_dev_s *priv)
1180{
1181  FAR struct rndis_notification *notif =
1182    (FAR struct rndis_notification *)priv->epintin_req->buf;
1183
1184  notif->notification       = RNDIS_NOTIFICATION_RESPONSE_AVAILABLE;
1185  notif->reserved           = 0;
1186  priv->epintin_req->len    = sizeof(struct rndis_notification);
1187  priv->epintin->handle_req = priv->epintin_req;
1188
1189  EP_SUBMIT(priv->epintin, priv->epintin_req);
1190
1191  return OK;
1192}
1193
1194/****************************************************************************
1195 * Name: rndis_handle_control_message
1196 *
1197 * Description:
1198 *   Handle a RNDIS control message.
1199 *
1200 * Input Parameters:
1201 *   ctrlreq: pointer to RNDIS control request
1202 *
1203 * Assumptions:
1204 *   Called from critical section
1205 *
1206 ****************************************************************************/
1207
1208static void rndis_handle_control_message(struct usbdev_ep_s *ep, struct usbdev_req_s *ctrlreq)
1209{
1210  FAR struct rndis_dev_s *priv = (struct rndis_dev_s *)ctrlreq->priv;
1211  FAR struct rndis_command_header *cmd_hdr =
1212    (FAR struct rndis_command_header *)ctrlreq->buf;
1213  int ret;
1214  bool resp_flag;
1215
1216  (void)ep;
1217
1218  switch (cmd_hdr->msgtype)
1219    {
1220      case RNDIS_INITIALIZE_MSG:
1221        {
1222          UINFO("rndis initialize msg!\n");
1223          FAR struct rndis_initialize_cmplt *resp;
1224
1225          resp_flag = rndis_prepare_response(priv, sizeof(struct rndis_initialize_cmplt), cmd_hdr);
1226          if (!resp_flag)
1227            {
1228              return;
1229            }
1230
1231          resp = (FAR struct rndis_initialize_cmplt *)priv->resp_buf;
1232
1233          resp->major      = RNDIS_MAJOR_VERSION;
1234          resp->minor      = RNDIS_MINOR_VERSION;
1235          resp->devflags   = RNDIS_DEVICEFLAGS;
1236          resp->medium     = RNDIS_MEDIUM_802_3;
1237          resp->pktperxfer = 1;
1238          resp->xfrsize    = (4 + 44 + 22) + RNDIS_BUFFER_SIZE;
1239          resp->pktalign   = 2;
1240
1241          rndis_send_encapsulated_response(priv);
1242        }
1243        break;
1244
1245      case RNDIS_HALT_MSG:
1246        {
1247          UINFO("rndis halt msg disconnect!\n");
1248          priv->connected = false;
1249        }
1250        break;
1251
1252      case RNDIS_QUERY_MSG:
1253        {
1254          int i;
1255          size_t max_reply_size = sizeof(struct rndis_query_cmplt) +
1256                                  sizeof(g_rndis_supported_oids);
1257          FAR struct rndis_query_msg req;
1258          ret = memcpy_s(&req, sizeof(struct rndis_query_msg), ctrlreq->buf, sizeof(struct rndis_query_msg));
1259          if (ret != EOK)
1260            {
1261              usb_err("memcpy failed!\n");
1262              return;
1263            }
1264
1265          resp_flag = rndis_prepare_response(priv, max_reply_size, cmd_hdr);
1266          if (!resp_flag)
1267            {
1268              return;
1269            }
1270
1271          FAR struct rndis_query_cmplt *resp =
1272            (FAR struct rndis_query_cmplt *)priv->resp_buf;
1273
1274          resp->hdr.msglen = sizeof(struct rndis_query_cmplt);
1275          resp->bufoffset  = 0;
1276          resp->buflen     = 0;
1277          resp->hdr.status = RNDIS_STATUS_NOT_SUPPORTED;
1278
1279          for (i = 0;
1280               i < sizeof(g_rndis_oid_values)/sizeof(g_rndis_oid_values[0]);
1281               i++)
1282            {
1283              bool match = (g_rndis_oid_values[i].objid == req.objid);
1284
1285              if (!match && g_rndis_oid_values[i].objid == 0)
1286                {
1287                  int j;
1288
1289                  /* Check whether to apply the fallback entry */
1290
1291                  for (j = 0; j < sizeof(g_rndis_supported_oids)/sizeof(uint32_t); j++)
1292                    {
1293                      if (g_rndis_supported_oids[j] == req.objid)
1294                        {
1295                          match = true;
1296                          break;
1297                        }
1298                    }
1299                }
1300
1301              if (match)
1302                {
1303                  resp->hdr.status = RNDIS_STATUS_SUCCESS;
1304                  resp->bufoffset  = 16;
1305                  resp->buflen     = g_rndis_oid_values[i].length;
1306
1307                  if (req.objid == RNDIS_OID_GEN_CURRENT_PACKET_FILTER)
1308                    {
1309                      resp->buffer[0] = priv->rndis_packet_filter;
1310                    }
1311                  else if (req.objid == RNDIS_OID_GEN_XMIT_OK)
1312                    {
1313                      resp->buffer[0] = priv->rndis_host_tx_count;
1314                    }
1315                  else if (req.objid == RNDIS_OID_GEN_RCV_OK)
1316                    {
1317                      resp->buffer[0] = priv->rndis_host_rx_count;
1318                    }
1319                  else if (req.objid == RNDIS_OID_802_3_CURRENT_ADDRESS ||
1320                           req.objid == RNDIS_OID_802_3_PERMANENT_ADDRESS)
1321                    {
1322                      ret = memcpy_s(resp->buffer, USB_COMP_EP0_BUFSIZ - sizeof(struct rndis_query_cmplt),
1323                                     priv->host_mac_address, 6);
1324                      if (ret != EOK)
1325                        {
1326                          usb_err("memcpy failed!\n");
1327                          return;
1328                        }
1329                    }
1330                  else if (g_rndis_oid_values[i].data)
1331                    {
1332                      ret = memcpy_s(resp->buffer, USB_COMP_EP0_BUFSIZ - sizeof(struct rndis_query_cmplt),
1333                                     g_rndis_oid_values[i].data, resp->buflen);
1334                      if (ret != EOK)
1335                        {
1336                          usb_err("memcpy failed!\n");
1337                          return;
1338                        }
1339                    }
1340                  else
1341                    {
1342                      ret = memcpy_s(resp->buffer, USB_COMP_EP0_BUFSIZ - sizeof(struct rndis_query_cmplt),
1343                                     &g_rndis_oid_values[i].value, resp->buflen);
1344                      if (ret != EOK)
1345                        {
1346                          usb_err("memcpy failed!\n");
1347                          return;
1348                        }
1349                    }
1350                  break;
1351                }
1352            }
1353
1354          resp->hdr.msglen += resp->buflen;
1355
1356          rndis_send_encapsulated_response(priv);
1357        }
1358        break;
1359
1360      case RNDIS_SET_MSG:
1361        {
1362          FAR struct rndis_set_msg *req;
1363          FAR struct rndis_response_header *resp;
1364
1365          req = malloc(USB_DWC_MAX_PACKET_SIZE);
1366          if (!req)
1367            {
1368              usb_err("malloc fail!\n");
1369              return;
1370            }
1371          (void)memcpy_s(req, USB_DWC_MAX_PACKET_SIZE, ctrlreq->buf, USB_DWC_MAX_PACKET_SIZE);
1372
1373          resp_flag = rndis_prepare_response(priv, sizeof(struct rndis_response_header),
1374                                             cmd_hdr);
1375          if (!resp_flag)
1376            {
1377              free(req);
1378              return;
1379            }
1380
1381          resp = (FAR struct rndis_response_header *)priv->resp_buf;
1382
1383          if (req->objid == RNDIS_OID_GEN_CURRENT_PACKET_FILTER)
1384            {
1385              priv->rndis_packet_filter = req->buffer[0];
1386
1387              if (req->buffer[0] == 0)
1388                {
1389                  UINFO("rndis set msg disconnect!\n");
1390                  priv->connected = false;
1391                }
1392              else
1393                {
1394                  UINFO("RNDIS is now connected\n");
1395                  priv->connected = true;
1396                  link_status_change(priv);
1397                }
1398            }
1399          else if (req->objid == RNDIS_OID_802_3_MULTICAST_LIST)
1400            {
1401              UINFO("RNDIS multicast list ignored\n");
1402            }
1403          else
1404            {
1405              resp->status = RNDIS_STATUS_NOT_SUPPORTED;
1406            }
1407
1408          rndis_send_encapsulated_response(priv);
1409          free(req);
1410        }
1411        break;
1412
1413      case RNDIS_RESET_MSG:
1414        {
1415          FAR struct rndis_reset_cmplt *resp;
1416
1417          resp_flag = rndis_prepare_response(priv, sizeof(struct rndis_reset_cmplt),
1418                                             cmd_hdr);
1419          if (!resp_flag)
1420            {
1421              return;
1422            }
1423
1424          resp = (FAR struct rndis_reset_cmplt *)priv->resp_buf;
1425          resp->addreset  = 0;
1426          priv->connected = false;
1427          UINFO("rndis reset msg disconnect!\n");
1428          rndis_send_encapsulated_response(priv);
1429        }
1430        break;
1431
1432      case RNDIS_KEEPALIVE_MSG:
1433        {
1434          UINFO("rndis keepalive msg!\n");
1435          resp_flag = rndis_prepare_response(priv, sizeof(struct rndis_response_header),
1436                                             cmd_hdr);
1437          if (!resp_flag)
1438            {
1439              return;
1440            }
1441
1442          rndis_send_encapsulated_response(priv);
1443        }
1444        break;
1445
1446      default:
1447        usb_err("Unsupported RNDIS control message: %u\n", cmd_hdr->msgtype);
1448    }
1449}
1450
1451/****************************************************************************
1452 * Name: rndis_rdcomplete
1453 *
1454 * Description:
1455 *   Handle completion of read request on the bulk OUT endpoint.
1456 *
1457 ****************************************************************************/
1458
1459static void rndis_rdcomplete(FAR struct usbdev_ep_s *ep,
1460                             FAR struct usbdev_req_s *req)
1461{
1462  FAR struct rndis_dev_s *priv;
1463  irqstate_t flags;
1464  int ret;
1465
1466  /* Sanity check */
1467
1468#ifdef CONFIG_DEBUG_FEATURES
1469  if (!ep || !ep->priv || !req)
1470    {
1471      return;
1472     }
1473#endif
1474
1475  /* Extract references to private data */
1476
1477  priv = (FAR struct rndis_dev_s *)ep->priv;
1478
1479  /* Process the received data unless this is some unusual condition */
1480
1481  ret = OK;
1482
1483  flags = enter_critical_section();
1484  priv->rdreq_submitted = false;
1485
1486  switch (req->result)
1487    {
1488    case 0: /* Normal completion */
1489      ret = rndis_recvpacket(priv, req->buf, (uint16_t)req->xfrd);
1490      DEBUGASSERT(ret != -ENOMEM);
1491      break;
1492
1493    case -ESHUTDOWN: /* Disconnection */
1494      leave_critical_section(flags);
1495      return;
1496
1497    default: /* Some other error occurred */
1498      break;
1499    };
1500
1501  if (ret == OK)
1502    {
1503      rndis_submit_rdreq(priv);
1504    }
1505
1506  leave_critical_section(flags);
1507}
1508
1509/****************************************************************************
1510 * Name: rndis_wrcomplete
1511 *
1512 * Description:
1513 *   Handle completion of write request.  This function probably executes
1514 *   in the context of an interrupt handler.
1515 *
1516 ****************************************************************************/
1517
1518static void rndis_wrcomplete(FAR struct usbdev_ep_s *ep,
1519                             FAR struct usbdev_req_s *req)
1520{
1521  FAR struct rndis_dev_s *priv;
1522  FAR struct usbdev_req_s *req_wr;
1523  irqstate_t flags;
1524
1525  /* Sanity check */
1526
1527#ifdef CONFIG_DEBUG_FEATURES
1528  if (!ep || !ep->priv || !req || !req->priv)
1529    {
1530      return;
1531    }
1532#endif
1533
1534  /* Extract references to our private data */
1535
1536  priv   = (FAR struct rndis_dev_s *)ep->priv;
1537  req_wr = (FAR struct usbdev_req_s *)req->priv;
1538
1539  /* Return the write request to the free list */
1540
1541  flags = enter_critical_section();
1542
1543  switch (req_wr->result)
1544    {
1545    case OK: /* Normal completion */
1546      atomic_set(&priv->tx_transferring, 0);
1547      priv->rndis_host_rx_count++;
1548      break;
1549
1550    case -ESHUTDOWN: /* Disconnection */
1551      break;
1552
1553    default: /* Some other error occurred */
1554      break;
1555    }
1556
1557  rndis_freewrreq(priv, req_wr);
1558  priv->epbulkin->handle_req = NULL;
1559  if (!rndis_hasfreereqs(priv))
1560    {
1561      (void)rndis_txavail(priv);
1562    }
1563
1564  leave_critical_section(flags);
1565}
1566
1567/****************************************************************************
1568 * Name: usbclass_ep0incomplete
1569 *
1570 * Description:
1571 *   Handle completion of EP0 control operations
1572 *
1573 ****************************************************************************/
1574
1575static void usbclass_ep0incomplete(FAR struct usbdev_ep_s *ep,
1576                                   FAR struct usbdev_req_s *req)
1577{
1578  (void)ep;
1579
1580  if (req->result)
1581    {
1582      usb_err("result:%d, xfrd:%u, len:%u\n", req->result, req->xfrd, req->len);
1583    }
1584  else if (req->len > 0)
1585    {
1586      struct rndis_dev_s *priv = (FAR struct rndis_dev_s *)req->priv;
1587      priv->ctrlreq_has_encap_response = false;
1588    }
1589}
1590
1591/****************************************************************************
1592 * Name: usbclass_ep0incomplete
1593 *
1594 * Description:
1595 *   Handle completion of interrupt IN endpoint operations
1596 *
1597 ****************************************************************************/
1598
1599static void usbclass_epintin_complete(FAR struct usbdev_ep_s *ep,
1600                                      FAR struct usbdev_req_s *req)
1601{
1602  if (req->result || req->xfrd != req->len)
1603    {
1604      usb_err("result:%d, xfrd:%u, len:%u\n", req->result, req->xfrd, req->len);
1605    }
1606}
1607
1608/****************************************************************************
1609 * Name: usbclass_freereq
1610 *
1611 * Description:
1612 *   Free a request instance along with its buffer
1613 *
1614 ****************************************************************************/
1615
1616static void usbclass_freereq(FAR struct usbdev_ep_s *ep,
1617                             FAR struct usbdev_req_s *req)
1618{
1619  if (ep != NULL && req != NULL)
1620    {
1621      if (req->buf != NULL)
1622        {
1623          EP_FREEBUFFER(ep, req->buf);
1624        }
1625
1626      EP_FREEREQ(ep, req);
1627    }
1628}
1629
1630/****************************************************************************
1631 * Name: usbclass_allocreq
1632 *
1633 * Description:
1634 *   Allocate a request instance along with its buffer
1635 *
1636 ****************************************************************************/
1637
1638static FAR struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep,
1639                                                  uint16_t len)
1640{
1641  FAR struct usbdev_req_s *req;
1642
1643  req = EP_ALLOCREQ(ep);
1644  if (req != NULL)
1645    {
1646      req->len = len;
1647      req->buf = EP_ALLOCBUFFER(ep, len);
1648
1649      if (req->buf == NULL)
1650        {
1651          EP_FREEREQ(ep, req);
1652          req = NULL;
1653        }
1654    }
1655
1656  return req;
1657}
1658
1659/****************************************************************************
1660 * Name: usbclass_bind
1661 *
1662 * Description:
1663 *   Invoked when the driver is bound to a USB device driver
1664 *
1665 ****************************************************************************/
1666
1667static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
1668                         FAR struct usbdev_s *dev)
1669{
1670  FAR struct rndis_dev_s *priv = ((FAR struct rndis_driver_s *)driver)->dev;
1671  struct composite_devobj_s *devobj;
1672  struct usbdev_devinfo_s *devinfo;
1673  struct composite_dev_s *cdev;
1674  uint16_t reqlen;
1675  int ret;
1676
1677  /* Bind the structures */
1678
1679  priv->usbdev = dev;
1680
1681  cdev = dev->ep0->priv;
1682  if (cdev == NULL)
1683    {
1684      usb_err("rndis eth bind failed!\n");
1685      return -1;
1686    }
1687
1688  devobj = usbclass_devobj_get(cdev, DEV_ETHERNET);
1689  if (devobj == NULL)
1690    {
1691      return -1;
1692    }
1693  devinfo = &devobj->compdesc.devinfo;
1694
1695  /* Preallocate control request */
1696
1697  priv->ctrlreq = cdev->ctrlreq;
1698  if (priv->ctrlreq == NULL)
1699    {
1700      ret = -ENOMEM;
1701      goto errout;
1702    }
1703
1704  /* Pre-allocate all endpoints... the endpoints will not be functional
1705   * until the SET CONFIGURATION request is processed in usbclass_setconfig.
1706   * This is done here because there may be calls to kmm_malloc and the SET
1707   * CONFIGURATION processing probably occurrs within interrupt handling
1708   * logic where kmm_malloc calls will fail.
1709   */
1710
1711  priv->epintin = DEV_ALLOCEP(dev, g_rndis_hs_func_desc.nepd.bEndpointAddress,
1712                              (struct usb_endpoint_descriptor *)&g_rndis_hs_func_desc.nepd);
1713  if (!priv->epintin)
1714    {
1715      ret = -ENODEV;
1716      goto errout;
1717    }
1718  RNDIS_MKEPINTIN(devinfo) = priv->epintin->eplog;
1719  priv->epintin->priv      = priv;
1720  priv->epintin_enable     = false;
1721
1722  priv->epintin_req = usbclass_allocreq(priv->epintin, sizeof(struct rndis_notification));
1723  if (priv->epintin_req == NULL)
1724    {
1725      ret = -ENOMEM;
1726      goto errout;
1727    }
1728
1729  priv->epintin_req->callback = usbclass_epintin_complete;
1730
1731  priv->epbulkin = DEV_ALLOCEP(dev, g_rndis_hs_func_desc.iepd.bEndpointAddress,
1732                               (struct usb_endpoint_descriptor *)&g_rndis_hs_func_desc.iepd);
1733  if (!priv->epbulkin)
1734    {
1735      ret = -ENODEV;
1736      goto errout;
1737    }
1738  RNDIS_MKEPBULKIN(devinfo)  = priv->epbulkin->eplog;
1739  priv->epbulkin->handle_req = NULL;
1740  priv->epbulkin->priv       = priv;
1741  priv->epbulkin_enable      = false;
1742
1743  priv->epbulkout = DEV_ALLOCEP(dev, g_rndis_hs_func_desc.oepd.bEndpointAddress,
1744                                (struct usb_endpoint_descriptor *)&g_rndis_hs_func_desc.oepd);
1745  if (!priv->epbulkout)
1746    {
1747      ret = -ENODEV;
1748      goto errout;
1749    }
1750  RNDIS_MKEPBULKOUT(devinfo) = priv->epbulkout->eplog;
1751  priv->epbulkout->priv      = priv;
1752  priv->epbulkout_enable     = false;
1753
1754  /* Pre-allocate read requests.  The buffer size is one full packet. */
1755
1756  reqlen = 64;
1757  if (CONFIG_RNDIS_BULKOUT_REQLEN > reqlen)
1758    {
1759      reqlen = CONFIG_RNDIS_BULKOUT_REQLEN;
1760    }
1761
1762  priv->rdreq = usbclass_allocreq(priv->epbulkout, reqlen);
1763  if (priv->rdreq == NULL)
1764    {
1765      ret = -ENOMEM;
1766      goto errout;
1767    }
1768
1769  priv->rdreq->callback = rndis_rdcomplete;
1770
1771  g_rndis_hs_func_desc.ifcad.bFirstInterface            = (uint8_t)devinfo->ifnobase;
1772  g_rndis_hs_func_desc.ifcd.bInterfaceNumber            = (uint8_t)devinfo->ifnobase;
1773  g_rndis_hs_func_desc.cdc_union_desc.bMasterInterface0 = (uint8_t)devinfo->ifnobase;
1774
1775  g_rndis_hs_func_desc.ifdd.bInterfaceNumber            = (uint8_t)(devinfo->ifnobase + 1);
1776  g_rndis_hs_func_desc.cdc_union_desc.bSlaveInterface0  = (uint8_t)(devinfo->ifnobase + 1);
1777
1778  /* Report if we are selfpowered */
1779
1780#ifdef CONFIG_USBDEV_SELFPOWERED
1781  DEV_SETSELFPOWERED(dev);
1782#endif
1783
1784  INIT_WORK(&priv->rxwork, rndis_rxdispatch);
1785  priv->rxwork.data = (atomic_long_t)priv;
1786  INIT_WORK(&priv->pollwork, rndis_txavail_work);
1787  priv->pollwork.data = (atomic_long_t)priv;
1788  priv->wq = create_workqueue("rndis workqueue");
1789  if (!priv->wq)
1790    {
1791      ret = -EFAULT;
1792      goto errout;
1793    }
1794
1795  priv->connected = false;
1796  netdev_register(&priv->netdev);
1797
1798  link_status_check_init(priv);
1799
1800  /* And pull-up the data line for the soft connect function */
1801
1802  DEV_CONNECT(dev);
1803  return OK;
1804
1805errout:
1806  (void)usbclass_unbind(driver, dev);
1807  return ret;
1808}
1809
1810/****************************************************************************
1811 * Name: usbclass_unbind
1812 *
1813 * Description:
1814 *    Invoked when the driver is unbound from a USB device driver
1815 *
1816 ****************************************************************************/
1817
1818static int usbclass_unbind(FAR struct usbdevclass_driver_s *driver,
1819                           FAR struct usbdev_s *dev)
1820{
1821  FAR struct rndis_dev_s *priv;
1822
1823#ifdef CONFIG_DEBUG_FEATURES
1824  if (!driver || !dev || !dev->ep0)
1825    {
1826      return -1;
1827    }
1828#endif
1829
1830  /* Extract reference to private data */
1831
1832  priv = ((FAR struct rndis_driver_s *)driver)->dev;
1833
1834#ifdef CONFIG_DEBUG_FEATURES
1835  if (!priv)
1836    {
1837      return -1;
1838    }
1839#endif
1840
1841  /* Make sure that we are not already unbound */
1842
1843  if (priv != NULL)
1844    {
1845      destroy_workqueue(priv->wq);
1846      priv->wq = NULL;
1847
1848      /* Make sure that the endpoints have been unconfigured.  If
1849       * we were terminated gracefully, then the configuration should
1850       * already have been reset.  If not, then calling usbclass_resetconfig
1851       * should cause the endpoints to immediately terminate all
1852       * transfers and return the requests to us (with result == -ESHUTDOWN)
1853       */
1854
1855      usbclass_resetconfig(priv);
1856      mdelay(50);
1857
1858      netdev_unregister(&priv->netdev);
1859
1860      link_status_check_deinit(priv);
1861
1862      /* Free the bulk IN endpoint */
1863
1864      if (priv->epbulkin)
1865        {
1866          DEV_FREEEP(dev, priv->epbulkin);
1867          priv->epbulkin = NULL;
1868        }
1869
1870      /* Free the pre-allocated control request */
1871
1872      if (priv->ctrlreq != NULL)
1873        {
1874          priv->ctrlreq = NULL;
1875        }
1876
1877      if (priv->epintin_req != NULL)
1878        {
1879          usbclass_freereq(priv->epintin, priv->epintin_req);
1880          priv->epintin_req = NULL;
1881        }
1882
1883      /* Free the interrupt IN endpoint */
1884
1885      if (priv->epintin)
1886        {
1887          DEV_FREEEP(dev, priv->epintin);
1888          priv->epintin = NULL;
1889        }
1890
1891      /* Free pre-allocated read requests (which should all have
1892       * been returned to the free list at this time -- we don't check)
1893       */
1894
1895      if (priv->rdreq)
1896        {
1897          usbclass_freereq(priv->epbulkout, priv->rdreq);
1898          priv->rdreq = NULL;
1899        }
1900
1901      /* Free the bulk OUT endpoint */
1902
1903      if (priv->epbulkout)
1904        {
1905          DEV_FREEEP(dev, priv->epbulkout);
1906          priv->epbulkout = NULL;
1907        }
1908    }
1909
1910  return 0;
1911}
1912
1913/****************************************************************************
1914 * Name: usbclass_setup
1915 *
1916 * Description:
1917 *   Invoked for ep0 control requests.  This function probably executes
1918 *   in the context of an interrupt handler.
1919 *
1920 ****************************************************************************/
1921
1922static int usbclass_setup(FAR struct usbdevclass_driver_s *driver,
1923                          FAR struct usbdev_s *dev,
1924                          FAR const struct usb_device_request *ctrl,
1925                          FAR uint8_t *dataout, size_t outlen)
1926{
1927  FAR struct rndis_dev_s *priv;
1928  FAR struct usbdev_req_s *ctrlreq;
1929  uint16_t value;
1930  uint16_t len;
1931  int ret = -EOPNOTSUPP;
1932
1933  (void)dataout;
1934  (void)outlen;
1935
1936#ifdef CONFIG_DEBUG_FEATURES
1937  if (!driver || !dev || !dev->ep0 || !ctrl)
1938    {
1939      return -EIO;
1940     }
1941#endif
1942
1943  /* Extract reference to private data */
1944
1945  priv = ((FAR struct rndis_driver_s *)driver)->dev;
1946
1947#ifdef CONFIG_DEBUG_FEATURES
1948  if (!priv || !priv->ctrlreq || !priv->resp_buf)
1949    {
1950      return -ENODEV;
1951    }
1952#endif
1953  ctrlreq = priv->ctrlreq;
1954
1955  /* Extract the little-endian 16-bit values to host order */
1956
1957  value = UGETW(ctrl->wValue);
1958  len   = UGETW(ctrl->wLength);
1959
1960  switch (ctrl->bmRequestType & USB_TYPE_MASK)
1961    {
1962     /***********************************************************************
1963      * Standard Requests
1964      ***********************************************************************/
1965
1966    case USB_TYPE_STANDARD:
1967      {
1968        switch (ctrl->bRequest)
1969          {
1970          case USB_REQ_SET_CONFIGURATION:
1971          case USB_REQ_SET_INTERFACE:
1972            {
1973              if (ctrl->bmRequestType == 0)
1974                {
1975                  return usbclass_setconfig(priv, value);
1976                }
1977            }
1978            break;
1979
1980          default:
1981            usb_err("Request is not supported!\n");
1982            break;
1983          }
1984      }
1985      break;
1986
1987    /* Class requests */
1988
1989    case USB_TYPE_CLASS:
1990      {
1991        if ((ctrl->bmRequestType & USB_RECIP_MASK) == USB_RECIP_INTERFACE)
1992          {
1993            if (ctrl->bRequest == RNDIS_SEND_ENCAPSULATED_COMMAND)
1994              {
1995                ctrlreq->callback = rndis_handle_control_message;
1996                ctrlreq->priv     = priv;
1997                ret               = len;
1998              }
1999            else if (ctrl->bRequest == RNDIS_GET_ENCAPSULATED_RESPONSE)
2000              {
2001                if (!priv->ctrlreq_has_encap_response)
2002                  {
2003                    ret = 1;
2004                    ctrlreq->buf[0] = 0;
2005                  }
2006                else
2007                  {
2008                    FAR struct rndis_response_header *hdr =
2009                      (FAR struct rndis_response_header *)priv->resp_buf;
2010
2011                    /* Msglen represents the length of the message
2012                     * to be sent to the USB host.
2013                     */
2014
2015                    ret = memcpy_s(ctrlreq->buf, hdr->msglen, priv->resp_buf, hdr->msglen);
2016                    if (ret != EOK)
2017                      {
2018                        usb_err("memcpy failed!\n");
2019                        free(priv->resp_buf);
2020                        priv->resp_buf = NULL;
2021                        return ret;
2022                      }
2023                    ret = hdr->msglen;
2024                    ctrlreq->callback = usbclass_ep0incomplete;
2025                    ctrlreq->priv     = priv;
2026                    free(priv->resp_buf);
2027                    priv->resp_buf = NULL;
2028                  }
2029              }
2030          }
2031      }
2032      break;
2033
2034    default:
2035      break;
2036    }
2037
2038  /* Respond to the setup command if data was returned.  On an error return
2039   * value (ret < 0), the USB driver will stall.
2040   */
2041
2042  if (ret >= 0)
2043    {
2044      ctrlreq->len   = min(len, (uint32_t)ret);
2045      ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT;
2046      ret            = EP_SUBMIT(dev->ep0, ctrlreq);
2047      if (ret < 0)
2048        {
2049          ctrlreq->result = OK;
2050          usbclass_ep0incomplete(dev->ep0, ctrlreq);
2051        }
2052    }
2053
2054  return ret;
2055}
2056
2057/****************************************************************************
2058 * Name: usbclass_disconnect
2059 *
2060 * Description:
2061 *   Invoked after all transfers have been stopped, when the host is
2062 *   disconnected.  This function is probably called from the context of an
2063 *   interrupt handler.
2064 *
2065 ****************************************************************************/
2066
2067static void usbclass_disconnect(FAR struct usbdevclass_driver_s *driver,
2068                                FAR struct usbdev_s *dev)
2069{
2070  FAR struct rndis_dev_s *priv;
2071
2072#ifdef CONFIG_DEBUG_FEATURES
2073  if (!driver || !dev || !dev->ep0)
2074    {
2075      return;
2076     }
2077#endif
2078
2079  /* Extract reference to private data */
2080
2081  priv = ((FAR struct rndis_driver_s *)driver)->dev;
2082
2083#ifdef CONFIG_DEBUG_FEATURES
2084  if (!priv)
2085    {
2086      return;
2087    }
2088#endif
2089
2090  /* Reset the configuration */
2091
2092  usbclass_resetconfig(priv);
2093
2094  /* Perform the soft connect function so that we will we can be
2095   * re-enumerated.
2096   */
2097
2098  DEV_CONNECT(dev);
2099}
2100
2101/****************************************************************************
2102 * Name: usbclass_resetconfig
2103 *
2104 * Description:
2105 *   Mark the device as not configured and disable all endpoints.
2106 *
2107 ****************************************************************************/
2108
2109static void usbclass_resetconfig(FAR struct rndis_dev_s *priv)
2110{
2111  struct usbdev_req_s *req;
2112  irqstate_t flags;
2113
2114  link_status_change(priv);
2115
2116  /* Disable endpoints.  This should force completion of all pending
2117   * transfers.
2118   */
2119
2120  if (priv->epintin_enable == true)
2121    {
2122      EP_DISABLE(priv->epintin);
2123      priv->epintin_enable = false;
2124    }
2125  if (priv->epbulkin_enable == true)
2126    {
2127      EP_DISABLE(priv->epbulkin);
2128      priv->epbulkin_enable = false;
2129    }
2130  if (priv->epbulkout_enable == true)
2131    {
2132      EP_DISABLE(priv->epbulkout);
2133      priv->epbulkout_enable = false;
2134    }
2135
2136  flags = enter_critical_section();
2137
2138  /* Are we configured? */
2139
2140  if (priv->config != RNDIS_CONFIGIDNONE)
2141    {
2142      /* Yes.. but not anymore */
2143
2144      priv->config = RNDIS_CONFIGIDNONE;
2145
2146      priv->connected = false;
2147
2148      if (priv->resp_buf != NULL)
2149        {
2150          free(priv->resp_buf);
2151          priv->resp_buf = NULL;
2152        }
2153
2154      /* Free write requests that are not in use (which should be all
2155       * of them
2156       */
2157
2158      req = priv->epbulkin->handle_req;
2159      if (req != NULL)
2160        {
2161          usbclass_freereq(priv->epbulkin, req);
2162          priv->epbulkin->handle_req = NULL;
2163        }
2164
2165      if (priv->net_req)
2166        {
2167          usbclass_freereq(priv->epbulkout, priv->net_req);
2168          priv->net_req = NULL;
2169        }
2170
2171      if (priv->rx_req)
2172        {
2173          usbclass_freereq(priv->epbulkout, priv->rx_req);
2174          priv->rx_req = NULL;
2175        }
2176
2177      while (!list_empty(&priv->reqlist))
2178        {
2179          req = list_first_entry(&priv->reqlist, struct usbdev_req_s, list);
2180          list_del_init(&req->list);
2181
2182          if (req->priv != NULL)
2183            {
2184              req->priv = NULL;
2185            }
2186          usbclass_freereq(priv->epbulkin, req);
2187        }
2188      atomic_set(&priv->tx_transferring, 0);
2189    }
2190  leave_critical_section(flags);
2191}
2192
2193/****************************************************************************
2194 * Name: usbclass_setconfig
2195 *
2196 * Description:
2197 *   Set the device configuration by allocating and configuring endpoints and
2198 *   by allocating and queue read and write requests.
2199 *
2200 ****************************************************************************/
2201
2202static int usbclass_setconfig(FAR struct rndis_dev_s *priv, uint8_t config)
2203{
2204  struct usbdev_s *dev;
2205  int ret;
2206
2207#ifdef CONFIG_DEBUG_FEATURES
2208  if (priv == NULL)
2209    {
2210      return -EIO;
2211    }
2212#endif
2213
2214  if (config == priv->config)
2215    {
2216      /* Already configured -- Do nothing */
2217
2218      return 0;
2219    }
2220
2221  /* Discard the previous configuration data */
2222
2223  usbclass_resetconfig(priv);
2224
2225  /* Was this a request to simply discard the current configuration? */
2226
2227  if (config == RNDIS_CONFIGIDNONE)
2228    {
2229      return 0;
2230    }
2231
2232  /* We only accept one configuration */
2233
2234  if (config != RNDIS_CONFIGID)
2235    {
2236      return -EINVAL;
2237    }
2238  dev = priv->usbdev;
2239
2240  /* Configure the IN interrupt endpoint */
2241
2242  ret = EP_CONFIGURE(priv->epintin, &g_rndis_hs_func_desc.nepd, false);
2243  if (ret < 0)
2244    {
2245      goto errout;
2246    }
2247
2248  priv->epintin->priv  = priv;
2249  priv->epintin_enable = true;
2250
2251  /* Configure the IN bulk endpoint */
2252
2253  usbd_configep_byspeed(dev, &g_rndis_hs_func_desc.iepd);
2254  ret = EP_CONFIGURE(priv->epbulkin, &g_rndis_hs_func_desc.iepd, false);
2255  if (ret < 0)
2256    {
2257      goto errout;
2258    }
2259
2260  priv->epbulkin->priv  = priv;
2261  priv->epbulkin_enable = true;
2262
2263  /* Configure the OUT bulk endpoint */
2264
2265  usbd_configep_byspeed(dev, &g_rndis_hs_func_desc.oepd);
2266  ret = EP_CONFIGURE(priv->epbulkout, &g_rndis_hs_func_desc.oepd, true);
2267  if (ret < 0)
2268    {
2269      goto errout;
2270    }
2271
2272  priv->epbulkout->priv  = priv;
2273  priv->epbulkout_enable = true;
2274
2275  /* Queue read requests in the bulk OUT endpoint */
2276
2277  priv->rdreq->callback = rndis_rdcomplete;
2278
2279  ret = rndis_submit_rdreq(priv);
2280  if (ret != OK)
2281    {
2282      goto errout;
2283    }
2284
2285  /* We are successfully configured */
2286
2287  priv->config = config;
2288
2289  link_status_change(priv);
2290  return OK;
2291
2292errout:
2293  usbclass_resetconfig(priv);
2294  return ret;
2295}
2296
2297void rndis_tx(struct los_eth_driver *sc, const struct eth_drv_sg *sg_list,
2298              int sg_len, uint32_t total_len, UINTPTR key)
2299{
2300  struct rndis_dev_s *dev = (struct rndis_dev_s *)sc->driver_context;
2301  struct usbdev_req_s *req;
2302  irqstate_t flags;
2303  uint8_t *d_buf;
2304  uint32_t len = 0;
2305  int ret;
2306  int i;
2307
2308  (void)key;
2309
2310  req = usbclass_allocreq(dev->epbulkin, (uint16_t)(total_len + RNDIS_PACKET_HDR_SIZE));
2311  if (req == NULL)
2312    {
2313      usb_err("alloc req failed!\n");
2314      return;
2315    }
2316  req->priv     = req;
2317  req->callback = rndis_wrcomplete;
2318  req->len      = total_len + RNDIS_PACKET_HDR_SIZE;
2319
2320  d_buf = &req->buf[RNDIS_PACKET_HDR_SIZE];
2321  for (i = 0; i < sg_len; i++)
2322    {
2323      ret = memcpy_s((void *)(d_buf + len), total_len - len, (const void *)(sg_list[i].buf), sg_list[i].len);
2324      if (ret != EOK)
2325        {
2326          usb_err("memcpy fail, ret = %d\n", ret);
2327          return;
2328        }
2329      len += sg_list[i].len;
2330    }
2331
2332  flags = enter_critical_section();
2333
2334  if (dev->connected == false)
2335    {
2336      leave_critical_section(flags);
2337      usbclass_freereq(dev->epbulkin, req);
2338      return;
2339    }
2340
2341  list_add_tail(&req->list, &dev->reqlist);
2342
2343  (void)rndis_txavail(dev);
2344  leave_critical_section(flags);
2345}
2346
2347int rndis_classobject(int minor, struct usbdev_devinfo_s *devinfo,
2348                      struct usbdevclass_driver_s **devclass_drvr)
2349{
2350  FAR struct rndis_alloc_s *alloc;
2351  FAR struct rndis_dev_s *priv;
2352  FAR struct rndis_driver_s *drvr;
2353
2354  (void)minor;
2355  (void)devinfo;
2356
2357  /* Allocate the structures needed */
2358
2359  alloc = (FAR struct rndis_alloc_s *)malloc(sizeof(struct rndis_alloc_s));
2360  if (!alloc)
2361    {
2362      return -ENOMEM;
2363    }
2364
2365  /* Convenience pointers into the allocated blob */
2366
2367  priv = &alloc->dev;
2368  drvr = &alloc->drvr;
2369
2370  /* Initialize the USB ethernet driver structure */
2371
2372  (void)memset_s(priv, sizeof(struct rndis_dev_s), 0, sizeof(struct rndis_dev_s));
2373  INIT_LIST_HEAD(&priv->reqlist);
2374  eth_random_addr(priv->host_mac_address);
2375
2376  (void)memset_s(&priv->netdev, sizeof(struct los_eth_driver), 0, sizeof(struct los_eth_driver));
2377  priv->netdev.driver_context = priv;
2378
2379  /* Initialize the USB class driver structure */
2380
2381  drvr->drvr.speed = USB_SPEED_HIGH;
2382  drvr->drvr.ops   = &g_eth_driverops;
2383  drvr->dev        = priv;
2384  *devclass_drvr   = &drvr->drvr;
2385
2386  return 0;
2387}
2388
2389void rndis_uninitialize(struct usbdevclass_driver_s *devclass_drvr)
2390{
2391  struct rndis_driver_s *drvr = (struct rndis_driver_s *)devclass_drvr;
2392  struct rndis_dev_s *priv;
2393  struct rndis_alloc_s *alloc;
2394
2395  if (drvr == NULL)
2396    {
2397      return;
2398    }
2399
2400  priv = drvr->dev;
2401  if (priv == NULL)
2402    {
2403      return;
2404    }
2405
2406  alloc = container_of(drvr, struct rndis_alloc_s, drvr);
2407
2408  free(alloc);
2409}
2410
2411void usbdev_rndis_initialize_sub(struct composite_devdesc_s *dev, int ifnobase, int minor)
2412{
2413  /* Ask the ETH driver to fill in the constants we didn't
2414   * know here.
2415   */
2416
2417  rndis_get_composite_devdesc(dev);
2418
2419  /* Overwrite and correct some values... */
2420  /* The callback functions for the ETH class */
2421
2422  dev->classobject  = rndis_classobject;
2423  dev->uninitialize = rndis_uninitialize;
2424
2425  /* Interfaces */
2426
2427  dev->devinfo.ifnobase = ifnobase;    /* Offset to Interface-IDs */
2428  dev->minor            = minor;       /* The minor interface number */
2429
2430  /* Strings */
2431
2432  dev->devinfo.strbase = 0;            /* Offset to String Numbers */
2433}
2434
2435int usbdev_rndis_initialize(struct module *mod, int n, void *arg)
2436{
2437  struct composite_softc *com_s = (struct composite_softc *)arg;
2438  struct composite_devdesc_s dev;
2439  int ret;
2440
2441  (void)mod;
2442  (void)n;
2443
2444  if (com_s == NULL)
2445    {
2446      PRINTK("  ** Rndis device initialized failed! **\n");
2447      return -1;
2448    }
2449  usbdev_rndis_initialize_sub(&dev, 0, DEV_ETHERNET);
2450
2451  ret = composite_initialize(com_s, 1, &dev);
2452  if (ret < 0)
2453    {
2454      PRINTK("  ** Rndis device initialized failed! **\n");
2455      return -1;
2456    }
2457  PRINTK("  ** Rndis device initialized successfully! **\n");
2458  return 0;
2459}
2460