This commit is contained in:
2024-08-05 20:57:09 +08:00
commit 46d9ee7795
3020 changed files with 1725767 additions and 0 deletions

View File

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

View File

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

View File

@@ -0,0 +1,566 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
#include "usbd_rndis.h"
#include "rndis_protocol.h"
#define RNDIS_OUT_EP_IDX 0
#define RNDIS_IN_EP_IDX 1
#define RNDIS_INT_EP_IDX 2
/* Describe EndPoints configuration */
static struct usbd_endpoint rndis_ep_data[3];
#define RNDIS_INQUIRY_PUT(src, len) (memcpy(infomation_buffer, src, len))
#define RNDIS_INQUIRY_PUT_LE32(value) (*(uint32_t *)infomation_buffer = (value))
/* Device data structure */
struct usbd_rndis_priv {
uint32_t drv_version;
uint32_t link_status;
uint32_t net_filter;
usb_eth_stat_t eth_state;
rndis_state_t init_state;
uint8_t mac[6];
} g_usbd_rndis;
#if CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE < 140
#undef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
#endif
#if CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE < 1580
#undef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
#endif
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t rndis_encapsulated_resp_buffer[CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t NOTIFY_RESPONSE_AVAILABLE[8];
volatile uint8_t *g_rndis_rx_data_buffer;
volatile uint32_t g_rndis_rx_data_length;
volatile uint32_t g_rndis_tx_data_length;
/* RNDIS options list */
const uint32_t oid_supported_list[] = {
/* General OIDs */
OID_GEN_SUPPORTED_LIST,
OID_GEN_HARDWARE_STATUS,
OID_GEN_MEDIA_SUPPORTED,
OID_GEN_MEDIA_IN_USE,
OID_GEN_MAXIMUM_FRAME_SIZE,
OID_GEN_LINK_SPEED,
OID_GEN_TRANSMIT_BLOCK_SIZE,
OID_GEN_RECEIVE_BLOCK_SIZE,
OID_GEN_VENDOR_ID,
OID_GEN_VENDOR_DESCRIPTION,
OID_GEN_VENDOR_DRIVER_VERSION,
OID_GEN_CURRENT_PACKET_FILTER,
OID_GEN_MAXIMUM_TOTAL_SIZE,
OID_GEN_MEDIA_CONNECT_STATUS,
OID_GEN_PHYSICAL_MEDIUM,
/* General Statistic OIDs */
OID_GEN_XMIT_OK,
OID_GEN_RCV_OK,
OID_GEN_XMIT_ERROR,
OID_GEN_RCV_ERROR,
OID_GEN_RCV_NO_BUFFER,
/* Please configure us */
OID_GEN_RNDIS_CONFIG_PARAMETER,
/* 802.3 OIDs */
OID_802_3_PERMANENT_ADDRESS,
OID_802_3_CURRENT_ADDRESS,
OID_802_3_MULTICAST_LIST,
OID_802_3_MAXIMUM_LIST_SIZE,
/* 802.3 Statistic OIDs */
OID_802_3_RCV_ERROR_ALIGNMENT,
OID_802_3_XMIT_ONE_COLLISION,
OID_802_3_XMIT_MORE_COLLISIONS,
OID_802_3_MAC_OPTIONS,
};
static int rndis_encapsulated_cmd_handler(uint8_t *data, uint32_t len);
static void rndis_notify_rsp(void)
{
memset(NOTIFY_RESPONSE_AVAILABLE, 0, 8);
NOTIFY_RESPONSE_AVAILABLE[0] = 0x01;
usbd_ep_start_write(0, rndis_ep_data[RNDIS_INT_EP_IDX].ep_addr, NOTIFY_RESPONSE_AVAILABLE, 8);
}
static int rndis_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
{
switch (setup->bRequest) {
case CDC_REQUEST_SEND_ENCAPSULATED_COMMAND:
rndis_encapsulated_cmd_handler(*data, setup->wLength);
break;
case CDC_REQUEST_GET_ENCAPSULATED_RESPONSE:
*data = rndis_encapsulated_resp_buffer;
*len = ((rndis_generic_msg_t *)rndis_encapsulated_resp_buffer)->MessageLength;
break;
default:
return -1;
}
return 0;
}
static int rndis_init_cmd_handler(uint8_t *data, uint32_t len);
static int rndis_halt_cmd_handler(uint8_t *data, uint32_t len);
static int rndis_query_cmd_handler(uint8_t *data, uint32_t len);
static int rndis_set_cmd_handler(uint8_t *data, uint32_t len);
static int rndis_reset_cmd_handler(uint8_t *data, uint32_t len);
static int rndis_keepalive_cmd_handler(uint8_t *data, uint32_t len);
static int rndis_encapsulated_cmd_handler(uint8_t *data, uint32_t len)
{
switch (((rndis_generic_msg_t *)data)->MessageType) {
case REMOTE_NDIS_INITIALIZE_MSG:
return rndis_init_cmd_handler(data, len);
case REMOTE_NDIS_HALT_MSG:
return rndis_halt_cmd_handler(data, len);
case REMOTE_NDIS_QUERY_MSG:
return rndis_query_cmd_handler(data, len);
case REMOTE_NDIS_SET_MSG:
return rndis_set_cmd_handler(data, len);
case REMOTE_NDIS_RESET_MSG:
return rndis_reset_cmd_handler(data, len);
case REMOTE_NDIS_KEEPALIVE_MSG:
return rndis_keepalive_cmd_handler(data, len);
default:
break;
}
return -1;
}
static int rndis_init_cmd_handler(uint8_t *data, uint32_t len)
{
rndis_initialize_msg_t *cmd = (rndis_initialize_msg_t *)data;
rndis_initialize_cmplt_t *resp;
resp = ((rndis_initialize_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->RequestId = cmd->RequestId;
resp->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
resp->MessageLength = sizeof(rndis_initialize_cmplt_t);
resp->MajorVersion = RNDIS_MAJOR_VERSION;
resp->MinorVersion = RNDIS_MINOR_VERSION;
resp->Status = RNDIS_STATUS_SUCCESS;
resp->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
resp->Medium = RNDIS_MEDIUM_802_3;
resp->MaxPacketsPerTransfer = CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE / 1580;
resp->MaxTransferSize = CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE;
resp->PacketAlignmentFactor = 0;
resp->AfListOffset = 0;
resp->AfListSize = 0;
g_usbd_rndis.init_state = rndis_initialized;
rndis_notify_rsp();
return 0;
}
static int rndis_halt_cmd_handler(uint8_t *data, uint32_t len)
{
rndis_halt_msg_t *resp;
resp = ((rndis_halt_msg_t *)rndis_encapsulated_resp_buffer);
resp->MessageLength = 0;
g_usbd_rndis.init_state = rndis_uninitialized;
return 0;
}
static int rndis_query_cmd_handler(uint8_t *data, uint32_t len)
{
rndis_query_msg_t *cmd = (rndis_query_msg_t *)data;
rndis_query_cmplt_t *resp;
uint8_t *infomation_buffer;
uint32_t infomation_len = 0;
resp = ((rndis_query_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->MessageType = REMOTE_NDIS_QUERY_CMPLT;
resp->RequestId = cmd->RequestId;
resp->InformationBufferOffset = sizeof(rndis_query_cmplt_t) - sizeof(rndis_generic_msg_t);
resp->Status = RNDIS_STATUS_SUCCESS;
infomation_buffer = (uint8_t *)resp + sizeof(rndis_query_cmplt_t);
switch (cmd->Oid) {
case OID_GEN_SUPPORTED_LIST:
RNDIS_INQUIRY_PUT(oid_supported_list, sizeof(oid_supported_list));
infomation_len = sizeof(oid_supported_list);
break;
case OID_GEN_HARDWARE_STATUS:
RNDIS_INQUIRY_PUT_LE32(NDIS_HW_STS_READY);
infomation_len = 4;
break;
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
RNDIS_INQUIRY_PUT_LE32(NDIS_MEDIUM_802_3);
infomation_len = 4;
break;
case OID_GEN_MAXIMUM_FRAME_SIZE:
case OID_GEN_TRANSMIT_BLOCK_SIZE:
case OID_GEN_RECEIVE_BLOCK_SIZE:
RNDIS_INQUIRY_PUT_LE32(0x05DC); /* mtu 1500 */
infomation_len = 4;
break;
case OID_GEN_VENDOR_ID:
RNDIS_INQUIRY_PUT_LE32(CONFIG_USBDEV_RNDIS_VENDOR_ID);
infomation_len = 4;
break;
case OID_GEN_VENDOR_DRIVER_VERSION:
RNDIS_INQUIRY_PUT_LE32(0x0001);
infomation_len = 4;
break;
case OID_GEN_VENDOR_DESCRIPTION:
RNDIS_INQUIRY_PUT(CONFIG_USBDEV_RNDIS_VENDOR_DESC, strlen(CONFIG_USBDEV_RNDIS_VENDOR_DESC));
infomation_len = (strlen(CONFIG_USBDEV_RNDIS_VENDOR_DESC) + 1);
break;
case OID_802_3_CURRENT_ADDRESS:
case OID_802_3_PERMANENT_ADDRESS:
RNDIS_INQUIRY_PUT(g_usbd_rndis.mac, 6);
infomation_len = 6;
break;
case OID_GEN_PHYSICAL_MEDIUM:
RNDIS_INQUIRY_PUT_LE32(NDIS_MEDIUM_802_3);
infomation_len = 4;
break;
case OID_GEN_LINK_SPEED:
if (usbd_get_ep_mps(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr) > 64) {
RNDIS_INQUIRY_PUT_LE32(480000000 / 100);
} else {
RNDIS_INQUIRY_PUT_LE32(12000000 / 100);
}
infomation_len = 4;
break;
case OID_GEN_CURRENT_PACKET_FILTER:
RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.net_filter);
infomation_len = 4;
break;
case OID_GEN_MAXIMUM_TOTAL_SIZE:
RNDIS_INQUIRY_PUT_LE32(0x0616); /* 1514 + 44 */
infomation_len = 4;
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.link_status);
infomation_len = 4;
break;
case OID_GEN_RNDIS_CONFIG_PARAMETER:
RNDIS_INQUIRY_PUT_LE32(0);
infomation_len = 4;
break;
case OID_802_3_MAXIMUM_LIST_SIZE:
RNDIS_INQUIRY_PUT_LE32(1); /* one address */
infomation_len = 4;
break;
case OID_802_3_MULTICAST_LIST:
//RNDIS_INQUIRY_PUT_LE32(0xE0000000); /* 224.0.0.0 */
resp->Status = RNDIS_STATUS_NOT_SUPPORTED;
RNDIS_INQUIRY_PUT_LE32(0);
infomation_len = 4;
break;
case OID_802_3_MAC_OPTIONS:
// infomation_len = 0;
resp->Status = RNDIS_STATUS_NOT_SUPPORTED;
RNDIS_INQUIRY_PUT_LE32(0);
infomation_len = 4;
break;
case OID_GEN_MAC_OPTIONS:
RNDIS_INQUIRY_PUT_LE32(0);
infomation_len = 4;
break;
case OID_802_3_RCV_ERROR_ALIGNMENT:
RNDIS_INQUIRY_PUT_LE32(0);
infomation_len = 4;
break;
case OID_802_3_XMIT_ONE_COLLISION:
RNDIS_INQUIRY_PUT_LE32(0);
infomation_len = 4;
break;
case OID_802_3_XMIT_MORE_COLLISIONS:
RNDIS_INQUIRY_PUT_LE32(0);
infomation_len = 4;
break;
case OID_GEN_XMIT_OK:
RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.eth_state.txok);
infomation_len = 4;
break;
case OID_GEN_RCV_OK:
RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.eth_state.rxok);
infomation_len = 4;
break;
case OID_GEN_RCV_ERROR:
RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.eth_state.rxbad);
infomation_len = 4;
break;
case OID_GEN_XMIT_ERROR:
RNDIS_INQUIRY_PUT_LE32(g_usbd_rndis.eth_state.txbad);
infomation_len = 4;
break;
case OID_GEN_RCV_NO_BUFFER:
RNDIS_INQUIRY_PUT_LE32(0);
infomation_len = 4;
break;
default:
resp->Status = RNDIS_STATUS_FAILURE;
infomation_len = 0;
USB_LOG_WRN("Unhandled query for Object ID 0x%x\r\n", cmd->Oid);
break;
}
resp->MessageLength = sizeof(rndis_query_cmplt_t) + infomation_len;
resp->InformationBufferLength = infomation_len;
rndis_notify_rsp();
return 0;
}
static int rndis_set_cmd_handler(uint8_t *data, uint32_t len)
{
rndis_set_msg_t *cmd = (rndis_set_msg_t *)data;
rndis_set_cmplt_t *resp;
rndis_config_parameter_t *param;
resp = ((rndis_set_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->RequestId = cmd->RequestId;
resp->MessageType = REMOTE_NDIS_SET_CMPLT;
resp->MessageLength = sizeof(rndis_set_cmplt_t);
resp->Status = RNDIS_STATUS_SUCCESS;
switch (cmd->Oid) {
case OID_GEN_RNDIS_CONFIG_PARAMETER:
param = (rndis_config_parameter_t *)((uint8_t *)&(cmd->RequestId) + cmd->InformationBufferOffset);
USB_LOG_WRN("RNDIS cfg param: NameOfs=%d, NameLen=%d, ValueOfs=%d, ValueLen=%d\r\n",
param->ParameterNameOffset, param->ParameterNameLength,
param->ParameterValueOffset, param->ParameterValueLength);
break;
case OID_GEN_CURRENT_PACKET_FILTER:
if (cmd->InformationBufferLength < sizeof(g_usbd_rndis.net_filter)) {
USB_LOG_WRN("PACKET_FILTER!\r\n");
resp->Status = RNDIS_STATUS_INVALID_DATA;
} else {
uint32_t *filter;
/* Parameter starts at offset buf_offset of the req_id field */
filter = (uint32_t *)((uint8_t *)&(cmd->RequestId) + cmd->InformationBufferOffset);
//g_usbd_rndis.net_filter = param->ParameterNameOffset;
g_usbd_rndis.net_filter = *(uint32_t *)filter;
if (g_usbd_rndis.net_filter) {
g_usbd_rndis.init_state = rndis_data_initialized;
} else {
g_usbd_rndis.init_state = rndis_initialized;
}
}
break;
case OID_GEN_CURRENT_LOOKAHEAD:
break;
case OID_GEN_PROTOCOL_OPTIONS:
break;
case OID_802_3_MULTICAST_LIST:
break;
case OID_PNP_ADD_WAKE_UP_PATTERN:
case OID_PNP_REMOVE_WAKE_UP_PATTERN:
case OID_PNP_ENABLE_WAKE_UP:
default:
resp->Status = RNDIS_STATUS_FAILURE;
USB_LOG_WRN("Unhandled query for Object ID 0x%x\r\n", cmd->Oid);
break;
}
rndis_notify_rsp();
return 0;
}
static int rndis_reset_cmd_handler(uint8_t *data, uint32_t len)
{
// rndis_reset_msg_t *cmd = (rndis_reset_msg_t *)data;
rndis_reset_cmplt_t *resp;
resp = ((rndis_reset_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->MessageType = REMOTE_NDIS_RESET_CMPLT;
resp->MessageLength = sizeof(rndis_reset_cmplt_t);
resp->Status = RNDIS_STATUS_SUCCESS;
resp->AddressingReset = 1;
g_usbd_rndis.init_state = rndis_uninitialized;
rndis_notify_rsp();
return 0;
}
static int rndis_keepalive_cmd_handler(uint8_t *data, uint32_t len)
{
rndis_keepalive_msg_t *cmd = (rndis_keepalive_msg_t *)data;
rndis_keepalive_cmplt_t *resp;
resp = ((rndis_keepalive_cmplt_t *)rndis_encapsulated_resp_buffer);
resp->RequestId = cmd->RequestId;
resp->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
resp->MessageLength = sizeof(rndis_keepalive_cmplt_t);
resp->Status = RNDIS_STATUS_SUCCESS;
rndis_notify_rsp();
return 0;
}
static void rndis_notify_handler(uint8_t busid, uint8_t event, void *arg)
{
switch (event) {
case USBD_EVENT_RESET:
g_usbd_rndis.link_status = NDIS_MEDIA_STATE_DISCONNECTED;
break;
case USBD_EVENT_CONFIGURED:
g_rndis_rx_data_length = 0;
g_rndis_tx_data_length = 0;
g_usbd_rndis.link_status = NDIS_MEDIA_STATE_CONNECTED;
usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
break;
default:
break;
}
}
void rndis_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
rndis_data_packet_t *hdr;
hdr = (rndis_data_packet_t *)g_rndis_rx_buffer;
g_rndis_rx_data_buffer = g_rndis_rx_buffer;
if ((hdr->MessageType != REMOTE_NDIS_PACKET_MSG) || (nbytes < hdr->MessageLength)) {
usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
return;
}
/* Point to the payload and update the message length */
g_rndis_rx_data_buffer += hdr->DataOffset + sizeof(rndis_generic_msg_t);
g_rndis_rx_data_length = hdr->DataLength;
usbd_rndis_data_recv_done();
}
void rndis_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
/* send zlp */
usbd_ep_start_write(0, ep, NULL, 0);
} else {
g_rndis_tx_data_length = 0;
}
}
void rndis_int_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
{
//USB_LOG_DBG("len:%d\r\n", nbytes);
}
#ifdef CONFIG_USBDEV_RNDIS_USING_LWIP
#include <lwip/pbuf.h>
struct pbuf *usbd_rndis_eth_rx(void)
{
struct pbuf *p;
if (g_rndis_rx_data_length == 0) {
return NULL;
}
p = pbuf_alloc(PBUF_RAW, g_rndis_rx_data_length, PBUF_POOL);
if (p == NULL) {
return NULL;
}
usb_memcpy(p->payload, (uint8_t *)g_rndis_rx_data_buffer, g_rndis_rx_data_length);
p->len = g_rndis_rx_data_length;
USB_LOG_DBG("rxlen:%d\r\n", g_rndis_rx_data_length);
g_rndis_rx_data_length = 0;
usbd_ep_start_read(0, rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr, g_rndis_rx_buffer, sizeof(g_rndis_rx_buffer));
return p;
}
int usbd_rndis_eth_tx(struct pbuf *p)
{
struct pbuf *q;
uint8_t *buffer;
rndis_data_packet_t *hdr;
if (g_usbd_rndis.link_status == NDIS_MEDIA_STATE_DISCONNECTED) {
return -USB_ERR_NOTCONN;
}
if (g_rndis_tx_data_length > 0) {
return -USB_ERR_BUSY;
}
if (p->tot_len > sizeof(g_rndis_tx_buffer)) {
p->tot_len = sizeof(g_rndis_tx_buffer);
}
buffer = (uint8_t *)(g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
for (q = p; q != NULL; q = q->next) {
usb_memcpy(buffer, q->payload, q->len);
buffer += q->len;
}
hdr = (rndis_data_packet_t *)g_rndis_tx_buffer;
memset(hdr, 0, sizeof(rndis_data_packet_t));
hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
hdr->MessageLength = sizeof(rndis_data_packet_t) + p->tot_len;
hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
hdr->DataLength = p->tot_len;
g_rndis_tx_data_length = sizeof(rndis_data_packet_t) + p->tot_len;
USB_LOG_DBG("txlen:%d\r\n", g_rndis_tx_data_length);
return usbd_ep_start_write(0, rndis_ep_data[RNDIS_IN_EP_IDX].ep_addr, g_rndis_tx_buffer, g_rndis_tx_data_length);
}
#endif
struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
const uint8_t out_ep,
const uint8_t in_ep,
const uint8_t int_ep, uint8_t mac[6])
{
memcpy(g_usbd_rndis.mac, mac, 6);
g_usbd_rndis.drv_version = 0x0001;
g_usbd_rndis.link_status = NDIS_MEDIA_STATE_DISCONNECTED;
rndis_ep_data[RNDIS_OUT_EP_IDX].ep_addr = out_ep;
rndis_ep_data[RNDIS_OUT_EP_IDX].ep_cb = rndis_bulk_out;
rndis_ep_data[RNDIS_IN_EP_IDX].ep_addr = in_ep;
rndis_ep_data[RNDIS_IN_EP_IDX].ep_cb = rndis_bulk_in;
rndis_ep_data[RNDIS_INT_EP_IDX].ep_addr = int_ep;
rndis_ep_data[RNDIS_INT_EP_IDX].ep_cb = rndis_int_in;
usbd_add_endpoint(0, &rndis_ep_data[RNDIS_OUT_EP_IDX]);
usbd_add_endpoint(0, &rndis_ep_data[RNDIS_IN_EP_IDX]);
usbd_add_endpoint(0, &rndis_ep_data[RNDIS_INT_EP_IDX]);
intf->class_interface_handler = rndis_class_interface_request_handler;
intf->class_endpoint_handler = NULL;
intf->vendor_handler = NULL;
intf->notify_handler = rndis_notify_handler;
return intf;
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBD_RNDIS_H
#define USBD_RNDIS_H
#include "usb_cdc.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Init rndis interface driver */
struct usbd_interface *usbd_rndis_init_intf(struct usbd_interface *intf,
const uint8_t out_ep,
const uint8_t in_ep,
const uint8_t int_ep, uint8_t mac[6]);
void usbd_rndis_data_recv_done(void);
#ifdef CONFIG_USBDEV_RNDIS_USING_LWIP
struct pbuf *usbd_rndis_eth_rx(void);
int usbd_rndis_eth_tx(struct pbuf *p);
#endif
#ifdef __cplusplus
}
#endif
#endif /* USBD_RNDIS_H */

View File

@@ -0,0 +1,407 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_bluetooth.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_bluetooth"
#include "usb_log.h"
#define DEV_FORMAT "/dev/bluetooth"
static struct usbh_bluetooth g_bluetooth_class;
#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_tx_buf[1 + CONFIG_USBHOST_BLUETOOTH_TX_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_rx_buf[1 + CONFIG_USBHOST_BLUETOOTH_RX_SIZE];
#else
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_cmd_buf[1 + 256];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_evt_buf[1 + 256];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_tx_buf[1 + CONFIG_USBHOST_BLUETOOTH_TX_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_rx_buf[1 + CONFIG_USBHOST_BLUETOOTH_RX_SIZE];
#endif
static int usbh_bluetooth_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret = 0;
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
uint8_t mult;
uint16_t mps;
#endif
struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class;
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
if (intf != 0) {
return 0;
}
#endif
memset(bluetooth_class, 0, sizeof(struct usbh_bluetooth));
bluetooth_class->hport = hport;
bluetooth_class->intf = intf;
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
bluetooth_class->num_of_intf_altsettings = hport->config.intf[intf + 1].altsetting_num;
#endif
hport->config.intf[intf].priv = bluetooth_class;
for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
if (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(bluetooth_class->intin, ep_desc);
} else {
return -USB_ERR_NOTSUPP;
}
} else {
#endif
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(bluetooth_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(bluetooth_class->bulkout, ep_desc);
}
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
}
#endif
}
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
USB_LOG_INFO("Num of altsettings:%u\r\n", bluetooth_class->num_of_intf_altsettings);
for (uint8_t i = 0; i < bluetooth_class->num_of_intf_altsettings; i++) {
USB_LOG_INFO("Altsetting:%u\r\n", i);
for (uint8_t j = 0; j < hport->config.intf[intf + 1].altsetting[i].intf_desc.bNumEndpoints; j++) {
ep_desc = &bluetooth_class->hport->config.intf[intf + 1].altsetting[i].ep[j].ep_desc;
mult = USB_GET_MULT(ep_desc->wMaxPacketSize);
mps = USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize);
USB_LOG_INFO("\tEp=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
mps,
ep_desc->bInterval,
mult);
}
}
ret = usbh_set_interface(hport, intf, 0);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("Bluetooth select altsetting 0\r\n");
#endif
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register Bluetooth Class:%s\r\n", hport->config.intf[intf].devname);
usbh_bluetooth_run(bluetooth_class);
return ret;
}
static int usbh_bluetooth_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_bluetooth *bluetooth_class = (struct usbh_bluetooth *)hport->config.intf[intf].priv;
if (hport->config.config_desc.bNumInterfaces == (intf + 1)) {
return 0;
}
if (bluetooth_class) {
if (bluetooth_class->bulkin) {
usbh_kill_urb(&bluetooth_class->bulkin_urb);
}
if (bluetooth_class->bulkout) {
usbh_kill_urb(&bluetooth_class->bulkout_urb);
}
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
if (bluetooth_class->intin) {
usbh_kill_urb(&bluetooth_class->intin_urb);
}
// if (bluetooth_class->isoin) {
// usbh_kill_urb(&bluetooth_class->isoin_urb);
// }
// if (bluetooth_class->isoin) {
// usbh_kill_urb(&bluetooth_class->isoinin_urb);
// }
#endif
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister Bluetooth Class:%s\r\n", hport->config.intf[intf].devname);
usbh_bluetooth_stop(bluetooth_class);
}
memset(bluetooth_class, 0, sizeof(struct usbh_bluetooth));
}
return ret;
}
#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_LOG
static void usbh_bluetooth_hci_dump(uint8_t *data, uint32_t len)
{
uint32_t i = 0;
for (i = 0; i < len; i++) {
if (i % 16 == 0) {
USB_LOG_RAW("\r\n");
}
USB_LOG_RAW("%02x ", data[i]);
}
USB_LOG_RAW("\r\n");
}
#else
#define usbh_bluetooth_hci_dump(data, len)
#endif
static int usbh_bluetooth_hci_bulk_out(uint8_t *buffer, uint32_t buflen)
{
struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class;
struct usbh_urb *urb = &bluetooth_class->bulkout_urb;
int ret;
usbh_bulk_urb_fill(urb, bluetooth_class->hport, bluetooth_class->bulkout, buffer, buflen, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(urb);
if (ret == 0) {
ret = urb->actual_length;
}
return ret;
}
#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen)
{
int ret;
g_bluetooth_tx_buf[0] = hci_type;
memcpy(&g_bluetooth_tx_buf[1], buffer, buflen);
usbh_bluetooth_hci_dump(g_bluetooth_tx_buf, buflen + 1);
ret = usbh_bluetooth_hci_bulk_out(g_bluetooth_tx_buf, buflen + 1);
return ret;
}
void usbh_bluetooth_hci_rx_thread(void *argument)
{
int ret;
uint32_t ep_mps;
uint8_t retry = 0;
uint16_t actual_len = 0;
ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.bulkin->wMaxPacketSize);
USB_LOG_INFO("Create hc rx thread\r\n");
while (1) {
usbh_bulk_urb_fill(&g_bluetooth_class.bulkin_urb, g_bluetooth_class.hport, g_bluetooth_class.bulkin, &g_bluetooth_rx_buf[actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_bluetooth_class.bulkin_urb);
if (ret < 0) {
if (ret == -USB_ERR_SHUTDOWN) {
goto delete;
} else {
retry++;
if (retry == 3) {
retry = 0;
goto delete;
}
continue;
}
}
actual_len += g_bluetooth_class.bulkin_urb.actual_length;
if (g_bluetooth_class.bulkin_urb.actual_length != ep_mps) {
usbh_bluetooth_hci_dump(g_bluetooth_rx_buf, actual_len);
usbh_bluetooth_hci_read_callback(g_bluetooth_rx_buf, actual_len);
actual_len = 0;
} else {
/* read continue util read short packet */
}
}
// clang-format off
delete :
USB_LOG_INFO("Delete hc acl rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
}
#else
static int usbh_bluetooth_hci_cmd(uint8_t *buffer, uint32_t buflen)
{
struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class;
struct usb_setup_packet *setup;
if (!bluetooth_class || !bluetooth_class->hport) {
return -USB_ERR_INVAL;
}
setup = bluetooth_class->hport->setup;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = 0x00;
setup->wValue = 0;
setup->wIndex = bluetooth_class->intf;
setup->wLength = buflen;
return usbh_control_transfer(bluetooth_class->hport, setup, buffer);
}
int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen)
{
int ret;
if (hci_type == USB_BLUETOOTH_HCI_CMD) {
g_bluetooth_cmd_buf[0] = USB_BLUETOOTH_HCI_CMD;
memcpy(&g_bluetooth_cmd_buf[1], buffer, buflen);
usbh_bluetooth_hci_dump(g_bluetooth_cmd_buf, buflen + 1);
ret = usbh_bluetooth_hci_cmd(&g_bluetooth_cmd_buf[1], buflen);
} else if (hci_type == USB_BLUETOOTH_HCI_ACL) {
g_bluetooth_tx_buf[0] = USB_BLUETOOTH_HCI_ACL;
memcpy(&g_bluetooth_tx_buf[1], buffer, buflen);
usbh_bluetooth_hci_dump(g_bluetooth_tx_buf, buflen + 1);
ret = usbh_bluetooth_hci_bulk_out(&g_bluetooth_tx_buf[1], buflen);
} else {
ret = -1;
}
return ret;
}
void usbh_bluetooth_hci_evt_rx_thread(void *argument)
{
int ret;
uint32_t ep_mps;
uint32_t interval;
uint8_t retry = 0;
uint16_t actual_len = 0;
ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.intin->wMaxPacketSize);
interval = g_bluetooth_class.intin->bInterval;
USB_LOG_INFO("Create hc event rx thread\r\n");
while (1) {
usbh_int_urb_fill(&g_bluetooth_class.intin_urb, g_bluetooth_class.hport, g_bluetooth_class.intin, &g_bluetooth_evt_buf[1 + actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_bluetooth_class.intin_urb);
if (ret < 0) {
if (ret == -USB_ERR_SHUTDOWN) {
goto delete;
} else if (ret == -USB_ERR_NAK) {
usb_osal_msleep(interval);
continue;
} else {
retry++;
if (retry == 3) {
retry = 0;
goto delete;
}
usb_osal_msleep(interval);
continue;
}
}
actual_len += g_bluetooth_class.intin_urb.actual_length;
if (g_bluetooth_class.intin_urb.actual_length != ep_mps) {
g_bluetooth_evt_buf[0] = USB_BLUETOOTH_HCI_EVT;
usbh_bluetooth_hci_dump(g_bluetooth_evt_buf, actual_len + 1);
usbh_bluetooth_hci_read_callback(g_bluetooth_evt_buf, actual_len + 1);
actual_len = 0;
} else {
/* read continue util read short packet */
}
usb_osal_msleep(interval);
}
// clang-format off
delete :
USB_LOG_INFO("Delete hc event rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
}
void usbh_bluetooth_hci_acl_rx_thread(void *argument)
{
int ret;
uint32_t ep_mps;
uint8_t retry = 0;
uint16_t actual_len = 0;
ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.bulkin->wMaxPacketSize);
USB_LOG_INFO("Create hc acl rx thread\r\n");
while (1) {
usbh_bulk_urb_fill(&g_bluetooth_class.bulkin_urb, g_bluetooth_class.hport, g_bluetooth_class.bulkin, &g_bluetooth_rx_buf[1 + actual_len], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_bluetooth_class.bulkin_urb);
if (ret < 0) {
if (ret == -USB_ERR_SHUTDOWN) {
goto delete;
} else {
retry++;
if (retry == 3) {
retry = 0;
goto delete;
}
continue;
}
}
actual_len += g_bluetooth_class.bulkin_urb.actual_length;
if (g_bluetooth_class.bulkin_urb.actual_length != ep_mps) {
g_bluetooth_rx_buf[0] = USB_BLUETOOTH_HCI_ACL;
usbh_bluetooth_hci_dump(g_bluetooth_rx_buf, actual_len + 1);
usbh_bluetooth_hci_read_callback(g_bluetooth_rx_buf, actual_len + 1);
actual_len = 0;
} else {
/* read continue util read short packet */
}
}
// clang-format off
delete :
USB_LOG_INFO("Delete hc acl rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
}
#endif
__WEAK void usbh_bluetooth_hci_read_callback(uint8_t *data, uint32_t len)
{
}
__WEAK void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class)
{
}
__WEAK void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class)
{
}
static const struct usbh_class_driver bluetooth_class_driver = {
.driver_name = "bluetooth",
.connect = usbh_bluetooth_connect,
.disconnect = usbh_bluetooth_disconnect
};
#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
static const uint16_t bluetooth_id_table[][2] = {
{ 0x2fe3, 0x000c },
{ 0, 0 },
};
CLASS_INFO_DEFINE const struct usbh_class_info bluetooth_h4_nrf_class_info = {
.match_flags = USB_CLASS_MATCH_VID_PID | USB_CLASS_MATCH_INTF_CLASS,
.class = 0xff,
.subclass = 0x00,
.protocol = 0x00,
.id_table = bluetooth_id_table,
.class_driver = &bluetooth_class_driver
};
#else
CLASS_INFO_DEFINE const struct usbh_class_info bluetooth_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_WIRELESS,
.subclass = 0x01,
.protocol = 0x01,
.id_table = NULL,
.class_driver = &bluetooth_class_driver
};
#endif

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2024, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_BLUETOOTH_H
#define USBH_BLUETOOTH_H
#define USB_BLUETOOTH_HCI_NONE 0x00
#define USB_BLUETOOTH_HCI_CMD 0x01
#define USB_BLUETOOTH_HCI_ACL 0x02
#define USB_BLUETOOTH_HCI_SCO 0x03
#define USB_BLUETOOTH_HCI_EVT 0x04
#define USB_BLUETOOTH_HCI_ISO 0x05
struct usbh_bluetooth {
struct usbh_hubport *hport;
uint8_t intf;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usbh_urb bulkin_urb; /* Bulk IN urb */
struct usbh_urb bulkout_urb; /* Bulk OUT urb */
#ifndef CONFIG_USBHOST_BLUETOOTH_HCI_H4
struct usb_endpoint_descriptor *intin; /* INTR endpoint */
struct usb_endpoint_descriptor *isoin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *isoout; /* Bulk OUT endpoint */
struct usbh_urb intin_urb; /* INTR IN urb */
struct usbh_urb *isoin_urb; /* Bulk IN urb */
struct usbh_urb *isoout_urb; /* Bulk OUT urb */
uint8_t num_of_intf_altsettings;
#endif
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_bluetooth_hci_write(uint8_t hci_type, uint8_t *buffer, uint32_t buflen);
void usbh_bluetooth_hci_read_callback(uint8_t *data, uint32_t len);
#ifdef CONFIG_USBHOST_BLUETOOTH_HCI_H4
void usbh_bluetooth_hci_rx_thread(void *argument);
#else
void usbh_bluetooth_hci_evt_rx_thread(void *argument);
void usbh_bluetooth_hci_acl_rx_thread(void *argument);
#endif
void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class);
void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class);
#ifdef __cplusplus
}
#endif
#endif /* USBH_BLUETOOTH_H */

View File

@@ -0,0 +1,603 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbh_core.h"
#include "usbh_rndis.h"
#include "rndis_protocol.h"
#undef USB_DBG_TAG
#define USB_DBG_TAG "usbh_rndis"
#include "usb_log.h"
#define DEV_FORMAT "/dev/rndis"
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_buf[4096];
#define CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE 1514
#define CONFIG_USBHOST_RNDIS_ETH_MSG_SIZE (CONFIG_USBHOST_RNDIS_ETH_MAX_FRAME_SIZE + 44)
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_rx_buffer[CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE];
static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_tx_buffer[CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE];
// static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_rndis_inttx_buffer[16];
static struct usbh_rndis g_rndis_class;
static int usbh_rndis_get_notification(struct usbh_rndis *rndis_class)
{
// int ret;
// struct usbh_urb *urb = &rndis_class->intin_urb;
// usbh_int_urb_fill(urb, rndis_class->hport, rndis_class->intin, g_rndis_inttx_buffer, rndis_class->intin->wMaxPacketSize, USB_OSAL_WAITING_FOREVER, NULL, NULL);
// ret = usbh_submit_urb(urb);
// if (ret == 0) {
// ret = urb->actual_length;
// }
// return ret;
return 0;
}
static int usbh_rndis_init_msg_transfer(struct usbh_rndis *rndis_class)
{
struct usb_setup_packet *setup;
int ret = 0;
rndis_initialize_msg_t *cmd;
rndis_initialize_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
}
setup = rndis_class->hport->setup;
cmd = (rndis_initialize_msg_t *)g_rndis_buf;
cmd->MessageType = REMOTE_NDIS_INITIALIZE_MSG;
cmd->MessageLength = sizeof(rndis_initialize_msg_t);
cmd->RequestId = rndis_class->request_id++;
cmd->MajorVersion = 1;
cmd->MinorVersion = 0;
cmd->MaxTransferSize = 0x4000;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = sizeof(rndis_initialize_msg_t);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
USB_LOG_ERR("rndis_initialize_msg_t send error, ret: %d\r\n", ret);
return ret;
}
usbh_rndis_get_notification(rndis_class);
resp = (rndis_initialize_cmplt_t *)g_rndis_buf;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 4096;
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
USB_LOG_ERR("rndis_initialize_cmplt_t recv error, ret: %d\r\n", ret);
return ret;
}
rndis_class->max_transfer_pkts = resp->MaxPacketsPerTransfer;
rndis_class->max_transfer_size = resp->MaxTransferSize;
USB_LOG_INFO("MaxPacketsPerTransfer:%d\r\n", resp->MaxPacketsPerTransfer);
USB_LOG_INFO("MaxTransferSize:%d\r\n", resp->MaxTransferSize);
return ret;
}
int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint32_t query_len, uint8_t *info, uint32_t *info_len)
{
struct usb_setup_packet *setup;
int ret = 0;
rndis_query_msg_t *cmd;
rndis_query_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
}
setup = rndis_class->hport->setup;
cmd = (rndis_query_msg_t *)g_rndis_buf;
cmd->MessageType = REMOTE_NDIS_QUERY_MSG;
cmd->MessageLength = query_len + sizeof(rndis_query_msg_t);
cmd->RequestId = rndis_class->request_id++;
cmd->Oid = oid;
cmd->InformationBufferLength = query_len;
cmd->InformationBufferOffset = 20;
cmd->DeviceVcHandle = 0;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = query_len + sizeof(rndis_query_msg_t);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
return ret;
}
usbh_rndis_get_notification(rndis_class);
resp = (rndis_query_cmplt_t *)g_rndis_buf;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 4096;
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
return ret;
}
memcpy(info, ((uint8_t *)resp + sizeof(rndis_query_cmplt_t)), resp->InformationBufferLength);
*info_len = resp->InformationBufferLength;
return ret;
}
static int usbh_rndis_set_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint8_t *info, uint32_t info_len)
{
struct usb_setup_packet *setup;
int ret = 0;
rndis_set_msg_t *cmd;
rndis_set_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
}
setup = rndis_class->hport->setup;
cmd = (rndis_set_msg_t *)g_rndis_buf;
cmd->MessageType = REMOTE_NDIS_SET_MSG;
cmd->MessageLength = info_len + sizeof(rndis_set_msg_t);
cmd->RequestId = rndis_class->request_id++;
cmd->Oid = oid;
cmd->InformationBufferLength = info_len;
cmd->InformationBufferOffset = 20;
cmd->DeviceVcHandle = 0;
memcpy(((uint8_t *)cmd + sizeof(rndis_set_msg_t)), info, info_len);
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = info_len + sizeof(rndis_set_msg_t);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
USB_LOG_ERR("oid:%08x send error, ret: %d\r\n", (unsigned int)oid, ret);
return ret;
}
usbh_rndis_get_notification(rndis_class);
resp = (rndis_set_cmplt_t *)g_rndis_buf;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 4096;
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
USB_LOG_ERR("oid:%08x recv error, ret: %d\r\n", (unsigned int)oid, ret);
return ret;
}
return ret;
}
int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class)
{
int ret;
uint8_t data[32];
uint32_t data_len;
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, &data_len);
if (ret < 0) {
return ret;
}
if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
rndis_class->connect_status = true;
} else {
rndis_class->connect_status = false;
}
return 0;
}
int usbh_rndis_keepalive(struct usbh_rndis *rndis_class)
{
struct usb_setup_packet *setup;
int ret = 0;
rndis_keepalive_msg_t *cmd;
rndis_keepalive_cmplt_t *resp;
if (!rndis_class || !rndis_class->hport) {
return -USB_ERR_INVAL;
}
setup = rndis_class->hport->setup;
cmd = (rndis_keepalive_msg_t *)g_rndis_buf;
cmd->MessageType = REMOTE_NDIS_KEEPALIVE_MSG;
cmd->MessageLength = sizeof(rndis_keepalive_msg_t);
cmd->RequestId = rndis_class->request_id++;
setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_SEND_ENCAPSULATED_COMMAND;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = sizeof(rndis_keepalive_msg_t);
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)cmd);
if (ret < 0) {
USB_LOG_ERR("keepalive send error, ret: %d\r\n", ret);
return ret;
}
usbh_rndis_get_notification(rndis_class);
resp = (rndis_keepalive_cmplt_t *)g_rndis_buf;
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
setup->bRequest = CDC_REQUEST_GET_ENCAPSULATED_RESPONSE;
setup->wValue = 0;
setup->wIndex = 0;
setup->wLength = 4096;
ret = usbh_control_transfer(rndis_class->hport, setup, (uint8_t *)resp);
if (ret < 0) {
USB_LOG_ERR("keepalive recv error, ret: %d\r\n", ret);
return ret;
}
return ret;
}
static int usbh_rndis_connect(struct usbh_hubport *hport, uint8_t intf)
{
struct usb_endpoint_descriptor *ep_desc;
int ret;
uint32_t *oid_support_list;
unsigned int oid = 0;
unsigned int oid_num = 0;
uint32_t data_len;
uint8_t tmp_buffer[512];
uint8_t data[32];
struct usbh_rndis *rndis_class = &g_rndis_class;
memset(rndis_class, 0, sizeof(struct usbh_rndis));
rndis_class->hport = hport;
rndis_class->ctrl_intf = intf;
rndis_class->data_intf = intf + 1;
hport->config.intf[intf].priv = rndis_class;
hport->config.intf[intf + 1].priv = NULL;
// ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
// USBH_EP_INIT(rndis_class->intin, ep_desc);
for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
if (ep_desc->bEndpointAddress & 0x80) {
USBH_EP_INIT(rndis_class->bulkin, ep_desc);
} else {
USBH_EP_INIT(rndis_class->bulkout, ep_desc);
}
}
ret = usbh_rndis_init_msg_transfer(rndis_class);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("rndis init success\r\n");
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_SUPPORTED_LIST, 0, tmp_buffer, &data_len);
if (ret < 0) {
return ret;
}
oid_num = (data_len / 4);
USB_LOG_INFO("rndis query OID_GEN_SUPPORTED_LIST success,oid num :%d\r\n", oid_num);
oid_support_list = (uint32_t *)tmp_buffer;
for (uint8_t i = 0; i < oid_num; i++) {
oid = oid_support_list[i];
switch (oid) {
case OID_GEN_PHYSICAL_MEDIUM:
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_PHYSICAL_MEDIUM, 4, data, &data_len);
if (ret < 0) {
goto query_errorout;
}
break;
case OID_GEN_MAXIMUM_FRAME_SIZE:
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MAXIMUM_FRAME_SIZE, 4, data, &data_len);
if (ret < 0) {
goto query_errorout;
}
break;
case OID_GEN_LINK_SPEED:
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_LINK_SPEED, 4, data, &data_len);
if (ret < 0) {
goto query_errorout;
}
memcpy(&rndis_class->link_speed, data, 4);
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, 4, data, &data_len);
if (ret < 0) {
goto query_errorout;
}
if (NDIS_MEDIA_STATE_CONNECTED == data[0]) {
rndis_class->connect_status = true;
} else {
rndis_class->connect_status = false;
}
break;
case OID_802_3_MAXIMUM_LIST_SIZE:
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_MAXIMUM_LIST_SIZE, 4, data, &data_len);
if (ret < 0) {
goto query_errorout;
}
break;
case OID_802_3_CURRENT_ADDRESS:
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_CURRENT_ADDRESS, 6, data, &data_len);
if (ret < 0) {
goto query_errorout;
}
for (uint8_t j = 0; j < 6; j++) {
rndis_class->mac[j] = data[j];
}
break;
case OID_802_3_PERMANENT_ADDRESS:
ret = usbh_rndis_query_msg_transfer(rndis_class, OID_802_3_PERMANENT_ADDRESS, 6, data, &data_len);
if (ret < 0) {
goto query_errorout;
}
break;
default:
USB_LOG_WRN("Ignore rndis query iod:%08x\r\n", oid);
continue;
}
USB_LOG_INFO("rndis query iod:%08x success\r\n", oid);
}
uint32_t packet_filter = 0x0f;
usbh_rndis_set_msg_transfer(rndis_class, OID_GEN_CURRENT_PACKET_FILTER, (uint8_t *)&packet_filter, 4);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("rndis set OID_GEN_CURRENT_PACKET_FILTER success\r\n");
uint8_t multicast_list[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x01 };
usbh_rndis_set_msg_transfer(rndis_class, OID_802_3_MULTICAST_LIST, multicast_list, 6);
if (ret < 0) {
return ret;
}
USB_LOG_INFO("rndis set OID_802_3_MULTICAST_LIST success\r\n");
USB_LOG_INFO("rndis MAC address %02x:%02x:%02x:%02x:%02x:%02x\r\n",
rndis_class->mac[0],
rndis_class->mac[1],
rndis_class->mac[2],
rndis_class->mac[3],
rndis_class->mac[4],
rndis_class->mac[5]);
strncpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
usbh_rndis_run(rndis_class);
return ret;
query_errorout:
USB_LOG_ERR("rndis query iod:%08x error\r\n", oid);
return ret;
}
static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
{
int ret = 0;
struct usbh_rndis *rndis_class = (struct usbh_rndis *)hport->config.intf[intf].priv;
if (rndis_class) {
if (rndis_class->bulkin) {
usbh_kill_urb(&rndis_class->bulkin_urb);
}
if (rndis_class->bulkout) {
usbh_kill_urb(&rndis_class->bulkout_urb);
}
// if (rndis_class->intin) {
// usbh_kill_urb(&rndis_class->intin_urb);
// }
if (hport->config.intf[intf].devname[0] != '\0') {
USB_LOG_INFO("Unregister RNDIS Class:%s\r\n", hport->config.intf[intf].devname);
usbh_rndis_stop(rndis_class);
}
memset(rndis_class, 0, sizeof(struct usbh_rndis));
}
return ret;
}
void usbh_rndis_rx_thread(void *argument)
{
uint32_t g_rndis_rx_length;
int ret;
uint32_t pmg_offset;
rndis_data_packet_t *pmsg;
rndis_data_packet_t temp;
#if CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE <= (16 * 1024)
uint32_t transfer_size = CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE;
#else
uint32_t transfer_size = (16 * 1024);
#endif
USB_LOG_INFO("Create rndis rx thread\r\n");
// clang-format off
find_class:
// clang-format on
g_rndis_class.connect_status = false;
if (usbh_find_class_instance("/dev/rndis") == NULL) {
goto delete;
}
while (g_rndis_class.connect_status == false) {
ret = usbh_rndis_get_connect_status(&g_rndis_class);
if (ret < 0) {
usb_osal_msleep(100);
goto find_class;
}
usb_osal_msleep(128);
}
g_rndis_rx_length = 0;
while (1) {
usbh_bulk_urb_fill(&g_rndis_class.bulkin_urb, g_rndis_class.hport, g_rndis_class.bulkin, &g_rndis_rx_buffer[g_rndis_rx_length], transfer_size, USB_OSAL_WAITING_FOREVER, NULL, NULL);
ret = usbh_submit_urb(&g_rndis_class.bulkin_urb);
if (ret < 0) {
goto find_class;
}
g_rndis_rx_length += g_rndis_class.bulkin_urb.actual_length;
/* A transfer is complete because last packet is a short packet.
* Short packet is not zero, match g_rndis_rx_length % USB_GET_MAXPACKETSIZE(g_rndis_class.bulkin->wMaxPacketSize).
* Short packet cannot be zero.
*/
if (g_rndis_rx_length % USB_GET_MAXPACKETSIZE(g_rndis_class.bulkin->wMaxPacketSize)) {
pmg_offset = 0;
uint32_t total_len = g_rndis_rx_length;
while (g_rndis_rx_length > 0) {
USB_LOG_DBG("rxlen:%d\r\n", g_rndis_rx_length);
pmsg = (rndis_data_packet_t *)(g_rndis_rx_buffer + pmg_offset);
/* Not word-aligned case */
if (pmg_offset & 0x3) {
usb_memcpy(&temp, pmsg, sizeof(rndis_data_packet_t));
pmsg = &temp;
}
if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
uint8_t *buf = (uint8_t *)(g_rndis_rx_buffer + pmg_offset + sizeof(rndis_generic_msg_t) + pmsg->DataOffset);
usbh_rndis_eth_input(buf, pmsg->DataLength);
pmg_offset += pmsg->MessageLength;
g_rndis_rx_length -= pmsg->MessageLength;
/* drop the last dummy byte, it is a short packet to tell us we have received a multiple of wMaxPacketSize */
if (g_rndis_rx_length < 4) {
g_rndis_rx_length = 0;
}
} else {
USB_LOG_ERR("offset:%d,remain:%d,total:%d\r\n", pmg_offset, g_rndis_rx_length, total_len);
g_rndis_rx_length = 0;
USB_LOG_ERR("Error rndis packet message\r\n");
}
}
} else {
#if CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE <= (16 * 1024)
if (g_rndis_rx_length == CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE) {
#else
if ((g_rndis_rx_length + (16 * 1024)) > CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE) {
#endif
USB_LOG_ERR("Rx packet is overflow, please ruduce tcp window size or increase CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE\r\n");
while (1) {
}
}
}
}
// clang-format off
delete:
USB_LOG_INFO("Delete rndis rx thread\r\n");
usb_osal_thread_delete(NULL);
// clang-format on
}
uint8_t *usbh_rndis_get_eth_txbuf(void)
{
return (g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
}
int usbh_rndis_eth_output(uint32_t buflen)
{
rndis_data_packet_t *hdr;
uint32_t len;
if (g_rndis_class.connect_status == false) {
return -USB_ERR_NOTCONN;
}
hdr = (rndis_data_packet_t *)g_rndis_tx_buffer;
memset(hdr, 0, sizeof(rndis_data_packet_t));
hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
hdr->MessageLength = sizeof(rndis_data_packet_t) + buflen;
hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
hdr->DataLength = buflen;
len = hdr->MessageLength;
/* if message length is the multiple of wMaxPacketSize, we should add a short packet to tell device transfer is over. */
if (!(len % g_rndis_class.bulkout->wMaxPacketSize)) {
len += 1;
}
USB_LOG_DBG("txlen:%d\r\n", len);
usbh_bulk_urb_fill(&g_rndis_class.bulkout_urb, g_rndis_class.hport, g_rndis_class.bulkout, g_rndis_tx_buffer, len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
return usbh_submit_urb(&g_rndis_class.bulkout_urb);
}
__WEAK void usbh_rndis_run(struct usbh_rndis *rndis_class)
{
}
__WEAK void usbh_rndis_stop(struct usbh_rndis *rndis_class)
{
}
static const struct usbh_class_driver rndis_class_driver = {
.driver_name = "rndis",
.connect = usbh_rndis_connect,
.disconnect = usbh_rndis_disconnect
};
CLASS_INFO_DEFINE const struct usbh_class_info rndis_class_info = {
.match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
.class = USB_DEVICE_CLASS_WIRELESS,
.subclass = 0x01,
.protocol = 0x03,
.id_table = NULL,
.class_driver = &rndis_class_driver
};

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef USBH_RNDIS_H
#define USBH_RNDIS_H
#include "usb_cdc.h"
struct usbh_rndis {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
struct usb_endpoint_descriptor *intin; /* INTR endpoint */
struct usbh_urb bulkin_urb; /* Bulk IN urb */
struct usbh_urb bulkout_urb; /* Bulk OUT urb */
struct usbh_urb intin_urb; /* INTR IN urb */
uint8_t ctrl_intf; /* Control interface number */
uint8_t data_intf; /* Data interface number */
uint8_t minor;
uint32_t request_id;
uint32_t tx_offset;
uint32_t max_transfer_pkts; /* max packets in one transfer */
uint32_t max_transfer_size; /* max size in one transfer */
uint32_t link_speed;
bool connect_status;
uint8_t mac[6];
void *user_data;
};
#ifdef __cplusplus
extern "C" {
#endif
int usbh_rndis_get_connect_status(struct usbh_rndis *rndis_class);
int usbh_rndis_keepalive(struct usbh_rndis *rndis_class);
void usbh_rndis_run(struct usbh_rndis *rndis_class);
void usbh_rndis_stop(struct usbh_rndis *rndis_class);
uint8_t *usbh_rndis_get_eth_txbuf(void);
int usbh_rndis_eth_output(uint32_t buflen);
void usbh_rndis_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_rndis_rx_thread(void *argument);
#ifdef __cplusplus
}
#endif
#endif /* USBH_RNDIS_H */