-/*\r
- LUFA Library\r
- Copyright (C) Dean Camera, 2009.\r
- \r
- dean [at] fourwalledcubicle [dot] com\r
- www.fourwalledcubicle.com\r
-*/\r
-\r
-/*\r
- Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
-\r
- Permission to use, copy, modify, and distribute this software\r
- and its documentation for any purpose and without fee is hereby\r
- granted, provided that the above copyright notice appear in all\r
- copies and that both that the copyright notice and this\r
- permission notice and warranty disclaimer appear in supporting\r
- documentation, and that the name of the author not be used in\r
- advertising or publicity pertaining to distribution of the\r
- software without specific, written prior permission.\r
-\r
- The author disclaim all warranties with regard to this\r
- software, including all implied warranties of merchantability\r
- and fitness. In no event shall the author be liable for any\r
- special, indirect or consequential damages or any damages\r
- whatsoever resulting from loss of use, data or profits, whether\r
- in an action of contract, negligence or other tortious action,\r
- arising out of or in connection with the use or performance of\r
- this software.\r
-*/\r
-\r
-#define INCLUDE_FROM_RNDIS_CLASS_C\r
-#include "RNDIS.h"\r
-\r
-static const uint32_t PROGMEM AdapterSupportedOIDList[] =\r
- {\r
- OID_GEN_SUPPORTED_LIST,\r
- OID_GEN_PHYSICAL_MEDIUM,\r
- OID_GEN_HARDWARE_STATUS,\r
- OID_GEN_MEDIA_SUPPORTED,\r
- OID_GEN_MEDIA_IN_USE,\r
- OID_GEN_MAXIMUM_FRAME_SIZE,\r
- OID_GEN_MAXIMUM_TOTAL_SIZE,\r
- OID_GEN_LINK_SPEED,\r
- OID_GEN_TRANSMIT_BLOCK_SIZE,\r
- OID_GEN_RECEIVE_BLOCK_SIZE,\r
- OID_GEN_VENDOR_ID,\r
- OID_GEN_VENDOR_DESCRIPTION,\r
- OID_GEN_CURRENT_PACKET_FILTER,\r
- OID_GEN_MAXIMUM_TOTAL_SIZE,\r
- OID_GEN_MEDIA_CONNECT_STATUS,\r
- OID_GEN_XMIT_OK,\r
- OID_GEN_RCV_OK,\r
- OID_GEN_XMIT_ERROR,\r
- OID_GEN_RCV_ERROR,\r
- OID_GEN_RCV_NO_BUFFER,\r
- OID_802_3_PERMANENT_ADDRESS,\r
- OID_802_3_CURRENT_ADDRESS,\r
- OID_802_3_MULTICAST_LIST,\r
- OID_802_3_MAXIMUM_LIST_SIZE,\r
- OID_802_3_RCV_ERROR_ALIGNMENT,\r
- OID_802_3_XMIT_ONE_COLLISION,\r
- OID_802_3_XMIT_MORE_COLLISIONS,\r
- };\r
-\r
-void USB_RNDIS_ProcessControlPacket(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)\r
-{\r
- if (!(Endpoint_IsSETUPReceived()))\r
- return;\r
- \r
- if (USB_ControlRequest.wIndex != RNDISInterfaceInfo->ControlInterfaceNumber)\r
- return;\r
-\r
- switch (USB_ControlRequest.bRequest)\r
- {\r
- case REQ_SendEncapsulatedCommand:\r
- if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))\r
- {\r
- Endpoint_ClearSETUP();\r
-\r
- Endpoint_Read_Control_Stream_LE(RNDISInterfaceInfo->RNDISMessageBuffer, USB_ControlRequest.wLength);\r
- Endpoint_ClearIN();\r
-\r
- USB_RNDIS_ProcessRNDISControlMessage(RNDISInterfaceInfo);\r
- }\r
- \r
- break;\r
- case REQ_GetEncapsulatedResponse:\r
- if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))\r
- {\r
- Endpoint_ClearSETUP();\r
-\r
- RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
-\r
- if (!(MessageHeader->MessageLength))\r
- {\r
- RNDISInterfaceInfo->RNDISMessageBuffer[0] = 0;\r
- MessageHeader->MessageLength = 1;\r
- }\r
-\r
- Endpoint_Write_Control_Stream_LE(RNDISInterfaceInfo->RNDISMessageBuffer, MessageHeader->MessageLength); \r
- Endpoint_ClearOUT();\r
-\r
- MessageHeader->MessageLength = 0;\r
- }\r
- \r
- break;\r
- }\r
-}\r
-\r
-bool USB_RNDIS_ConfigureEndpoints(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)\r
-{\r
- if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->DataINEndpointNumber, EP_TYPE_BULK,\r
- ENDPOINT_DIR_IN, RNDISInterfaceInfo->DataINEndpointSize,\r
- ENDPOINT_BANK_SINGLE)))\r
- {\r
- return false;\r
- }\r
-\r
- if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->DataOUTEndpointNumber, EP_TYPE_BULK,\r
- ENDPOINT_DIR_OUT, RNDISInterfaceInfo->DataOUTEndpointSize,\r
- ENDPOINT_BANK_SINGLE)))\r
- {\r
- return false;\r
- }\r
-\r
- if (!(Endpoint_ConfigureEndpoint(RNDISInterfaceInfo->NotificationEndpointNumber, EP_TYPE_INTERRUPT,\r
- ENDPOINT_DIR_IN, RNDISInterfaceInfo->NotificationEndpointSize,\r
- ENDPOINT_BANK_SINGLE)))\r
- {\r
- return false;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-void USB_RNDIS_USBTask(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)\r
-{\r
- if (!(USB_IsConnected))\r
- return;\r
-\r
- RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
-\r
- Endpoint_SelectEndpoint(RNDISInterfaceInfo->NotificationEndpointNumber);\r
-\r
- if (Endpoint_IsINReady() && RNDISInterfaceInfo->ResponseReady)\r
- {\r
- USB_Request_Header_t Notification = (USB_Request_Header_t)\r
- {\r
- .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),\r
- .bRequest = NOTIF_ResponseAvailable,\r
- .wValue = 0,\r
- .wIndex = 0,\r
- .wLength = 0,\r
- };\r
- \r
- Endpoint_Write_Stream_LE(&Notification, sizeof(Notification), NO_STREAM_CALLBACK);\r
-\r
- Endpoint_ClearIN();\r
-\r
- RNDISInterfaceInfo->ResponseReady = false;\r
- }\r
- \r
- if ((RNDISInterfaceInfo->CurrRNDISState == RNDIS_Data_Initialized) && !(MessageHeader->MessageLength))\r
- {\r
- RNDIS_PACKET_MSG_t RNDISPacketHeader;\r
-\r
- Endpoint_SelectEndpoint(RNDISInterfaceInfo->DataOUTEndpointNumber);\r
-\r
- if (Endpoint_IsOUTReceived() && !(RNDISInterfaceInfo->FrameIN.FrameInBuffer))\r
- {\r
- Endpoint_Read_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK);\r
-\r
- if (RNDISPacketHeader.DataLength > ETHERNET_FRAME_SIZE_MAX)\r
- {\r
- Endpoint_StallTransaction();\r
- return;\r
- }\r
- \r
- Endpoint_Read_Stream_LE(RNDISInterfaceInfo->FrameIN.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK);\r
-\r
- Endpoint_ClearOUT();\r
- \r
- RNDISInterfaceInfo->FrameIN.FrameLength = RNDISPacketHeader.DataLength;\r
-\r
- RNDISInterfaceInfo->FrameIN.FrameInBuffer = true;\r
- }\r
- \r
- Endpoint_SelectEndpoint(RNDISInterfaceInfo->DataINEndpointNumber);\r
- \r
- if (Endpoint_IsINReady() && RNDISInterfaceInfo->FrameOUT.FrameInBuffer)\r
- {\r
- memset(&RNDISPacketHeader, 0, sizeof(RNDIS_PACKET_MSG_t));\r
-\r
- RNDISPacketHeader.MessageType = REMOTE_NDIS_PACKET_MSG;\r
- RNDISPacketHeader.MessageLength = (sizeof(RNDIS_PACKET_MSG_t) + RNDISInterfaceInfo->FrameOUT.FrameLength);\r
- RNDISPacketHeader.DataOffset = (sizeof(RNDIS_PACKET_MSG_t) - sizeof(RNDIS_Message_Header_t));\r
- RNDISPacketHeader.DataLength = RNDISInterfaceInfo->FrameOUT.FrameLength;\r
-\r
- Endpoint_Write_Stream_LE(&RNDISPacketHeader, sizeof(RNDIS_PACKET_MSG_t), NO_STREAM_CALLBACK);\r
- Endpoint_Write_Stream_LE(RNDISInterfaceInfo->FrameOUT.FrameData, RNDISPacketHeader.DataLength, NO_STREAM_CALLBACK);\r
- Endpoint_ClearIN();\r
- \r
- RNDISInterfaceInfo->FrameOUT.FrameInBuffer = false;\r
- }\r
- }\r
-} \r
-\r
-void USB_RNDIS_ProcessRNDISControlMessage(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo)\r
-{\r
- /* Note: Only a single buffer is used for both the received message and its response to save SRAM. Because of\r
- this, response bytes should be filled in order so that they do not clobber unread data in the buffer. */\r
-\r
- RNDIS_Message_Header_t* MessageHeader = (RNDIS_Message_Header_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
-\r
- switch (MessageHeader->MessageType)\r
- {\r
- case REMOTE_NDIS_INITIALIZE_MSG:\r
- RNDISInterfaceInfo->ResponseReady = true;\r
- \r
- RNDIS_INITIALIZE_MSG_t* INITIALIZE_Message = (RNDIS_INITIALIZE_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
- RNDIS_INITIALIZE_CMPLT_t* INITIALIZE_Response = (RNDIS_INITIALIZE_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
- \r
- INITIALIZE_Response->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;\r
- INITIALIZE_Response->MessageLength = sizeof(RNDIS_INITIALIZE_CMPLT_t);\r
- INITIALIZE_Response->RequestId = INITIALIZE_Message->RequestId;\r
- INITIALIZE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;\r
- \r
- INITIALIZE_Response->MajorVersion = REMOTE_NDIS_VERSION_MAJOR;\r
- INITIALIZE_Response->MinorVersion = REMOTE_NDIS_VERSION_MINOR; \r
- INITIALIZE_Response->DeviceFlags = REMOTE_NDIS_DF_CONNECTIONLESS;\r
- INITIALIZE_Response->Medium = REMOTE_NDIS_MEDIUM_802_3;\r
- INITIALIZE_Response->MaxPacketsPerTransfer = 1;\r
- INITIALIZE_Response->MaxTransferSize = (sizeof(RNDIS_PACKET_MSG_t) + ETHERNET_FRAME_SIZE_MAX);\r
- INITIALIZE_Response->PacketAlignmentFactor = 0;\r
- INITIALIZE_Response->AFListOffset = 0;\r
- INITIALIZE_Response->AFListSize = 0;\r
- \r
- RNDISInterfaceInfo->CurrRNDISState = RNDIS_Initialized;\r
- \r
- break;\r
- case REMOTE_NDIS_HALT_MSG:\r
- RNDISInterfaceInfo->ResponseReady = false;\r
- MessageHeader->MessageLength = 0;\r
-\r
- RNDISInterfaceInfo->CurrRNDISState = RNDIS_Uninitialized;\r
-\r
- break;\r
- case REMOTE_NDIS_QUERY_MSG:\r
- RNDISInterfaceInfo->ResponseReady = true;\r
- \r
- RNDIS_QUERY_MSG_t* QUERY_Message = (RNDIS_QUERY_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
- RNDIS_QUERY_CMPLT_t* QUERY_Response = (RNDIS_QUERY_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
- uint32_t Query_Oid = QUERY_Message->Oid;\r
- \r
- void* QueryData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +\r
- QUERY_Message->InformationBufferOffset];\r
- void* ResponseData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_QUERY_CMPLT_t)]; \r
- uint16_t ResponseSize;\r
-\r
- QUERY_Response->MessageType = REMOTE_NDIS_QUERY_CMPLT;\r
- QUERY_Response->MessageLength = sizeof(RNDIS_QUERY_CMPLT_t);\r
- \r
- if (USB_RNDIS_ProcessNDISQuery(RNDISInterfaceInfo, Query_Oid, QueryData, QUERY_Message->InformationBufferLength,\r
- ResponseData, &ResponseSize))\r
- {\r
- QUERY_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;\r
- QUERY_Response->MessageLength += ResponseSize;\r
- \r
- QUERY_Response->InformationBufferLength = ResponseSize;\r
- QUERY_Response->InformationBufferOffset = (sizeof(RNDIS_QUERY_CMPLT_t) - sizeof(RNDIS_Message_Header_t));\r
- }\r
- else\r
- { \r
- QUERY_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;\r
-\r
- QUERY_Response->InformationBufferLength = 0;\r
- QUERY_Response->InformationBufferOffset = 0;\r
- }\r
- \r
- break;\r
- case REMOTE_NDIS_SET_MSG:\r
- RNDISInterfaceInfo->ResponseReady = true;\r
- \r
- RNDIS_SET_MSG_t* SET_Message = (RNDIS_SET_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
- RNDIS_SET_CMPLT_t* SET_Response = (RNDIS_SET_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
- uint32_t SET_Oid = SET_Message->Oid;\r
-\r
- SET_Response->MessageType = REMOTE_NDIS_SET_CMPLT;\r
- SET_Response->MessageLength = sizeof(RNDIS_SET_CMPLT_t);\r
- SET_Response->RequestId = SET_Message->RequestId;\r
-\r
- void* SetData = &RNDISInterfaceInfo->RNDISMessageBuffer[sizeof(RNDIS_Message_Header_t) +\r
- SET_Message->InformationBufferOffset];\r
- \r
- if (USB_RNDIS_ProcessNDISSet(RNDISInterfaceInfo, SET_Oid, SetData, SET_Message->InformationBufferLength))\r
- SET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;\r
- else\r
- SET_Response->Status = REMOTE_NDIS_STATUS_NOT_SUPPORTED;\r
-\r
- break;\r
- case REMOTE_NDIS_RESET_MSG:\r
- RNDISInterfaceInfo->ResponseReady = true;\r
- \r
- RNDIS_RESET_CMPLT_t* RESET_Response = (RNDIS_RESET_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
-\r
- RESET_Response->MessageType = REMOTE_NDIS_RESET_CMPLT;\r
- RESET_Response->MessageLength = sizeof(RNDIS_RESET_CMPLT_t);\r
- RESET_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;\r
- RESET_Response->AddressingReset = 0;\r
-\r
- break;\r
- case REMOTE_NDIS_KEEPALIVE_MSG:\r
- RNDISInterfaceInfo->ResponseReady = true;\r
- \r
- RNDIS_KEEPALIVE_MSG_t* KEEPALIVE_Message = (RNDIS_KEEPALIVE_MSG_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
- RNDIS_KEEPALIVE_CMPLT_t* KEEPALIVE_Response = (RNDIS_KEEPALIVE_CMPLT_t*)&RNDISInterfaceInfo->RNDISMessageBuffer;\r
-\r
- KEEPALIVE_Response->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;\r
- KEEPALIVE_Response->MessageLength = sizeof(RNDIS_KEEPALIVE_CMPLT_t);\r
- KEEPALIVE_Response->RequestId = KEEPALIVE_Message->RequestId;\r
- KEEPALIVE_Response->Status = REMOTE_NDIS_STATUS_SUCCESS;\r
- \r
- break;\r
- }\r
-}\r
-\r
-static bool USB_RNDIS_ProcessNDISQuery(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo,\r
- uint32_t OId, void* QueryData, uint16_t QuerySize,\r
- void* ResponseData, uint16_t* ResponseSize)\r
-{\r
- switch (OId)\r
- {\r
- case OID_GEN_SUPPORTED_LIST:\r
- *ResponseSize = sizeof(AdapterSupportedOIDList);\r
- \r
- memcpy_P(ResponseData, AdapterSupportedOIDList, sizeof(AdapterSupportedOIDList));\r
- \r
- return true;\r
- case OID_GEN_PHYSICAL_MEDIUM:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- /* Indicate that the device is a true ethernet link */\r
- *((uint32_t*)ResponseData) = 0;\r
- \r
- return true;\r
- case OID_GEN_HARDWARE_STATUS:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- *((uint32_t*)ResponseData) = NDIS_HardwareStatus_Ready;\r
- \r
- return true;\r
- case OID_GEN_MEDIA_SUPPORTED:\r
- case OID_GEN_MEDIA_IN_USE:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- *((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIUM_802_3;\r
- \r
- return true;\r
- case OID_GEN_VENDOR_ID:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- /* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */\r
- *((uint32_t*)ResponseData) = 0x00FFFFFF;\r
- \r
- return true;\r
- case OID_GEN_MAXIMUM_FRAME_SIZE:\r
- case OID_GEN_TRANSMIT_BLOCK_SIZE:\r
- case OID_GEN_RECEIVE_BLOCK_SIZE:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- *((uint32_t*)ResponseData) = ETHERNET_FRAME_SIZE_MAX;\r
- \r
- return true;\r
- case OID_GEN_VENDOR_DESCRIPTION:\r
- *ResponseSize = (strlen(RNDISInterfaceInfo->AdapterVendorDescription) + 1);\r
- \r
- memcpy(ResponseData, RNDISInterfaceInfo->AdapterVendorDescription, *ResponseSize);\r
- \r
- return true;\r
- case OID_GEN_MEDIA_CONNECT_STATUS:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- *((uint32_t*)ResponseData) = REMOTE_NDIS_MEDIA_STATE_CONNECTED;\r
- \r
- return true;\r
- case OID_GEN_LINK_SPEED:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- /* Indicate 10Mb/s link speed */\r
- *((uint32_t*)ResponseData) = 100000;\r
-\r
- return true;\r
- case OID_802_3_PERMANENT_ADDRESS:\r
- case OID_802_3_CURRENT_ADDRESS:\r
- *ResponseSize = sizeof(MAC_Address_t);\r
- \r
- memcpy(ResponseData, &RNDISInterfaceInfo->AdapterMACAddress, sizeof(MAC_Address_t));\r
-\r
- return true;\r
- case OID_802_3_MAXIMUM_LIST_SIZE:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- /* Indicate only one multicast address supported */\r
- *((uint32_t*)ResponseData) = 1;\r
- \r
- return true;\r
- case OID_GEN_CURRENT_PACKET_FILTER:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- *((uint32_t*)ResponseData) = RNDISInterfaceInfo->CurrPacketFilter;\r
- \r
- return true; \r
- case OID_GEN_XMIT_OK:\r
- case OID_GEN_RCV_OK:\r
- case OID_GEN_XMIT_ERROR:\r
- case OID_GEN_RCV_ERROR:\r
- case OID_GEN_RCV_NO_BUFFER:\r
- case OID_802_3_RCV_ERROR_ALIGNMENT:\r
- case OID_802_3_XMIT_ONE_COLLISION:\r
- case OID_802_3_XMIT_MORE_COLLISIONS:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- /* Unused statistic OIDs - always return 0 for each */\r
- *((uint32_t*)ResponseData) = 0;\r
- \r
- return true;\r
- case OID_GEN_MAXIMUM_TOTAL_SIZE:\r
- *ResponseSize = sizeof(uint32_t);\r
- \r
- /* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */\r
- *((uint32_t*)ResponseData) = (RNDIS_MESSAGE_BUFFER_SIZE + ETHERNET_FRAME_SIZE_MAX);\r
- \r
- return true;\r
- default:\r
- return false;\r
- }\r
-}\r
-\r
-static bool USB_RNDIS_ProcessNDISSet(USB_ClassInfo_RNDIS_t* RNDISInterfaceInfo, uint32_t OId, void* SetData, uint16_t SetSize)\r
-{\r
- switch (OId)\r
- {\r
- case OID_GEN_CURRENT_PACKET_FILTER:\r
- RNDISInterfaceInfo->CurrPacketFilter = *((uint32_t*)SetData);\r
- RNDISInterfaceInfo->CurrRNDISState = ((RNDISInterfaceInfo->CurrPacketFilter) ?\r
- RNDIS_Data_Initialized : RNDIS_Data_Initialized);\r
- \r
- return true;\r
- case OID_802_3_MULTICAST_LIST:\r
- /* Do nothing - throw away the value from the host as it is unused */\r
- \r
- return true;\r
- default:\r
- return false;\r
- }\r
-}\r
+/*
+ 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
+