3      Copyright (C) Dean Camera, 2010. 
   5   dean [at] fourwalledcubicle [dot] com 
   6       www.fourwalledcubicle.com 
  10   Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  12   Permission to use, copy, modify, distribute, and sell this  
  13   software and its documentation for any purpose is hereby granted 
  14   without fee, provided that the above copyright notice appear in  
  15   all copies and that both that the copyright notice and this 
  16   permission notice and warranty disclaimer appear in supporting  
  17   documentation, and that the name of the author not be used in  
  18   advertising or publicity pertaining to distribution of the  
  19   software without specific, written prior permission. 
  21   The author disclaim all warranties with regard to this 
  22   software, including all implied warranties of merchantability 
  23   and fitness.  In no event shall the author be liable for any 
  24   special, indirect or consequential damages or any damages 
  25   whatsoever resulting from loss of use, data or profits, whether 
  26   in an action of contract, negligence or other tortious action, 
  27   arising out of or in connection with the use or performance of 
  33  *  RNDIS command handler functions. This handles RNDIS commands according to 
  34  *  the Microsoft RNDIS specification, creating a USB Ethernet network adapter. 
  37 #define  INCLUDE_FROM_RNDIS_C 
  40 /** Physical MAC address of the network adapter, which becomes the MAC address of the host for packets sent to the adapter. */ 
  41 static MAC_Address_t  PROGMEM AdapterMACAddress          
= {ADAPTER_MAC_ADDRESS
}; 
  43 /** Vendor description of the adapter. This is overridden by the INF file required to install the appropriate RNDIS drivers for 
  44  *  the device, but may still be used by the OS in some circumstances. 
  46 static char           PROGMEM AdapterVendorDescription
[] = "LUFA RNDIS Adapter"; 
  48 /** List of RNDIS OID commands supported by this adapter. */ 
  49 static const uint32_t PROGMEM AdapterSupportedOIDList
[]  = 
  51                                                                 OID_GEN_SUPPORTED_LIST
, 
  52                                                                 OID_GEN_PHYSICAL_MEDIUM
, 
  53                                                                 OID_GEN_HARDWARE_STATUS
, 
  54                                                                 OID_GEN_MEDIA_SUPPORTED
, 
  56                                                                 OID_GEN_MAXIMUM_FRAME_SIZE
, 
  57                                                                 OID_GEN_MAXIMUM_TOTAL_SIZE
, 
  59                                                                 OID_GEN_TRANSMIT_BLOCK_SIZE
, 
  60                                                                 OID_GEN_RECEIVE_BLOCK_SIZE
, 
  62                                                                 OID_GEN_VENDOR_DESCRIPTION
, 
  63                                                                 OID_GEN_CURRENT_PACKET_FILTER
, 
  64                                                                 OID_GEN_MAXIMUM_TOTAL_SIZE
, 
  65                                                                 OID_GEN_MEDIA_CONNECT_STATUS
, 
  70                                                                 OID_GEN_RCV_NO_BUFFER
, 
  71                                                                 OID_802_3_PERMANENT_ADDRESS
, 
  72                                                                 OID_802_3_CURRENT_ADDRESS
, 
  73                                                                 OID_802_3_MULTICAST_LIST
, 
  74                                                                 OID_802_3_MAXIMUM_LIST_SIZE
, 
  75                                                                 OID_802_3_RCV_ERROR_ALIGNMENT
, 
  76                                                                 OID_802_3_XMIT_ONE_COLLISION
, 
  77                                                                 OID_802_3_XMIT_MORE_COLLISIONS
, 
  80 /** Buffer for RNDIS messages (as distinct from Ethernet frames sent through the adapter. This must be big enough to hold the entire 
  81  *  Supported OID list, plus the response header. The buffer is half-duplex, and is written to as it is read to save on SRAM - for this 
  82  *  reason, care must be taken when constructing RNDIS responses that unread data is not overwritten when writing in responses. 
  84 uint8_t                 RNDISMessageBuffer
[sizeof(AdapterSupportedOIDList
) + sizeof(RNDIS_Query_Complete_t
)]; 
  86 /** Pointer to the RNDIS message header at the top of the RNDIS message buffer, for convenience. */ 
  87 RNDIS_Message_Header_t
* MessageHeader 
= (RNDIS_Message_Header_t
*)&RNDISMessageBuffer
; 
  89 /** Indicates if a RNDIS message response is ready to be sent back to the host. */ 
  90 bool                    ResponseReady               
= false; 
  92 /** Current RNDIS adapter state, a value from the RNDIS_States_t enum. */ 
  93 uint8_t                 CurrRNDISState              
= RNDIS_Uninitialized
; 
  95 /** Current Ethernet packet filter mask. This is non-zero when the adapter is initialized, or zero when disabled. */ 
  96 uint32_t                CurrPacketFilter            
= 0;                                                         
  99 /** Processes the RNDIS message received by the host and stored in the RNDISMessageBuffer global buffer. If a response is 
 100  *  created, the ResponseReady global is updated so that the response is written back to the host upon request. 
 102 void ProcessRNDISControlMessage(void) 
 104         /* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of 
 105                  this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */ 
 107         switch (MessageHeader
->MessageType
) 
 109                 case REMOTE_NDIS_INITIALIZE_MSG
: 
 110                         /* Initialize the adapter - return information about the supported RNDIS version and buffer sizes */ 
 112                         ResponseReady 
= true; 
 114                         RNDIS_Initialize_Message_t
*  INITIALIZE_Message  
= (RNDIS_Initialize_Message_t
*)&RNDISMessageBuffer
; 
 115                         RNDIS_Initialize_Complete_t
* INITIALIZE_Response 
= (RNDIS_Initialize_Complete_t
*)&RNDISMessageBuffer
; 
 117                         INITIALIZE_Response
->MessageType           
= REMOTE_NDIS_INITIALIZE_CMPLT
; 
 118                         INITIALIZE_Response
->MessageLength         
= sizeof(RNDIS_Initialize_Complete_t
); 
 119                         INITIALIZE_Response
->RequestId             
= INITIALIZE_Message
->RequestId
; 
 120                         INITIALIZE_Response
->Status                
= REMOTE_NDIS_STATUS_SUCCESS
; 
 122                         INITIALIZE_Response
->MajorVersion          
= REMOTE_NDIS_VERSION_MAJOR
; 
 123                         INITIALIZE_Response
->MinorVersion          
= REMOTE_NDIS_VERSION_MINOR
;                  
 124                         INITIALIZE_Response
->DeviceFlags           
= REMOTE_NDIS_DF_CONNECTIONLESS
; 
 125                         INITIALIZE_Response
->Medium                
= REMOTE_NDIS_MEDIUM_802_3
; 
 126                         INITIALIZE_Response
->MaxPacketsPerTransfer 
= 1; 
 127                         INITIALIZE_Response
->MaxTransferSize       
= (sizeof(RNDIS_Packet_Message_t
) + ETHERNET_FRAME_SIZE_MAX
); 
 128                         INITIALIZE_Response
->PacketAlignmentFactor 
= 0; 
 129                         INITIALIZE_Response
->AFListOffset          
= 0; 
 130                         INITIALIZE_Response
->AFListSize            
= 0; 
 132                         CurrRNDISState 
= RNDIS_Initialized
; 
 135                 case REMOTE_NDIS_HALT_MSG
: 
 136                         /* Halt the adapter, reset the adapter state - note that no response should be returned when completed */ 
 138                         ResponseReady 
= false; 
 139                         MessageHeader
->MessageLength 
= 0; 
 141                         CurrRNDISState 
= RNDIS_Uninitialized
; 
 144                 case REMOTE_NDIS_QUERY_MSG
: 
 145                         /* Request for information about a parameter about the adapter, specified as an OID token */ 
 147                         ResponseReady 
= true; 
 149                         RNDIS_Query_Message_t
*  QUERY_Message  
= (RNDIS_Query_Message_t
*)&RNDISMessageBuffer
; 
 150                         RNDIS_Query_Complete_t
* QUERY_Response 
= (RNDIS_Query_Complete_t
*)&RNDISMessageBuffer
; 
 151                         uint32_t                Query_Oid      
= QUERY_Message
->Oid
; 
 153                         void*     QueryData                 
= &RNDISMessageBuffer
[sizeof(RNDIS_Message_Header_t
) + 
 154                                                                                   QUERY_Message
->InformationBufferOffset
]; 
 155                         void*     ResponseData              
= &RNDISMessageBuffer
[sizeof(RNDIS_Query_Complete_t
)];               
 156                         uint16_t  ResponseSize
; 
 158                         QUERY_Response
->MessageType         
= REMOTE_NDIS_QUERY_CMPLT
; 
 159                         QUERY_Response
->MessageLength       
= sizeof(RNDIS_Query_Complete_t
); 
 161                         if (ProcessNDISQuery(Query_Oid
, QueryData
, QUERY_Message
->InformationBufferLength
, 
 162                                              ResponseData
, &ResponseSize
)) 
 164                                 QUERY_Response
->Status                  
= REMOTE_NDIS_STATUS_SUCCESS
; 
 165                                 QUERY_Response
->MessageLength          
+= ResponseSize
; 
 167                                 QUERY_Response
->InformationBufferLength 
= ResponseSize
; 
 168                                 QUERY_Response
->InformationBufferOffset 
= (sizeof(RNDIS_Query_Complete_t
) - sizeof(RNDIS_Message_Header_t
)); 
 172                                 QUERY_Response
->Status                  
= REMOTE_NDIS_STATUS_NOT_SUPPORTED
; 
 174                                 QUERY_Response
->InformationBufferLength 
= 0; 
 175                                 QUERY_Response
->InformationBufferOffset 
= 0; 
 179                 case REMOTE_NDIS_SET_MSG
: 
 180                         /* Request to set a parameter of the adapter, specified as an OID token */ 
 182                         ResponseReady 
= true; 
 184                         RNDIS_Set_Message_t
*  SET_Message  
= (RNDIS_Set_Message_t
*)&RNDISMessageBuffer
; 
 185                         RNDIS_Set_Complete_t
* SET_Response 
= (RNDIS_Set_Complete_t
*)&RNDISMessageBuffer
; 
 186                         uint32_t              SET_Oid      
= SET_Message
->Oid
; 
 188                         SET_Response
->MessageType       
= REMOTE_NDIS_SET_CMPLT
; 
 189                         SET_Response
->MessageLength     
= sizeof(RNDIS_Set_Complete_t
); 
 190                         SET_Response
->RequestId         
= SET_Message
->RequestId
; 
 192                         void* SetData                   
= &RNDISMessageBuffer
[sizeof(RNDIS_Message_Header_t
) + 
 193                                                                               SET_Message
->InformationBufferOffset
]; 
 195                         if (ProcessNDISSet(SET_Oid
, SetData
, SET_Message
->InformationBufferLength
)) 
 196                           SET_Response
->Status        
= REMOTE_NDIS_STATUS_SUCCESS
; 
 198                           SET_Response
->Status        
= REMOTE_NDIS_STATUS_NOT_SUPPORTED
; 
 201                 case REMOTE_NDIS_RESET_MSG
: 
 202                         /* Soft reset the adapter */ 
 204                         ResponseReady 
= true; 
 206                         RNDIS_Reset_Complete_t
* RESET_Response 
= (RNDIS_Reset_Complete_t
*)&RNDISMessageBuffer
; 
 208                         RESET_Response
->MessageType         
= REMOTE_NDIS_RESET_CMPLT
; 
 209                         RESET_Response
->MessageLength       
= sizeof(RNDIS_Reset_Complete_t
); 
 210                         RESET_Response
->Status              
= REMOTE_NDIS_STATUS_SUCCESS
; 
 211                         RESET_Response
->AddressingReset     
= 0; 
 214                 case REMOTE_NDIS_KEEPALIVE_MSG
: 
 215                         /* Keep alive message sent to the adapter every 5 seconds when idle to ensure it is still responding */ 
 217                         ResponseReady 
= true; 
 219                         RNDIS_KeepAlive_Message_t
*  KEEPALIVE_Message  
= (RNDIS_KeepAlive_Message_t
*)&RNDISMessageBuffer
; 
 220                         RNDIS_KeepAlive_Complete_t
* KEEPALIVE_Response 
= (RNDIS_KeepAlive_Complete_t
*)&RNDISMessageBuffer
; 
 222                         KEEPALIVE_Response
->MessageType     
= REMOTE_NDIS_KEEPALIVE_CMPLT
; 
 223                         KEEPALIVE_Response
->MessageLength   
= sizeof(RNDIS_KeepAlive_Complete_t
); 
 224                         KEEPALIVE_Response
->RequestId       
= KEEPALIVE_Message
->RequestId
; 
 225                         KEEPALIVE_Response
->Status          
= REMOTE_NDIS_STATUS_SUCCESS
; 
 231 /** Processes RNDIS query commands, retrieving information from the adapter and reporting it back to the host. The requested 
 232  *  parameter is given as an OID value. 
 234  *  \param[in] OId            OId value of the parameter being queried 
 235  *  \param[in] QueryData      Pointer to any extra query data being sent by the host to the device inside the RNDIS message buffer 
 236  *  \param[in] QuerySize      Size in bytes of the extra query data being sent by the host 
 237  *  \param[out] ResponseData  Pointer to the start of the query response inside the RNDIS message buffer 
 238  *  \param[out] ResponseSize  Pointer to the size in bytes of the response data being sent to the host 
 240  *  \return Boolean true if the query was handled, false otherwise 
 242 static bool ProcessNDISQuery(const uint32_t OId
, void* QueryData
, uint16_t QuerySize
, 
 243                              void* ResponseData
, uint16_t* ResponseSize
) 
 245         /* Handler for REMOTE_NDIS_QUERY_MSG messages */ 
 249                 case OID_GEN_SUPPORTED_LIST
: 
 250                         *ResponseSize 
= sizeof(AdapterSupportedOIDList
); 
 252                         /* Copy the list of supported NDIS OID tokens to the response buffer */ 
 253                         memcpy_P(ResponseData
, AdapterSupportedOIDList
, sizeof(AdapterSupportedOIDList
)); 
 256                 case OID_GEN_PHYSICAL_MEDIUM
: 
 257                         *ResponseSize 
= sizeof(uint32_t); 
 259                         /* Indicate that the device is a true ethernet link */ 
 260                         *((uint32_t*)ResponseData
) = 0; 
 263                 case OID_GEN_HARDWARE_STATUS
: 
 264                         *ResponseSize 
= sizeof(uint32_t); 
 266                         /* Always indicate hardware ready */ 
 267                         *((uint32_t*)ResponseData
) = NdisHardwareStatusReady
; 
 270                 case OID_GEN_MEDIA_SUPPORTED
: 
 271                 case OID_GEN_MEDIA_IN_USE
: 
 272                         *ResponseSize 
= sizeof(uint32_t); 
 274                         /* Indicate 802.3 (Ethernet) supported by the adapter */ 
 275                         *((uint32_t*)ResponseData
) = REMOTE_NDIS_MEDIUM_802_3
; 
 278                 case OID_GEN_VENDOR_ID
: 
 279                         *ResponseSize 
= sizeof(uint32_t); 
 281                         /* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */ 
 282                         *((uint32_t*)ResponseData
) = 0x00FFFFFF; 
 285                 case OID_GEN_MAXIMUM_FRAME_SIZE
: 
 286                 case OID_GEN_TRANSMIT_BLOCK_SIZE
: 
 287                 case OID_GEN_RECEIVE_BLOCK_SIZE
: 
 288                         *ResponseSize 
= sizeof(uint32_t); 
 290                         /* Indicate that the maximum frame size is the size of the ethernet frame buffer */ 
 291                         *((uint32_t*)ResponseData
) = ETHERNET_FRAME_SIZE_MAX
; 
 294                 case OID_GEN_VENDOR_DESCRIPTION
: 
 295                         *ResponseSize 
= sizeof(AdapterVendorDescription
); 
 297                         /* Copy vendor description string to the response buffer */ 
 298                         memcpy_P(ResponseData
, AdapterVendorDescription
, sizeof(AdapterVendorDescription
)); 
 301                 case OID_GEN_MEDIA_CONNECT_STATUS
: 
 302                         *ResponseSize 
= sizeof(uint32_t); 
 304                         /* Always indicate that the adapter is connected to a network */ 
 305                         *((uint32_t*)ResponseData
) = REMOTE_NDIS_MEDIA_STATE_CONNECTED
; 
 308                 case OID_GEN_LINK_SPEED
: 
 309                         *ResponseSize 
= sizeof(uint32_t); 
 311                         /* Indicate 10Mb/s link speed */ 
 312                         *((uint32_t*)ResponseData
) = 100000; 
 315                 case OID_802_3_PERMANENT_ADDRESS
: 
 316                 case OID_802_3_CURRENT_ADDRESS
: 
 317                         *ResponseSize 
= sizeof(MAC_Address_t
); 
 319                         /* Copy over the fixed adapter MAC to the response buffer */ 
 320                         memcpy_P(ResponseData
, &AdapterMACAddress
, sizeof(MAC_Address_t
)); 
 323                 case OID_802_3_MAXIMUM_LIST_SIZE
: 
 324                         *ResponseSize 
= sizeof(uint32_t); 
 326                         /* Indicate only one multicast address supported */ 
 327                         *((uint32_t*)ResponseData
) = 1; 
 330                 case OID_GEN_CURRENT_PACKET_FILTER
: 
 331                         *ResponseSize 
= sizeof(uint32_t); 
 333                         /* Indicate the current packet filter mask */ 
 334                         *((uint32_t*)ResponseData
) = CurrPacketFilter
; 
 337                 case OID_GEN_XMIT_OK
: 
 339                 case OID_GEN_XMIT_ERROR
: 
 340                 case OID_GEN_RCV_ERROR
: 
 341                 case OID_GEN_RCV_NO_BUFFER
: 
 342                 case OID_802_3_RCV_ERROR_ALIGNMENT
: 
 343                 case OID_802_3_XMIT_ONE_COLLISION
: 
 344                 case OID_802_3_XMIT_MORE_COLLISIONS
: 
 345                         *ResponseSize 
= sizeof(uint32_t); 
 347                         /* Unused statistic OIDs - always return 0 for each */ 
 348                         *((uint32_t*)ResponseData
) = 0; 
 351                 case OID_GEN_MAXIMUM_TOTAL_SIZE
: 
 352                         *ResponseSize 
= sizeof(uint32_t); 
 354                         /* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */ 
 355                         *((uint32_t*)ResponseData
) = (sizeof(RNDISMessageBuffer
) + ETHERNET_FRAME_SIZE_MAX
); 
 363 /** Processes RNDIS set commands, setting adapter parameters to values given by the host. The requested parameter is given  
 366  *  \param[in] OId      OId value of the parameter being set 
 367  *  \param[in] SetData  Pointer to the parameter value in the RNDIS message buffer 
 368  *  \param[in] SetSize  Size in bytes of the parameter value being sent by the host 
 370  *  \return Boolean true if the set was handled, false otherwise 
 372 static bool ProcessNDISSet(uint32_t OId
, void* SetData
, uint16_t SetSize
) 
 374         /* Handler for REMOTE_NDIS_SET_MSG messages */ 
 378                 case OID_GEN_CURRENT_PACKET_FILTER
: 
 379                         /* Save the packet filter mask in case the host queries it again later */ 
 380                         CurrPacketFilter 
= *((uint32_t*)SetData
); 
 382                         /* Set the RNDIS state to initialized if the packet filter is non-zero */ 
 383                         CurrRNDISState 
= ((CurrPacketFilter
) ? RNDIS_Data_Initialized 
: RNDIS_Data_Initialized
); 
 386                 case OID_802_3_MULTICAST_LIST
: 
 387                         /* Do nothing - throw away the value from the host as it is unused */