Jelajahi Sumber

add CDC-ECM/RNDIS/CDC-EEM network device class with example

Peter Lawrence 6 tahun lalu
induk
melakukan
fee79d7466

+ 4 - 1
.gitmodules

@@ -21,4 +21,7 @@
 	url = https://github.com/hathach/microchip_driver.git
 [submodule "hw/mcu/nuvoton"]
 	path = hw/mcu/nuvoton
-	url = https://github.com/majbthrd/nuc_driver.git
+	url = https://github.com/majbthrd/nuc_driver.git
+[submodule "lib/lwip"]
+	path = lib/lwip
+	url = https://git.savannah.nongnu.org/git/lwip.git

+ 57 - 0
examples/device/lwip_webserver/Makefile

@@ -0,0 +1,57 @@
+include ../../../tools/top.mk
+include ../../make.mk
+
+CFLAGS += \
+  -DPBUF_POOL_SIZE=2 \
+  -DTCP_WND=2*TCP_MSS \
+  -DHTTPD_USE_CUSTOM_FSDATA=0
+
+INC += \
+  src \
+  $(TOP)/hw \
+  $(TOP)/lib/lwip/src/include \
+  $(TOP)/lib/lwip/src/include/ipv4 \
+  $(TOP)/lib/lwip/src/include/lwip/apps \
+  $(TOP)/lib/networking
+
+# Example source
+EXAMPLE_SOURCE += $(wildcard src/*.c)
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+SRC_C += \
+  lib/lwip/src/core/altcp.c \
+  lib/lwip/src/core/altcp_alloc.c \
+  lib/lwip/src/core/altcp_tcp.c \
+  lib/lwip/src/core/def.c \
+  lib/lwip/src/core/dns.c \
+  lib/lwip/src/core/inet_chksum.c \
+  lib/lwip/src/core/init.c \
+  lib/lwip/src/core/ip.c \
+  lib/lwip/src/core/mem.c \
+  lib/lwip/src/core/memp.c \
+  lib/lwip/src/core/netif.c \
+  lib/lwip/src/core/pbuf.c \
+  lib/lwip/src/core/raw.c \
+  lib/lwip/src/core/stats.c \
+  lib/lwip/src/core/sys.c \
+  lib/lwip/src/core/tcp.c \
+  lib/lwip/src/core/tcp_in.c \
+  lib/lwip/src/core/tcp_out.c \
+  lib/lwip/src/core/timeouts.c \
+  lib/lwip/src/core/udp.c \
+  lib/lwip/src/core/ipv4/autoip.c \
+  lib/lwip/src/core/ipv4/dhcp.c \
+  lib/lwip/src/core/ipv4/etharp.c \
+  lib/lwip/src/core/ipv4/icmp.c \
+  lib/lwip/src/core/ipv4/igmp.c \
+  lib/lwip/src/core/ipv4/ip4.c \
+  lib/lwip/src/core/ipv4/ip4_addr.c \
+  lib/lwip/src/core/ipv4/ip4_frag.c \
+  lib/lwip/src/netif/ethernet.c \
+  lib/lwip/src/netif/slipif.c \
+  lib/lwip/src/apps/http/httpd.c \
+  lib/lwip/src/apps/http/fs.c \
+  lib/networking/dhserver.c \
+  lib/networking/dnserver.c \
+  lib/networking/rndis_reports.c
+
+include ../../rules.mk

+ 75 - 0
examples/device/lwip_webserver/src/arch/cc.h

@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved. 
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ */
+#ifndef __CC_H__
+#define __CC_H__
+
+//#include "cpu.h"
+
+typedef int sys_prot_t;
+
+
+
+/* define compiler specific symbols */
+#if defined (__ICCARM__)
+
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT 
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+#define PACK_STRUCT_USE_INCLUDES
+
+#elif defined (__CC_ARM)
+
+#define PACK_STRUCT_BEGIN __packed
+#define PACK_STRUCT_STRUCT 
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+
+#elif defined (__GNUC__)
+
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+
+#elif defined (__TASKING__)
+
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_END
+#define PACK_STRUCT_FIELD(x) x
+
+#endif
+
+#define LWIP_PLATFORM_ASSERT(x) do { if(!(x)) while(1); } while(0)
+
+#endif /* __CC_H__ */

+ 57 - 0
examples/device/lwip_webserver/src/lwipopts.h

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved. 
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Simon Goldschmidt
+ *
+ */
+#ifndef __LWIPOPTS_H__
+#define __LWIPOPTS_H__
+
+/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */
+#define NO_SYS                          1
+#define MEM_ALIGNMENT                   4
+#define LWIP_RAW                        1
+#define LWIP_NETCONN                    0
+#define LWIP_SOCKET                     0
+#define LWIP_DHCP                       0
+#define LWIP_ICMP                       1
+#define LWIP_UDP                        1
+#define LWIP_TCP                        1
+#define ETH_PAD_SIZE                    0
+#define LWIP_IP_ACCEPT_UDP_PORT(p)      ((p) == PP_NTOHS(67))
+
+#define TCP_MSS                         (1500 /*mtu*/ - 20 /*iphdr*/ - 20 /*tcphhr*/)
+#define TCP_SND_BUF                     (2 * TCP_MSS)
+
+#define ETHARP_SUPPORT_STATIC_ENTRIES   1
+
+#define LWIP_HTTPD_CGI                  0
+#define LWIP_HTTPD_SSI                  0
+#define LWIP_HTTPD_SSI_INCLUDE_TAG      0
+
+#endif /* __LWIPOPTS_H__ */

+ 214 - 0
examples/device/lwip_webserver/src/main.c

@@ -0,0 +1,214 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Peter Lawrence
+ *
+ * influenced by lrndis https://github.com/fetisov/lrndis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+/*
+depending on the value of CFG_TUD_NET (tusb_config.h), this can be a CDC-ECM, RNDIS, or CDC-EEM USB virtual network adapter
+
+CDC-ECM should be valid on Linux and MacOS hosts
+RNDIS   should be valid on Linux and Windows hosts
+CDC-EEM should be valid on Linux hosts
+
+You *must* customize tusb_config.h to set the CFG_TUD_NET definition to the type of these network adapters to emulate.
+
+The MCU appears to the host as IP address 192.168.7.1, and provides a DHCP server, DNS server, and web server.
+*/
+
+#include "bsp/board.h"
+#include "tusb.h"
+
+#include "dhserver.h"
+#include "dnserver.h"
+#include "lwip/init.h"
+#include "httpd.h"
+
+/* lwip context */
+static struct netif netif_data;
+
+/* shared between network_recv_callback() and service_traffic() */
+static struct pbuf *received_frame;
+
+/* this is used by this code, ./class/net/net_driver.c, and usb_descriptors.c */
+/* ideally speaking, this should be generated from the hardware's unique ID (if available) */
+const uint8_t network_mac_address[6] = {0x20,0x89,0x84,0x6A,0x96,0x00};
+
+/* network parameters of this MCU */
+static const ip_addr_t ipaddr  = IPADDR4_INIT_BYTES(192, 168, 7, 1);
+static const ip_addr_t netmask = IPADDR4_INIT_BYTES(255, 255, 255, 0);
+static const ip_addr_t gateway = IPADDR4_INIT_BYTES(0, 0, 0, 0);
+
+/* database IP addresses that can be offered to the host; this must be in RAM to store assigned MAC addresses */
+static dhcp_entry_t entries[] =
+{
+  /* mac    ip address        subnet mask        lease time */
+  { {0}, {192, 168, 7, 2}, {255, 255, 255, 0}, 24 * 60 * 60 },
+  { {0}, {192, 168, 7, 3}, {255, 255, 255, 0}, 24 * 60 * 60 },
+  { {0}, {192, 168, 7, 4}, {255, 255, 255, 0}, 24 * 60 * 60 }
+};
+
+/* DHCP configuration parameters, leveraging "entries" above */
+static const dhcp_config_t dhcp_config =
+{
+  {192, 168, 7, 1}, 67,    /* server address (self), port */
+  {192, 168, 7, 1},        /* dns server (self) */
+  "usb",                   /* dns suffix */
+  TU_ARRAY_SIZE(entries),  /* number of entries */
+  entries                  /* pointer to entries */
+};
+
+static err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
+{
+  (void)netif;
+
+  for (;;)
+  {
+    /* if TinyUSB isn't ready, we must signal back to lwip that there is nothing we can do */
+    if (!tud_ready())
+      return ERR_USE;
+
+    /* if the network driver can accept another packet, we make it happen */
+    if (network_can_xmit())
+    {
+      network_xmit(p);
+      return ERR_OK;
+    }
+
+    /* transfer execution to TinyUSB in the hopes that it will finish transmitting the prior packet */
+    tud_task();
+  }
+}
+
+static err_t output_fn(struct netif *netif, struct pbuf *p, const ip_addr_t *addr)
+{
+  return etharp_output(netif, p, addr);
+}
+
+static err_t netif_init_cb(struct netif *netif)
+{
+  LWIP_ASSERT("netif != NULL", (netif != NULL));
+  netif->mtu = CFG_TUD_NET_MTU;
+  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
+  netif->state = NULL;
+  netif->name[0] = 'E';
+  netif->name[1] = 'X';
+  netif->linkoutput = linkoutput_fn;
+  netif->output = output_fn;
+  return ERR_OK;
+}
+
+static void init_lwip(void)
+{
+  struct netif *netif = &netif_data;
+
+  lwip_init();
+  netif->hwaddr_len = sizeof(network_mac_address);
+  memcpy(netif->hwaddr, network_mac_address, sizeof(network_mac_address));
+
+  netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, ip_input);
+  netif_set_default(netif);
+}
+
+/* handle any DNS requests from dns-server */
+bool dns_query_proc(const char *name, ip_addr_t *addr)
+{
+  if (0 == strcmp(name, "tiny.usb"))
+  {
+    *addr = ipaddr;
+    return true;
+  }
+  return false;
+}
+
+bool network_recv_callback(struct pbuf *p)
+{
+  /* this shouldn't happen, but if we get another packet before 
+  parsing the previous, we must signal our inability to accept it */
+  if (received_frame) return false;
+
+  /* store away the pointer for service_traffic() to later handle */
+  received_frame = p;
+  return true;
+}
+
+static void service_traffic(void)
+{
+  /* handle any packet received by network_recv_callback() */
+  if (received_frame)
+  {
+    ethernet_input(received_frame, &netif_data);
+    pbuf_free(received_frame);
+    received_frame = NULL;
+    network_recv_renew();
+  }
+}
+
+void network_init_callback(void)
+{
+  /* if the network is re-initializing and we have a leftover packet, we must do a cleanup */
+  if (received_frame)
+  {
+    pbuf_free(received_frame);
+    received_frame = NULL;
+  }
+}
+
+int main(void)
+{
+  /* initialize TinyUSB */
+  board_init();
+  tusb_init();
+
+  /* initialize lwip, dhcp-server, dns-server, and http */
+  init_lwip();
+  while (!netif_is_up(&netif_data));
+  while (dhserv_init(&dhcp_config) != ERR_OK);
+  while (dnserv_init(&ipaddr, 53, dns_query_proc) != ERR_OK);
+  httpd_init();
+
+  while (1)
+  {
+    tud_task();
+    service_traffic();
+  }
+
+  return 0;
+}
+
+/* lwip has provision for using a mutex, when applicable */
+sys_prot_t sys_arch_protect(void)
+{
+  return 0;
+}
+void sys_arch_unprotect(sys_prot_t pval)
+{
+  (void)pval;
+}
+
+/* lwip needs a millisecond time source, and the TinyUSB board support code has one available */
+uint32_t sys_now(void)
+{
+  return board_millis();
+}

+ 90 - 0
examples/device/lwip_webserver/src/tusb_config.h

@@ -0,0 +1,90 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+  #error CFG_TUSB_MCU must be defined
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
+#else
+#define CFG_TUSB_RHPORT0_MODE       OPT_MODE_DEVICE
+#endif
+
+#define CFG_TUSB_OS                 OPT_OS_NONE
+
+// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
+// #define CFG_TUSB_DEBUG           0
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------
+
+#ifndef CFG_TUD_ENDPOINT0_SIZE
+#define CFG_TUD_ENDPOINT0_SIZE    64
+#endif
+
+//------------- CLASS -------------//
+#define CFG_TUD_CDC               0
+#define CFG_TUD_MSC               0
+#define CFG_TUD_HID               0
+#define CFG_TUD_MIDI              0
+#define CFG_TUD_VENDOR            0
+//#define CFG_TUD_NET               OPT_NET_ECM
+#define CFG_TUD_NET               OPT_NET_RNDIS
+//#define CFG_TUD_NET               OPT_NET_EEM
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */

+ 199 - 0
examples/device/lwip_webserver/src/usb_descriptors.c

@@ -0,0 +1,199 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "tusb.h"
+#include "usb_descriptors.h"
+
+/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
+ * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
+ *
+ * Auto ProductID layout's Bitmap:
+ *   [MSB]       NET1:NET0 | VENDOR | MIDI | HID | MSC | CDC          [LSB]
+ */
+#define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+                           _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(NET, 5) )
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+tusb_desc_device_t const desc_device =
+{
+    .bLength            = sizeof(tusb_desc_device_t),
+    .bDescriptorType    = TUSB_DESC_DEVICE,
+    .bcdUSB             = 0x0200,
+
+    .bDeviceClass       = TUSB_CLASS_UNSPECIFIED,
+    .bDeviceSubClass    = 0,
+    .bDeviceProtocol    = 0,
+    .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE,
+
+    .idVendor           = 0xCafe,
+    .idProduct          = USB_PID,
+    .bcdDevice          = 0x0100,
+
+    .iManufacturer      = 0x01,
+    .iProduct           = 0x02,
+    .iSerialNumber      = 0x03,
+
+    .bNumConfigurations = 0x01
+};
+
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void)
+{
+  return (uint8_t const *) &desc_device;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+enum
+{
+  ITF_NUM_CDC = 0,
+  ITF_NUM_CDC_DATA,
+  ITF_NUM_TOTAL
+};
+
+enum
+{
+  STR_LANGID = 0,
+  STR_MANUFACTURER,
+  STR_PRODUCT,
+  STR_ITFNAME,
+  STR_MAC,
+};
+
+#if CFG_TUD_NET == OPT_NET_ECM
+#define CONFIG_TOTAL_LEN    (TUD_CONFIG_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
+#elif CFG_TUD_NET == OPT_NET_RNDIS
+#define CONFIG_TOTAL_LEN    (TUD_CONFIG_DESC_LEN + TUD_RNDIS_DESC_LEN)
+#elif CFG_TUD_NET == OPT_NET_EEM
+#define CONFIG_TOTAL_LEN    (TUD_CONFIG_DESC_LEN + TUD_CDC_EEM_DESC_LEN)
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
+  // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
+  // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
+  #define EPNUM_CDC     2
+#else
+  #define EPNUM_CDC     2
+#endif
+
+uint8_t const desc_configuration[] =
+{
+  // Interface count, string index, total length, attribute, power in mA
+  TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 100),
+
+#if CFG_TUD_NET == OPT_NET_ECM
+  // Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
+  TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STR_ITFNAME, STR_MAC, 0x81, 8, EPNUM_CDC, 0x80 | EPNUM_CDC, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
+#elif CFG_TUD_NET == OPT_NET_RNDIS
+  // Interface number, string index, EP notification address and size, EP data address (out, in) and size.
+  TUD_RNDIS_DESCRIPTOR(ITF_NUM_CDC, STR_ITFNAME, 0x81, 8, EPNUM_CDC, 0x80 | EPNUM_CDC, CFG_TUD_NET_ENDPOINT_SIZE),
+#elif CFG_TUD_NET == OPT_NET_EEM
+  // Interface number, description string index, EP data address (out, in) and size.
+  TUD_CDC_EEM_DESCRIPTOR(ITF_NUM_CDC, STR_ITFNAME, EPNUM_CDC, 0x80 | EPNUM_CDC, CFG_TUD_NET_ENDPOINT_SIZE),
+#endif
+};
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
+{
+  (void) index; // for multiple configurations
+  return desc_configuration;
+}
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// array of pointer to string descriptors
+char const* string_desc_arr [] =
+{
+  [STR_LANGID]       = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409)
+  [STR_MANUFACTURER] = "TinyUSB",                     // Manufacturer
+  [STR_PRODUCT]      = "TinyUSB Device",              // Product
+  [STR_ITFNAME]      =                                // CDC-ECM Interface
+#if CFG_TUD_NET == OPT_NET_ECM
+                       "TinyUSB CDC-ECM",
+#elif CFG_TUD_NET == OPT_NET_RNDIS
+                       "TinyUSB RNDIS",
+#elif CFG_TUD_NET == OPT_NET_EEM
+                       "TinyUSB CDC-EEM",
+#endif
+};
+
+static uint16_t _desc_str[32];
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
+{
+  (void)langid;
+
+  unsigned chr_count = 0;
+
+  if (STR_LANGID == index)
+  {
+    memcpy(&_desc_str[1], string_desc_arr[0], 2);
+    chr_count = 1;
+  }
+  else if (STR_MAC == index)
+  {
+    // Convert MAC address into UTF-16
+
+    for (unsigned i=0; i<sizeof(network_mac_address); i++)
+    {
+      _desc_str[1+chr_count++] = "0123456789ABCDEF"[(network_mac_address[i] >> 4) & 0xf];
+      _desc_str[1+chr_count++] = "0123456789ABCDEF"[(network_mac_address[i] >> 0) & 0xf];
+    }
+  }
+  else
+  {
+    // Convert ASCII string into UTF-16
+
+    if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
+
+    const char* str = string_desc_arr[index];
+
+    // Cap at max char
+    chr_count = strlen(str);
+    if ( chr_count > (TU_ARRAY_SIZE(_desc_str) - 1)) chr_count = TU_ARRAY_SIZE(_desc_str) - 1;
+
+    for (unsigned i=0; i<chr_count; i++)
+    {
+      _desc_str[1+i] = str[i];
+    }
+  }
+
+  // first byte is length (including header), second byte is string type
+  _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
+
+  return _desc_str;
+}

+ 28 - 0
examples/device/lwip_webserver/src/usb_descriptors.h

@@ -0,0 +1,28 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef USB_DESCRIPTORS_H_
+#define USB_DESCRIPTORS_H_
+
+#endif /* USB_DESCRIPTORS_H_ */

+ 1 - 0
examples/rules.mk

@@ -22,6 +22,7 @@ SRC_C += \
 	src/class/midi/midi_device.c \
 	src/class/usbtmc/usbtmc_device.c \
 	src/class/vendor/vendor_device.c \
+	src/class/net/net_device.c \
 	src/portable/$(VENDOR)/$(CHIP_FAMILY)/dcd_$(CHIP_FAMILY).c
 
 # TinyUSB stack include

+ 1 - 0
lib/lwip

@@ -0,0 +1 @@
+Subproject commit 0192fe773ec28e11f66ec76f4e827fbb58b7e257

+ 347 - 0
lib/networking/dhserver.c

@@ -0,0 +1,347 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "dhserver.h"
+
+/* DHCP message type */
+#define DHCP_DISCOVER       1
+#define DHCP_OFFER          2
+#define DHCP_REQUEST        3
+#define DHCP_DECLINE        4
+#define DHCP_ACK            5
+#define DHCP_NAK            6
+#define DHCP_RELEASE        7
+#define DHCP_INFORM         8
+
+/* DHCP options */
+enum DHCP_OPTIONS
+{
+	DHCP_PAD                    = 0,
+	DHCP_SUBNETMASK             = 1,
+	DHCP_ROUTER                 = 3,
+	DHCP_DNSSERVER              = 6,
+	DHCP_HOSTNAME               = 12,
+	DHCP_DNSDOMAIN              = 15,
+	DHCP_MTU                    = 26,
+	DHCP_BROADCAST              = 28,
+	DHCP_PERFORMROUTERDISC      = 31,
+	DHCP_STATICROUTE            = 33,
+	DHCP_NISDOMAIN              = 40,
+	DHCP_NISSERVER              = 41,
+	DHCP_NTPSERVER              = 42,
+	DHCP_VENDOR                 = 43,
+	DHCP_IPADDRESS              = 50,
+	DHCP_LEASETIME              = 51,
+	DHCP_OPTIONSOVERLOADED      = 52,
+	DHCP_MESSAGETYPE            = 53,
+	DHCP_SERVERID               = 54,
+	DHCP_PARAMETERREQUESTLIST   = 55,
+	DHCP_MESSAGE                = 56,
+	DHCP_MAXMESSAGESIZE         = 57,
+	DHCP_RENEWALTIME            = 58,
+	DHCP_REBINDTIME             = 59,
+	DHCP_CLASSID                = 60,
+	DHCP_CLIENTID               = 61,
+	DHCP_USERCLASS              = 77,  /* RFC 3004 */
+	DHCP_FQDN                   = 81,
+	DHCP_DNSSEARCH              = 119, /* RFC 3397 */
+	DHCP_CSR                    = 121, /* RFC 3442 */
+	DHCP_MSCSR                  = 249, /* MS code for RFC 3442 */
+	DHCP_END                    = 255
+};
+
+typedef struct
+{
+    uint8_t  dp_op;           /* packet opcode type */
+    uint8_t  dp_htype;        /* hardware addr type */
+    uint8_t  dp_hlen;         /* hardware addr length */
+    uint8_t  dp_hops;         /* gateway hops */
+    uint32_t dp_xid;          /* transaction ID */
+    uint16_t dp_secs;         /* seconds since boot began */
+    uint16_t dp_flags;
+    uint8_t  dp_ciaddr[4];    /* client IP address */
+    uint8_t  dp_yiaddr[4];    /* 'your' IP address */
+    uint8_t  dp_siaddr[4];    /* server IP address */
+    uint8_t  dp_giaddr[4];    /* gateway IP address */
+    uint8_t  dp_chaddr[16];   /* client hardware address */
+    uint8_t  dp_legacy[192];
+    uint8_t  dp_magic[4];     
+    uint8_t  dp_options[275]; /* options area */
+} DHCP_TYPE;
+
+DHCP_TYPE dhcp_data;
+static struct udp_pcb *pcb = NULL;
+static const dhcp_config_t *config = NULL;
+
+char magic_cookie[] = {0x63,0x82,0x53,0x63};
+
+static uint32_t get_ip(const uint8_t *pnt)
+{
+  uint32_t result;
+  memcpy(&result, pnt, sizeof(result));
+  return result;
+}
+
+static void set_ip(uint8_t *pnt, uint32_t value)
+{
+  memcpy(pnt, &value, sizeof(value));
+}
+
+static dhcp_entry_t *entry_by_ip(uint32_t ip)
+{
+	int i;
+	for (i = 0; i < config->num_entry; i++)
+		if (get_ip(config->entries[i].addr) == ip)
+			return &config->entries[i];
+	return NULL;
+}
+
+static dhcp_entry_t *entry_by_mac(uint8_t *mac)
+{
+	int i;
+	for (i = 0; i < config->num_entry; i++)
+		if (memcmp(config->entries[i].mac, mac, 6) == 0)
+			return &config->entries[i];
+	return NULL;
+}
+
+static __inline bool is_vacant(dhcp_entry_t *entry)
+{
+	return memcmp("\0\0\0\0\0", entry->mac, 6) == 0;
+}
+
+static dhcp_entry_t *vacant_address(void)
+{
+	int i;
+	for (i = 0; i < config->num_entry; i++)
+		if (is_vacant(config->entries + i))
+			return config->entries + i;
+	return NULL;
+}
+
+static __inline void free_entry(dhcp_entry_t *entry)
+{
+	memset(entry->mac, 0, 6);
+}
+
+uint8_t *find_dhcp_option(uint8_t *attrs, int size, uint8_t attr)
+{
+	int i = 0;
+	while ((i + 1) < size)
+	{
+		int next = i + attrs[i + 1] + 2;
+		if (next > size) return NULL;
+		if (attrs[i] == attr)
+			return attrs + i;
+		i = next;
+	}
+	return NULL;
+}
+
+int fill_options(void *dest,
+	uint8_t msg_type,
+	const char *domain,
+	uint32_t dns,
+	int lease_time,
+	uint32_t serverid,
+	uint32_t router,
+	uint32_t subnet)
+{
+	uint8_t *ptr = (uint8_t *)dest;
+	/* ACK message type */
+	*ptr++ = 53;
+	*ptr++ = 1;
+	*ptr++ = msg_type;
+
+	/* dhcp server identifier */
+	*ptr++ = DHCP_SERVERID;
+	*ptr++ = 4;
+	set_ip(ptr, serverid);
+	ptr += 4;
+
+	/* lease time */
+	*ptr++ = DHCP_LEASETIME;
+	*ptr++ = 4;
+	*ptr++ = (lease_time >> 24) & 0xFF;
+	*ptr++ = (lease_time >> 16) & 0xFF;
+	*ptr++ = (lease_time >> 8) & 0xFF;
+	*ptr++ = (lease_time >> 0) & 0xFF;
+
+	/* subnet mask */
+	*ptr++ = DHCP_SUBNETMASK;
+	*ptr++ = 4;
+	set_ip(ptr, subnet);
+	ptr += 4;
+
+	/* router */
+	if (router != 0)
+	{
+		*ptr++ = DHCP_ROUTER;
+		*ptr++ = 4;
+		set_ip(ptr, router);
+		ptr += 4;
+	}
+
+	/* domain name */
+	if (domain != NULL)
+	{
+		int len = strlen(domain);
+		*ptr++ = DHCP_DNSDOMAIN;
+		*ptr++ = len;
+		memcpy(ptr, domain, len);
+		ptr += len;
+	}
+
+	/* domain name server (DNS) */
+	if (dns != 0)
+	{
+		*ptr++ = DHCP_DNSSERVER;
+		*ptr++ = 4;
+		set_ip(ptr, dns);
+		ptr += 4;
+	}
+
+	/* end */
+	*ptr++ = DHCP_END;
+	return ptr - (uint8_t *)dest;
+}
+
+static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
+{
+	uint8_t *ptr;
+	dhcp_entry_t *entry;
+	struct pbuf *pp;
+
+	(void)arg;
+	(void)addr;
+
+	unsigned n = p->len;
+	if (n > sizeof(dhcp_data)) n = sizeof(dhcp_data);
+	memcpy(&dhcp_data, p->payload, n);
+	switch (dhcp_data.dp_options[2])
+	{
+		case DHCP_DISCOVER:
+			entry = entry_by_mac(dhcp_data.dp_chaddr);
+			if (entry == NULL) entry = vacant_address();
+			if (entry == NULL) break;
+
+			dhcp_data.dp_op = 2; /* reply */
+			dhcp_data.dp_secs = 0;
+			dhcp_data.dp_flags = 0;
+			set_ip(dhcp_data.dp_yiaddr, get_ip(entry->addr));
+			memcpy(dhcp_data.dp_magic, magic_cookie, 4);
+
+			memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));
+
+			fill_options(dhcp_data.dp_options,
+				DHCP_OFFER,
+				config->domain,
+				get_ip(config->dns),
+				entry->lease, 
+				get_ip(config->addr),
+				get_ip(config->addr), 
+				get_ip(entry->subnet));
+
+			pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);
+			if (pp == NULL) break;
+			memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));
+			udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);
+			pbuf_free(pp);
+			break;
+
+		case DHCP_REQUEST:
+			/* 1. find requested ipaddr in option list */
+			ptr = find_dhcp_option(dhcp_data.dp_options, sizeof(dhcp_data.dp_options), DHCP_IPADDRESS);
+			if (ptr == NULL) break;
+			if (ptr[1] != 4) break;
+			ptr += 2;
+
+			/* 2. does hw-address registered? */
+			entry = entry_by_mac(dhcp_data.dp_chaddr);
+			if (entry != NULL) free_entry(entry);
+
+			/* 3. find requested ipaddr */
+			entry = entry_by_ip(get_ip(ptr));
+			if (entry == NULL) break;
+			if (!is_vacant(entry)) break;
+
+			/* 4. fill struct fields */
+			memcpy(dhcp_data.dp_yiaddr, ptr, 4);
+			dhcp_data.dp_op = 2; /* reply */
+			dhcp_data.dp_secs = 0;
+			dhcp_data.dp_flags = 0;
+			memcpy(dhcp_data.dp_magic, magic_cookie, 4);
+
+			/* 5. fill options */
+			memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));
+
+			fill_options(dhcp_data.dp_options,
+				DHCP_ACK,
+				config->domain,
+				get_ip(config->dns),
+				entry->lease, 
+				get_ip(config->addr),
+				get_ip(config->addr), 
+				get_ip(entry->subnet));
+
+			/* 6. send ACK */
+			pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);
+			if (pp == NULL) break;
+			memcpy(entry->mac, dhcp_data.dp_chaddr, 6);
+			memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));
+			udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);
+			pbuf_free(pp);
+			break;
+
+		default:
+				break;
+	}
+	pbuf_free(p);
+}
+
+err_t dhserv_init(const dhcp_config_t *c)
+{
+	err_t err;
+	udp_init();
+	dhserv_free();
+	pcb = udp_new();
+	if (pcb == NULL)
+		return ERR_MEM;
+	err = udp_bind(pcb, IP_ADDR_ANY, c->port);
+	if (err != ERR_OK)
+	{
+		dhserv_free();
+		return err;
+	}
+	udp_recv(pcb, udp_recv_proc, NULL);
+	config = c;
+	return ERR_OK;
+}
+
+void dhserv_free(void)
+{
+	if (pcb == NULL) return;
+	udp_remove(pcb);
+	pcb = NULL;
+}

+ 63 - 0
lib/networking/dhserver.h

@@ -0,0 +1,63 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * version: 1.0 demo (7.02.2015)
+ * brief:   tiny dhcp ipv4 server using lwip (pcb)
+ * ref:     https://lists.gnu.org/archive/html/lwip-users/2012-12/msg00016.html
+ */
+
+#ifndef DHSERVER_H
+#define DHSERVER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include "lwip/err.h"
+#include "lwip/udp.h"
+#include "netif/etharp.h"
+
+typedef struct dhcp_entry
+{
+	uint8_t  mac[6];
+	uint8_t  addr[4];
+	uint8_t  subnet[4];
+	uint32_t lease;
+} dhcp_entry_t;
+
+typedef struct dhcp_config
+{
+	uint8_t       addr[4];
+	uint16_t      port;
+	uint8_t       dns[4];
+	const char   *domain;
+	int           num_entry;
+	dhcp_entry_t *entries;
+} dhcp_config_t;
+
+err_t dhserv_init(const dhcp_config_t *config);
+void dhserv_free(void);
+
+#endif /* DHSERVER_H */

+ 200 - 0
lib/networking/dnserver.c

@@ -0,0 +1,200 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * version: 1.0 demo (7.02.2015)
+ * brief:   tiny dns ipv4 server using lwip (pcb)
+ */
+
+#include "dnserver.h"
+
+#define DNS_MAX_HOST_NAME_LEN 128
+
+static struct udp_pcb *pcb = NULL;
+dns_query_proc_t query_proc = NULL;
+
+#pragma pack(push, 1)
+typedef struct
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+	uint8_t rd: 1,     /* Recursion Desired */
+	        tc: 1,     /* Truncation Flag */
+	        aa: 1,     /* Authoritative Answer Flag */
+	        opcode: 4, /* Operation code */
+	        qr: 1;     /* Query/Response Flag */
+	uint8_t rcode: 4,  /* Response Code */
+	        z: 3,      /* Zero */
+	        ra: 1;     /* Recursion Available */
+#else
+	uint8_t qr: 1,     /* Query/Response Flag */
+	        opcode: 4, /* Operation code */
+	        aa: 1,     /* Authoritative Answer Flag */
+	        tc: 1,     /* Truncation Flag */
+	        rd: 1;     /* Recursion Desired */
+	uint8_t ra: 1,     /* Recursion Available */
+	        z: 3,      /* Zero */
+	        rcode: 4;  /* Response Code */
+#endif
+} dns_header_flags_t;
+
+typedef struct
+{
+	uint16_t id;
+	dns_header_flags_t flags;
+	uint16_t n_record[4];
+} dns_header_t;
+
+typedef struct dns_answer
+{
+	uint16_t name;
+	uint16_t type;
+	uint16_t Class;
+	uint32_t ttl;
+	uint16_t len;
+	uint32_t addr;
+} dns_answer_t;
+#pragma pack(pop)
+
+typedef struct dns_query
+{
+	char name[DNS_MAX_HOST_NAME_LEN];
+	uint16_t type;
+	uint16_t Class;
+} dns_query_t;
+
+static uint16_t get_uint16(const uint8_t *pnt)
+{
+  uint16_t result;
+  memcpy(&result, pnt, sizeof(result));
+  return result;
+}
+
+static int parse_next_query(void *data, int size, dns_query_t *query)
+{
+	int len;
+	int lables;
+	uint8_t *ptr;
+
+	len = 0;
+	lables = 0;
+	ptr = (uint8_t *)data;
+
+	while (true)
+	{
+		uint8_t lable_len;
+		if (size <= 0) return -1;
+		lable_len = *ptr++;
+		size--;
+		if (lable_len == 0) break;
+		if (lables > 0)
+		{
+			if (len == DNS_MAX_HOST_NAME_LEN) return -2;
+			query->name[len++] = '.';
+		}
+		if (lable_len > size) return -1;
+		if (len + lable_len >= DNS_MAX_HOST_NAME_LEN) return -2;
+		memcpy(&query->name[len], ptr, lable_len);
+		len += lable_len;
+		ptr += lable_len;
+		size -= lable_len;
+		lables++;
+	}
+
+	if (size < 4) return -1;
+	query->name[len] = 0;
+	query->type = get_uint16(ptr);
+	ptr += 2;
+	query->Class = get_uint16(ptr);
+	ptr += 2;
+	return ptr - (uint8_t *)data;
+}
+
+static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
+{
+	int len;
+	dns_header_t *header;
+	static dns_query_t query;
+	struct pbuf *out;
+	ip_addr_t host_addr;
+	dns_answer_t *answer;
+
+	(void)arg;
+
+	if (p->len <= sizeof(dns_header_t)) goto error;
+	header = (dns_header_t *)p->payload;
+	if (header->flags.qr != 0) goto error;
+	if (ntohs(header->n_record[0]) != 1) goto error;
+
+	len = parse_next_query(header + 1, p->len - sizeof(dns_header_t), &query);
+	if (len < 0) goto error;
+	if (!query_proc(query.name, &host_addr)) goto error;
+
+	len += sizeof(dns_header_t);
+	out = pbuf_alloc(PBUF_TRANSPORT, len + 16, PBUF_POOL);
+	if (out == NULL) goto error;
+
+	memcpy(out->payload, p->payload, len);
+	header = (dns_header_t *)out->payload;
+	header->flags.qr = 1;
+	header->n_record[1] = htons(1);
+	answer = (struct dns_answer *)((uint8_t *)out->payload + len);
+	answer->name = htons(0xC00C);
+	answer->type = htons(1);
+	answer->Class = htons(1);
+	answer->ttl = htonl(32);
+	answer->len = htons(4);
+	answer->addr = host_addr.addr;
+	
+	udp_sendto(upcb, out, addr, port);
+	pbuf_free(out);
+
+error:
+	pbuf_free(p);
+}
+
+err_t dnserv_init(const ip_addr_t *bind, uint16_t port, dns_query_proc_t qp)
+{
+	err_t err;
+	udp_init();
+	dnserv_free();
+	pcb = udp_new();
+	if (pcb == NULL)
+		return ERR_MEM;
+	err = udp_bind(pcb, bind, port);
+	if (err != ERR_OK)
+	{
+		dnserv_free();
+		return err;
+	}
+	udp_recv(pcb, udp_recv_proc, NULL);
+	query_proc = qp;
+	return ERR_OK;
+}
+
+void dnserv_free()
+{
+	if (pcb == NULL) return;
+	udp_remove(pcb);
+	pcb = NULL;
+}

+ 47 - 0
lib/networking/dnserver.h

@@ -0,0 +1,47 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * version: 1.0 demo (7.02.2015)
+ * brief:   tiny dns ipv4 server using lwip (pcb)
+ */
+
+#ifndef DNSERVER
+#define DNSERVER
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include "lwip/def.h"
+#include "lwip/err.h"
+#include "lwip/udp.h"
+#include "netif/etharp.h"
+
+typedef bool (*dns_query_proc_t)(const char *name, ip_addr_t *addr);
+
+err_t dnserv_init(const ip_addr_t *bind, uint16_t port, dns_query_proc_t query_proc);
+void  dnserv_free(void);
+
+#endif

+ 266 - 0
lib/networking/ndis.h

@@ -0,0 +1,266 @@
+/* This file has been prepared for Doxygen automatic documentation generation.*/
+/*! \file ndis.h ***************************************************************
+ *
+ * \brief
+ *      This file contains the possible external configuration of the USB.
+ *
+ * \addtogroup usbstick
+ *
+ *
+ ******************************************************************************/
+
+/**
+ \ingroup usbstick
+ \defgroup RNDIS RNDIS Support
+ @{
+ */
+
+/*
+ * ndis.h 
+ * 
+ * Modified by Colin O'Flynn <coflynn@newae.com>
+ * ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de>
+ * 
+ * Thanks to the cygwin development team, 
+ * espacially to Casper S. Hornstrup <chorns@users.sourceforge.net>
+ * 
+ * THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ * This source code is offered for use in the public domain. You may
+ * use, modify or distribute it freely.
+ *
+ * This code is distributed in the hope that it will be useful but
+ * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ * DISCLAIMED. This includes but is not limited to warranties of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef _LINUX_NDIS_H
+#define _LINUX_NDIS_H
+
+
+#define NDIS_STATUS_MULTICAST_FULL	      0xC0010009
+#define NDIS_STATUS_MULTICAST_EXISTS      0xC001000A
+#define NDIS_STATUS_MULTICAST_NOT_FOUND   0xC001000B
+
+/* from drivers/net/sk98lin/h/skgepnmi.h */
+#define OID_PNP_CAPABILITIES                    0xFD010100
+#define OID_PNP_SET_POWER                       0xFD010101
+#define OID_PNP_QUERY_POWER                     0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN             0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN          0xFD010104
+#define OID_PNP_ENABLE_WAKE_UP                  0xFD010106
+
+enum NDIS_DEVICE_POWER_STATE {
+	NdisDeviceStateUnspecified = 0,
+	NdisDeviceStateD0,
+	NdisDeviceStateD1,
+	NdisDeviceStateD2,
+	NdisDeviceStateD3,
+	NdisDeviceStateMaximum
+};
+
+struct NDIS_PM_WAKE_UP_CAPABILITIES {
+	enum NDIS_DEVICE_POWER_STATE  MinMagicPacketWakeUp;
+	enum NDIS_DEVICE_POWER_STATE  MinPatternWakeUp;
+	enum NDIS_DEVICE_POWER_STATE  MinLinkChangeWakeUp;
+};
+
+/* NDIS_PNP_CAPABILITIES.Flags constants */
+#define NDIS_DEVICE_WAKE_UP_ENABLE                0x00000001
+#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE  0x00000002
+#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE   0x00000004
+
+/*
+struct NDIS_PNP_CAPABILITIES {
+	__le32					Flags;
+	struct NDIS_PM_WAKE_UP_CAPABILITIES	WakeUpCapabilities;
+};
+
+struct NDIS_PM_PACKET_PATTERN {
+	__le32	Priority;
+	__le32	Reserved;
+	__le32	MaskSize;
+	__le32	PatternOffset;
+	__le32	PatternSize;
+	__le32	PatternFlags;
+};
+*/
+
+/* Required Object IDs (OIDs) */
+#define OID_GEN_SUPPORTED_LIST            0x00010101
+#define OID_GEN_HARDWARE_STATUS           0x00010102
+#define OID_GEN_MEDIA_SUPPORTED           0x00010103
+#define OID_GEN_MEDIA_IN_USE              0x00010104
+#define OID_GEN_MAXIMUM_LOOKAHEAD         0x00010105
+#define OID_GEN_MAXIMUM_FRAME_SIZE        0x00010106
+#define OID_GEN_LINK_SPEED                0x00010107
+#define OID_GEN_TRANSMIT_BUFFER_SPACE     0x00010108
+#define OID_GEN_RECEIVE_BUFFER_SPACE      0x00010109
+#define OID_GEN_TRANSMIT_BLOCK_SIZE       0x0001010A
+#define OID_GEN_RECEIVE_BLOCK_SIZE        0x0001010B
+#define OID_GEN_VENDOR_ID                 0x0001010C
+#define OID_GEN_VENDOR_DESCRIPTION        0x0001010D
+#define OID_GEN_CURRENT_PACKET_FILTER     0x0001010E
+#define OID_GEN_CURRENT_LOOKAHEAD         0x0001010F
+#define OID_GEN_DRIVER_VERSION            0x00010110
+#define OID_GEN_MAXIMUM_TOTAL_SIZE        0x00010111
+#define OID_GEN_PROTOCOL_OPTIONS          0x00010112
+#define OID_GEN_MAC_OPTIONS               0x00010113
+#define OID_GEN_MEDIA_CONNECT_STATUS      0x00010114
+#define OID_GEN_MAXIMUM_SEND_PACKETS      0x00010115
+#define OID_GEN_VENDOR_DRIVER_VERSION     0x00010116
+#define OID_GEN_SUPPORTED_GUIDS           0x00010117
+#define OID_GEN_NETWORK_LAYER_ADDRESSES   0x00010118
+#define OID_GEN_TRANSPORT_HEADER_OFFSET   0x00010119
+#define OID_GEN_MACHINE_NAME              0x0001021A
+#define OID_GEN_RNDIS_CONFIG_PARAMETER    0x0001021B
+#define OID_GEN_VLAN_ID                   0x0001021C
+
+/* Optional OIDs */
+#define OID_GEN_MEDIA_CAPABILITIES        0x00010201
+#define OID_GEN_PHYSICAL_MEDIUM           0x00010202
+
+/* Required statistics OIDs */
+#define OID_GEN_XMIT_OK                   0x00020101
+#define OID_GEN_RCV_OK                    0x00020102
+#define OID_GEN_XMIT_ERROR                0x00020103
+#define OID_GEN_RCV_ERROR                 0x00020104
+#define OID_GEN_RCV_NO_BUFFER             0x00020105
+
+/* Optional statistics OIDs */
+#define OID_GEN_DIRECTED_BYTES_XMIT       0x00020201
+#define OID_GEN_DIRECTED_FRAMES_XMIT      0x00020202
+#define OID_GEN_MULTICAST_BYTES_XMIT      0x00020203
+#define OID_GEN_MULTICAST_FRAMES_XMIT     0x00020204
+#define OID_GEN_BROADCAST_BYTES_XMIT      0x00020205
+#define OID_GEN_BROADCAST_FRAMES_XMIT     0x00020206
+#define OID_GEN_DIRECTED_BYTES_RCV        0x00020207
+#define OID_GEN_DIRECTED_FRAMES_RCV       0x00020208
+#define OID_GEN_MULTICAST_BYTES_RCV       0x00020209
+#define OID_GEN_MULTICAST_FRAMES_RCV      0x0002020A
+#define OID_GEN_BROADCAST_BYTES_RCV       0x0002020B
+#define OID_GEN_BROADCAST_FRAMES_RCV      0x0002020C
+#define OID_GEN_RCV_CRC_ERROR             0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH     0x0002020E
+#define OID_GEN_GET_TIME_CAPS             0x0002020F
+#define OID_GEN_GET_NETCARD_TIME          0x00020210
+#define OID_GEN_NETCARD_LOAD              0x00020211
+#define OID_GEN_DEVICE_PROFILE            0x00020212
+#define OID_GEN_INIT_TIME_MS              0x00020213
+#define OID_GEN_RESET_COUNTS              0x00020214
+#define OID_GEN_MEDIA_SENSE_COUNTS        0x00020215
+#define OID_GEN_FRIENDLY_NAME             0x00020216
+#define OID_GEN_MINIPORT_INFO             0x00020217
+#define OID_GEN_RESET_VERIFY_PARAMETERS   0x00020218
+
+/* IEEE 802.3 (Ethernet) OIDs */
+#define NDIS_802_3_MAC_OPTION_PRIORITY    0x00000001
+
+#define OID_802_3_PERMANENT_ADDRESS       0x01010101
+#define OID_802_3_CURRENT_ADDRESS         0x01010102
+#define OID_802_3_MULTICAST_LIST          0x01010103
+#define OID_802_3_MAXIMUM_LIST_SIZE       0x01010104
+#define OID_802_3_MAC_OPTIONS             0x01010105
+#define OID_802_3_RCV_ERROR_ALIGNMENT     0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION      0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS    0x01020103
+#define OID_802_3_XMIT_DEFERRED           0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS     0x01020202
+#define OID_802_3_RCV_OVERRUN             0x01020203
+#define OID_802_3_XMIT_UNDERRUN           0x01020204
+#define OID_802_3_XMIT_HEARTBEAT_FAILURE  0x01020205
+#define OID_802_3_XMIT_TIMES_CRS_LOST     0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS    0x01020207
+
+/* Wireless LAN OIDs */
+/* Mandatory */
+#define OID_802_11_BSSID                  0x0D010101 /* Q  S     */
+#define OID_802_11_SSID                   0x0D010102 /* Q  S     */
+#define OID_802_11_NETWORK_TYPE_IN_USE    0x0D010204 /* Q  S     */
+#define OID_802_11_RSSI                   0x0D010206 /* Q      I */
+#define OID_802_11_BSSID_LIST             0x0D010217 /* Q        */
+#define OID_802_11_BSSID_LIST_SCAN        0x0D01011A /*    S     */
+#define OID_802_11_INFRASTRUCTURE_MODE    0x0D010108 /* Q  S     */
+#define OID_802_11_SUPPORTED_RATES        0x0D01020E /* Q        */
+#define OID_802_11_CONFIGURATION          0x0D010211 /* Q  S     */
+#define OID_802_11_ADD_WEP                0x0D010113 /*    S     */
+#define OID_802_11_WEP_STATUS             0x0D01011B /* Q  S     */
+#define OID_802_11_REMOVE_WEP             0x0D010114 /*    S     */
+#define OID_802_11_DISASSOCIATE           0x0D010115 /*    S     */
+#define OID_802_11_AUTHENTICATION_MODE    0x0D010118 /* Q  S     */
+#define OID_802_11_RELOAD_DEFAULTS        0x0D01011C /*    S     */
+
+
+
+/* OID_GEN_MINIPORT_INFO constants */
+#define NDIS_MINIPORT_BUS_MASTER                      0x00000001
+#define NDIS_MINIPORT_WDM_DRIVER                      0x00000002
+#define NDIS_MINIPORT_SG_LIST                         0x00000004
+#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY            0x00000008
+#define NDIS_MINIPORT_INDICATES_PACKETS               0x00000010
+#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE             0x00000020
+#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE            0x00000040
+#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS        0x00000080
+#define NDIS_MINIPORT_INTERMEDIATE_DRIVER             0x00000100
+#define NDIS_MINIPORT_IS_NDIS_5                       0x00000200
+#define NDIS_MINIPORT_IS_CO                           0x00000400
+#define NDIS_MINIPORT_DESERIALIZE                     0x00000800
+#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING          0x00001000
+#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE            0x00002000
+#define NDIS_MINIPORT_NETBOOT_CARD                    0x00004000
+#define NDIS_MINIPORT_PM_SUPPORTED                    0x00008000
+#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE  0x00010000
+#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS           0x00020000
+#define NDIS_MINIPORT_HIDDEN                          0x00040000
+#define NDIS_MINIPORT_SWENUM                          0x00080000
+#define NDIS_MINIPORT_SURPRISE_REMOVE_OK              0x00100000
+#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND              0x00200000
+#define NDIS_MINIPORT_HARDWARE_DEVICE                 0x00400000
+#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS    0x00800000
+#define NDIS_MINIPORT_64BITS_DMA                      0x01000000
+
+#define NDIS_MEDIUM_802_3		0x00000000
+#define NDIS_MEDIUM_802_5		0x00000001
+#define NDIS_MEDIUM_FDDI		0x00000002
+#define NDIS_MEDIUM_WAN			0x00000003
+#define NDIS_MEDIUM_LOCAL_TALK		0x00000004
+#define NDIS_MEDIUM_DIX			0x00000005
+#define NDIS_MEDIUM_ARCENT_RAW		0x00000006
+#define NDIS_MEDIUM_ARCENT_878_2	0x00000007
+#define NDIS_MEDIUM_ATM			0x00000008
+#define NDIS_MEDIUM_WIRELESS_LAN	0x00000009
+#define NDIS_MEDIUM_IRDA		0x0000000A
+#define NDIS_MEDIUM_BPC			0x0000000B
+#define NDIS_MEDIUM_CO_WAN		0x0000000C
+#define NDIS_MEDIUM_1394		0x0000000D
+
+#define NDIS_PACKET_TYPE_DIRECTED	0x00000001
+#define NDIS_PACKET_TYPE_MULTICAST	0x00000002
+#define NDIS_PACKET_TYPE_ALL_MULTICAST	0x00000004
+#define NDIS_PACKET_TYPE_BROADCAST	0x00000008
+#define NDIS_PACKET_TYPE_SOURCE_ROUTING	0x00000010
+#define NDIS_PACKET_TYPE_PROMISCUOUS	0x00000020
+#define NDIS_PACKET_TYPE_SMT		0x00000040
+#define NDIS_PACKET_TYPE_ALL_LOCAL	0x00000080
+#define NDIS_PACKET_TYPE_GROUP		0x00000100
+#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL	0x00000200
+#define NDIS_PACKET_TYPE_FUNCTIONAL	0x00000400
+#define NDIS_PACKET_TYPE_MAC_FRAME	0x00000800
+
+#define NDIS_MEDIA_STATE_CONNECTED	0x00000000
+#define NDIS_MEDIA_STATE_DISCONNECTED	0x00000001
+
+#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA     0x00000001
+#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED      0x00000002
+#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND      0x00000004
+#define NDIS_MAC_OPTION_NO_LOOPBACK             0x00000008
+#define NDIS_MAC_OPTION_FULL_DUPLEX             0x00000010
+#define NDIS_MAC_OPTION_EOTX_INDICATION         0x00000020
+#define NDIS_MAC_OPTION_8021P_PRIORITY          0x00000040
+#define NDIS_MAC_OPTION_RESERVED                0x80000000
+
+#endif /* _LINUX_NDIS_H */
+
+/** @} */

+ 307 - 0
lib/networking/rndis_protocol.h

@@ -0,0 +1,307 @@
+/**
+ * \file rndis_protocol.h
+ *         RNDIS Defines
+ *
+ * \author
+ *         Colin O'Flynn <coflynn@newae.com>
+ *
+ * \addtogroup usbstick
+ */
+
+/* Copyright (c) 2008  Colin O'Flynn
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+
+   * Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+   * Neither the name of the copyright holders nor the names of
+     contributors may be used to endorse or promote products derived
+     from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _RNDIS_H
+#define _RNDIS_H
+
+/** 
+  \addtogroup RNDIS
+  @{
+  */
+
+#include <stdint.h>
+
+#define RNDIS_MAJOR_VERSION	1
+#define RNDIS_MINOR_VERSION 0
+
+#define RNDIS_STATUS_SUCCESS            0X00000000
+#define RNDIS_STATUS_FAILURE            0XC0000001
+#define RNDIS_STATUS_INVALID_DATA       0XC0010015
+#define RNDIS_STATUS_NOT_SUPPORTED      0XC00000BB
+#define RNDIS_STATUS_MEDIA_CONNECT      0X4001000B
+#define RNDIS_STATUS_MEDIA_DISCONNECT   0X4001000C
+
+
+/* Message set for Connectionless (802.3) Devices */
+#define REMOTE_NDIS_PACKET_MSG          0x00000001
+#define REMOTE_NDIS_INITIALIZE_MSG      0X00000002
+#define REMOTE_NDIS_HALT_MSG            0X00000003
+#define REMOTE_NDIS_QUERY_MSG           0X00000004
+#define REMOTE_NDIS_SET_MSG             0X00000005
+#define REMOTE_NDIS_RESET_MSG           0X00000006
+#define REMOTE_NDIS_INDICATE_STATUS_MSG 0X00000007
+#define REMOTE_NDIS_KEEPALIVE_MSG       0X00000008
+#define REMOTE_NDIS_INITIALIZE_CMPLT    0X80000002
+#define REMOTE_NDIS_QUERY_CMPLT         0X80000004
+#define REMOTE_NDIS_SET_CMPLT           0X80000005
+#define REMOTE_NDIS_RESET_CMPLT         0X80000006
+#define REMOTE_NDIS_KEEPALIVE_CMPLT     0X80000008
+
+typedef uint32_t rndis_MessageType_t;
+typedef uint32_t rndis_MessageLength_t;
+typedef uint32_t rndis_RequestId_t;
+typedef uint32_t rndis_MajorVersion_t;
+typedef uint32_t rndis_MinorVersion_t;
+typedef uint32_t rndis_MaxTransferSize_t;
+typedef uint32_t rndis_Status_t;
+
+
+/* Device Flags */
+#define RNDIS_DF_CONNECTIONLESS      0x00000001
+#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002
+typedef uint32_t rndis_DeviceFlags_t;
+
+/* Mediums */
+#define RNDIS_MEDIUM_802_3           0x00000000
+typedef uint32_t rndis_Medium_t;
+
+
+typedef uint32_t rndis_MaxPacketsPerTransfer_t;
+typedef uint32_t rndis_PacketAlignmentFactor_t;
+typedef uint32_t rndis_AfListOffset_t;
+typedef uint32_t rndis_AfListSize_t;
+
+/*** Remote NDIS Generic Message type ***/
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	} rndis_generic_msg_t;
+
+
+/*** Remote NDIS Initialize Message ***/
+typedef struct{
+	rndis_MessageType_t 	MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_RequestId_t		RequestId;
+	rndis_MajorVersion_t	MajorVersion;
+	rndis_MinorVersion_t	MinorVersion;
+	rndis_MaxTransferSize_t	MaxTransferSize;
+	} rndis_initialize_msg_t;
+	
+/* Response: */
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_RequestId_t		RequestId;
+	rndis_Status_t			Status;
+	rndis_MajorVersion_t	MajorVersion;
+	rndis_MinorVersion_t	MinorVersion;
+	rndis_DeviceFlags_t		DeviceFlags;
+	rndis_Medium_t			Medium;
+	rndis_MaxPacketsPerTransfer_t 	MaxPacketsPerTransfer;
+	rndis_MaxTransferSize_t			MaxTransferSize;
+	rndis_PacketAlignmentFactor_t 	PacketAlignmentFactor;
+	rndis_AfListOffset_t	AfListOffset;
+	rndis_AfListSize_t		AfListSize;
+	} rndis_initialize_cmplt_t;
+	
+
+/*** Remote NDIS Halt Message ***/
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_RequestId_t		RequestId;
+	} rndis_halt_msg_t;
+	
+typedef uint32_t rndis_Oid_t;
+typedef uint32_t rndis_InformationBufferLength_t;
+typedef uint32_t rndis_InformationBufferOffset_t;
+typedef uint32_t rndis_DeviceVcHandle_t;
+
+/*** Remote NDIS Query Message ***/
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_RequestId_t		RequestId;
+	rndis_Oid_t				Oid;
+	rndis_InformationBufferLength_t	InformationBufferLength;
+	rndis_InformationBufferOffset_t	InformationBufferOffset;
+	rndis_DeviceVcHandle_t			DeviceVcHandle;
+	}  rndis_query_msg_t;
+	
+/* Response: */
+
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_RequestId_t		RequestId;
+	rndis_Status_t			Status;
+	rndis_InformationBufferLength_t	InformationBufferLength;
+	rndis_InformationBufferOffset_t	InformationBufferOffset;
+	} rndis_query_cmplt_t;
+	
+/*** Remote NDIS Set Message ***/
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_RequestId_t		RequestId;
+	rndis_Oid_t				Oid;
+	rndis_InformationBufferLength_t	InformationBufferLength;
+	rndis_InformationBufferOffset_t	InformationBufferOffset;
+	rndis_DeviceVcHandle_t			DeviceVcHandle;
+	} rndis_set_msg_t;
+	
+/* Response */
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_RequestId_t		RequestId;
+	rndis_Status_t			Status;
+	}rndis_set_cmplt_t;
+
+/* Information buffer layout for OID_GEN_RNDIS_CONFIG_PARAMETER */
+typedef uint32_t rndis_ParameterNameOffset_t;
+typedef uint32_t rndis_ParameterNameLength_t;
+typedef uint32_t rndis_ParameterType_t;
+typedef uint32_t rndis_ParameterValueOffset_t;
+typedef uint32_t rndis_ParameterValueLength_t;
+
+#define PARAMETER_TYPE_STRING		2
+#define PARAMETER_TYPE_NUMERICAL	0
+
+typedef struct{
+	rndis_ParameterNameOffset_t		ParameterNameOffset;
+	rndis_ParameterNameLength_t		ParameterNameLength;
+	rndis_ParameterType_t			ParameterType;
+	rndis_ParameterValueOffset_t	ParameterValueOffset;
+	rndis_ParameterValueLength_t	ParameterValueLength;	
+	}rndis_config_parameter_t;
+	
+typedef uint32_t rndis_Reserved_t;
+
+/*** Remote NDIS Soft Reset Message ***/
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_Reserved_t		Reserved;
+	} rndis_reset_msg_t;
+	
+typedef uint32_t rndis_AddressingReset_t;
+
+/* Response: */
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_Status_t			Status;
+	rndis_AddressingReset_t	AddressingReset;
+	}  rndis_reset_cmplt_t;
+	
+/*** Remote NDIS Indicate Status Message ***/
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_Status_t			Status;
+	rndis_Status_t			StatusBufferLength;
+	rndis_Status_t			StatusBufferOffset;
+	}  rndis_indicate_status_t;
+	
+typedef uint32_t rndis_DiagStatus_t;
+typedef uint32_t rndis_ErrorOffset_t;
+
+typedef struct {
+	rndis_DiagStatus_t		DiagStatus;
+	rndis_ErrorOffset_t		ErrorOffset;
+	}rndis_diagnostic_info_t;
+	
+/*** Remote NDIS Keepalive Message */
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_RequestId_t		RequestId;
+	}rndis_keepalive_msg_t;
+	
+/* Response: */
+typedef struct{
+	rndis_MessageType_t		MessageType;
+	rndis_MessageLength_t	MessageLength;
+	rndis_RequestId_t		RequestId;
+	rndis_Status_t			Status;
+	}rndis_keepalive_cmplt_t;
+
+/*** Remote NDIS Data Packet ***/
+
+typedef uint32_t rndis_DataOffset_t;
+typedef uint32_t rndis_DataLength_t;
+typedef uint32_t rndis_OOBDataOffset_t;
+typedef uint32_t rndis_OOBDataLength_t;
+typedef uint32_t rndis_NumOOBDataElements_t;
+typedef uint32_t rndis_PerPacketInfoOffset_t;
+typedef uint32_t rndis_PerPacketInfoLength_t;
+
+typedef struct{
+	rndis_MessageType_t			MessageType;
+	rndis_MessageLength_t		MessageLength;
+	rndis_DataOffset_t			DataOffset;
+	rndis_DataLength_t			DataLength;
+	rndis_OOBDataOffset_t		OOBDataOffset;
+	rndis_OOBDataLength_t		OOBDataLength;
+	rndis_NumOOBDataElements_t	NumOOBDataElements;
+	rndis_PerPacketInfoOffset_t	PerPacketInfoOffset;
+	rndis_PerPacketInfoLength_t PerPacketInfoLength;
+	rndis_DeviceVcHandle_t		DeviceVcHandle;
+	rndis_Reserved_t			Reserved;
+	}rndis_data_packet_t;
+
+typedef uint32_t rndis_ClassInformationOffset_t;
+typedef uint32_t rndis_Size_t;
+typedef uint32_t rndis_Type_t;
+
+typedef struct{
+	rndis_Size_t					Size;
+	rndis_Type_t					Type;
+	rndis_ClassInformationOffset_t	ClassInformationType;
+	}rndis_OOB_packet_t;
+
+#include "ndis.h"
+
+typedef enum rnids_state_e {
+	rndis_uninitialized,
+	rndis_initialized,
+	rndis_data_initialized
+	} rndis_state_t;
+
+typedef struct {
+	uint32_t		txok;
+	uint32_t		rxok;
+	uint32_t		txbad;
+	uint32_t		rxbad;
+} usb_eth_stat_t;
+
+#endif /* _RNDIS_H */
+
+/** @} */

+ 303 - 0
lib/networking/rndis_reports.c

@@ -0,0 +1,303 @@
+/*
+  The original version of this code was lrndis/usbd_rndis_core.c from https://github.com/fetisov/lrndis
+  It has since been overhauled to suit this application
+*/
+
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdalign.h>
+#include <string.h>
+#include "class/net/net_device.h"
+#include "rndis_protocol.h"
+#include "netif/ethernet.h"
+
+#define RNDIS_LINK_SPEED 12000000                       /* Link baudrate (12Mbit/s for USB-FS) */
+#define RNDIS_VENDOR     "TinyUSB"                      /* NIC vendor name */
+
+static const uint8_t *const station_hwaddr = network_mac_address;
+static const uint8_t *const permanent_hwaddr = network_mac_address;
+
+static usb_eth_stat_t usb_eth_stat = { 0, 0, 0, 0 };
+static uint32_t oid_packet_filter = 0x0000000;
+static rndis_state_t rndis_state;
+
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t ndis_report[8] = { 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+
+static const uint32_t OIDSupportedList[] = 
+{
+  OID_GEN_SUPPORTED_LIST,
+  OID_GEN_HARDWARE_STATUS,
+  OID_GEN_MEDIA_SUPPORTED,
+  OID_GEN_MEDIA_IN_USE,
+  OID_GEN_MAXIMUM_FRAME_SIZE,
+  OID_GEN_LINK_SPEED,
+  OID_GEN_TRANSMIT_BLOCK_SIZE,
+  OID_GEN_RECEIVE_BLOCK_SIZE,
+  OID_GEN_VENDOR_ID,
+  OID_GEN_VENDOR_DESCRIPTION,
+  OID_GEN_VENDOR_DRIVER_VERSION,
+  OID_GEN_CURRENT_PACKET_FILTER,
+  OID_GEN_MAXIMUM_TOTAL_SIZE,
+  OID_GEN_PROTOCOL_OPTIONS,
+  OID_GEN_MAC_OPTIONS,
+  OID_GEN_MEDIA_CONNECT_STATUS,
+  OID_GEN_MAXIMUM_SEND_PACKETS,
+  OID_802_3_PERMANENT_ADDRESS,
+  OID_802_3_CURRENT_ADDRESS,
+  OID_802_3_MULTICAST_LIST,
+  OID_802_3_MAXIMUM_LIST_SIZE,
+  OID_802_3_MAC_OPTIONS
+};
+
+#define OID_LIST_LENGTH TU_ARRAY_SIZE(OIDSupportedList)
+#define ENC_BUF_SIZE    (OID_LIST_LENGTH * 4 + 32)
+
+static uint8_t *encapsulated_buffer;
+
+static void rndis_report(void)
+{
+  netd_report(ndis_report, sizeof(ndis_report));
+}
+
+static void rndis_query_cmplt32(int status, uint32_t data)
+{
+  rndis_query_cmplt_t *c;
+  c = (rndis_query_cmplt_t *)encapsulated_buffer;
+  c->MessageType = REMOTE_NDIS_QUERY_CMPLT;
+  c->MessageLength = sizeof(rndis_query_cmplt_t) + 4;
+  c->InformationBufferLength = 4;
+  c->InformationBufferOffset = 16;
+  c->Status = status;
+  memcpy(c + 1, &data, sizeof(data));
+  rndis_report();
+}
+
+static void rndis_query_cmplt(int status, const void *data, int size)
+{
+  rndis_query_cmplt_t *c;
+  c = (rndis_query_cmplt_t *)encapsulated_buffer;
+  c->MessageType = REMOTE_NDIS_QUERY_CMPLT;
+  c->MessageLength = sizeof(rndis_query_cmplt_t) + size;
+  c->InformationBufferLength = size;
+  c->InformationBufferOffset = 16;
+  c->Status = status;
+  memcpy(c + 1, data, size);
+  rndis_report();
+}
+
+#define MAC_OPT NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \
+                NDIS_MAC_OPTION_RECEIVE_SERIALIZED  | \
+                NDIS_MAC_OPTION_TRANSFERS_NOT_PEND  | \
+                NDIS_MAC_OPTION_NO_LOOPBACK
+
+static const char *rndis_vendor = RNDIS_VENDOR;
+
+static void rndis_query(void)
+{
+  switch (((rndis_query_msg_t *)encapsulated_buffer)->Oid)
+  {
+    case OID_GEN_SUPPORTED_LIST:         rndis_query_cmplt(RNDIS_STATUS_SUCCESS, OIDSupportedList, 4 * OID_LIST_LENGTH); return;
+    case OID_GEN_VENDOR_DRIVER_VERSION:  rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0x00001000);  return;
+    case OID_802_3_CURRENT_ADDRESS:      rndis_query_cmplt(RNDIS_STATUS_SUCCESS, &station_hwaddr, 6); return;
+    case OID_802_3_PERMANENT_ADDRESS:    rndis_query_cmplt(RNDIS_STATUS_SUCCESS, &permanent_hwaddr, 6); return;
+    case OID_GEN_MEDIA_SUPPORTED:        rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return;
+    case OID_GEN_MEDIA_IN_USE:           rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return;
+    case OID_GEN_PHYSICAL_MEDIUM:        rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIUM_802_3); return;
+    case OID_GEN_HARDWARE_STATUS:        rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return;
+    case OID_GEN_LINK_SPEED:             rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, RNDIS_LINK_SPEED / 100); return;
+    case OID_GEN_VENDOR_ID:              rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0x00FFFFFF); return;
+    case OID_GEN_VENDOR_DESCRIPTION:     rndis_query_cmplt(RNDIS_STATUS_SUCCESS, rndis_vendor, strlen(rndis_vendor) + 1); return;
+    case OID_GEN_CURRENT_PACKET_FILTER:  rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, oid_packet_filter); return;
+    case OID_GEN_MAXIMUM_FRAME_SIZE:     rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU - SIZEOF_ETH_HDR); return;
+    case OID_GEN_MAXIMUM_TOTAL_SIZE:     rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return;
+    case OID_GEN_TRANSMIT_BLOCK_SIZE:    rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return;
+    case OID_GEN_RECEIVE_BLOCK_SIZE:     rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, CFG_TUD_NET_MTU); return;
+    case OID_GEN_MEDIA_CONNECT_STATUS:   rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, NDIS_MEDIA_STATE_CONNECTED); return;
+    case OID_GEN_RNDIS_CONFIG_PARAMETER: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return;
+    case OID_802_3_MAXIMUM_LIST_SIZE:    rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 1); return;
+    case OID_802_3_MULTICAST_LIST:       rndis_query_cmplt32(RNDIS_STATUS_NOT_SUPPORTED, 0); return;
+    case OID_802_3_MAC_OPTIONS:          rndis_query_cmplt32(RNDIS_STATUS_NOT_SUPPORTED, 0); return;
+    case OID_GEN_MAC_OPTIONS:            rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, /*MAC_OPT*/ 0); return;
+    case OID_802_3_RCV_ERROR_ALIGNMENT:  rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return;
+    case OID_802_3_XMIT_ONE_COLLISION:   rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return;
+    case OID_802_3_XMIT_MORE_COLLISIONS: rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return;
+    case OID_GEN_XMIT_OK:                rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.txok); return;
+    case OID_GEN_RCV_OK:                 rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.rxok); return;
+    case OID_GEN_RCV_ERROR:              rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.rxbad); return;
+    case OID_GEN_XMIT_ERROR:             rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, usb_eth_stat.txbad); return;
+    case OID_GEN_RCV_NO_BUFFER:          rndis_query_cmplt32(RNDIS_STATUS_SUCCESS, 0); return;
+    default:                             rndis_query_cmplt(RNDIS_STATUS_FAILURE, NULL, 0); return;
+  }
+}
+
+#define INFBUF ((uint32_t *)((uint8_t *)&(m->RequestId) + m->InformationBufferOffset))
+
+static void rndis_handle_config_parm(const char *data, int keyoffset, int valoffset, int keylen, int vallen)
+{
+    (void)data;
+    (void)keyoffset;
+    (void)valoffset;
+    (void)keylen;
+    (void)vallen;
+}
+
+static void rndis_packetFilter(uint32_t newfilter)
+{
+    (void)newfilter;
+}
+
+static void rndis_handle_set_msg(void)
+{
+  rndis_set_cmplt_t *c;
+  rndis_set_msg_t *m;
+  rndis_Oid_t oid;
+
+  c = (rndis_set_cmplt_t *)encapsulated_buffer;
+  m = (rndis_set_msg_t *)encapsulated_buffer;
+
+  oid = m->Oid;
+  c->MessageType = REMOTE_NDIS_SET_CMPLT;
+  c->MessageLength = sizeof(rndis_set_cmplt_t);
+  c->Status = RNDIS_STATUS_SUCCESS;
+
+  switch (oid)
+  {
+    /* Parameters set up in 'Advanced' tab */
+    case OID_GEN_RNDIS_CONFIG_PARAMETER:
+      {
+        rndis_config_parameter_t *p;
+        char *ptr = (char *)m;
+        ptr += sizeof(rndis_generic_msg_t);
+        ptr += m->InformationBufferOffset;
+        p = (rndis_config_parameter_t *)ptr;
+        rndis_handle_config_parm(ptr, p->ParameterNameOffset, p->ParameterValueOffset, p->ParameterNameLength, p->ParameterValueLength);
+      }
+      break;
+
+    /* Mandatory general OIDs */
+    case OID_GEN_CURRENT_PACKET_FILTER:
+      oid_packet_filter = *INFBUF;
+      if (oid_packet_filter)
+      {
+        rndis_packetFilter(oid_packet_filter);
+        rndis_state = rndis_data_initialized;
+      } 
+      else 
+      {
+        rndis_state = rndis_initialized;
+      }
+      break;
+
+    case OID_GEN_CURRENT_LOOKAHEAD:
+      break;
+
+    case OID_GEN_PROTOCOL_OPTIONS:
+      break;
+
+    /* Mandatory 802_3 OIDs */
+    case OID_802_3_MULTICAST_LIST:
+      break;
+
+    /* Power Managment: fails for now */
+    case OID_PNP_ADD_WAKE_UP_PATTERN:
+    case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+    case OID_PNP_ENABLE_WAKE_UP:
+    default:
+      c->Status = RNDIS_STATUS_FAILURE;
+      break;
+  }
+
+  /* c->MessageID is same as before */
+  rndis_report();
+  return;
+}
+
+void rndis_class_set_handler(uint8_t *data, int size)
+{
+  encapsulated_buffer = data;
+  (void)size;
+
+  switch (((rndis_generic_msg_t *)data)->MessageType)
+  {
+    case REMOTE_NDIS_INITIALIZE_MSG:
+      {
+        rndis_initialize_cmplt_t *m;
+        m = ((rndis_initialize_cmplt_t *)encapsulated_buffer);
+        /* m->MessageID is same as before */
+        m->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
+        m->MessageLength = sizeof(rndis_initialize_cmplt_t);
+        m->MajorVersion = RNDIS_MAJOR_VERSION;
+        m->MinorVersion = RNDIS_MINOR_VERSION;
+        m->Status = RNDIS_STATUS_SUCCESS;
+        m->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
+        m->Medium = RNDIS_MEDIUM_802_3;
+        m->MaxPacketsPerTransfer = 1;
+        m->MaxTransferSize = CFG_TUD_NET_MTU + sizeof(rndis_data_packet_t);
+        m->PacketAlignmentFactor = 0;
+        m->AfListOffset = 0;
+        m->AfListSize = 0;
+        rndis_state = rndis_initialized;
+        rndis_report();
+      }
+      break;
+
+    case REMOTE_NDIS_QUERY_MSG:
+      rndis_query();
+      break;
+      
+    case REMOTE_NDIS_SET_MSG:
+      rndis_handle_set_msg();
+      break;
+
+    case REMOTE_NDIS_RESET_MSG:
+      {
+        rndis_reset_cmplt_t * m;
+        m = ((rndis_reset_cmplt_t *)encapsulated_buffer);
+        rndis_state = rndis_uninitialized;
+        m->MessageType = REMOTE_NDIS_RESET_CMPLT;
+        m->MessageLength = sizeof(rndis_reset_cmplt_t);
+        m->Status = RNDIS_STATUS_SUCCESS;
+        m->AddressingReset = 1; /* Make it look like we did something */
+          /* m->AddressingReset = 0; - Windows halts if set to 1 for some reason */
+        rndis_report();
+      }
+      break;
+
+    case REMOTE_NDIS_KEEPALIVE_MSG:
+      {
+        rndis_keepalive_cmplt_t * m;
+        m = (rndis_keepalive_cmplt_t *)encapsulated_buffer;
+        m->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
+        m->MessageLength = sizeof(rndis_keepalive_cmplt_t);
+        m->Status = RNDIS_STATUS_SUCCESS;
+      }
+      /* We have data to send back */
+      rndis_report();
+      break;
+
+    default:
+      break;
+  }
+}

+ 345 - 0
src/class/net/net_device.c

@@ -0,0 +1,345 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Peter Lawrence
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if ( TUSB_OPT_DEVICE_ENABLED && (CFG_TUD_NET != OPT_NET_NONE) )
+
+#include "net_device.h"
+#include "device/usbd_pvt.h"
+#include "rndis_protocol.h"
+
+void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networking/rndis_reports.c */
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+typedef struct
+{
+  uint8_t itf_num;
+  uint8_t ep_notif;
+  uint8_t ep_in;
+  uint8_t ep_out;
+} netd_interface_t;
+
+#if CFG_TUD_NET == OPT_NET_ECM
+  #define CFG_TUD_NET_PACKET_PREFIX_LEN 0
+  #define CFG_TUD_NET_PACKET_SUFFIX_LEN 0
+  #define CFG_TUD_NET_INTERFACESUBCLASS CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL
+#elif CFG_TUD_NET == OPT_NET_RNDIS
+  #define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t)
+  #define CFG_TUD_NET_PACKET_SUFFIX_LEN 0
+  #define CFG_TUD_NET_INTERFACESUBCLASS TUD_RNDIS_ITF_SUBCLASS
+#elif CFG_TUD_NET == OPT_NET_EEM
+  #define CFG_TUD_NET_PACKET_PREFIX_LEN 2
+  #define CFG_TUD_NET_PACKET_SUFFIX_LEN 4
+  #define CFG_TUD_NET_INTERFACESUBCLASS CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL
+#endif
+
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN];
+CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN];
+
+#if CFG_TUD_NET == OPT_NET_RNDIS
+  CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t rndis_buf[128];
+#endif
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+CFG_TUSB_MEM_SECTION static netd_interface_t _netd_itf;
+
+static bool can_xmit;
+
+void network_recv_renew(void)
+{
+  usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_out, received, sizeof(received));
+}
+
+static void do_in_xfer(uint8_t *buf, uint16_t len)
+{
+  can_xmit = false;
+  usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_in, buf, len);
+}
+
+void netd_report(uint8_t *buf, uint16_t len)
+{
+  usbd_edpt_xfer(TUD_OPT_RHPORT, _netd_itf.ep_notif, buf, len);
+}
+
+//--------------------------------------------------------------------+
+// USBD Driver API
+//--------------------------------------------------------------------+
+void netd_init(void)
+{
+  tu_memclr(&_netd_itf, sizeof(_netd_itf));
+}
+
+void netd_reset(uint8_t rhport)
+{
+  (void) rhport;
+
+  netd_init();
+}
+
+bool netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length)
+{
+  // sanity check the descriptor
+  TU_ASSERT (CFG_TUD_NET_INTERFACESUBCLASS == itf_desc->bInterfaceSubClass);
+
+  // confirm interface hasn't already been allocated
+  TU_ASSERT(0 == _netd_itf.ep_in);
+
+  //------------- first Interface -------------//
+  _netd_itf.itf_num = itf_desc->bInterfaceNumber;
+
+  uint8_t const * p_desc = tu_desc_next( itf_desc );
+  (*p_length) = sizeof(tusb_desc_interface_t);
+
+#if CFG_TUD_NET != OPT_NET_EEM
+  // Communication Functional Descriptors
+  while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) )
+  {
+    (*p_length) += tu_desc_len(p_desc);
+    p_desc = tu_desc_next(p_desc);
+  }
+
+  // notification endpoint (if any)
+  if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
+  {
+    TU_ASSERT( dcd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc) );
+
+    _netd_itf.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
+
+    (*p_length) += p_desc[DESC_OFFSET_LEN];
+    p_desc = tu_desc_next(p_desc);
+  }
+
+  //------------- second Interface -------------//
+  if ( (TUSB_DESC_INTERFACE == p_desc[DESC_OFFSET_TYPE]) &&
+       (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
+  {
+    // next to endpoint descriptor
+    p_desc = tu_desc_next(p_desc);
+    (*p_length) += sizeof(tusb_desc_interface_t);
+  }
+#endif
+
+  if (TUSB_DESC_ENDPOINT == p_desc[DESC_OFFSET_TYPE])
+  {
+    // Open endpoint pair
+    TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) );
+
+    (*p_length) += 2*sizeof(tusb_desc_endpoint_t);
+  }
+
+  network_init_callback();
+
+  // we are ready to transmit a packet
+  can_xmit = true;
+
+  // prepare for incoming packets
+  network_recv_renew();
+
+  return true;
+}
+
+// Invoked when class request DATA stage is finished.
+// return false to stall control endpoint (e.g Host send nonsense DATA)
+bool netd_control_complete(uint8_t rhport, tusb_control_request_t const * request)
+{
+  (void) rhport;
+
+  // Handle class request only
+  TU_VERIFY (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
+
+  TU_VERIFY (_netd_itf.itf_num == request->wIndex);
+
+#if CFG_TUD_NET == OPT_NET_RNDIS
+  if (request->bmRequestType_bit.direction == TUSB_DIR_OUT)
+  {
+    rndis_class_set_handler(rndis_buf, request->wLength);
+  }
+#endif
+
+  return true;
+}
+
+// Handle class control request
+// return false to stall control endpoint (e.g unsupported request)
+bool netd_control_request(uint8_t rhport, tusb_control_request_t const * request)
+{
+  // Handle class request only
+  TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
+
+  TU_VERIFY (_netd_itf.itf_num == request->wIndex);
+
+#if CFG_TUD_NET == OPT_NET_RNDIS
+  tud_control_xfer(rhport, request, rndis_buf, sizeof(rndis_buf));
+#else
+  (void)rhport;
+#endif
+
+  return true;
+}
+
+struct cdc_eem_packet_header
+{
+  uint16_t length:14;
+  uint16_t bmCRC:1;
+  uint16_t bmType:1;
+};
+
+static void handle_incoming_packet(uint32_t len)
+{
+  uint8_t *pnt = received;
+  uint32_t size = 0;
+
+#if CFG_TUD_NET == OPT_NET_ECM
+  size = len;
+#elif CFG_TUD_NET == OPT_NET_RNDIS
+  rndis_data_packet_t *r = (rndis_data_packet_t *)pnt;
+  if (len >= sizeof(rndis_data_packet_t))
+    if ( (r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len))
+      if ( (r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len)
+      {
+        pnt = &received[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)];
+        size = r->DataLength;
+      }
+#elif CFG_TUD_NET == OPT_NET_EEM
+  struct cdc_eem_packet_header *hdr = (struct cdc_eem_packet_header *)pnt;
+
+  (void)len;
+
+  if (hdr->bmType)
+  {
+    /* EEM Control Packet: discard it */
+    network_recv_renew();
+  }
+  else
+  {
+    /* EEM Data Packet */
+    pnt += CFG_TUD_NET_PACKET_PREFIX_LEN;
+    size = hdr->length - 4; /* discard the unused CRC-32 */
+  }
+#endif
+
+  if (size)
+  {
+    struct pbuf *p = pbuf_alloc(PBUF_RAW, size, PBUF_POOL);
+    bool accepted = true;
+
+    if (p)
+    {
+      memcpy(p->payload, pnt, size);
+      p->len = size;
+      accepted = network_recv_callback(p);
+    }
+
+    if (!p || !accepted)
+    {
+      /* if a buffer couldn't be allocated or accepted by the callback, we must discard this packet */
+      network_recv_renew();
+    }
+  }
+}
+
+bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
+{
+  (void) rhport;
+  (void) result;
+
+  /* new packet received */
+  if ( ep_addr == _netd_itf.ep_out )
+  {
+    handle_incoming_packet(xferred_bytes);
+  }
+
+  /* data transmission finished */
+  if ( ep_addr == _netd_itf.ep_in )
+  {
+    /* TinyUSB requires the class driver to implement ZLP (since ZLP usage is class-specific) */
+
+    if ( xferred_bytes && (0 == (xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE)) )
+    {
+      do_in_xfer(NULL, 0); /* a ZLP is needed */
+    }
+    else
+    {
+      /* we're finally finished */
+      can_xmit = true;
+    }
+  }
+
+  return true;
+}
+
+bool network_can_xmit(void)
+{
+  return can_xmit;
+}
+
+void network_xmit(struct pbuf *p)
+{
+  struct pbuf *q;
+  uint8_t *data;
+  uint16_t len;
+
+  if (!can_xmit)
+    return;
+
+  len = CFG_TUD_NET_PACKET_PREFIX_LEN;
+  data = transmitted + len;
+
+  for(q = p; q != NULL; q = q->next)
+  {
+    memcpy(data, (char *)q->payload, q->len);
+    data += q->len;
+    len += q->len;
+  }
+
+#if CFG_TUD_NET == OPT_NET_RNDIS
+  rndis_data_packet_t *hdr = (rndis_data_packet_t *)transmitted;
+  memset(hdr, 0, sizeof(rndis_data_packet_t));
+  hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
+  hdr->MessageLength = len;
+  hdr->DataOffset = sizeof(rndis_data_packet_t) - offsetof(rndis_data_packet_t, DataOffset);
+  hdr->DataLength = len - sizeof(rndis_data_packet_t);
+#elif CFG_TUD_NET == OPT_NET_EEM
+  struct cdc_eem_packet_header *hdr = (struct cdc_eem_packet_header *)transmitted;
+  /* append a fake CRC-32; the standard allows 0xDEADBEEF, which takes less CPU time */
+  data[0] = 0xDE; data[1] = 0xAD; data[2] = 0xBE; data[3] = 0xEF;
+  /* adjust length to reflect added fake CRC-32 */
+  len += 4;
+  hdr->bmType = 0; /* EEM Data Packet */
+  hdr->length = len - sizeof(struct cdc_eem_packet_header);
+  hdr->bmCRC = 0; /* Ethernet Frame CRC-32 set to 0xDEADBEEF */
+#endif
+
+  do_in_xfer(transmitted, len);
+}
+
+#endif

+ 84 - 0
src/class/net/net_device.h

@@ -0,0 +1,84 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Peter Lawrence
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_NET_DEVICE_H_
+#define _TUSB_NET_DEVICE_H_
+
+#include "common/tusb_common.h"
+#include "device/usbd.h"
+#include "class/cdc/cdc.h"
+#include "lwip/pbuf.h"
+#include "netif/ethernet.h"
+
+/* declared here, NOT in usb_descriptors.c, so that the driver can intelligently ZLP as needed */
+#define CFG_TUD_NET_ENDPOINT_SIZE ((CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 512 : 64)
+
+/* Maximum Tranmission Unit (in bytes) of the network, including Ethernet header */
+#define CFG_TUD_NET_MTU           (1500 + SIZEOF_ETH_HDR)
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
+
+// client must provide this: initialize any network state back to the beginning
+void network_init_callback(void);
+
+// client must provide this: return false if the packet buffer was not accepted
+bool network_recv_callback(struct pbuf *p);
+
+// client must provide this: 48-bit MAC address
+extern const uint8_t network_mac_address[6];
+
+// indicate to network driver that client has finished with the packet provided to network_recv_callback()
+void network_recv_renew(void);
+
+// poll network driver for its ability to accept another packet to transmit
+bool network_can_xmit(void);
+
+// if network_can_xmit() returns true, network_xmit() can be called once
+void network_xmit(struct pbuf *p);
+
+//--------------------------------------------------------------------+
+// INTERNAL USBD-CLASS DRIVER API
+//--------------------------------------------------------------------+
+void netd_init             (void);
+void netd_reset            (uint8_t rhport);
+bool netd_open             (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t *p_length);
+bool netd_control_request  (uint8_t rhport, tusb_control_request_t const * request);
+bool netd_control_complete (uint8_t rhport, tusb_control_request_t const * request);
+bool netd_xfer_cb          (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+void netd_report           (uint8_t *buf, uint16_t len);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_NET_DEVICE_H_ */

+ 18 - 0
src/device/usbd.c

@@ -181,6 +181,24 @@ static usbd_class_driver_t const _usbd_driver[] =
       .sof              = NULL
   },
   #endif
+
+  #if CFG_TUD_NET
+  {
+      .class_code       = 
+#if CFG_TUD_NET == OPT_NET_RNDIS
+                          TUD_RNDIS_ITF_CLASS,
+#else
+                          TUSB_CLASS_CDC,
+#endif
+      .init             = netd_init,
+      .reset            = netd_reset,
+      .open             = netd_open,
+      .control_request  = netd_control_request,
+      .control_complete = netd_control_complete,
+      .xfer_cb          = netd_xfer_cb,
+      .sof              = NULL
+  },
+  #endif
 };
 
 enum { USBD_CLASS_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) };

+ 84 - 0
src/device/usbd.h

@@ -326,6 +326,90 @@ TU_ATTR_WEAK bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_re
   9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
 
 
+//------------- CDC-ECM -------------//
+
+// Length of template descriptor: 62 bytes
+#define TUD_CDC_ECM_DESC_LEN  (9+5+5+13+7+9+7+7)
+
+// CDC-ECM Descriptor Template
+// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
+#define TUD_CDC_ECM_DESCRIPTOR(_itfnum, _desc_stridx, _mac_stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize, _maxsegmentsize) \
+  /* CDC Control Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0, _desc_stridx,\
+  /* CDC-ECM Header */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
+  /* CDC-ECM Union */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
+  /* CDC-ECM Functional Descriptor */\
+  13, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ETHERNET_NETWORKING, _mac_stridx, 0, 0, 0, 0, U16_TO_U8S_LE(_maxsegmentsize), U16_TO_U8S_LE(0), 0,\
+  /* Endpoint Notification */\
+  7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\
+  /* CDC Data Interface */\
+  9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
+
+//------------- RNDIS -------------//
+
+#if 0
+  /* Windows XP */
+  #define TUD_RNDIS_ITF_CLASS    TUSB_CLASS_CDC
+  #define TUD_RNDIS_ITF_SUBCLASS CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL
+  #define TUD_RNDIS_ITF_PROTOCOL CDC_COMM_PROTOCOL_MICROSOFT_RNDIS
+#else
+  /* Windows 7+ */
+  #define TUD_RNDIS_ITF_CLASS    0xE0
+  #define TUD_RNDIS_ITF_SUBCLASS 0x01
+  #define TUD_RNDIS_ITF_PROTOCOL 0x03
+#endif
+
+// Length of template descriptor: 66 bytes
+#define TUD_RNDIS_DESC_LEN  (8+9+5+5+4+5+7+9+7+7)
+
+// RNDIS Descriptor Template
+// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
+#define TUD_RNDIS_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \
+  /* Interface Association */\
+  8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, 0,\
+  /* CDC Control Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUD_RNDIS_ITF_CLASS, TUD_RNDIS_ITF_SUBCLASS, TUD_RNDIS_ITF_PROTOCOL, _stridx,\
+  /* CDC-ACM Header */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0110),\
+  /* CDC Call Management */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
+  /* ACM */\
+  4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 0,\
+  /* CDC Union */\
+  5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
+  /* Endpoint Notification */\
+  7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\
+  /* CDC Data Interface */\
+  9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
+
+//------------- CDC-EEM -------------//
+
+// Length of template descriptor: 23 bytes
+#define TUD_CDC_EEM_DESC_LEN  (9+7+7)
+
+// CDC-EEM Descriptor Template
+// Interface number, description string index, EP data address (out, in) and size.
+#define TUD_CDC_EEM_DESCRIPTOR(_itfnum, _stridx, _epout, _epin, _epsize) \
+  /* EEM Interface */\
+  9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ETHERNET_EMULATION_MODEL, CDC_COMM_PROTOCOL_ETHERNET_EMULATION_MODEL, _stridx,\
+  /* Endpoint In */\
+  7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0,\
+  /* Endpoint Out */\
+  7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
+
+
 #ifdef __cplusplus
  }
 #endif

+ 4 - 0
src/tusb.h

@@ -91,6 +91,10 @@
   #if CFG_TUD_DFU_RT
     #include "class/dfu/dfu_rt_device.h"
   #endif
+
+  #if CFG_TUD_NET
+    #include "class/net/net_device.h"
+  #endif
 #endif
 
 

+ 12 - 0
src/tusb_option.h

@@ -117,6 +117,15 @@
 #define OPT_MODE_HIGH_SPEED   0x10 ///< High speed
 /** @} */
 
+/** \defgroup group_supported_netif Supported Network Interface
+ *  \ref CFG_TUD_NET must be defined to one of these
+ *  @{ */
+#define OPT_NET_NONE      0 ///< No network interface
+#define OPT_NET_ECM       1 ///< CDC-ECM
+#define OPT_NET_RNDIS     2 ///< RNDIS
+#define OPT_NET_EEM       3 ///< CDC-EEM
+/** @} */
+
 #ifndef CFG_TUSB_RHPORT0_MODE
   #define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE
 #endif
@@ -204,6 +213,9 @@
   #define CFG_TUD_DFU_RT          0
 #endif
 
+#ifndef CFG_TUD_NET
+  #define CFG_TUD_NET             0
+#endif
 
 //--------------------------------------------------------------------
 // HOST OPTIONS