|
|
/*++
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); }
|