616 lines
20 KiB
C
616 lines
20 KiB
C
/*++
|
|
|
|
Copyright (c) 1990-1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Request.c
|
|
|
|
Abstract:
|
|
|
|
|
|
Author:
|
|
|
|
Tony Bell (TonyBe) June 06, 1995
|
|
|
|
Environment:
|
|
|
|
Kernel Mode
|
|
|
|
Revision History:
|
|
|
|
TonyBe 06/06/95 Created
|
|
|
|
--*/
|
|
|
|
#include "wan.h"
|
|
|
|
#define __FILE_SIG__ REQUEST_FILESIG
|
|
|
|
static UINT CoSupportedOids[] =
|
|
{
|
|
OID_GEN_CO_SUPPORTED_LIST,
|
|
OID_GEN_CO_HARDWARE_STATUS,
|
|
OID_GEN_CO_MEDIA_SUPPORTED,
|
|
OID_GEN_CO_MEDIA_IN_USE,
|
|
OID_GEN_MAXIMUM_LOOKAHEAD,
|
|
OID_GEN_MAXIMUM_FRAME_SIZE,
|
|
OID_GEN_CO_LINK_SPEED,
|
|
OID_GEN_TRANSMIT_BUFFER_SPACE,
|
|
OID_GEN_RECEIVE_BUFFER_SPACE,
|
|
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
|
OID_GEN_RECEIVE_BLOCK_SIZE,
|
|
OID_GEN_CO_VENDOR_ID,
|
|
OID_GEN_CO_VENDOR_DESCRIPTION,
|
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|
OID_GEN_CURRENT_LOOKAHEAD,
|
|
OID_GEN_CO_DRIVER_VERSION,
|
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
OID_GEN_CO_PROTOCOL_OPTIONS,
|
|
OID_GEN_CO_MAC_OPTIONS,
|
|
OID_GEN_CO_MEDIA_CONNECT_STATUS,
|
|
OID_GEN_MAXIMUM_SEND_PACKETS,
|
|
OID_GEN_CO_VENDOR_DRIVER_VERSION,
|
|
OID_GEN_CO_MINIMUM_LINK_SPEED,
|
|
OID_802_3_PERMANENT_ADDRESS,
|
|
OID_802_3_CURRENT_ADDRESS,
|
|
OID_802_3_MULTICAST_LIST,
|
|
OID_802_3_MAXIMUM_LIST_SIZE,
|
|
OID_WAN_PERMANENT_ADDRESS,
|
|
OID_WAN_CURRENT_ADDRESS,
|
|
OID_WAN_QUALITY_OF_SERVICE,
|
|
OID_WAN_MEDIUM_SUBTYPE,
|
|
OID_WAN_PROTOCOL_TYPE,
|
|
OID_WAN_HEADER_FORMAT,
|
|
OID_WAN_LINE_COUNT,
|
|
OID_QOS_ISSLOW_FRAGMENT_SIZE
|
|
};
|
|
|
|
NDIS_STATUS
|
|
NdisWanCoOidProc(
|
|
IN PMINIPORTCB pMiniportCB,
|
|
IN PCM_VCCB CmVcCB OPTIONAL,
|
|
IN OUT PNDIS_REQUEST NdisRequest
|
|
)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
NDIS_MEDIUM MediumType;
|
|
ULONG GenericULong = 0, i;
|
|
USHORT GenericUShort = 0;
|
|
UCHAR GenericArray[6];
|
|
PVOID MoveSource = (PVOID)&GenericULong;
|
|
ULONG MoveBytes = sizeof(ULONG);
|
|
NDIS_HARDWARE_STATUS HardwareStatus;
|
|
ULONG Filter = 0, Oid, OidCat;
|
|
ULONG InformationBufferLength;
|
|
PUCHAR InformationBuffer;
|
|
PROTOCOL_INFO ProtocolInfo = {0};
|
|
|
|
|
|
Oid = NdisRequest->DATA.QUERY_INFORMATION.Oid;
|
|
OidCat = Oid & 0xFF000000;
|
|
InformationBufferLength =
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
|
|
InformationBuffer =
|
|
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
NdisAcquireSpinLock(&pMiniportCB->Lock);
|
|
|
|
//
|
|
// We will break the OID's down into smaller categories
|
|
//
|
|
switch (OidCat) {
|
|
|
|
//
|
|
// Swith on General Oid's
|
|
//
|
|
case OID_CO_GEN:
|
|
switch (Oid) {
|
|
case OID_GEN_CO_SUPPORTED_LIST:
|
|
MoveSource = (PVOID)CoSupportedOids;
|
|
MoveBytes = sizeof(CoSupportedOids);
|
|
break;
|
|
|
|
case OID_GEN_CO_HARDWARE_STATUS:
|
|
HardwareStatus = pMiniportCB->HardwareStatus;
|
|
MoveSource = (PVOID)&HardwareStatus;
|
|
MoveBytes = sizeof(HardwareStatus);
|
|
break;
|
|
|
|
case OID_GEN_CO_MEDIA_SUPPORTED:
|
|
case OID_GEN_CO_MEDIA_IN_USE:
|
|
MediumType = pMiniportCB->MediumType;
|
|
MoveSource = (PVOID)&MediumType;
|
|
MoveBytes = sizeof(MediumType);
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_LOOKAHEAD:
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
GenericULong = glMRRU;
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
ProtocolInfo.ProtocolType = pMiniportCB->ProtocolType;
|
|
GetProtocolInfo(&ProtocolInfo);
|
|
GenericULong =
|
|
(ProtocolInfo.MTU == 0) ? glMaxMTU : ProtocolInfo.MTU;
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
ProtocolInfo.ProtocolType = pMiniportCB->ProtocolType;
|
|
GetProtocolInfo(&ProtocolInfo);
|
|
GenericULong =
|
|
(ProtocolInfo.MTU == 0) ? glMaxMTU : ProtocolInfo.MTU;
|
|
GenericULong += 14;
|
|
break;
|
|
|
|
case OID_GEN_CO_LINK_SPEED:
|
|
//
|
|
// Who knows what the initial link speed is?
|
|
// This should not be called, right?
|
|
//
|
|
GenericULong = (ULONG)288;
|
|
break;
|
|
|
|
case OID_GEN_TRANSMIT_BUFFER_SPACE:
|
|
case OID_GEN_RECEIVE_BUFFER_SPACE:
|
|
ProtocolInfo.ProtocolType = pMiniportCB->ProtocolType;
|
|
GetProtocolInfo(&ProtocolInfo);
|
|
GenericULong =
|
|
(ProtocolInfo.MTU == 0) ?
|
|
(ULONG)(glMaxMTU * MAX_OUTSTANDING_PACKETS) :
|
|
(ULONG)(ProtocolInfo.MTU * MAX_OUTSTANDING_PACKETS);
|
|
break;
|
|
|
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
ProtocolInfo.ProtocolType = pMiniportCB->ProtocolType;
|
|
GetProtocolInfo(&ProtocolInfo);
|
|
GenericULong =
|
|
(ProtocolInfo.MTU == 0) ? glMaxMTU : ProtocolInfo.MTU;
|
|
break;
|
|
|
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
GenericULong = glMRRU;
|
|
break;
|
|
|
|
case OID_GEN_CO_VENDOR_ID:
|
|
GenericULong = 0xFFFFFFFF;
|
|
MoveBytes = 3;
|
|
break;
|
|
|
|
case OID_GEN_CO_VENDOR_DESCRIPTION:
|
|
MoveSource = (PVOID)"NdisWan Adapter";
|
|
MoveBytes = 16;
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
if (NdisRequest->RequestType == NdisRequestSetInformation) {
|
|
if (InformationBufferLength > 3) {
|
|
NdisMoveMemory(&Filter, InformationBuffer, 4);
|
|
|
|
NdisAcquireSpinLock(&NdisWanCB.Lock);
|
|
if (Filter &
|
|
(NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL)) {
|
|
NdisWanCB.PromiscuousAdapter = pMiniportCB;
|
|
} else if (NdisWanCB.PromiscuousAdapter == pMiniportCB) {
|
|
NdisWanCB.PromiscuousAdapter = NULL;
|
|
}
|
|
|
|
NdisReleaseSpinLock(&NdisWanCB.Lock);
|
|
|
|
} else {
|
|
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 4;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OID_GEN_CO_DRIVER_VERSION:
|
|
GenericUShort = 0x0500;
|
|
MoveSource = (PVOID)&GenericUShort;
|
|
MoveBytes = sizeof(USHORT);
|
|
break;
|
|
|
|
case OID_GEN_CO_MAC_OPTIONS:
|
|
GenericULong = (ULONG)(NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
|
|
NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
|
|
NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
|
|
NDIS_MAC_OPTION_RESERVED |
|
|
NDIS_MAC_OPTION_NDISWAN);
|
|
break;
|
|
|
|
case OID_GEN_CO_MEDIA_CONNECT_STATUS:
|
|
GenericULong = (ULONG)NdisMediaStateConnected;
|
|
break;
|
|
|
|
case OID_GEN_CO_XMIT_PDUS_OK:
|
|
//
|
|
//
|
|
//
|
|
break;
|
|
|
|
case OID_GEN_CO_RCV_PDUS_OK:
|
|
//
|
|
//
|
|
//
|
|
break;
|
|
|
|
case OID_GEN_CO_XMIT_PDUS_ERROR:
|
|
//
|
|
//
|
|
//
|
|
break;
|
|
|
|
case OID_GEN_CO_RCV_PDUS_ERROR:
|
|
//
|
|
//
|
|
//
|
|
break;
|
|
|
|
case OID_GEN_CO_RCV_PDUS_NO_BUFFER:
|
|
//
|
|
//
|
|
//
|
|
break;
|
|
|
|
case OID_GEN_CO_TRANSMIT_QUEUE_LENGTH:
|
|
//
|
|
//
|
|
//
|
|
break;
|
|
|
|
default:
|
|
Status = NDIS_STATUS_INVALID_OID;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Switch on ethernet media specific Oid's
|
|
//
|
|
case OID_802_3:
|
|
switch (Oid) {
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
|
case OID_802_3_CURRENT_ADDRESS:
|
|
ETH_COPY_NETWORK_ADDRESS(GenericArray, pMiniportCB->NetworkAddress);
|
|
MoveSource = (PVOID)GenericArray;
|
|
MoveBytes = ETH_LENGTH_OF_ADDRESS;
|
|
break;
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
|
MoveBytes = 0;
|
|
break;
|
|
|
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
|
GenericULong = 1;
|
|
break;
|
|
|
|
default:
|
|
Status = NDIS_STATUS_INVALID_OID;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Switch on WAN specific Oid's
|
|
//
|
|
case OID_WAN:
|
|
switch (Oid) {
|
|
case OID_WAN_PERMANENT_ADDRESS:
|
|
case OID_WAN_CURRENT_ADDRESS:
|
|
ETH_COPY_NETWORK_ADDRESS(GenericArray, pMiniportCB->NetworkAddress);
|
|
MoveSource = (PVOID)GenericArray;
|
|
MoveBytes = ETH_LENGTH_OF_ADDRESS;
|
|
break;
|
|
|
|
case OID_WAN_QUALITY_OF_SERVICE:
|
|
GenericULong = NdisWanReliable;
|
|
break;
|
|
|
|
case OID_WAN_MEDIUM_SUBTYPE:
|
|
GenericULong = NdisWanMediumHub;
|
|
break;
|
|
|
|
case OID_WAN_PROTOCOL_TYPE:
|
|
{
|
|
PMINIPORTCB mcb;
|
|
BOOLEAN Found = FALSE;
|
|
|
|
if (InformationBufferLength > 5) {
|
|
|
|
pMiniportCB->ProtocolType =
|
|
(((PUCHAR)InformationBuffer)[4] << 8) |
|
|
((PUCHAR)InformationBuffer)[5];
|
|
|
|
pMiniportCB->NumberofProtocols++;
|
|
MoveBytes = 6;
|
|
|
|
NdisReleaseSpinLock(&pMiniportCB->Lock);
|
|
//
|
|
// Walk the miniportcb list and see if this is the only
|
|
// instance of this protocol. If it is we need to notify
|
|
// user-mode that a new protocol is available.
|
|
//
|
|
NdisAcquireSpinLock(&MiniportCBList.Lock);
|
|
|
|
mcb = (PMINIPORTCB)MiniportCBList.List.Flink;
|
|
|
|
while ((PVOID)mcb != (PVOID)&MiniportCBList.List) {
|
|
if (mcb != pMiniportCB) {
|
|
|
|
if (mcb->ProtocolType ==
|
|
pMiniportCB->ProtocolType) {
|
|
Found = TRUE;
|
|
}
|
|
}
|
|
|
|
mcb = (PMINIPORTCB)mcb->Linkage.Flink;
|
|
}
|
|
|
|
NdisReleaseSpinLock(&MiniportCBList.Lock);
|
|
|
|
if (Found == FALSE) {
|
|
PROTOCOL_INFO pinfo;
|
|
|
|
NdisZeroMemory(&pinfo, sizeof(pinfo));
|
|
pinfo.ProtocolType = pMiniportCB->ProtocolType;
|
|
pinfo.Flags = PROTOCOL_BOUND;
|
|
SetProtocolInfo(&pinfo);
|
|
}
|
|
|
|
NdisAcquireSpinLock(&pMiniportCB->Lock);
|
|
|
|
} else {
|
|
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 6;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OID_WAN_HEADER_FORMAT:
|
|
GenericULong = NdisWanHeaderEthernet;
|
|
break;
|
|
|
|
case OID_WAN_LINE_COUNT:
|
|
GenericULong = NdisWanCB.NumberOfLinks;
|
|
break;
|
|
|
|
case OID_WAN_PROTOCOL_CAPS:
|
|
do {
|
|
PNDIS_WAN_PROTOCOL_CAPS pcaps;
|
|
|
|
if (InformationBufferLength < sizeof(NDIS_WAN_PROTOCOL_CAPS)) {
|
|
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded =
|
|
sizeof(NDIS_WAN_PROTOCOL_CAPS);
|
|
break;
|
|
}
|
|
|
|
pcaps = (PNDIS_WAN_PROTOCOL_CAPS)InformationBuffer;
|
|
|
|
if (pcaps->Flags & WAN_PROTOCOL_KEEPS_STATS) {
|
|
pMiniportCB->Flags |= PROTOCOL_KEEPS_STATS;
|
|
}
|
|
|
|
MoveBytes = sizeof(NDIS_WAN_PROTOCOL_CAPS);
|
|
|
|
} while (FALSE);
|
|
break;
|
|
|
|
default:
|
|
Status = NDIS_STATUS_INVALID_OID;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case OID_PNP:
|
|
switch (Oid) {
|
|
case OID_PNP_CAPABILITIES:
|
|
break;
|
|
case OID_PNP_SET_POWER:
|
|
break;
|
|
case OID_PNP_QUERY_POWER:
|
|
break;
|
|
case OID_PNP_ENABLE_WAKE_UP:
|
|
break;
|
|
default:
|
|
Status = NDIS_STATUS_INVALID_OID;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case OID_QOS:
|
|
switch (Oid) {
|
|
case OID_QOS_ISSLOW_FRAGMENT_SIZE:
|
|
|
|
do {
|
|
PBUNDLECB BundleCB;
|
|
PSEND_FRAG_INFO FragInfo;
|
|
|
|
if (InformationBufferLength < 4) {
|
|
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 4;
|
|
break;
|
|
}
|
|
|
|
if (((PLONG)InformationBuffer)[0] < 0) {
|
|
Status = NDIS_STATUS_INVALID_DATA;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 4;
|
|
break;
|
|
}
|
|
|
|
if (((PULONG)InformationBuffer)[0] == 0) {
|
|
Status = NDIS_STATUS_INVALID_DATA;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 4;
|
|
break;
|
|
}
|
|
|
|
if (CmVcCB == NULL) {
|
|
|
|
if (((PULONG)InformationBuffer)[0] < glMaxFragSize) {
|
|
glMaxFragSize = ((PULONG)InformationBuffer)[0];
|
|
}
|
|
|
|
if (glMaxFragSize < glMinFragSize) {
|
|
glMinFragSize = glMaxFragSize;
|
|
}
|
|
|
|
} else {
|
|
BundleCB = CmVcCB->ProtocolCB->BundleCB;
|
|
|
|
AcquireBundleLock(BundleCB);
|
|
|
|
FragInfo = &BundleCB->SendFragInfo[0];
|
|
|
|
if (((PULONG)InformationBuffer)[0] < FragInfo->MaxFragSize) {
|
|
|
|
FragInfo->MaxFragSize =
|
|
((PULONG)InformationBuffer)[0];
|
|
}
|
|
|
|
if (FragInfo->MaxFragSize < glMinFragSize) {
|
|
FragInfo->MaxFragSize = glMinFragSize;
|
|
}
|
|
|
|
if (FragInfo->MaxFragSize > glMaxFragSize) {
|
|
FragInfo->MaxFragSize = glMaxFragSize;
|
|
}
|
|
|
|
ReleaseBundleLock(BundleCB);
|
|
|
|
}
|
|
|
|
|
|
MoveBytes = 4;
|
|
|
|
} while (FALSE);
|
|
|
|
break;
|
|
|
|
default:
|
|
Status = NDIS_STATUS_INVALID_OID;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Status = NDIS_STATUS_INVALID_OID;
|
|
break;
|
|
}
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
if (NdisRequest->RequestType == NdisRequestSetInformation) {
|
|
NdisRequest->DATA.SET_INFORMATION.BytesRead = MoveBytes;
|
|
} else if (NdisRequest->RequestType == NdisRequestQueryInformation ||
|
|
NdisRequest->RequestType == NdisRequestQueryStatistics) {
|
|
|
|
if (MoveBytes > InformationBufferLength) {
|
|
|
|
//
|
|
// Not enough room in the information buffer
|
|
//
|
|
NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded =
|
|
MoveBytes;
|
|
|
|
Status = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
} else {
|
|
|
|
NdisRequest->DATA.QUERY_INFORMATION.BytesWritten =
|
|
MoveBytes;
|
|
|
|
NdisMoveMemory(InformationBuffer,
|
|
MoveSource,
|
|
MoveBytes);
|
|
}
|
|
} else {
|
|
Status = NDIS_STATUS_INVALID_OID;
|
|
}
|
|
}
|
|
|
|
NdisReleaseSpinLock(&pMiniportCB->Lock);
|
|
|
|
return (Status);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NdisWanSubmitNdisRequest(
|
|
IN POPENCB pOpenCB,
|
|
IN PWAN_REQUEST WanRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Name:
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Values:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
BOOLEAN SyncRequest;
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("SubmitNdisRequest: Enter - WanRequest %p", WanRequest));
|
|
|
|
NdisAcquireSpinLock(&pOpenCB->Lock);
|
|
|
|
if (pOpenCB->Flags & OPEN_CLOSING) {
|
|
|
|
NdisReleaseSpinLock(&pOpenCB->Lock);
|
|
|
|
return (NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
REF_OPENCB(pOpenCB);
|
|
|
|
NdisReleaseSpinLock(&pOpenCB->Lock);
|
|
|
|
SyncRequest = (WanRequest->Type == SYNC);
|
|
|
|
if (pOpenCB->Flags & OPEN_LEGACY ||
|
|
WanRequest->VcHandle == NULL) {
|
|
NdisRequest(&Status,
|
|
pOpenCB->BindingHandle,
|
|
&WanRequest->NdisRequest);
|
|
} else {
|
|
Status =
|
|
NdisCoRequest(pOpenCB->BindingHandle,
|
|
WanRequest->AfHandle,
|
|
WanRequest->VcHandle,
|
|
NULL,
|
|
&WanRequest->NdisRequest);
|
|
}
|
|
|
|
//
|
|
// We will only wait for request that are to complete
|
|
// synchronously with respect to this function. We will
|
|
// wait here for completion.
|
|
//
|
|
if ((SyncRequest == TRUE) &&
|
|
(Status == NDIS_STATUS_PENDING)) {
|
|
|
|
NdisWanWaitForNotificationEvent(&WanRequest->NotificationEvent);
|
|
|
|
Status = WanRequest->NotificationStatus;
|
|
|
|
NdisWanClearNotificationEvent(&WanRequest->NotificationEvent);
|
|
}
|
|
|
|
NdisWanDbgOut(DBG_TRACE, DBG_REQUEST,
|
|
("SubmitNdisRequest: Exit Status 0x%x", Status));
|
|
|
|
DEREF_OPENCB(pOpenCB);
|
|
|
|
return (Status);
|
|
}
|