X-Git-Url: http://git.linex4red.de/pub/USBasp.git/blobdiff_plain/f896c00c48f04fb9273555ab8d9b1af99f865d25..77a9df36a77d2523dd2bc24fa17f9f04c6c175c5:/LUFA/Drivers/USB/Class/Device/RNDIS.c diff --git a/LUFA/Drivers/USB/Class/Device/RNDIS.c b/LUFA/Drivers/USB/Class/Device/RNDIS.c index 7ac84709b..9a89ae077 100644 --- a/LUFA/Drivers/USB/Class/Device/RNDIS.c +++ b/LUFA/Drivers/USB/Class/Device/RNDIS.c @@ -1,462 +1,530 @@ -/* - LUFA Library - Copyright (C) Dean Camera, 2009. - - dean [at] fourwalledcubicle [dot] com - www.fourwalledcubicle.com -*/ - -/* - Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com) - - Permission to use, copy, modify, and distribute this software - and its documentation for any purpose and without fee is hereby - granted, provided that the above copyright notice appear in all - copies and that both that the copyright notice and this - permission notice and warranty disclaimer appear in supporting - documentation, and that the name of the author not be used in - advertising or publicity pertaining to distribution of the - software without specific, written prior permission. - - The author disclaim all warranties with regard to this - software, including all implied warranties of merchantability - and fitness. In no event shall the author be liable for any - special, indirect or consequential damages or any damages - whatsoever resulting from loss of use, data or profits, whether - in an action of contract, negligence or other tortious action, - arising out of or in connection with the use or performance of - this software. -*/ - -#include "../../HighLevel/USBMode.h" -#if defined(USB_CAN_BE_DEVICE) - -#define INCLUDE_FROM_RNDIS_CLASS_DEVICE_C -#include "RNDIS.h" - -static const uint32_t PROGMEM AdapterSupportedOIDList[] = - { - OID_GEN_SUPPORTED_LIST, - OID_GEN_PHYSICAL_MEDIUM, - OID_GEN_HARDWARE_STATUS, - OID_GEN_MEDIA_SUPPORTED, - OID_GEN_MEDIA_IN_USE, - OID_GEN_MAXIMUM_FRAME_SIZE, - OID_GEN_MAXIMUM_TOTAL_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_CURRENT_PACKET_FILTER, - OID_GEN_MAXIMUM_TOTAL_SIZE, - OID_GEN_MEDIA_CONNECT_STATUS, - OID_GEN_XMIT_OK, - OID_GEN_RCV_OK, - OID_GEN_XMIT_ERROR, - OID_GEN_RCV_ERROR, - OID_GEN_RCV_NO_BUFFER, - OID_802_3_PERMANENT_ADDRESS, - OID_802_3_CURRENT_ADDRESS, - OID_802_3_MULTICAST_LIST, - OID_802_3_MAXIMUM_LIST_SIZE, - OID_802_3_RCV_ERROR_ALIGNMENT, - OID_802_3_XMIT_ONE_COLLISION, - OID_802_3_XMIT_MORE_COLLISIONS, - }; - -void RNDIS_Device_ProcessControlPacket(USB_ClassInfo_RNDIS_Device_t* RNDISInterfaceInfo) -{ - if (!(Endpoint_IsSETUPReceived())) - return; - - if (USB_ControlRequest.wIndex != RNDISInterfaceInfo->Config.ControlInterfaceNumber) - return; - - switch (USB_ControlRequest.bRequest) - { - case REQ_SendEncapsulatedCommand: - if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) - { - Endpoint_ClearSETUP(); - - Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo->State.RNDISMessageBuffer, USB_ControlRequest.wLength); - Endpoint_ClearIN(); - - RNDIS_Device_ProcessRNDISControlMessage(RNDISInterfaceInfo); - } - - break; - case REQ_GetEncapsulatedResponse: - if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) - { - Endpoint_ClearSETUP(); - - RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - - if (!(MessageHeader->MessageLength)) - { - RNDISInterfaceInfo->State.RNDISMessageBuffer[0] = 0; - MessageHeader->MessageLength = 1; - } - - Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo->State.RNDISMessageBuffer, MessageHeader->MessageLength); - Endpoint_ClearOUT(); - - MessageHeader->MessageLength = 0; - } - - break; - } -} - -bool RNDIS_Device_ConfigureEndpoints(USB_ClassInfo_RNDIS_Device_t* RNDISInterfaceInfo) -{ - if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->Config.DataINEndpointNumber, EP_TYPE_BULK, - ENDPOINT_DIR_IN, RNDISInterfaceInfo->Config.DataINEndpointSize, - ENDPOINT_BANK_SINGLE))) - { - return false; - } - - if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber, EP_TYPE_BULK, - ENDPOINT_DIR_OUT, RNDISInterfaceInfo->Config.DataOUTEndpointSize, - ENDPOINT_BANK_SINGLE))) - { - return false; - } - - if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->Config.NotificationEndpointNumber, EP_TYPE_INTERRUPT, - ENDPOINT_DIR_IN, RNDISInterfaceInfo->Config.NotificationEndpointSize, - ENDPOINT_BANK_SINGLE))) - { - return false; - } - - return true; -} - -void RNDIS_Device_USBTask(USB_ClassInfo_RNDIS_Device_t* RNDISInterfaceInfo) -{ - if (!(USB_IsConnected)) - return; - - RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - - Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.NotificationEndpointNumber); - - if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.ResponseReady) - { - USB_Request_Header_t Notification = (USB_Request_Header_t) - { - .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), - .bRequest = NOTIF_ResponseAvailable, - .wValue = 0, - .wIndex = 0, - .wLength = 0, - }; - - Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK); - - Endpoint_ClearIN(); - - RNDISInterfaceInfo->State.ResponseReady = false; - } - - if ((RNDISInterfaceInfo->State.CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength)) - { - RNDIS_PACKET_MSG_t RNDISPacketHeader; - - Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber); - - if (Endpoint_IsOUTReceived() && !(RNDISInterfaceInfo->State.FrameIN.FrameInBuffer)) - { - Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK); - - if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX) - { - Endpoint_StallTransaction(); - return; - } - - Endpoint_Read_Stream_LE(RNDISInterfaceInfo->State.FrameIN.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK); - - Endpoint_ClearOUT(); - - RNDISInterfaceInfo->State.FrameIN.FrameLength = RNDISPacketHeader.DataLength; - - RNDISInterfaceInfo->State.FrameIN.FrameInBuffer = true; - } - - Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataINEndpointNumber); - - if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.FrameOUT.FrameInBuffer) - { - memset(&RNDISPacketHeader, 0, sizeof(RNDIS_PACKET_MSG_t)); - - RNDISPacketHeader.MessageType = REMOTE_NDIS_PACKET_MSG; - RNDISPacketHeader.MessageLength = (sizeof(RNDIS_PACKET_MSG_t) + RNDISInterfaceInfo->State.FrameOUT.FrameLength); - RNDISPacketHeader.DataOffset = (sizeof(RNDIS_PACKET_MSG_t) - sizeof(RNDIS_Message_Header_t)); - RNDISPacketHeader.DataLength = RNDISInterfaceInfo->State.FrameOUT.FrameLength; - - Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK); - Endpoint_Write_Stream_LE(RNDISInterfaceInfo->State.FrameOUT.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK); - Endpoint_ClearIN(); - - RNDISInterfaceInfo->State.FrameOUT.FrameInBuffer = false; - } - } -} - -void RNDIS_Device_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_Device_t* RNDISInterfaceInfo) -{ - /* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of - this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */ - - RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - - switch (MessageHeader->MessageType) - { - case REMOTE_NDIS_INITIALIZE_MSG: - RNDISInterfaceInfo->State.ResponseReady = true; - - RNDIS_INITIALIZE_MSG_t* INITIALIZE_Message = (RNDIS_INITIALIZE_MSG_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - RNDIS_INITIALIZE_CMPLT_t* INITIALIZE_Response = (RNDIS_INITIALIZE_CMPLT_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - - INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT; - INITIALIZE_Response->MessageLength = sizeof(RNDIS_INITIALIZE_CMPLT_t); - INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId; - INITIALIZE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS; - - INITIALIZE_Response->MajorVersion = REMOTE_NDIS_VERSION_MAJOR; - INITIALIZE_Response->MinorVersion = REMOTE_NDIS_VERSION_MINOR; - INITIALIZE_Response->DeviceFlags = REMOTE_NDIS_DF_CONNECTIONLESS; - INITIALIZE_Response->Medium = REMOTE_NDIS_MEDIUM_802_3; - INITIALIZE_Response->MaxPacketsPerTransfer = 1; - INITIALIZE_Response->MaxTransferSize = (sizeof(RNDIS_PACKET_MSG_t) + ETHERNET_FRAME_SIZE_MAX); - INITIALIZE_Response->PacketAlignmentFactor = 0; - INITIALIZE_Response->AFListOffset = 0; - INITIALIZE_Response->AFListSize = 0; - - RNDISInterfaceInfo->State.CurrRNDISState = RNDIS_Initialized; - - break; - case REMOTE_NDIS_HALT_MSG: - RNDISInterfaceInfo->State.ResponseReady = false; - MessageHeader->MessageLength = 0; - - RNDISInterfaceInfo->State.CurrRNDISState = RNDIS_Uninitialized; - - break; - case REMOTE_NDIS_QUERY_MSG: - RNDISInterfaceInfo->State.ResponseReady = true; - - RNDIS_QUERY_MSG_t* QUERY_Message = (RNDIS_QUERY_MSG_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - RNDIS_QUERY_CMPLT_t* QUERY_Response = (RNDIS_QUERY_CMPLT_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - uint32_t Query_Oid = QUERY_Message->Oid; - - void* QueryData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) + - QUERY_Message->InformationBufferOffset]; - void* ResponseData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_QUERY_CMPLT_t)]; - uint16_t ResponseSize; - - QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT; - QUERY_Response->MessageLength = sizeof(RNDIS_QUERY_CMPLT_t); - - if (RNDIS_Device_ProcessNDISQuery(RNDISInterfaceInfo, Query_Oid, QueryData, QUERY_Message->InformationBufferLength, - ResponseData, &ResponseSize)) - { - QUERY_Response->Status = REMOTE_NDIS_STATUS_SUCCESS; - QUERY_Response->MessageLength += ResponseSize; - - QUERY_Response->InformationBufferLength = ResponseSize; - QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_QUERY_CMPLT_t) - sizeof(RNDIS_Message_Header_t)); - } - else - { - QUERY_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED; - - QUERY_Response->InformationBufferLength = 0; - QUERY_Response->InformationBufferOffset = 0; - } - - break; - case REMOTE_NDIS_SET_MSG: - RNDISInterfaceInfo->State.ResponseReady = true; - - RNDIS_SET_MSG_t* SET_Message = (RNDIS_SET_MSG_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - RNDIS_SET_CMPLT_t* SET_Response = (RNDIS_SET_CMPLT_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - uint32_t SET_Oid = SET_Message->Oid; - - SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT; - SET_Response->MessageLength = sizeof(RNDIS_SET_CMPLT_t); - SET_Response->RequestId = SET_Message->RequestId; - - void* SetData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) + - SET_Message->InformationBufferOffset]; - - if (RNDIS_Device_ProcessNDISSet(RNDISInterfaceInfo, SET_Oid, SetData, SET_Message->InformationBufferLength)) - SET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS; - else - SET_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED; - - break; - case REMOTE_NDIS_RESET_MSG: - RNDISInterfaceInfo->State.ResponseReady = true; - - RNDIS_RESET_CMPLT_t* RESET_Response = (RNDIS_RESET_CMPLT_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - - RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT; - RESET_Response->MessageLength = sizeof(RNDIS_RESET_CMPLT_t); - RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS; - RESET_Response->AddressingReset = 0; - - break; - case REMOTE_NDIS_KEEPALIVE_MSG: - RNDISInterfaceInfo->State.ResponseReady = true; - - RNDIS_KEEPALIVE_MSG_t* KEEPALIVE_Message = (RNDIS_KEEPALIVE_MSG_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - RNDIS_KEEPALIVE_CMPLT_t* KEEPALIVE_Response = (RNDIS_KEEPALIVE_CMPLT_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; - - KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT; - KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KEEPALIVE_CMPLT_t); - KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId; - KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS; - - break; - } -} - -static bool RNDIS_Device_ProcessNDISQuery(USB_ClassInfo_RNDIS_Device_t* RNDISInterfaceInfo, - uint32_t OId, void* QueryData, uint16_t QuerySize, - void* ResponseData, uint16_t* ResponseSize) -{ - switch (OId) - { - case OID_GEN_SUPPORTED_LIST: - *ResponseSize = sizeof(AdapterSupportedOIDList); - - memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList)); - - return true; - case OID_GEN_PHYSICAL_MEDIUM: - *ResponseSize = sizeof(uint32_t); - - /* Indicate that the device is a true ethernet link */ - *((uint32_t*)ResponseData) = 0; - - return true; - case OID_GEN_HARDWARE_STATUS: - *ResponseSize = sizeof(uint32_t); - - *((uint32_t*)ResponseData) = NDIS_HardwareStatus_Ready; - - return true; - case OID_GEN_MEDIA_SUPPORTED: - case OID_GEN_MEDIA_IN_USE: - *ResponseSize = sizeof(uint32_t); - - *((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3; - - return true; - case OID_GEN_VENDOR_ID: - *ResponseSize = sizeof(uint32_t); - - /* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */ - *((uint32_t*)ResponseData) = 0x00FFFFFF; - - return true; - case OID_GEN_MAXIMUM_FRAME_SIZE: - case OID_GEN_TRANSMIT_BLOCK_SIZE: - case OID_GEN_RECEIVE_BLOCK_SIZE: - *ResponseSize = sizeof(uint32_t); - - *((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX; - - return true; - case OID_GEN_VENDOR_DESCRIPTION: - *ResponseSize = (strlen(RNDISInterfaceInfo->Config.AdapterVendorDescription) + 1); - - memcpy(ResponseData, RNDISInterfaceInfo->Config.AdapterVendorDescription, *ResponseSize); - - return true; - case OID_GEN_MEDIA_CONNECT_STATUS: - *ResponseSize = sizeof(uint32_t); - - *((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED; - - return true; - case OID_GEN_LINK_SPEED: - *ResponseSize = sizeof(uint32_t); - - /* Indicate 10Mb/s link speed */ - *((uint32_t*)ResponseData) = 100000; - - return true; - case OID_802_3_PERMANENT_ADDRESS: - case OID_802_3_CURRENT_ADDRESS: - *ResponseSize = sizeof(MAC_Address_t); - - memcpy(ResponseData, &RNDISInterfaceInfo->Config.AdapterMACAddress, sizeof(MAC_Address_t)); - - return true; - case OID_802_3_MAXIMUM_LIST_SIZE: - *ResponseSize = sizeof(uint32_t); - - /* Indicate only one multicast address supported */ - *((uint32_t*)ResponseData) = 1; - - return true; - case OID_GEN_CURRENT_PACKET_FILTER: - *ResponseSize = sizeof(uint32_t); - - *((uint32_t*)ResponseData) = RNDISInterfaceInfo->State.CurrPacketFilter; - - return true; - case OID_GEN_XMIT_OK: - case OID_GEN_RCV_OK: - case OID_GEN_XMIT_ERROR: - case OID_GEN_RCV_ERROR: - case OID_GEN_RCV_NO_BUFFER: - case OID_802_3_RCV_ERROR_ALIGNMENT: - case OID_802_3_XMIT_ONE_COLLISION: - case OID_802_3_XMIT_MORE_COLLISIONS: - *ResponseSize = sizeof(uint32_t); - - /* Unused statistic OIDs - always return 0 for each */ - *((uint32_t*)ResponseData) = 0; - - return true; - case OID_GEN_MAXIMUM_TOTAL_SIZE: - *ResponseSize = sizeof(uint32_t); - - /* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */ - *((uint32_t*)ResponseData) = (RNDIS_MESSAGE_BUFFER_SIZE + ETHERNET_FRAME_SIZE_MAX); - - return true; - default: - return false; - } -} - -static bool RNDIS_Device_ProcessNDISSet(USB_ClassInfo_RNDIS_Device_t* RNDISInterfaceInfo, uint32_t OId, void* SetData, - uint16_t SetSize) -{ - switch (OId) - { - case OID_GEN_CURRENT_PACKET_FILTER: - RNDISInterfaceInfo->State.CurrPacketFilter = *((uint32_t*)SetData); - RNDISInterfaceInfo->State.CurrRNDISState = ((RNDISInterfaceInfo->State.CurrPacketFilter) ? - RNDIS_Data_Initialized : RNDIS_Data_Initialized); - - return true; - case OID_802_3_MULTICAST_LIST: - /* Do nothing - throw away the value from the host as it is unused */ - - return true; - default: - return false; - } -} - -#endif +/* + LUFA Library + Copyright (C) Dean Camera, 2011. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaim all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +#define __INCLUDE_FROM_USB_DRIVER +#include "../../Core/USBMode.h" + +#if defined(USB_CAN_BE_DEVICE) + +#define __INCLUDE_FROM_RNDIS_DRIVER +#define __INCLUDE_FROM_RNDIS_DEVICE_C +#include "RNDIS.h" + +static const uint32_t PROGMEM AdapterSupportedOIDList[] = + { + CPU_TO_LE32(OID_GEN_SUPPORTED_LIST), + CPU_TO_LE32(OID_GEN_PHYSICAL_MEDIUM), + CPU_TO_LE32(OID_GEN_HARDWARE_STATUS), + CPU_TO_LE32(OID_GEN_MEDIA_SUPPORTED), + CPU_TO_LE32(OID_GEN_MEDIA_IN_USE), + CPU_TO_LE32(OID_GEN_MAXIMUM_FRAME_SIZE), + CPU_TO_LE32(OID_GEN_MAXIMUM_TOTAL_SIZE), + CPU_TO_LE32(OID_GEN_LINK_SPEED), + CPU_TO_LE32(OID_GEN_TRANSMIT_BLOCK_SIZE), + CPU_TO_LE32(OID_GEN_RECEIVE_BLOCK_SIZE), + CPU_TO_LE32(OID_GEN_VENDOR_ID), + CPU_TO_LE32(OID_GEN_VENDOR_DESCRIPTION), + CPU_TO_LE32(OID_GEN_CURRENT_PACKET_FILTER), + CPU_TO_LE32(OID_GEN_MAXIMUM_TOTAL_SIZE), + CPU_TO_LE32(OID_GEN_MEDIA_CONNECT_STATUS), + CPU_TO_LE32(OID_GEN_XMIT_OK), + CPU_TO_LE32(OID_GEN_RCV_OK), + CPU_TO_LE32(OID_GEN_XMIT_ERROR), + CPU_TO_LE32(OID_GEN_RCV_ERROR), + CPU_TO_LE32(OID_GEN_RCV_NO_BUFFER), + CPU_TO_LE32(OID_802_3_PERMANENT_ADDRESS), + CPU_TO_LE32(OID_802_3_CURRENT_ADDRESS), + CPU_TO_LE32(OID_802_3_MULTICAST_LIST), + CPU_TO_LE32(OID_802_3_MAXIMUM_LIST_SIZE), + CPU_TO_LE32(OID_802_3_RCV_ERROR_ALIGNMENT), + CPU_TO_LE32(OID_802_3_XMIT_ONE_COLLISION), + CPU_TO_LE32(OID_802_3_XMIT_MORE_COLLISIONS), + }; + +void RNDIS_Device_ProcessControlRequest(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) +{ + if (!(Endpoint_IsSETUPReceived())) + return; + + if (USB_ControlRequest.wIndex != RNDISInterfaceInfo->Config.ControlInterfaceNumber) + return; + + switch (USB_ControlRequest.bRequest) + { + case RNDIS_REQ_SendEncapsulatedCommand: + if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) + { + Endpoint_ClearSETUP(); + Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo->State.RNDISMessageBuffer, USB_ControlRequest.wLength); + Endpoint_ClearIN(); + + RNDIS_Device_ProcessRNDISControlMessage(RNDISInterfaceInfo); + } + + break; + case RNDIS_REQ_GetEncapsulatedResponse: + if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) + { + RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + + if (!(MessageHeader->MessageLength)) + { + RNDISInterfaceInfo->State.RNDISMessageBuffer[0] = 0; + MessageHeader->MessageLength = CPU_TO_LE32(1); + } + + Endpoint_ClearSETUP(); + Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo->State.RNDISMessageBuffer, le32_to_cpu(MessageHeader->MessageLength)); + Endpoint_ClearOUT(); + + MessageHeader->MessageLength = CPU_TO_LE32(0); + } + + break; + } +} + +bool RNDIS_Device_ConfigureEndpoints(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) +{ + memset(&RNDISInterfaceInfo->State, 0x00, sizeof(RNDISInterfaceInfo->State)); + + for (uint8_t EndpointNum = 1; EndpointNum < ENDPOINT_TOTAL_ENDPOINTS; EndpointNum++) + { + uint16_t Size; + uint8_t Type; + uint8_t Direction; + bool DoubleBanked; + + if (EndpointNum == RNDISInterfaceInfo->Config.DataINEndpointNumber) + { + Size = RNDISInterfaceInfo->Config.DataINEndpointSize; + Direction = ENDPOINT_DIR_IN; + Type = EP_TYPE_BULK; + DoubleBanked = RNDISInterfaceInfo->Config.DataINEndpointDoubleBank; + } + else if (EndpointNum == RNDISInterfaceInfo->Config.DataOUTEndpointNumber) + { + Size = RNDISInterfaceInfo->Config.DataOUTEndpointSize; + Direction = ENDPOINT_DIR_OUT; + Type = EP_TYPE_BULK; + DoubleBanked = RNDISInterfaceInfo->Config.DataOUTEndpointDoubleBank; + } + else if (EndpointNum == RNDISInterfaceInfo->Config.NotificationEndpointNumber) + { + Size = RNDISInterfaceInfo->Config.NotificationEndpointSize; + Direction = ENDPOINT_DIR_IN; + Type = EP_TYPE_INTERRUPT; + DoubleBanked = RNDISInterfaceInfo->Config.NotificationEndpointDoubleBank; + } + else + { + continue; + } + + if (!(Endpoint_ConfigureEndpoint(EndpointNum, Type, Direction, Size, + DoubleBanked ? ENDPOINT_BANK_DOUBLE : ENDPOINT_BANK_SINGLE))) + { + return false; + } + } + + return true; +} + +void RNDIS_Device_USBTask(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) +{ + if (USB_DeviceState != DEVICE_STATE_Configured) + return; + + Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.NotificationEndpointNumber); + + if (Endpoint_IsINReady() && RNDISInterfaceInfo->State.ResponseReady) + { + USB_Request_Header_t Notification = (USB_Request_Header_t) + { + .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE), + .bRequest = RNDIS_NOTIF_ResponseAvailable, + .wValue = CPU_TO_LE16(0), + .wIndex = CPU_TO_LE16(0), + .wLength = CPU_TO_LE16(0), + }; + + Endpoint_Write_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NULL); + + Endpoint_ClearIN(); + + RNDISInterfaceInfo->State.ResponseReady = false; + } +} + +void RNDIS_Device_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) +{ + /* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of + this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */ + + RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + + switch (le32_to_cpu(MessageHeader->MessageType)) + { + case REMOTE_NDIS_INITIALIZE_MSG: + RNDISInterfaceInfo->State.ResponseReady = true; + + RNDIS_Initialize_Message_t* INITIALIZE_Message = + (RNDIS_Initialize_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + RNDIS_Initialize_Complete_t* INITIALIZE_Response = + (RNDIS_Initialize_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + + INITIALIZE_Response->MessageType = CPU_TO_LE32(REMOTE_NDIS_INITIALIZE_CMPLT); + INITIALIZE_Response->MessageLength = CPU_TO_LE32(sizeof(RNDIS_Initialize_Complete_t)); + INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId; + INITIALIZE_Response->Status = CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS); + + INITIALIZE_Response->MajorVersion = CPU_TO_LE32(REMOTE_NDIS_VERSION_MAJOR); + INITIALIZE_Response->MinorVersion = CPU_TO_LE32(REMOTE_NDIS_VERSION_MINOR); + INITIALIZE_Response->DeviceFlags = CPU_TO_LE32(REMOTE_NDIS_DF_CONNECTIONLESS); + INITIALIZE_Response->Medium = CPU_TO_LE32(REMOTE_NDIS_MEDIUM_802_3); + INITIALIZE_Response->MaxPacketsPerTransfer = CPU_TO_LE32(1); + INITIALIZE_Response->MaxTransferSize = CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t) + ETHERNET_FRAME_SIZE_MAX); + INITIALIZE_Response->PacketAlignmentFactor = CPU_TO_LE32(0); + INITIALIZE_Response->AFListOffset = CPU_TO_LE32(0); + INITIALIZE_Response->AFListSize = CPU_TO_LE32(0); + + RNDISInterfaceInfo->State.CurrRNDISState = RNDIS_Initialized; + break; + case REMOTE_NDIS_HALT_MSG: + RNDISInterfaceInfo->State.ResponseReady = false; + + MessageHeader->MessageLength = CPU_TO_LE32(0); + + RNDISInterfaceInfo->State.CurrRNDISState = RNDIS_Uninitialized; + break; + case REMOTE_NDIS_QUERY_MSG: + RNDISInterfaceInfo->State.ResponseReady = true; + + RNDIS_Query_Message_t* QUERY_Message = (RNDIS_Query_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + RNDIS_Query_Complete_t* QUERY_Response = (RNDIS_Query_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + uint32_t Query_Oid = CPU_TO_LE32(QUERY_Message->Oid); + + void* QueryData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) + + le32_to_cpu(QUERY_Message->InformationBufferOffset)]; + void* ResponseData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Query_Complete_t)]; + uint16_t ResponseSize; + + QUERY_Response->MessageType = CPU_TO_LE32(REMOTE_NDIS_QUERY_CMPLT); + + if (RNDIS_Device_ProcessNDISQuery(RNDISInterfaceInfo, Query_Oid, QueryData, le32_to_cpu(QUERY_Message->InformationBufferLength), + ResponseData, &ResponseSize)) + { + QUERY_Response->Status = CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS); + QUERY_Response->MessageLength = cpu_to_le32(sizeof(RNDIS_Query_Complete_t) + ResponseSize); + + QUERY_Response->InformationBufferLength = CPU_TO_LE32(ResponseSize); + QUERY_Response->InformationBufferOffset = CPU_TO_LE32(sizeof(RNDIS_Query_Complete_t) - sizeof(RNDIS_Message_Header_t)); + } + else + { + QUERY_Response->Status = CPU_TO_LE32(REMOTE_NDIS_STATUS_NOT_SUPPORTED); + QUERY_Response->MessageLength = CPU_TO_LE32(sizeof(RNDIS_Query_Complete_t)); + + QUERY_Response->InformationBufferLength = CPU_TO_LE32(0); + QUERY_Response->InformationBufferOffset = CPU_TO_LE32(0); + } + + break; + case REMOTE_NDIS_SET_MSG: + RNDISInterfaceInfo->State.ResponseReady = true; + + RNDIS_Set_Message_t* SET_Message = (RNDIS_Set_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + RNDIS_Set_Complete_t* SET_Response = (RNDIS_Set_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + uint32_t SET_Oid = le32_to_cpu(SET_Message->Oid); + + SET_Response->MessageType = CPU_TO_LE32(REMOTE_NDIS_SET_CMPLT); + SET_Response->MessageLength = CPU_TO_LE32(sizeof(RNDIS_Set_Complete_t)); + SET_Response->RequestId = SET_Message->RequestId; + + void* SetData = &RNDISInterfaceInfo->State.RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) + + le32_to_cpu(SET_Message->InformationBufferOffset)]; + + SET_Response->Status = RNDIS_Device_ProcessNDISSet(RNDISInterfaceInfo, SET_Oid, SetData, + le32_to_cpu(SET_Message->InformationBufferLength)) ? + REMOTE_NDIS_STATUS_SUCCESS : REMOTE_NDIS_STATUS_NOT_SUPPORTED; + break; + case REMOTE_NDIS_RESET_MSG: + RNDISInterfaceInfo->State.ResponseReady = true; + + RNDIS_Reset_Complete_t* RESET_Response = (RNDIS_Reset_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + + RESET_Response->MessageType = CPU_TO_LE32(REMOTE_NDIS_RESET_CMPLT); + RESET_Response->MessageLength = CPU_TO_LE32(sizeof(RNDIS_Reset_Complete_t)); + RESET_Response->Status = CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS); + RESET_Response->AddressingReset = CPU_TO_LE32(0); + + break; + case REMOTE_NDIS_KEEPALIVE_MSG: + RNDISInterfaceInfo->State.ResponseReady = true; + + RNDIS_KeepAlive_Message_t* KEEPALIVE_Message = + (RNDIS_KeepAlive_Message_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + RNDIS_KeepAlive_Complete_t* KEEPALIVE_Response = + (RNDIS_KeepAlive_Complete_t*)&RNDISInterfaceInfo->State.RNDISMessageBuffer; + + KEEPALIVE_Response->MessageType = CPU_TO_LE32(REMOTE_NDIS_KEEPALIVE_CMPLT); + KEEPALIVE_Response->MessageLength = CPU_TO_LE32(sizeof(RNDIS_KeepAlive_Complete_t)); + KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId; + KEEPALIVE_Response->Status = CPU_TO_LE32(REMOTE_NDIS_STATUS_SUCCESS); + + break; + } +} + +static bool RNDIS_Device_ProcessNDISQuery(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, + const uint32_t OId, + void* const QueryData, + const uint16_t QuerySize, + void* ResponseData, + uint16_t* const ResponseSize) +{ + (void)QueryData; + (void)QuerySize; + + switch (OId) + { + case OID_GEN_SUPPORTED_LIST: + *ResponseSize = sizeof(AdapterSupportedOIDList); + + memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList)); + + return true; + case OID_GEN_PHYSICAL_MEDIUM: + *ResponseSize = sizeof(uint32_t); + + /* Indicate that the device is a true ethernet link */ + *((uint32_t*)ResponseData) = CPU_TO_LE32(0); + + return true; + case OID_GEN_HARDWARE_STATUS: + *ResponseSize = sizeof(uint32_t); + + *((uint32_t*)ResponseData) = CPU_TO_LE32(NDIS_HardwareStatus_Ready); + + return true; + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + *ResponseSize = sizeof(uint32_t); + + *((uint32_t*)ResponseData) = CPU_TO_LE32(REMOTE_NDIS_MEDIUM_802_3); + + return true; + case OID_GEN_VENDOR_ID: + *ResponseSize = sizeof(uint32_t); + + /* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */ + *((uint32_t*)ResponseData) = CPU_TO_LE32(0x00FFFFFF); + + return true; + case OID_GEN_MAXIMUM_FRAME_SIZE: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + *ResponseSize = sizeof(uint32_t); + + *((uint32_t*)ResponseData) = CPU_TO_LE32(ETHERNET_FRAME_SIZE_MAX); + + return true; + case OID_GEN_VENDOR_DESCRIPTION: + *ResponseSize = (strlen(RNDISInterfaceInfo->Config.AdapterVendorDescription) + 1); + + memcpy(ResponseData, RNDISInterfaceInfo->Config.AdapterVendorDescription, *ResponseSize); + + return true; + case OID_GEN_MEDIA_CONNECT_STATUS: + *ResponseSize = sizeof(uint32_t); + + *((uint32_t*)ResponseData) = CPU_TO_LE32(REMOTE_NDIS_MEDIA_STATE_CONNECTED); + + return true; + case OID_GEN_LINK_SPEED: + *ResponseSize = sizeof(uint32_t); + + /* Indicate 10Mb/s link speed */ + *((uint32_t*)ResponseData) = CPU_TO_LE32(100000); + + return true; + case OID_802_3_PERMANENT_ADDRESS: + case OID_802_3_CURRENT_ADDRESS: + *ResponseSize = sizeof(MAC_Address_t); + + memcpy(ResponseData, &RNDISInterfaceInfo->Config.AdapterMACAddress, sizeof(MAC_Address_t)); + + return true; + case OID_802_3_MAXIMUM_LIST_SIZE: + *ResponseSize = sizeof(uint32_t); + + /* Indicate only one multicast address supported */ + *((uint32_t*)ResponseData) = CPU_TO_LE32(1); + + return true; + case OID_GEN_CURRENT_PACKET_FILTER: + *ResponseSize = sizeof(uint32_t); + + *((uint32_t*)ResponseData) = cpu_to_le32(RNDISInterfaceInfo->State.CurrPacketFilter); + + return true; + case OID_GEN_XMIT_OK: + case OID_GEN_RCV_OK: + case OID_GEN_XMIT_ERROR: + case OID_GEN_RCV_ERROR: + case OID_GEN_RCV_NO_BUFFER: + case OID_802_3_RCV_ERROR_ALIGNMENT: + case OID_802_3_XMIT_ONE_COLLISION: + case OID_802_3_XMIT_MORE_COLLISIONS: + *ResponseSize = sizeof(uint32_t); + + /* Unused statistic OIDs - always return 0 for each */ + *((uint32_t*)ResponseData) = CPU_TO_LE32(0); + + return true; + case OID_GEN_MAXIMUM_TOTAL_SIZE: + *ResponseSize = sizeof(uint32_t); + + /* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */ + *((uint32_t*)ResponseData) = CPU_TO_LE32(RNDIS_MESSAGE_BUFFER_SIZE + ETHERNET_FRAME_SIZE_MAX); + + return true; + default: + return false; + } +} + +static bool RNDIS_Device_ProcessNDISSet(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, + const uint32_t OId, + const void* SetData, + const uint16_t SetSize) +{ + (void)SetSize; + + switch (OId) + { + case OID_GEN_CURRENT_PACKET_FILTER: + RNDISInterfaceInfo->State.CurrPacketFilter = le32_to_cpu(*((uint32_t*)SetData)); + RNDISInterfaceInfo->State.CurrRNDISState = le32_to_cpu((RNDISInterfaceInfo->State.CurrPacketFilter) ? + RNDIS_Data_Initialized : RNDIS_Data_Initialized); + + return true; + case OID_802_3_MULTICAST_LIST: + /* Do nothing - throw away the value from the host as it is unused */ + + return true; + default: + return false; + } +} + +bool RNDIS_Device_IsPacketReceived(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo) +{ + if ((USB_DeviceState != DEVICE_STATE_Configured) || + (RNDISInterfaceInfo->State.CurrRNDISState != RNDIS_Data_Initialized)) + { + return false; + } + + Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber); + return Endpoint_IsOUTReceived(); +} + +uint8_t RNDIS_Device_ReadPacket(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, + void* Buffer, + uint16_t* const PacketLength) +{ + if ((USB_DeviceState != DEVICE_STATE_Configured) || + (RNDISInterfaceInfo->State.CurrRNDISState != RNDIS_Data_Initialized)) + { + return ENDPOINT_RWSTREAM_DeviceDisconnected; + } + + Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataOUTEndpointNumber); + + *PacketLength = 0; + + if (!(Endpoint_IsOUTReceived())) + return ENDPOINT_RWSTREAM_NoError; + + RNDIS_Packet_Message_t RNDISPacketHeader; + Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL); + + if (le32_to_cpu(RNDISPacketHeader.DataLength) > ETHERNET_FRAME_SIZE_MAX) + { + Endpoint_StallTransaction(); + + return RNDIS_ERROR_LOGICAL_CMD_FAILED; + } + + *PacketLength = (uint16_t)le32_to_cpu(RNDISPacketHeader.DataLength); + + Endpoint_Read_Stream_LE(Buffer, *PacketLength, NULL); + Endpoint_ClearOUT(); + + return ENDPOINT_RWSTREAM_NoError; +} + +uint8_t RNDIS_Device_SendPacket(USB_ClassInfo_RNDIS_Device_t* const RNDISInterfaceInfo, + void* Buffer, + const uint16_t PacketLength) +{ + uint8_t ErrorCode; + + if ((USB_DeviceState != DEVICE_STATE_Configured) || + (RNDISInterfaceInfo->State.CurrRNDISState != RNDIS_Data_Initialized)) + { + return ENDPOINT_RWSTREAM_DeviceDisconnected; + } + + Endpoint_SelectEndpoint(RNDISInterfaceInfo->Config.DataINEndpointNumber); + + if ((ErrorCode = Endpoint_WaitUntilReady()) != ENDPOINT_READYWAIT_NoError) + return ErrorCode; + + RNDIS_Packet_Message_t RNDISPacketHeader; + + memset(&RNDISPacketHeader, 0, sizeof(RNDIS_Packet_Message_t)); + + RNDISPacketHeader.MessageType = CPU_TO_LE32(REMOTE_NDIS_PACKET_MSG); + RNDISPacketHeader.MessageLength = cpu_to_le32(sizeof(RNDIS_Packet_Message_t) + PacketLength); + RNDISPacketHeader.DataOffset = CPU_TO_LE32(sizeof(RNDIS_Packet_Message_t) - sizeof(RNDIS_Message_Header_t)); + RNDISPacketHeader.DataLength = cpu_to_le32(PacketLength); + + Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_Packet_Message_t), NULL); + Endpoint_Write_Stream_LE(Buffer, PacketLength, NULL); + Endpoint_ClearIN(); + + return ENDPOINT_RWSTREAM_NoError; +} + +#endif +