mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-22 14:22:23 +00:00
1029 lines
31 KiB
C
1029 lines
31 KiB
C
/*
|
|
* TAP-Windows -- A kernel driver to provide virtual tap
|
|
* device functionality on Windows.
|
|
*
|
|
* This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
|
|
*
|
|
* This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
|
|
* and is released under the GPL version 2 (see below).
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program (see the file COPYING included with this
|
|
* distribution); if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
//
|
|
// Include files.
|
|
//
|
|
|
|
#include "tap.h"
|
|
|
|
#ifndef DBG
|
|
|
|
#define DBG_PRINT_OID_NAME
|
|
|
|
#else
|
|
|
|
VOID
|
|
DBG_PRINT_OID_NAME(
|
|
__in NDIS_OID Oid
|
|
)
|
|
{
|
|
PCHAR oidName = NULL;
|
|
|
|
switch (Oid){
|
|
|
|
#undef MAKECASE
|
|
#define MAKECASE(oidx) case oidx: oidName = #oidx "\n"; break;
|
|
|
|
/* Operational OIDs */
|
|
MAKECASE(OID_GEN_SUPPORTED_LIST)
|
|
MAKECASE(OID_GEN_HARDWARE_STATUS)
|
|
MAKECASE(OID_GEN_MEDIA_SUPPORTED)
|
|
MAKECASE(OID_GEN_MEDIA_IN_USE)
|
|
MAKECASE(OID_GEN_MAXIMUM_LOOKAHEAD)
|
|
MAKECASE(OID_GEN_MAXIMUM_FRAME_SIZE)
|
|
MAKECASE(OID_GEN_LINK_SPEED)
|
|
MAKECASE(OID_GEN_TRANSMIT_BUFFER_SPACE)
|
|
MAKECASE(OID_GEN_RECEIVE_BUFFER_SPACE)
|
|
MAKECASE(OID_GEN_TRANSMIT_BLOCK_SIZE)
|
|
MAKECASE(OID_GEN_RECEIVE_BLOCK_SIZE)
|
|
MAKECASE(OID_GEN_VENDOR_ID)
|
|
MAKECASE(OID_GEN_VENDOR_DESCRIPTION)
|
|
MAKECASE(OID_GEN_VENDOR_DRIVER_VERSION)
|
|
MAKECASE(OID_GEN_CURRENT_PACKET_FILTER)
|
|
MAKECASE(OID_GEN_CURRENT_LOOKAHEAD)
|
|
MAKECASE(OID_GEN_DRIVER_VERSION)
|
|
MAKECASE(OID_GEN_MAXIMUM_TOTAL_SIZE)
|
|
MAKECASE(OID_GEN_PROTOCOL_OPTIONS)
|
|
MAKECASE(OID_GEN_MAC_OPTIONS)
|
|
MAKECASE(OID_GEN_MEDIA_CONNECT_STATUS)
|
|
MAKECASE(OID_GEN_MAXIMUM_SEND_PACKETS)
|
|
MAKECASE(OID_GEN_SUPPORTED_GUIDS)
|
|
MAKECASE(OID_GEN_NETWORK_LAYER_ADDRESSES)
|
|
MAKECASE(OID_GEN_TRANSPORT_HEADER_OFFSET)
|
|
MAKECASE(OID_GEN_MEDIA_CAPABILITIES)
|
|
MAKECASE(OID_GEN_PHYSICAL_MEDIUM)
|
|
MAKECASE(OID_GEN_MACHINE_NAME)
|
|
MAKECASE(OID_GEN_VLAN_ID)
|
|
MAKECASE(OID_GEN_RNDIS_CONFIG_PARAMETER)
|
|
|
|
/* Operational OIDs for NDIS 6.0 */
|
|
MAKECASE(OID_GEN_MAX_LINK_SPEED)
|
|
MAKECASE(OID_GEN_LINK_STATE)
|
|
MAKECASE(OID_GEN_LINK_PARAMETERS)
|
|
MAKECASE(OID_GEN_MINIPORT_RESTART_ATTRIBUTES)
|
|
MAKECASE(OID_GEN_ENUMERATE_PORTS)
|
|
MAKECASE(OID_GEN_PORT_STATE)
|
|
MAKECASE(OID_GEN_PORT_AUTHENTICATION_PARAMETERS)
|
|
MAKECASE(OID_GEN_INTERRUPT_MODERATION)
|
|
MAKECASE(OID_GEN_PHYSICAL_MEDIUM_EX)
|
|
|
|
/* Statistical OIDs */
|
|
MAKECASE(OID_GEN_XMIT_OK)
|
|
MAKECASE(OID_GEN_RCV_OK)
|
|
MAKECASE(OID_GEN_XMIT_ERROR)
|
|
MAKECASE(OID_GEN_RCV_ERROR)
|
|
MAKECASE(OID_GEN_RCV_NO_BUFFER)
|
|
MAKECASE(OID_GEN_DIRECTED_BYTES_XMIT)
|
|
MAKECASE(OID_GEN_DIRECTED_FRAMES_XMIT)
|
|
MAKECASE(OID_GEN_MULTICAST_BYTES_XMIT)
|
|
MAKECASE(OID_GEN_MULTICAST_FRAMES_XMIT)
|
|
MAKECASE(OID_GEN_BROADCAST_BYTES_XMIT)
|
|
MAKECASE(OID_GEN_BROADCAST_FRAMES_XMIT)
|
|
MAKECASE(OID_GEN_DIRECTED_BYTES_RCV)
|
|
MAKECASE(OID_GEN_DIRECTED_FRAMES_RCV)
|
|
MAKECASE(OID_GEN_MULTICAST_BYTES_RCV)
|
|
MAKECASE(OID_GEN_MULTICAST_FRAMES_RCV)
|
|
MAKECASE(OID_GEN_BROADCAST_BYTES_RCV)
|
|
MAKECASE(OID_GEN_BROADCAST_FRAMES_RCV)
|
|
MAKECASE(OID_GEN_RCV_CRC_ERROR)
|
|
MAKECASE(OID_GEN_TRANSMIT_QUEUE_LENGTH)
|
|
|
|
/* Statistical OIDs for NDIS 6.0 */
|
|
MAKECASE(OID_GEN_STATISTICS)
|
|
MAKECASE(OID_GEN_BYTES_RCV)
|
|
MAKECASE(OID_GEN_BYTES_XMIT)
|
|
MAKECASE(OID_GEN_RCV_DISCARDS)
|
|
MAKECASE(OID_GEN_XMIT_DISCARDS)
|
|
|
|
/* Misc OIDs */
|
|
MAKECASE(OID_GEN_GET_TIME_CAPS)
|
|
MAKECASE(OID_GEN_GET_NETCARD_TIME)
|
|
MAKECASE(OID_GEN_NETCARD_LOAD)
|
|
MAKECASE(OID_GEN_DEVICE_PROFILE)
|
|
MAKECASE(OID_GEN_INIT_TIME_MS)
|
|
MAKECASE(OID_GEN_RESET_COUNTS)
|
|
MAKECASE(OID_GEN_MEDIA_SENSE_COUNTS)
|
|
|
|
/* PnP power management operational OIDs */
|
|
MAKECASE(OID_PNP_CAPABILITIES)
|
|
MAKECASE(OID_PNP_SET_POWER)
|
|
MAKECASE(OID_PNP_QUERY_POWER)
|
|
MAKECASE(OID_PNP_ADD_WAKE_UP_PATTERN)
|
|
MAKECASE(OID_PNP_REMOVE_WAKE_UP_PATTERN)
|
|
MAKECASE(OID_PNP_ENABLE_WAKE_UP)
|
|
MAKECASE(OID_PNP_WAKE_UP_PATTERN_LIST)
|
|
|
|
/* PnP power management statistical OIDs */
|
|
MAKECASE(OID_PNP_WAKE_UP_ERROR)
|
|
MAKECASE(OID_PNP_WAKE_UP_OK)
|
|
|
|
/* Ethernet operational OIDs */
|
|
MAKECASE(OID_802_3_PERMANENT_ADDRESS)
|
|
MAKECASE(OID_802_3_CURRENT_ADDRESS)
|
|
MAKECASE(OID_802_3_MULTICAST_LIST)
|
|
MAKECASE(OID_802_3_MAXIMUM_LIST_SIZE)
|
|
MAKECASE(OID_802_3_MAC_OPTIONS)
|
|
|
|
/* Ethernet operational OIDs for NDIS 6.0 */
|
|
MAKECASE(OID_802_3_ADD_MULTICAST_ADDRESS)
|
|
MAKECASE(OID_802_3_DELETE_MULTICAST_ADDRESS)
|
|
|
|
/* Ethernet statistical OIDs */
|
|
MAKECASE(OID_802_3_RCV_ERROR_ALIGNMENT)
|
|
MAKECASE(OID_802_3_XMIT_ONE_COLLISION)
|
|
MAKECASE(OID_802_3_XMIT_MORE_COLLISIONS)
|
|
MAKECASE(OID_802_3_XMIT_DEFERRED)
|
|
MAKECASE(OID_802_3_XMIT_MAX_COLLISIONS)
|
|
MAKECASE(OID_802_3_RCV_OVERRUN)
|
|
MAKECASE(OID_802_3_XMIT_UNDERRUN)
|
|
MAKECASE(OID_802_3_XMIT_HEARTBEAT_FAILURE)
|
|
MAKECASE(OID_802_3_XMIT_TIMES_CRS_LOST)
|
|
MAKECASE(OID_802_3_XMIT_LATE_COLLISIONS)
|
|
|
|
/* TCP/IP OIDs */
|
|
MAKECASE(OID_TCP_TASK_OFFLOAD)
|
|
MAKECASE(OID_TCP_TASK_IPSEC_ADD_SA)
|
|
MAKECASE(OID_TCP_TASK_IPSEC_DELETE_SA)
|
|
MAKECASE(OID_TCP_SAN_SUPPORT)
|
|
MAKECASE(OID_TCP_TASK_IPSEC_ADD_UDPESP_SA)
|
|
MAKECASE(OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA)
|
|
MAKECASE(OID_TCP4_OFFLOAD_STATS)
|
|
MAKECASE(OID_TCP6_OFFLOAD_STATS)
|
|
MAKECASE(OID_IP4_OFFLOAD_STATS)
|
|
MAKECASE(OID_IP6_OFFLOAD_STATS)
|
|
|
|
/* TCP offload OIDs for NDIS 6 */
|
|
MAKECASE(OID_TCP_OFFLOAD_CURRENT_CONFIG)
|
|
MAKECASE(OID_TCP_OFFLOAD_PARAMETERS)
|
|
MAKECASE(OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES)
|
|
MAKECASE(OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG)
|
|
MAKECASE(OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES)
|
|
MAKECASE(OID_OFFLOAD_ENCAPSULATION)
|
|
|
|
#if (NDIS_SUPPORT_NDIS620)
|
|
/* VMQ OIDs for NDIS 6.20 */
|
|
MAKECASE(OID_RECEIVE_FILTER_FREE_QUEUE)
|
|
MAKECASE(OID_RECEIVE_FILTER_CLEAR_FILTER)
|
|
MAKECASE(OID_RECEIVE_FILTER_ALLOCATE_QUEUE)
|
|
MAKECASE(OID_RECEIVE_FILTER_QUEUE_ALLOCATION_COMPLETE)
|
|
MAKECASE(OID_RECEIVE_FILTER_SET_FILTER)
|
|
#endif
|
|
|
|
#if (NDIS_SUPPORT_NDIS630)
|
|
/* NDIS QoS OIDs for NDIS 6.30 */
|
|
MAKECASE(OID_QOS_PARAMETERS)
|
|
#endif
|
|
}
|
|
|
|
if (oidName)
|
|
{
|
|
DEBUGP(("OID: %s", oidName));
|
|
}
|
|
else
|
|
{
|
|
DEBUGP(("<** Unknown OID 0x%08x **>\n", Oid));
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
//======================================================================
|
|
// TAP NDIS 6 OID Request Callbacks
|
|
//======================================================================
|
|
|
|
NDIS_STATUS
|
|
tapSetMulticastList(
|
|
__in PTAP_ADAPTER_CONTEXT Adapter,
|
|
__in PNDIS_OID_REQUEST OidRequest
|
|
)
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
OidRequest->DATA.SET_INFORMATION.BytesNeeded = MACADDR_SIZE;
|
|
OidRequest->DATA.SET_INFORMATION.BytesRead
|
|
= OidRequest->DATA.SET_INFORMATION.InformationBufferLength;
|
|
|
|
|
|
do
|
|
{
|
|
if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength % MACADDR_SIZE)
|
|
{
|
|
status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength > (TAP_MAX_MCAST_LIST * MACADDR_SIZE))
|
|
{
|
|
status = NDIS_STATUS_MULTICAST_FULL;
|
|
OidRequest->DATA.SET_INFORMATION.BytesNeeded = TAP_MAX_MCAST_LIST * MACADDR_SIZE;
|
|
break;
|
|
}
|
|
|
|
// BUGBUG!!! Is lock needed??? If so, use NDIS_RW_LOCK. Also apply to packet filter.
|
|
|
|
NdisZeroMemory(Adapter->MCList,
|
|
TAP_MAX_MCAST_LIST * MACADDR_SIZE);
|
|
|
|
NdisMoveMemory(Adapter->MCList,
|
|
OidRequest->DATA.SET_INFORMATION.InformationBuffer,
|
|
OidRequest->DATA.SET_INFORMATION.InformationBufferLength);
|
|
|
|
Adapter->ulMCListSize = OidRequest->DATA.SET_INFORMATION.InformationBufferLength / MACADDR_SIZE;
|
|
|
|
} while(FALSE);
|
|
return status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
tapSetPacketFilter(
|
|
__in PTAP_ADAPTER_CONTEXT Adapter,
|
|
__in ULONG PacketFilter
|
|
)
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
|
|
// any bits not supported?
|
|
if (PacketFilter & ~(TAP_SUPPORTED_FILTERS))
|
|
{
|
|
DEBUGP (("[TAP] Unsupported packet filter: 0x%08x\n", PacketFilter));
|
|
status = NDIS_STATUS_NOT_SUPPORTED;
|
|
}
|
|
else
|
|
{
|
|
// Any actual filtering changes?
|
|
if (PacketFilter != Adapter->PacketFilter)
|
|
{
|
|
//
|
|
// Change the filtering modes on hardware
|
|
//
|
|
|
|
// Save the new packet filter value
|
|
Adapter->PacketFilter = PacketFilter;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
AdapterSetPowerD0(
|
|
__in PTAP_ADAPTER_CONTEXT Adapter
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
NIC power has been restored to the working power state (D0).
|
|
Prepare the NIC for normal operation:
|
|
- Restore hardware context (packet filters, multicast addresses, MAC address, etc.)
|
|
- Enable interrupts and the NIC's DMA engine.
|
|
|
|
Arguments:
|
|
|
|
Adapter - Pointer to adapter block
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
|
|
DEBUGP (("[TAP] PowerState: Fully powered\n"));
|
|
|
|
// Start data path...
|
|
|
|
return status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
AdapterSetPowerLow(
|
|
__in PTAP_ADAPTER_CONTEXT Adapter,
|
|
__in NDIS_DEVICE_POWER_STATE PowerState
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
The NIC is about to be transitioned to a low power state.
|
|
Prepare the NIC for the sleeping state:
|
|
- Disable interrupts and the NIC's DMA engine, cancel timers.
|
|
- Save any hardware context that the NIC cannot preserve in
|
|
a sleeping state (packet filters, multicast addresses,
|
|
the current MAC address, etc.)
|
|
A miniport driver cannot access the NIC hardware after
|
|
the NIC has been set to the D3 state by the bus driver.
|
|
|
|
Miniport drivers NDIS v6.30 and above
|
|
Do NOT wait for NDIS to return the ownership of all
|
|
NBLs from outstanding receive indications
|
|
Retain ownership of all the receive descriptors and
|
|
packet buffers previously owned by the hardware.
|
|
|
|
Arguments:
|
|
|
|
Adapter - Pointer to adapter block
|
|
PowerState - New power state
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
|
|
DEBUGP (("[TAP] PowerState: Low-power\n"));
|
|
|
|
//
|
|
// Miniport drivers NDIS v6.20 and below are
|
|
// paused prior the low power transition
|
|
//
|
|
|
|
// Check for paused state...
|
|
// Verify data path stopped...
|
|
|
|
return status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
tapSetInformation(
|
|
__in PTAP_ADAPTER_CONTEXT Adapter,
|
|
__in PNDIS_OID_REQUEST OidRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper function to perform a set OID request
|
|
|
|
Arguments:
|
|
|
|
Adapter -
|
|
NdisSetRequest - The OID to set
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
|
|
DBG_PRINT_OID_NAME(OidRequest->DATA.SET_INFORMATION.Oid);
|
|
|
|
switch(OidRequest->DATA.SET_INFORMATION.Oid)
|
|
{
|
|
case OID_802_3_MULTICAST_LIST:
|
|
//
|
|
// Set the multicast address list on the NIC for packet reception.
|
|
// The NIC driver can set a limit on the number of multicast
|
|
// addresses bound protocol drivers can enable simultaneously.
|
|
// NDIS returns NDIS_STATUS_MULTICAST_FULL if a protocol driver
|
|
// exceeds this limit or if it specifies an invalid multicast
|
|
// address.
|
|
//
|
|
status = tapSetMulticastList(Adapter,OidRequest);
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
//
|
|
// A protocol driver can set a suggested value for the number
|
|
// of bytes to be used in its binding; however, the underlying
|
|
// NIC driver is never required to limit its indications to
|
|
// the value set.
|
|
//
|
|
if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG))
|
|
{
|
|
OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG);
|
|
status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
Adapter->ulLookahead = *(PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
|
|
OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(ULONG);
|
|
status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
//
|
|
// Program the hardware to indicate the packets
|
|
// of certain filter types.
|
|
//
|
|
if(OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG))
|
|
{
|
|
OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG);
|
|
status = NDIS_STATUS_INVALID_LENGTH;
|
|
break;
|
|
}
|
|
|
|
OidRequest->DATA.SET_INFORMATION.BytesRead
|
|
= OidRequest->DATA.SET_INFORMATION.InformationBufferLength;
|
|
|
|
status = tapSetPacketFilter(
|
|
Adapter,
|
|
*((PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer)
|
|
);
|
|
|
|
break;
|
|
|
|
case OID_PNP_SET_POWER:
|
|
{
|
|
// Sanity check.
|
|
if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength
|
|
< sizeof(NDIS_DEVICE_POWER_STATE)
|
|
)
|
|
{
|
|
status = NDIS_STATUS_INVALID_LENGTH;
|
|
}
|
|
else
|
|
{
|
|
NDIS_DEVICE_POWER_STATE PowerState;
|
|
|
|
PowerState = *(PNDIS_DEVICE_POWER_STATE UNALIGNED)OidRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
|
|
|
|
if(PowerState < NdisDeviceStateD0 ||
|
|
PowerState > NdisDeviceStateD3)
|
|
{
|
|
status = NDIS_STATUS_INVALID_DATA;
|
|
}
|
|
else
|
|
{
|
|
Adapter->CurrentPowerState = PowerState;
|
|
|
|
if (PowerState == NdisDeviceStateD0)
|
|
{
|
|
status = AdapterSetPowerD0(Adapter);
|
|
}
|
|
else
|
|
{
|
|
status = AdapterSetPowerLow(Adapter, PowerState);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
#if (NDIS_SUPPORT_NDIS61)
|
|
case OID_PNP_ADD_WAKE_UP_PATTERN:
|
|
case OID_PNP_REMOVE_WAKE_UP_PATTERN:
|
|
case OID_PNP_ENABLE_WAKE_UP:
|
|
#endif
|
|
ASSERT(!"NIC does not support wake on LAN OIDs");
|
|
default:
|
|
//
|
|
// The entry point may by used by other requests
|
|
//
|
|
status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
tapQueryInformation(
|
|
__in PTAP_ADAPTER_CONTEXT Adapter,
|
|
__in PNDIS_OID_REQUEST OidRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper function to perform a query OID request
|
|
|
|
Arguments:
|
|
|
|
Adapter -
|
|
OidRequest - The OID request that is being queried
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
|
NDIS_MEDIUM Medium = TAP_MEDIUM_TYPE;
|
|
NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
|
|
UCHAR VendorDesc[] = TAP_VENDOR_DESC;
|
|
ULONG ulInfo;
|
|
USHORT usInfo;
|
|
ULONG64 ulInfo64;
|
|
|
|
// Default to returning the ULONG value
|
|
PVOID pInfo=NULL;
|
|
ULONG ulInfoLen = sizeof(ulInfo);
|
|
|
|
// ATTENTION!!! Ignore OIDs to noisy to print...
|
|
if((OidRequest->DATA.QUERY_INFORMATION.Oid != OID_GEN_STATISTICS)
|
|
&& (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP4_OFFLOAD_STATS)
|
|
&& (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP6_OFFLOAD_STATS)
|
|
)
|
|
{
|
|
DBG_PRINT_OID_NAME(OidRequest->DATA.QUERY_INFORMATION.Oid);
|
|
}
|
|
|
|
// Dispatch based on object identifier (OID).
|
|
switch(OidRequest->DATA.QUERY_INFORMATION.Oid)
|
|
{
|
|
case OID_GEN_HARDWARE_STATUS:
|
|
//
|
|
// Specify the current hardware status of the underlying NIC as
|
|
// one of the following NDIS_HARDWARE_STATUS-type values.
|
|
//
|
|
pInfo = (PVOID) &HardwareStatus;
|
|
ulInfoLen = sizeof(NDIS_HARDWARE_STATUS);
|
|
break;
|
|
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
|
//
|
|
// Return the MAC address of the NIC burnt in the hardware.
|
|
//
|
|
pInfo = Adapter->PermanentAddress;
|
|
ulInfoLen = MACADDR_SIZE;
|
|
break;
|
|
|
|
case OID_802_3_CURRENT_ADDRESS:
|
|
//
|
|
// Return the MAC address the NIC is currently programmed to
|
|
// use. Note that this address could be different from the
|
|
// permananent address as the user can override using
|
|
// registry. Read NdisReadNetworkAddress doc for more info.
|
|
//
|
|
pInfo = Adapter->CurrentAddress;
|
|
ulInfoLen = MACADDR_SIZE;
|
|
break;
|
|
|
|
case OID_GEN_MEDIA_SUPPORTED:
|
|
//
|
|
// Return an array of media that are supported by the miniport.
|
|
// This miniport only supports one medium (Ethernet), so the OID
|
|
// returns identical results to OID_GEN_MEDIA_IN_USE.
|
|
//
|
|
|
|
__fallthrough;
|
|
|
|
case OID_GEN_MEDIA_IN_USE:
|
|
//
|
|
// Return an array of media that are currently in use by the
|
|
// miniport. This array should be a subset of the array returned
|
|
// by OID_GEN_MEDIA_SUPPORTED.
|
|
//
|
|
pInfo = &Medium;
|
|
ulInfoLen = sizeof(Medium);
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
//
|
|
// Specify the maximum total packet length, in bytes, the NIC
|
|
// supports including the header. A protocol driver might use
|
|
// this returned length as a gauge to determine the maximum
|
|
// size packet that a NIC driver could forward to the
|
|
// protocol driver. The miniport driver must never indicate
|
|
// up to the bound protocol driver packets received over the
|
|
// network that are longer than the packet size specified by
|
|
// OID_GEN_MAXIMUM_TOTAL_SIZE.
|
|
//
|
|
|
|
__fallthrough;
|
|
|
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
//
|
|
// The OID_GEN_TRANSMIT_BLOCK_SIZE OID specifies the minimum
|
|
// number of bytes that a single net packet occupies in the
|
|
// transmit buffer space of the NIC. In our case, the transmit
|
|
// block size is identical to its maximum packet size.
|
|
__fallthrough;
|
|
|
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
//
|
|
// The OID_GEN_RECEIVE_BLOCK_SIZE OID specifies the amount of
|
|
// storage, in bytes, that a single packet occupies in the receive
|
|
// buffer space of the NIC.
|
|
//
|
|
ulInfo = (ULONG) TAP_MAX_FRAME_SIZE;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_GEN_INTERRUPT_MODERATION:
|
|
{
|
|
PNDIS_INTERRUPT_MODERATION_PARAMETERS moderationParams
|
|
= (PNDIS_INTERRUPT_MODERATION_PARAMETERS)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
moderationParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
|
|
moderationParams->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
|
|
moderationParams->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
|
|
moderationParams->Flags = 0;
|
|
moderationParams->InterruptModeration = NdisInterruptModerationNotSupported;
|
|
ulInfoLen = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
|
|
}
|
|
break;
|
|
|
|
case OID_PNP_QUERY_POWER:
|
|
// Simply succeed this.
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_ID:
|
|
//
|
|
// Specify a three-byte IEEE-registered vendor code, followed
|
|
// by a single byte that the vendor assigns to identify a
|
|
// particular NIC. The IEEE code uniquely identifies the vendor
|
|
// and is the same as the three bytes appearing at the beginning
|
|
// of the NIC hardware address. Vendors without an IEEE-registered
|
|
// code should use the value 0xFFFFFF.
|
|
//
|
|
|
|
ulInfo = TAP_VENDOR_ID;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
|
//
|
|
// Specify a zero-terminated string describing the NIC vendor.
|
|
//
|
|
pInfo = VendorDesc;
|
|
ulInfoLen = sizeof(VendorDesc);
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_DRIVER_VERSION:
|
|
//
|
|
// Specify the vendor-assigned version number of the NIC driver.
|
|
// The low-order half of the return value specifies the minor
|
|
// version; the high-order half specifies the major version.
|
|
//
|
|
|
|
ulInfo = TAP_DRIVER_VENDOR_VERSION;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_GEN_DRIVER_VERSION:
|
|
//
|
|
// Specify the NDIS version in use by the NIC driver. The high
|
|
// byte is the major version number; the low byte is the minor
|
|
// version number.
|
|
//
|
|
usInfo = (USHORT) (TAP_NDIS_MAJOR_VERSION<<8) + TAP_NDIS_MINOR_VERSION;
|
|
pInfo = (PVOID) &usInfo;
|
|
ulInfoLen = sizeof(USHORT);
|
|
break;
|
|
|
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
|
//
|
|
// The maximum number of multicast addresses the NIC driver
|
|
// can manage. This list is global for all protocols bound
|
|
// to (or above) the NIC. Consequently, a protocol can receive
|
|
// NDIS_STATUS_MULTICAST_FULL from the NIC driver when
|
|
// attempting to set the multicast address list, even if
|
|
// the number of elements in the given list is less than
|
|
// the number originally returned for this query.
|
|
//
|
|
|
|
ulInfo = TAP_MAX_MCAST_LIST;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_GEN_XMIT_ERROR:
|
|
ulInfo = (ULONG)
|
|
(Adapter->TxAbortExcessCollisions +
|
|
Adapter->TxDmaUnderrun +
|
|
Adapter->TxLostCRS +
|
|
Adapter->TxLateCollisions+
|
|
Adapter->TransmitFailuresOther);
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_GEN_RCV_ERROR:
|
|
ulInfo = (ULONG)
|
|
(Adapter->RxCrcErrors +
|
|
Adapter->RxAlignmentErrors +
|
|
Adapter->RxDmaOverrunErrors +
|
|
Adapter->RxRuntErrors);
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_GEN_RCV_DISCARDS:
|
|
ulInfo = (ULONG)Adapter->RxResourceErrors;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_GEN_RCV_NO_BUFFER:
|
|
ulInfo = (ULONG)Adapter->RxResourceErrors;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_GEN_XMIT_OK:
|
|
ulInfo64 = Adapter->FramesTxBroadcast
|
|
+ Adapter->FramesTxMulticast
|
|
+ Adapter->FramesTxDirected;
|
|
pInfo = &ulInfo64;
|
|
if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) ||
|
|
OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0)
|
|
{
|
|
ulInfoLen = sizeof(ULONG64);
|
|
}
|
|
else
|
|
{
|
|
ulInfoLen = sizeof(ULONG);
|
|
}
|
|
|
|
// We should always report that only 8 bytes are required to keep ndistest happy
|
|
OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64);
|
|
break;
|
|
|
|
case OID_GEN_RCV_OK:
|
|
ulInfo64 = Adapter->FramesRxBroadcast
|
|
+ Adapter->FramesRxMulticast
|
|
+ Adapter->FramesRxDirected;
|
|
|
|
pInfo = &ulInfo64;
|
|
|
|
if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) ||
|
|
OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0)
|
|
{
|
|
ulInfoLen = sizeof(ULONG64);
|
|
}
|
|
else
|
|
{
|
|
ulInfoLen = sizeof(ULONG);
|
|
}
|
|
|
|
// We should always report that only 8 bytes are required to keep ndistest happy
|
|
OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64);
|
|
break;
|
|
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
|
|
ulInfo = Adapter->RxAlignmentErrors;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
|
|
|
ulInfo = Adapter->OneRetry;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
|
|
ulInfo = Adapter->MoreThanOneRetry;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_802_3_XMIT_DEFERRED:
|
|
|
|
ulInfo = Adapter->TxOKButDeferred;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_802_3_XMIT_MAX_COLLISIONS:
|
|
|
|
ulInfo = Adapter->TxAbortExcessCollisions;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_802_3_RCV_OVERRUN:
|
|
|
|
ulInfo = Adapter->RxDmaOverrunErrors;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_802_3_XMIT_UNDERRUN:
|
|
|
|
ulInfo = Adapter->TxDmaUnderrun;
|
|
pInfo = &ulInfo;
|
|
break;
|
|
|
|
case OID_GEN_STATISTICS:
|
|
|
|
if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(NDIS_STATISTICS_INFO))
|
|
{
|
|
status = NDIS_STATUS_INVALID_LENGTH;
|
|
OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(NDIS_STATISTICS_INFO);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
PNDIS_STATISTICS_INFO Statistics
|
|
= (PNDIS_STATISTICS_INFO)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
{C_ASSERT(sizeof(NDIS_STATISTICS_INFO) >= NDIS_SIZEOF_STATISTICS_INFO_REVISION_1);}
|
|
Statistics->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
|
|
Statistics->Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
|
|
Statistics->Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
|
|
|
|
Statistics->SupportedStatistics = TAP_SUPPORTED_STATISTICS;
|
|
|
|
/* Bytes in */
|
|
Statistics->ifHCInOctets =
|
|
Adapter->BytesRxDirected +
|
|
Adapter->BytesRxMulticast +
|
|
Adapter->BytesRxBroadcast;
|
|
|
|
Statistics->ifHCInUcastOctets =
|
|
Adapter->BytesRxDirected;
|
|
|
|
Statistics->ifHCInMulticastOctets =
|
|
Adapter->BytesRxMulticast;
|
|
|
|
Statistics->ifHCInBroadcastOctets =
|
|
Adapter->BytesRxBroadcast;
|
|
|
|
/* Packets in */
|
|
Statistics->ifHCInUcastPkts =
|
|
Adapter->FramesRxDirected;
|
|
|
|
Statistics->ifHCInMulticastPkts =
|
|
Adapter->FramesRxMulticast;
|
|
|
|
Statistics->ifHCInBroadcastPkts =
|
|
Adapter->FramesRxBroadcast;
|
|
|
|
/* Errors in */
|
|
Statistics->ifInErrors =
|
|
Adapter->RxCrcErrors +
|
|
Adapter->RxAlignmentErrors +
|
|
Adapter->RxDmaOverrunErrors +
|
|
Adapter->RxRuntErrors;
|
|
|
|
Statistics->ifInDiscards =
|
|
Adapter->RxResourceErrors;
|
|
|
|
|
|
/* Bytes out */
|
|
Statistics->ifHCOutOctets =
|
|
Adapter->BytesTxDirected +
|
|
Adapter->BytesTxMulticast +
|
|
Adapter->BytesTxBroadcast;
|
|
|
|
Statistics->ifHCOutUcastOctets =
|
|
Adapter->BytesTxDirected;
|
|
|
|
Statistics->ifHCOutMulticastOctets =
|
|
Adapter->BytesTxMulticast;
|
|
|
|
Statistics->ifHCOutBroadcastOctets =
|
|
Adapter->BytesTxBroadcast;
|
|
|
|
/* Packets out */
|
|
Statistics->ifHCOutUcastPkts =
|
|
Adapter->FramesTxDirected;
|
|
|
|
Statistics->ifHCOutMulticastPkts =
|
|
Adapter->FramesTxMulticast;
|
|
|
|
Statistics->ifHCOutBroadcastPkts =
|
|
Adapter->FramesTxBroadcast;
|
|
|
|
/* Errors out */
|
|
Statistics->ifOutErrors =
|
|
Adapter->TxAbortExcessCollisions +
|
|
Adapter->TxDmaUnderrun +
|
|
Adapter->TxLostCRS +
|
|
Adapter->TxLateCollisions+
|
|
Adapter->TransmitFailuresOther;
|
|
|
|
Statistics->ifOutDiscards = 0ULL;
|
|
|
|
ulInfoLen = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
|
|
}
|
|
|
|
break;
|
|
|
|
// TODO: Inplement these query information requests.
|
|
case OID_GEN_RECEIVE_BUFFER_SPACE:
|
|
case OID_GEN_MAXIMUM_SEND_PACKETS:
|
|
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
|
|
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
|
|
case OID_802_3_XMIT_TIMES_CRS_LOST:
|
|
case OID_802_3_XMIT_LATE_COLLISIONS:
|
|
|
|
default:
|
|
//
|
|
// The entry point may by used by other requests
|
|
//
|
|
status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
if (status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ASSERT(ulInfoLen > 0);
|
|
|
|
if (ulInfoLen <= OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength)
|
|
{
|
|
if(pInfo)
|
|
{
|
|
// Copy result into InformationBuffer
|
|
NdisMoveMemory(
|
|
OidRequest->DATA.QUERY_INFORMATION.InformationBuffer,
|
|
pInfo,
|
|
ulInfoLen
|
|
);
|
|
}
|
|
|
|
OidRequest->DATA.QUERY_INFORMATION.BytesWritten = ulInfoLen;
|
|
}
|
|
else
|
|
{
|
|
// too short
|
|
OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = ulInfoLen;
|
|
status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
AdapterOidRequest(
|
|
__in NDIS_HANDLE MiniportAdapterContext,
|
|
__in PNDIS_OID_REQUEST OidRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Entry point called by NDIS to get or set the value of a specified OID.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - Our adapter handle
|
|
NdisRequest - The OID request to handle
|
|
|
|
Return Value:
|
|
|
|
Return code from the NdisRequest below.
|
|
|
|
--*/
|
|
{
|
|
PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
|
|
NDIS_STATUS status;
|
|
|
|
// Dispatch based on request type.
|
|
switch (OidRequest->RequestType)
|
|
{
|
|
case NdisRequestSetInformation:
|
|
status = tapSetInformation(adapter,OidRequest);
|
|
break;
|
|
|
|
case NdisRequestQueryInformation:
|
|
case NdisRequestQueryStatistics:
|
|
status = tapQueryInformation(adapter,OidRequest);
|
|
break;
|
|
|
|
case NdisRequestMethod: // TAP doesn't need to respond to this request type.
|
|
default:
|
|
//
|
|
// The entry point may by used by other requests
|
|
//
|
|
status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
AdapterCancelOidRequest(
|
|
__in NDIS_HANDLE MiniportAdapterContext,
|
|
__in PVOID RequestId
|
|
)
|
|
{
|
|
PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
|
|
|
|
UNREFERENCED_PARAMETER(RequestId);
|
|
|
|
//
|
|
// This miniport sample does not pend any OID requests, so we don't have
|
|
// to worry about cancelling them.
|
|
//
|
|
}
|
|
|