| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | /* 
 | 
					
						
							|  |  |  |  * 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"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-23 21:46:40 +07:00
										 |  |  | #if ( CFG_TUD_ENABLED && CFG_TUD_ECM_RNDIS )
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-27 17:40:39 +07:00
										 |  |  | #include "device/usbd.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | #include "device/usbd_pvt.h"
 | 
					
						
							| 
									
										
										
										
											2021-05-27 17:40:39 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "net_device.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | #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 | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |   uint8_t itf_num;      // Index number of Management Interface, +1 for Data Interface
 | 
					
						
							|  |  |  |   uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  |   uint8_t ep_notif; | 
					
						
							|  |  |  |   uint8_t ep_in; | 
					
						
							|  |  |  |   uint8_t ep_out; | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   bool ecm_mode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Endpoint descriptor use to open/close when receving SetInterface
 | 
					
						
							|  |  |  |   // TODO since configuration descriptor may not be long-lived memory, we should
 | 
					
						
							|  |  |  |   // keep a copy of endpoint attribute instead
 | 
					
						
							|  |  |  |   uint8_t const * ecm_desc_epdata; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | } netd_interface_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-14 21:10:43 -05:00
										 |  |  | #define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t)
 | 
					
						
							|  |  |  | #define CFG_TUD_NET_PACKET_SUFFIX_LEN 0
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  | struct ecm_notify_struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   tusb_control_request_t header; | 
					
						
							|  |  |  |   uint32_t downlink, uplink; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct ecm_notify_struct ecm_notify_nc = | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   .header = { | 
					
						
							|  |  |  |     .bmRequestType = 0xA1, | 
					
						
							|  |  |  |     .bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */, | 
					
						
							| 
									
										
										
										
											2020-03-27 20:30:57 -05:00
										 |  |  |     .wValue = 1 /* Connected */, | 
					
						
							|  |  |  |     .wLength = 0, | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  |   }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct ecm_notify_struct ecm_notify_csc = | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   .header = { | 
					
						
							|  |  |  |     .bmRequestType = 0xA1, | 
					
						
							|  |  |  |     .bRequest = 0x2A /* CONNECTION_SPEED_CHANGE aka ConnectionSpeedChange */, | 
					
						
							|  |  |  |     .wLength = 8, | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   .downlink = 9728000, | 
					
						
							|  |  |  |   .uplink = 9728000, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-26 22:03:05 +07:00
										 |  |  | // TODO remove CFG_TUSB_MEM_SECTION, control internal buffer is already in this special section
 | 
					
						
							| 
									
										
										
										
											2020-04-26 23:04:17 +07:00
										 |  |  | CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static union | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  | { | 
					
						
							|  |  |  |   uint8_t rndis_buf[120]; | 
					
						
							|  |  |  |   struct ecm_notify_struct ecm_buf; | 
					
						
							|  |  |  | } notify; | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // INTERNAL OBJECT & FUNCTION DECLARATION
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2020-04-26 22:03:05 +07:00
										 |  |  | // TODO remove CFG_TUSB_MEM_SECTION
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | CFG_TUSB_MEM_SECTION static netd_interface_t _netd_itf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool can_xmit; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-03 10:31:46 -06:00
										 |  |  | void tud_network_recv_renew(void) | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-06-02 16:51:17 +07:00
										 |  |  |   usbd_edpt_xfer(0, _netd_itf.ep_out, received, sizeof(received)); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void do_in_xfer(uint8_t *buf, uint16_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   can_xmit = false; | 
					
						
							| 
									
										
										
										
											2022-06-02 16:51:17 +07:00
										 |  |  |   usbd_edpt_xfer(0, _netd_itf.ep_in, buf, len); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void netd_report(uint8_t *buf, uint16_t len) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-06-02 16:51:17 +07:00
										 |  |  |   uint8_t const rhport = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:28:44 -05:00
										 |  |  |   // skip if previous report not yet acknowledged by host
 | 
					
						
							| 
									
										
										
										
											2022-06-02 16:51:17 +07:00
										 |  |  |   if ( usbd_edpt_busy(rhport, _netd_itf.ep_notif) ) return; | 
					
						
							|  |  |  |   usbd_edpt_xfer(rhport, _netd_itf.ep_notif, buf, len); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // USBD Driver API
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | void netd_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   tu_memclr(&_netd_itf, sizeof(_netd_itf)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void netd_reset(uint8_t rhport) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   netd_init(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  | uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-04-15 11:41:26 +07:00
										 |  |  |   bool const is_rndis = (TUD_RNDIS_ITF_CLASS    == itf_desc->bInterfaceClass    && | 
					
						
							|  |  |  |                          TUD_RNDIS_ITF_SUBCLASS == itf_desc->bInterfaceSubClass && | 
					
						
							|  |  |  |                          TUD_RNDIS_ITF_PROTOCOL == itf_desc->bInterfaceProtocol); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-31 10:57:53 -06:00
										 |  |  |   bool const is_ecm = (TUSB_CLASS_CDC                           == itf_desc->bInterfaceClass && | 
					
						
							|  |  |  |                        CDC_COMM_SUBCLASS_ETHERNET_CONTROL_MODEL == itf_desc->bInterfaceSubClass && | 
					
						
							|  |  |  |                        0x00                                     == itf_desc->bInterfaceProtocol); | 
					
						
							| 
									
										
										
										
											2020-04-15 11:41:26 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |   TU_VERIFY(is_rndis || is_ecm, 0); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // confirm interface hasn't already been allocated
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |   TU_ASSERT(0 == _netd_itf.ep_notif, 0); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 11:41:26 +07:00
										 |  |  |   // sanity check the descriptor
 | 
					
						
							|  |  |  |   _netd_itf.ecm_mode = is_ecm; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  |   //------------- Management Interface -------------//
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  |   _netd_itf.itf_num = itf_desc->bInterfaceNumber; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |   uint16_t drv_len = sizeof(tusb_desc_interface_t); | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |   uint8_t const * p_desc = tu_desc_next( itf_desc ); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Communication Functional Descriptors
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |   while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len ) | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |     drv_len += tu_desc_len(p_desc); | 
					
						
							|  |  |  |     p_desc   = tu_desc_next(p_desc); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // notification endpoint (if any)
 | 
					
						
							|  |  |  |   if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) ) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |     TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 ); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     _netd_itf.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |     drv_len += tu_desc_len(p_desc); | 
					
						
							|  |  |  |     p_desc   = tu_desc_next(p_desc); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  |   //------------- Data Interface -------------//
 | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |   // - RNDIS Data followed immediately by a pair of endpoints
 | 
					
						
							|  |  |  |   // - CDC-ECM data interface has 2 alternate settings
 | 
					
						
							|  |  |  |   //   - 0 : zero endpoints for inactive (default)
 | 
					
						
							|  |  |  |   //   - 1 : IN & OUT endpoints for active networking
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |   TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0); | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   do | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |     tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc; | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |     TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0); | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |     drv_len += tu_desc_len(p_desc); | 
					
						
							|  |  |  |     p_desc   = tu_desc_next(p_desc); | 
					
						
							|  |  |  |   }while( _netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len) ); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |   // Pair of endpoints
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |   TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0); | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if ( _netd_itf.ecm_mode ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // ECM by default is in-active, save the endpoint attribute
 | 
					
						
							|  |  |  |     // to open later when received setInterface
 | 
					
						
							|  |  |  |     _netd_itf.ecm_desc_epdata = p_desc; | 
					
						
							|  |  |  |   }else | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |     // Open endpoint pair for RNDIS
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |     TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0 ); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |     tud_network_init_cb(); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |     // we are ready to transmit a packet
 | 
					
						
							|  |  |  |     can_xmit = true; | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |     // prepare for incoming packets
 | 
					
						
							|  |  |  |     tud_network_recv_renew(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |   drv_len += 2*sizeof(tusb_desc_endpoint_t); | 
					
						
							| 
									
										
										
										
											2020-04-15 16:18:24 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-28 11:51:25 +07:00
										 |  |  |   return drv_len; | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  | static void ecm_report(bool nc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   notify.ecm_buf = (nc) ? ecm_notify_nc : ecm_notify_csc; | 
					
						
							|  |  |  |   notify.ecm_buf.header.wIndex = _netd_itf.itf_num; | 
					
						
							|  |  |  |   netd_report((uint8_t *)¬ify.ecm_buf, (nc) ? sizeof(notify.ecm_buf.header) : sizeof(notify.ecm_buf)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  | // Invoked when a control transfer occurred on an interface of this class
 | 
					
						
							|  |  |  | // Driver response accordingly to the request and the transfer stage (setup/data/ack)
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | // return false to stall control endpoint (e.g unsupported request)
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  | bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |   if ( stage == CONTROL_STAGE_SETUP ) | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |     switch ( request->bmRequestType_bit.type ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       case TUSB_REQ_TYPE_STANDARD: | 
					
						
							|  |  |  |         switch ( request->bRequest ) | 
					
						
							| 
									
										
										
										
											2020-04-16 11:13:54 +07:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |           case TUSB_REQ_GET_INTERFACE: | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             uint8_t const req_itfnum = (uint8_t) request->wIndex; | 
					
						
							|  |  |  |             TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum); | 
					
						
							| 
									
										
										
										
											2020-04-16 11:13:54 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |             tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |           case TUSB_REQ_SET_INTERFACE: | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             uint8_t const req_itfnum = (uint8_t) request->wIndex; | 
					
						
							|  |  |  |             uint8_t const req_alt    = (uint8_t) request->wValue; | 
					
						
							| 
									
										
										
										
											2020-04-15 23:10:52 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |             // Only valid for Data Interface with Alternate is either 0 or 1
 | 
					
						
							|  |  |  |             TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum && req_alt < 2); | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |             // ACM-ECM only: qequest to enable/disable network activities
 | 
					
						
							|  |  |  |             TU_VERIFY(_netd_itf.ecm_mode); | 
					
						
							| 
									
										
										
										
											2020-04-15 23:10:52 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |             _netd_itf.itf_data_alt = req_alt; | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |             if ( _netd_itf.itf_data_alt ) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               // TODO since we don't actually close endpoint
 | 
					
						
							|  |  |  |               // hack here to not re-open it
 | 
					
						
							|  |  |  |               if ( _netd_itf.ep_in == 0 && _netd_itf.ep_out == 0 ) | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 TU_ASSERT(_netd_itf.ecm_desc_epdata); | 
					
						
							|  |  |  |                 TU_ASSERT( usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // TODO should be merge with RNDIS's after endpoint opened
 | 
					
						
							|  |  |  |                 // Also should have opposite callback for application to disable network !!
 | 
					
						
							|  |  |  |                 tud_network_init_cb(); | 
					
						
							|  |  |  |                 can_xmit = true; // we are ready to transmit a packet
 | 
					
						
							|  |  |  |                 tud_network_recv_renew(); // prepare for incoming packets
 | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }else | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |               // TODO close the endpoint pair
 | 
					
						
							|  |  |  |               // For now pretend that we did, this should have no harm since host won't try to
 | 
					
						
							|  |  |  |               // communicate with the endpoints again
 | 
					
						
							|  |  |  |               // _netd_itf.ep_in = _netd_itf.ep_out = 0
 | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             tud_control_status(rhport, request); | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |           break; | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |           // unsupported request
 | 
					
						
							|  |  |  |           default: return false; | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |       case TUSB_REQ_TYPE_CLASS: | 
					
						
							|  |  |  |         TU_VERIFY (_netd_itf.itf_num == request->wIndex); | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |         if (_netd_itf.ecm_mode) | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |           /* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */ | 
					
						
							|  |  |  |           if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             tud_control_xfer(rhport, request, NULL, 0); | 
					
						
							|  |  |  |             ecm_report(true); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |           if (request->bmRequestType_bit.direction == TUSB_DIR_IN) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *) ((void*) notify.rndis_buf); | 
					
						
							|  |  |  |             uint32_t msglen = tu_le32toh(rndis_msg->MessageLength); | 
					
						
							|  |  |  |             TU_ASSERT(msglen <= sizeof(notify.rndis_buf)); | 
					
						
							| 
									
										
										
										
											2022-06-27 20:30:47 +07:00
										 |  |  |             tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) msglen); | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |           } | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |           { | 
					
						
							| 
									
										
										
										
											2022-06-27 20:30:47 +07:00
										 |  |  |             tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) sizeof(notify.rndis_buf)); | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2020-04-15 17:51:02 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 16:59:33 +07:00
										 |  |  |       // unsupported request
 | 
					
						
							|  |  |  |       default: return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if ( stage == CONTROL_STAGE_DATA ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Handle RNDIS class control OUT only
 | 
					
						
							|  |  |  |     if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && | 
					
						
							|  |  |  |         request->bmRequestType_bit.direction == TUSB_DIR_OUT   && | 
					
						
							|  |  |  |         _netd_itf.itf_num == request->wIndex) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if ( !_netd_itf.ecm_mode ) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         rndis_class_set_handler(notify.rndis_buf, request->wLength); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-03-15 16:05:45 -05:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void handle_incoming_packet(uint32_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   uint8_t *pnt = received; | 
					
						
							|  |  |  |   uint32_t size = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  |   if (_netd_itf.ecm_mode) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     size = len; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-05-18 13:23:40 +07:00
										 |  |  |     rndis_data_packet_t *r = (rndis_data_packet_t *) ((void*) pnt); | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  |     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; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-27 20:30:47 +07:00
										 |  |  |   if (!tud_network_recv_cb(pnt, (uint16_t) size)) | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  |   { | 
					
						
							|  |  |  |     /* if a buffer was never handled by user code, we must renew on the user's behalf */ | 
					
						
							|  |  |  |     tud_network_recv_renew(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  |   if ( _netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif) ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if (sizeof(notify.ecm_buf.header) == xferred_bytes) ecm_report(false); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-03 11:28:44 -05:00
										 |  |  | bool tud_network_can_xmit(uint16_t size) | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-03 11:28:44 -05:00
										 |  |  |   (void)size; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  |   return can_xmit; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-24 20:27:57 -05:00
										 |  |  | void tud_network_xmit(void *ref, uint16_t arg) | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | { | 
					
						
							|  |  |  |   uint8_t *data; | 
					
						
							|  |  |  |   uint16_t len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!can_xmit) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  |   len = (_netd_itf.ecm_mode) ? 0 : CFG_TUD_NET_PACKET_PREFIX_LEN; | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  |   data = transmitted + len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-24 20:27:57 -05:00
										 |  |  |   len += tud_network_xmit_cb(data, ref, arg); | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  |   if (!_netd_itf.ecm_mode) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-05-18 13:23:40 +07:00
										 |  |  |     rndis_data_packet_t *hdr = (rndis_data_packet_t *) ((void*) transmitted); | 
					
						
							| 
									
										
										
										
											2020-04-12 15:41:18 -05:00
										 |  |  |     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); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-02 21:15:01 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |   do_in_xfer(transmitted, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 |