windows-nt/Source/XPSP1/NT/net/rras/ndis/ndiswan/request.c
2020-09-26 16:20:57 +08:00

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);
}