536 lines
15 KiB
C
536 lines
15 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2001 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
send.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
NDIS entry points to handle requests.
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel mode only.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
alid 10/22/2001 modified for tunmp
|
||
|
arvindm 4/10/2000 Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
#define __FILENUMBER 'TQER'
|
||
|
|
||
|
NDIS_OID TunMpSupportedOidArray[] =
|
||
|
{
|
||
|
OID_GEN_SUPPORTED_LIST,
|
||
|
OID_GEN_HARDWARE_STATUS,
|
||
|
OID_GEN_MEDIA_SUPPORTED,
|
||
|
OID_GEN_MEDIA_IN_USE,
|
||
|
OID_GEN_MAXIMUM_LOOKAHEAD,
|
||
|
OID_GEN_MAXIMUM_FRAME_SIZE,
|
||
|
OID_GEN_MAC_OPTIONS,
|
||
|
OID_GEN_LINK_SPEED,
|
||
|
OID_GEN_TRANSMIT_BUFFER_SPACE,
|
||
|
OID_GEN_RECEIVE_BUFFER_SPACE,
|
||
|
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
||
|
OID_GEN_RECEIVE_BLOCK_SIZE,
|
||
|
OID_GEN_VENDOR_ID,
|
||
|
OID_GEN_VENDOR_DESCRIPTION,
|
||
|
OID_GEN_CURRENT_PACKET_FILTER,
|
||
|
OID_GEN_CURRENT_LOOKAHEAD,
|
||
|
OID_GEN_DRIVER_VERSION,
|
||
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
||
|
OID_GEN_MEDIA_CONNECT_STATUS,
|
||
|
OID_GEN_MAXIMUM_SEND_PACKETS,
|
||
|
OID_PNP_CAPABILITIES,
|
||
|
OID_PNP_SET_POWER,
|
||
|
OID_PNP_QUERY_POWER,
|
||
|
|
||
|
OID_GEN_XMIT_OK,
|
||
|
OID_GEN_RCV_OK,
|
||
|
OID_GEN_XMIT_ERROR,
|
||
|
OID_GEN_RCV_ERROR,
|
||
|
OID_GEN_RCV_NO_BUFFER,
|
||
|
|
||
|
OID_802_3_PERMANENT_ADDRESS,
|
||
|
OID_802_3_CURRENT_ADDRESS,
|
||
|
OID_802_3_MULTICAST_LIST,
|
||
|
OID_802_3_MAXIMUM_LIST_SIZE,
|
||
|
|
||
|
OID_802_3_RCV_ERROR_ALIGNMENT,
|
||
|
OID_802_3_XMIT_ONE_COLLISION,
|
||
|
OID_802_3_XMIT_MORE_COLLISIONS,
|
||
|
|
||
|
OID_CUSTOM_TUNMP_INSTANCE_ID
|
||
|
|
||
|
};
|
||
|
|
||
|
UINT TunMpSupportedOids = sizeof(TunMpSupportedOidArray)/sizeof(NDIS_OID);
|
||
|
UCHAR TunMpVendorDescription[] = "MS Tunnel Interface Driver";
|
||
|
UCHAR TunMpVendorId[3] = {0xFF, 0xFF, 0xFF};
|
||
|
|
||
|
NDIS_PNP_CAPABILITIES Power_Management_Capabilities = { 0,
|
||
|
NdisDeviceStateUnspecified,
|
||
|
NdisDeviceStateUnspecified,
|
||
|
NdisDeviceStateUnspecified
|
||
|
};
|
||
|
|
||
|
|
||
|
NDIS_STATUS
|
||
|
TunMpQueryInformation(
|
||
|
IN NDIS_HANDLE MiniportAdapterContext,
|
||
|
IN NDIS_OID Oid,
|
||
|
IN PVOID InformationBuffer,
|
||
|
IN ULONG InformationBufferLength,
|
||
|
OUT PULONG BytesWritten,
|
||
|
OUT PULONG BytesNeeded
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Miniport QueryInfo handler.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
MiniportAdapterContext Pointer to the adapter structure
|
||
|
Oid Oid for this query
|
||
|
InformationBuffer Buffer for information
|
||
|
InformationBufferLength Size of this buffer
|
||
|
BytesWritten Specifies how much info is written
|
||
|
BytesNeeded In case the buffer is smaller than what
|
||
|
we need, tell them how much is needed
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Return code from the NdisRequest below.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PTUN_ADAPTER pAdapter = (PTUN_ADAPTER)MiniportAdapterContext;
|
||
|
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
|
||
|
UINT i;
|
||
|
NDIS_OID MaskOid;
|
||
|
PVOID SourceBuffer;
|
||
|
UINT SourceBufferLength;
|
||
|
ULONG GenericUlong = 0;
|
||
|
USHORT GenericUshort;
|
||
|
|
||
|
DEBUGP(DL_LOUD, ("==>TunMpQueryInformation: Adapter %p, Oid %lx\n",
|
||
|
pAdapter, Oid));
|
||
|
|
||
|
*BytesWritten = 0;
|
||
|
*BytesNeeded = 0;
|
||
|
|
||
|
//
|
||
|
// Initialize these once, since this is the majority of cases.
|
||
|
//
|
||
|
|
||
|
SourceBuffer = (PVOID)&GenericUlong;
|
||
|
SourceBufferLength = sizeof(ULONG);
|
||
|
|
||
|
switch (Oid)
|
||
|
{
|
||
|
case OID_GEN_MAC_OPTIONS:
|
||
|
GenericUlong = (ULONG)(NDIS_MAC_OPTION_NO_LOOPBACK);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_SUPPORTED_LIST:
|
||
|
(NDIS_OID*)SourceBuffer = TunMpSupportedOidArray;
|
||
|
SourceBufferLength = TunMpSupportedOids * sizeof(ULONG);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_HARDWARE_STATUS:
|
||
|
GenericUlong = NdisHardwareStatusReady;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_MEDIA_SUPPORTED:
|
||
|
case OID_GEN_MEDIA_IN_USE:
|
||
|
GenericUlong = pAdapter->Medium;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_MAXIMUM_LOOKAHEAD:
|
||
|
GenericUlong = pAdapter->MaxLookAhead;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
||
|
GenericUlong = pAdapter->MediumMaxFrameLen;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_LINK_SPEED:
|
||
|
GenericUlong = pAdapter->MediumLinkSpeed;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_TRANSMIT_BUFFER_SPACE:
|
||
|
GenericUlong = (pAdapter->MediumMaxPacketLen);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_RECEIVE_BUFFER_SPACE:
|
||
|
GenericUlong = (pAdapter->MediumMaxPacketLen);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
||
|
GenericUlong = 1;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
||
|
GenericUlong = 1;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_VENDOR_ID:
|
||
|
SourceBuffer = TunMpVendorId;
|
||
|
SourceBufferLength = sizeof(TunMpVendorId);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_VENDOR_DESCRIPTION:
|
||
|
SourceBuffer = TunMpVendorDescription;
|
||
|
SourceBufferLength = sizeof(TunMpVendorDescription);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
||
|
GenericUlong = pAdapter->PacketFilter;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
||
|
GenericUlong = pAdapter->MaxLookAhead;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_DRIVER_VERSION:
|
||
|
GenericUshort = (NDIS_MINIPORT_MAJOR_VERSION << 8) + NDIS_MINIPORT_MINOR_VERSION;
|
||
|
SourceBuffer = &GenericUshort;
|
||
|
SourceBufferLength = sizeof(USHORT);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
||
|
GenericUlong = pAdapter->MediumMaxPacketLen;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_MEDIA_CONNECT_STATUS:
|
||
|
KdPrint(("OID_GEN_MEDIA_CONNECT_STATUS: %lx\n", Oid));
|
||
|
if(TUN_TEST_FLAG(pAdapter, TUN_ADAPTER_OPEN))
|
||
|
GenericUlong = NdisMediaStateConnected;
|
||
|
else
|
||
|
GenericUlong = NdisMediaStateDisconnected;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_MAXIMUM_SEND_PACKETS:
|
||
|
GenericUlong = MAX_RECV_QUEUE_SIZE;
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_XMIT_OK:
|
||
|
SourceBuffer = &(pAdapter->SendPackets);
|
||
|
SourceBufferLength = sizeof(ULONG);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_RCV_OK:
|
||
|
SourceBuffer = &(pAdapter->RcvPackets);
|
||
|
SourceBufferLength = sizeof(ULONG);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_XMIT_ERROR:
|
||
|
SourceBuffer = &(pAdapter->XmitError);
|
||
|
SourceBufferLength = sizeof(ULONG);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_RCV_ERROR:
|
||
|
SourceBuffer = &(pAdapter->RcvError);
|
||
|
SourceBufferLength = sizeof(ULONG);
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_RCV_NO_BUFFER:
|
||
|
SourceBuffer = &(pAdapter->RcvNoBuffer);
|
||
|
SourceBufferLength = sizeof(ULONG);
|
||
|
break;
|
||
|
|
||
|
case OID_802_3_PERMANENT_ADDRESS:
|
||
|
SourceBuffer = pAdapter->PermanentAddress;
|
||
|
SourceBufferLength = TUN_MAC_ADDR_LEN;
|
||
|
break;
|
||
|
|
||
|
case OID_802_3_CURRENT_ADDRESS:
|
||
|
SourceBuffer = pAdapter->CurrentAddress;
|
||
|
SourceBufferLength = TUN_MAC_ADDR_LEN;
|
||
|
break;
|
||
|
|
||
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
||
|
GenericUlong = TUN_MAX_MULTICAST_ADDRESS;
|
||
|
break;
|
||
|
|
||
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
||
|
case OID_802_3_XMIT_ONE_COLLISION:
|
||
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
||
|
GenericUlong = 0;
|
||
|
break;
|
||
|
|
||
|
case OID_PNP_CAPABILITIES:
|
||
|
//
|
||
|
// we support going to D3, but we don't do any WOL
|
||
|
//
|
||
|
SourceBufferLength = sizeof (NDIS_PNP_CAPABILITIES);
|
||
|
SourceBuffer = (PVOID)&Power_Management_Capabilities;
|
||
|
break;
|
||
|
|
||
|
case OID_PNP_QUERY_POWER:
|
||
|
//
|
||
|
// we should always succeed this OID.
|
||
|
//
|
||
|
SourceBufferLength = 0;
|
||
|
break;
|
||
|
|
||
|
case OID_CUSTOM_TUNMP_INSTANCE_ID:
|
||
|
GenericUlong = pAdapter->DeviceInstanceNumber;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
NdisStatus = NDIS_STATUS_NOT_SUPPORTED;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (NdisStatus == NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
*BytesNeeded = SourceBufferLength;
|
||
|
|
||
|
if (SourceBufferLength <= InformationBufferLength)
|
||
|
{
|
||
|
*BytesWritten = SourceBufferLength;
|
||
|
if (SourceBufferLength)
|
||
|
{
|
||
|
NdisMoveMemory(InformationBuffer, SourceBuffer, SourceBufferLength);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NdisStatus = NDIS_STATUS_BUFFER_TOO_SHORT;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
DEBUGP(DL_LOUD, ("<==TunMpQueryInformation: Adapter %p, NdisStatus %lx\n",
|
||
|
pAdapter, NdisStatus));
|
||
|
|
||
|
return (NdisStatus);
|
||
|
}
|
||
|
|
||
|
|
||
|
NDIS_STATUS
|
||
|
TunMpSetInformation(
|
||
|
IN NDIS_HANDLE MiniportAdapterContext,
|
||
|
IN NDIS_OID Oid,
|
||
|
IN PVOID InformationBuffer,
|
||
|
IN ULONG InformationBufferLength,
|
||
|
OUT PULONG BytesRead,
|
||
|
OUT PULONG BytesNeeded
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Miniport SetInfo handler.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
MiniportAdapterContext Pointer to the adapter structure
|
||
|
Oid Oid for this query
|
||
|
InformationBuffer Buffer for information
|
||
|
InformationBufferLength Size of this buffer
|
||
|
BytesRead Specifies how much info is read
|
||
|
BytesNeeded In case the buffer is smaller than what we need,
|
||
|
tell them how much is needed
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Return code from the NdisRequest below.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PTUN_ADAPTER pAdapter = (PTUN_ADAPTER)MiniportAdapterContext;
|
||
|
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
|
||
|
NDIS_DEVICE_POWER_STATE NewPowerState;
|
||
|
|
||
|
DEBUGP(DL_LOUD, ("==>TunMpSetInformation: Adapter %p, Oid %lx\n",
|
||
|
pAdapter, Oid));
|
||
|
|
||
|
|
||
|
*BytesRead = 0;
|
||
|
*BytesNeeded = 0;
|
||
|
|
||
|
switch (Oid)
|
||
|
{
|
||
|
|
||
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
||
|
if (InformationBufferLength != sizeof(ULONG))
|
||
|
{
|
||
|
NdisStatus = NDIS_STATUS_INVALID_DATA;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ULONG PacketFilter;
|
||
|
|
||
|
PacketFilter = *(UNALIGNED ULONG *)InformationBuffer;
|
||
|
|
||
|
|
||
|
pAdapter->PacketFilter = PacketFilter;
|
||
|
*BytesRead = InformationBufferLength;
|
||
|
|
||
|
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
|
||
|
|
||
|
if (PacketFilter != 0)
|
||
|
{
|
||
|
//
|
||
|
// if packet filter is set to a non-zero value, then activate
|
||
|
// the adapter. i.e. start indicating packets.
|
||
|
//
|
||
|
TUN_SET_FLAG(pAdapter, TUN_ADAPTER_ACTIVE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// if packet filter is set to zero, then we should
|
||
|
// fail all writes
|
||
|
//
|
||
|
TUN_CLEAR_FLAG(pAdapter, TUN_ADAPTER_ACTIVE);
|
||
|
if (pAdapter->PendedSendCount != 0)
|
||
|
{
|
||
|
NdisStatus = NDIS_STATUS_PENDING;
|
||
|
TUN_SET_FLAG(pAdapter, TUN_COMPLETE_REQUEST);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
TUN_RELEASE_LOCK(&pAdapter->Lock);
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
||
|
if (InformationBufferLength != sizeof(ULONG))
|
||
|
{
|
||
|
NdisStatus = NDIS_STATUS_INVALID_DATA;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ULONG CurrentLookahead;
|
||
|
|
||
|
CurrentLookahead = *(UNALIGNED ULONG *)InformationBuffer;
|
||
|
|
||
|
if (CurrentLookahead > TUN_MAX_LOOKAHEAD)
|
||
|
{
|
||
|
NdisStatus = NDIS_STATUS_INVALID_LENGTH;
|
||
|
}
|
||
|
else if (CurrentLookahead >= pAdapter->MaxLookAhead)
|
||
|
{
|
||
|
pAdapter->MaxLookAhead = CurrentLookahead;
|
||
|
*BytesRead = sizeof(ULONG);
|
||
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
|
||
|
case OID_802_3_MULTICAST_LIST:
|
||
|
if (pAdapter->Medium != NdisMedium802_3)
|
||
|
{
|
||
|
NdisStatus = NDIS_STATUS_INVALID_OID;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((InformationBufferLength % ETH_LENGTH_OF_ADDRESS) != 0)
|
||
|
{
|
||
|
NdisStatus = NDIS_STATUS_INVALID_LENGTH;
|
||
|
break;
|
||
|
}
|
||
|
//1 set BytesNeeded, check for max multicastlist
|
||
|
break;
|
||
|
|
||
|
case OID_PNP_SET_POWER:
|
||
|
|
||
|
if (InformationBufferLength != sizeof(NDIS_DEVICE_POWER_STATE ))
|
||
|
{
|
||
|
NdisStatus = NDIS_STATUS_INVALID_LENGTH;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
NewPowerState = *(PNDIS_DEVICE_POWER_STATE)InformationBuffer;
|
||
|
*BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
|
||
|
|
||
|
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
|
||
|
if (NewPowerState != NdisDeviceStateD0)
|
||
|
{
|
||
|
//
|
||
|
// complete any oustanding NDIS sends. do not allow any
|
||
|
// more NDIS sends. wait for all the indicated packets
|
||
|
// to return and do not allow any more packet
|
||
|
// indications (application Write)
|
||
|
//
|
||
|
TUN_CLEAR_FLAG(pAdapter, TUN_ADAPTER_ACTIVE);
|
||
|
TUN_SET_FLAG(pAdapter, TUN_ADAPTER_OFF);
|
||
|
|
||
|
//
|
||
|
// complete all outstanding NDIS Send requests
|
||
|
//
|
||
|
TUN_RELEASE_LOCK(&pAdapter->Lock);
|
||
|
//
|
||
|
// abort all pending NDIS send requests
|
||
|
TunFlushReceiveQueue(pAdapter);
|
||
|
//
|
||
|
// cancel all pending read IRPs if any
|
||
|
//
|
||
|
TunCancelPendingReads(pAdapter);
|
||
|
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
|
||
|
|
||
|
//
|
||
|
// is there any outstanding NDIS sends?
|
||
|
//
|
||
|
if ((pAdapter->PendedSendCount != 0) ||
|
||
|
(pAdapter->PendedReadCount != 0))
|
||
|
{
|
||
|
NdisStatus = NDIS_STATUS_PENDING;
|
||
|
TUN_SET_FLAG(pAdapter, TUN_COMPLETE_REQUEST);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TUN_CLEAR_FLAG(pAdapter, TUN_ADAPTER_OFF);
|
||
|
|
||
|
if (pAdapter->PacketFilter != 0)
|
||
|
{
|
||
|
TUN_SET_FLAG(pAdapter, TUN_ADAPTER_ACTIVE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
//
|
||
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
TUN_RELEASE_LOCK(&pAdapter->Lock);
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
NdisStatus = NDIS_STATUS_NOT_SUPPORTED;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DEBUGP(DL_LOUD, ("<==TunMpSetInformation: Adapter %p, NdisStatus %lx\n",
|
||
|
pAdapter, NdisStatus));
|
||
|
|
||
|
|
||
|
return NdisStatus;
|
||
|
}
|
||
|
|