Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1461 lines
42 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
rasirda.c
Abstract:
Miniport peice of the irda NDIS 5 miniport (WAN driver)
Author:
mbert 9-97
--*/
#include "rasirdap.h"
// Globals
#if DBG
#include <irioctl.h>
int DbgSettings =
DBG_INIT |
DBG_CONFIG |
DBG_CONNECT |
// DBG_SEND |
// DBG_RECV |
DBG_LIB_OBJ |
DBG_LIB_CONNECT |
DBG_ERROR |
1;
int DbgOutput =
DBG_OUTPUT_BUFFER |
// DBG_OUTPUT_DEBUGGER |
0;
PDRIVER_OBJECT pRasIrDriverObject;
PDEVICE_OBJECT pRasIrDeviceObject;
NTSTATUS
DbgDispatch(
PDEVICE_OBJECT pDeviceObject,
PIRP pIrp);
#endif
NDIS_SPIN_LOCK RasIrSpinLock;
LIST_ENTRY RasIrAdapterList;
const USHORT FcsTable[256] = {
0x0000,0x1189,0x2312,0x329B,0x4624,0x57AD,0x6536,0x74BF,
0x8C48,0x9DC1,0xAF5A,0xBED3,0xCA6C,0xDBE5,0xE97E,0xF8F7,
0x1081,0x0108,0x3393,0x221A,0x56A5,0x472C,0x75B7,0x643E,
0x9CC9,0x8D40,0xBFDB,0xAE52,0xDAED,0xCB64,0xF9FF,0xE876,
0x2102,0x308B,0x0210,0x1399,0x6726,0x76AF,0x4434,0x55BD,
0xAD4A,0xBCC3,0x8E58,0x9FD1,0xEB6E,0xFAE7,0xC87C,0xD9F5,
0x3183,0x200A,0x1291,0x0318,0x77A7,0x662E,0x54B5,0x453C,
0xBDCB,0xAC42,0x9ED9,0x8F50,0xFBEF,0xEA66,0xD8FD,0xC974,
0x4204,0x538D,0x6116,0x709F,0x0420,0x15A9,0x2732,0x36BB,
0xCE4C,0xDFC5,0xED5E,0xFCD7,0x8868,0x99E1,0xAB7A,0xBAF3,
0x5285,0x430C,0x7197,0x601E,0x14A1,0x0528,0x37B3,0x263A,
0xDECD,0xCF44,0xFDDF,0xEC56,0x98E9,0x8960,0xBBFB,0xAA72,
0x6306,0x728F,0x4014,0x519D,0x2522,0x34AB,0x0630,0x17B9,
0xEF4E,0xFEC7,0xCC5C,0xDDD5,0xA96A,0xB8E3,0x8A78,0x9BF1,
0x7387,0x620E,0x5095,0x411C,0x35A3,0x242A,0x16B1,0x0738,
0xFFCF,0xEE46,0xDCDD,0xCD54,0xB9EB,0xA862,0x9AF9,0x8B70,
0x8408,0x9581,0xA71A,0xB693,0xC22C,0xD3A5,0xE13E,0xF0B7,
0x0840,0x19C9,0x2B52,0x3ADB,0x4E64,0x5FED,0x6D76,0x7CFF,
0x9489,0x8500,0xB79B,0xA612,0xD2AD,0xC324,0xF1BF,0xE036,
0x18C1,0x0948,0x3BD3,0x2A5A,0x5EE5,0x4F6C,0x7DF7,0x6C7E,
0xA50A,0xB483,0x8618,0x9791,0xE32E,0xF2A7,0xC03C,0xD1B5,
0x2942,0x38CB,0x0A50,0x1BD9,0x6F66,0x7EEF,0x4C74,0x5DFD,
0xB58B,0xA402,0x9699,0x8710,0xF3AF,0xE226,0xD0BD,0xC134,
0x39C3,0x284A,0x1AD1,0x0B58,0x7FE7,0x6E6E,0x5CF5,0x4D7C,
0xC60C,0xD785,0xE51E,0xF497,0x8028,0x91A1,0xA33A,0xB2B3,
0x4A44,0x5BCD,0x6956,0x78DF,0x0C60,0x1DE9,0x2F72,0x3EFB,
0xD68D,0xC704,0xF59F,0xE416,0x90A9,0x8120,0xB3BB,0xA232,
0x5AC5,0x4B4C,0x79D7,0x685E,0x1CE1,0x0D68,0x3FF3,0x2E7A,
0xE70E,0xF687,0xC41C,0xD595,0xA12A,0xB0A3,0x8238,0x93B1,
0x6B46,0x7ACF,0x4854,0x59DD,0x2D62,0x3CEB,0x0E70,0x1FF9,
0xF78F,0xE606,0xD49D,0xC514,0xB1AB,0xA022,0x92B9,0x8330,
0x7BC7,0x6A4E,0x58D5,0x495C,0x3DE3,0x2C6A,0x1EF1,0x0F78
};
NDIS_STATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath);
NDIS_STATUS
QueryInformation(
IN PRASIR_ADAPTER pAdapter,
IN PRASIR_VC pVc,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG BytesWritten,
OUT PULONG BytesNeeded);
NDIS_STATUS
SetInformation(
IN PRASIR_ADAPTER pAdapter,
IN PRASIR_VC pVc,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG BytesRead,
OUT PULONG BytesNeeded);
#pragma NDIS_INIT_FUNCTION(DriverEntry)
NDIS_STATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath )
{
NDIS_STATUS Status;
NDIS_MINIPORT_CHARACTERISTICS MiniportChr;
NDIS_HANDLE NdisWrapperHandle;
#if DBG
UNICODE_STRING DeviceName;
int i;
#endif
DEBUGMSG(DBG_INIT, ("RASIR: DriverEntry\n"));
IrdaClientInitialize();
NdisAllocateSpinLock(&RasIrSpinLock);
InitializeListHead(&RasIrAdapterList);
NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject,
RegistryPath, NULL );
NdisZeroMemory( &MiniportChr, sizeof(MiniportChr) );
MiniportChr.MajorNdisVersion = NDIS_MajorVersion;
MiniportChr.MinorNdisVersion = NDIS_MinorVersion;
MiniportChr.Reserved = NDIS_USE_WAN_WRAPPER;
MiniportChr.HaltHandler = RasIrHalt;
MiniportChr.InitializeHandler = RasIrInitialize;
MiniportChr.ResetHandler = RasIrReset;
MiniportChr.ReturnPacketHandler = RasIrReturnPacket;
MiniportChr.CoActivateVcHandler = RasIrCoActivateVc;
MiniportChr.CoDeactivateVcHandler = RasIrCoDeactivateVc;
MiniportChr.CoSendPacketsHandler = RasIrCoSendPackets;
MiniportChr.CoRequestHandler = RasIrCoRequest;
// no CheckForHangHandler
// no DisableInterruptHandler
// no EnableInterruptHandler
// no HandleInterruptHandler
// no ISRHandler
// no QueryInformationHandler (see CoRequestHandler)
// no SendHandler (see CoSendPacketsHandler)
// no WanSendHandler (see CoSendPacketsHandler)
// no SetInformationHandler (see CoRequestHandler)
// no TransferDataHandler
// no WanTransferDataHandler
// no SendPacketsHandler (see CoSendPacketsHandler)
// no AllocateCompleteHandler
Status = NdisMRegisterMiniport(NdisWrapperHandle, &MiniportChr, sizeof(MiniportChr));
if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("RASIR: ->NdisMRegisterMiniport failed %x\n", Status));
NdisTerminateWrapper(NdisWrapperHandle, NULL);
}
#if 0
DbgMsgInit();
RtlInitUnicodeString(&DeviceName, L"\\Device\\RASIR");
Status = IoCreateDevice(
DriverObject, // DriverObject
0, // DeviceExtensionSize
&DeviceName, // DeviceName
FILE_DEVICE_NETWORK, // DeviceType
0, // DeviceCharacteristics
FALSE, // Exclusive?
&pRasIrDeviceObject); // DeviceObject pointer returned
if (Status != STATUS_SUCCESS)
DbgPrint("Failed to create device\n");
else
{
DriverObject->DriverUnload = NULL;
DriverObject->FastIoDispatch = NULL;
for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = DbgDispatch;
}
pRasIrDeviceObject->Flags |= DO_DIRECT_IO;
}
#endif
return Status;
}
VOID
FreeAdapter(PRASIR_ADAPTER pAdapter)
{
ASSERT(IsListEmpty(&pAdapter->VcList));
#if DBG
pAdapter->Sig = 0xBAD;
#endif
NdisDeleteNPagedLookasideList(&pAdapter->WorkItemsLList);
NdisDeleteNPagedLookasideList(&pAdapter->AsyncBufLList);
NdisFreeMemory(pAdapter, sizeof(PRASIR_ADAPTER), 0);
}
NDIS_STATUS
RasIrInitialize(
OUT PNDIS_STATUS OpenErrorStatus,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_HANDLE WrapperConfigurationContext)
{
UINT i;
PRASIR_ADAPTER pAdapter;
NDIS_CALL_MANAGER_CHARACTERISTICS CallMgrChr;
CO_ADDRESS_FAMILY Family;
NDIS_STATUS Status;
NDIS_HANDLE hConfig;
PNDIS_CONFIGURATION_PARAMETER Value;
NDIS_STRING TapiLineNameString = NDIS_STRING_CONST("TapiLineName");
NDIS_STRING ModemPortString = NDIS_STRING_CONST("ModemPort");
ULONG ModemPort;
DEBUGMSG(DBG_ERROR, ("RASIR: Miniport initialize\n"));
for (i = 0; i < MediumArraySize; ++i)
{
if (MediumArray[i] == NdisMediumCoWan)
break;
}
if (i == MediumArraySize)
{
DEBUGMSG(DBG_ERROR, ("RASIR: No matching media\n"));
return NDIS_STATUS_FAILURE;
}
*SelectedMediumIndex = i;
NdisAllocateMemoryWithTag((PVOID *)&pAdapter, sizeof(RASIR_ADAPTER),
MT_RASIR_ADAPTER);
if (pAdapter == NULL)
return NDIS_STATUS_RESOURCES;
NdisZeroMemory(pAdapter, sizeof(RASIR_ADAPTER));
InitializeListHead(&pAdapter->VcList);
InitializeListHead(&pAdapter->EndpList);
NdisInitializeNPagedLookasideList(
&pAdapter->WorkItemsLList,
NULL, NULL, 0,
sizeof(NDIS_WORK_ITEM),
MT_RASIR_WORKITEM, // RasIr work item
10);
NdisInitializeNPagedLookasideList(
&pAdapter->AsyncBufLList,
NULL, NULL, 0,
sizeof(ASYNC_BUFFER),
MT_RASIR_ASYNCBUF, // RasIr work item
0);
NdisAllocateSpinLock(&pAdapter->SpinLock);
NdisOpenConfiguration(&Status, &hConfig, WrapperConfigurationContext);
if (Status == NDIS_STATUS_SUCCESS)
{
pAdapter->TapiLineNameBuf[0] = 0;
pAdapter->TapiLineName.Buffer = pAdapter->TapiLineNameBuf;
pAdapter->TapiLineName.Length = 0;
pAdapter->TapiLineName.MaximumLength = sizeof(pAdapter->TapiLineNameBuf);
NdisReadConfiguration(&Status,
&Value,
hConfig,
&TapiLineNameString,
NdisParameterString);
if (Status == NDIS_STATUS_SUCCESS)
{
RtlCopyUnicodeString(&pAdapter->TapiLineName, &Value->ParameterData.StringData);
*(PWCHAR)(pAdapter->TapiLineName.Buffer + (pAdapter->TapiLineName.MaximumLength)/sizeof(WCHAR)) = UNICODE_NULL;
}
NdisReadConfiguration(&Status,
&Value,
hConfig,
&ModemPortString,
NdisParameterInteger);
if (Status == NDIS_STATUS_SUCCESS)
{
pAdapter->ModemPort = (BOOLEAN) Value->ParameterData.IntegerData;
}
NdisCloseConfiguration(hConfig);
}
DEBUGMSG(DBG_CONFIG, ("RASIR: ModemPort = %d\n", pAdapter->ModemPort));
pAdapter->MiniportAdapterHandle = MiniportAdapterHandle;
pAdapter->Info.MaxFrameSize = IRDA_MAX_DATA_SIZE;
pAdapter->Info.MaxSendWindow = 4;
pAdapter->Info.FramingBits = PPP_FRAMING |
PPP_COMPRESS_ADDRESS_CONTROL |
PPP_COMPRESS_PROTOCOL_FIELD;
pAdapter->Info.DesiredACCM = 0;
#if DBG
pAdapter->Sig = (ULONG)ADAPTER_SIG;
#endif
// Inform NDIS of the attributes of our adapter. Set the
// 'MiniportAdapterContext' returned to us by NDIS when it calls our
// handlers to the address of our adapter control block. Turn off
// hardware oriented timeouts.
//
NdisMSetAttributesEx(
MiniportAdapterHandle,
(NDIS_HANDLE)pAdapter,
(UINT)-1,
NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT
| NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT,
NdisInterfaceInternal);
NdisZeroMemory(&Family, sizeof(Family));
Family.MajorVersion = NDIS_MajorVersion;
Family.MinorVersion = NDIS_MinorVersion;
Family.AddressFamily = CO_ADDRESS_FAMILY_TAPI_PROXY;
NdisZeroMemory(&CallMgrChr, sizeof(CallMgrChr));
CallMgrChr.MajorVersion = NDIS_MajorVersion;
CallMgrChr.MinorVersion = NDIS_MinorVersion;
CallMgrChr.CmCreateVcHandler = RasIrCmCreateVc;
CallMgrChr.CmDeleteVcHandler = RasIrCmDeleteVc;
CallMgrChr.CmOpenAfHandler = RasIrCmOpenAf;
CallMgrChr.CmCloseAfHandler = RasIrCmCloseAf;
CallMgrChr.CmRegisterSapHandler = RasIrCmRegisterSap;
CallMgrChr.CmDeregisterSapHandler = RasIrCmDeregisterSap;
CallMgrChr.CmMakeCallHandler = RasIrCmMakeCall;
CallMgrChr.CmCloseCallHandler = RasIrCmCloseCall;
CallMgrChr.CmIncomingCallCompleteHandler= RasIrCmIncomingCallComplete;
CallMgrChr.CmActivateVcCompleteHandler = RasIrCmActivateVcComplete;
CallMgrChr.CmDeactivateVcCompleteHandler= RasIrCmDeactivateVcComplete;
CallMgrChr.CmModifyCallQoSHandler = RasIrCmModifyCallQoS;
CallMgrChr.CmRequestHandler = RasIrCmRequest;
// no CmAddPartyHandler
// no CmDropPartyHandler
Status = NdisMCmRegisterAddressFamily(
MiniportAdapterHandle, &Family, &CallMgrChr,
sizeof(CallMgrChr));
if (Status != NDIS_STATUS_SUCCESS)
{
FreeAdapter(pAdapter);
DEBUGMSG(DBG_ERROR, ("RASIR: NdisMCmRegisterFamily failed %X\n",
Status));
}
else
{
NdisInterlockedInsertTailList(&RasIrAdapterList,
&pAdapter->Linkage,
&RasIrSpinLock);
}
return Status;
}
VOID
RasIrHalt(
IN NDIS_HANDLE MiniportAdapterContext)
{
PRASIR_ADAPTER pAdapter = MiniportAdapterContext;
GOODADAPTER(pAdapter);
NdisAcquireSpinLock(&RasIrSpinLock);
RemoveEntryList(&pAdapter->Linkage);
NdisReleaseSpinLock(&RasIrSpinLock);
DEBUGMSG(DBG_ERROR, ("RASIR: Halt!\n"));
FreeAdapter(pAdapter);
return;
}
NDIS_STATUS
RasIrReset(
OUT PBOOLEAN AddressingReset,
IN NDIS_HANDLE MiniportAdapterContext)
{
return NDIS_STATUS_NOT_RESETTABLE;
}
NDIS_STATUS
RasIrCoActivateVc(
IN NDIS_HANDLE MiniportVcContext,
IN OUT PCO_CALL_PARAMETERS CallParameters)
{
#if DBG
DbgBreakPoint();
#endif
return STATUS_SUCCESS;
}
NDIS_STATUS
RasIrCoDeactivateVc(
IN NDIS_HANDLE MiniportVcContext)
{
#if DBG
DbgBreakPoint();
#endif
return STATUS_SUCCESS;
}
UINT
AddAsyncFraming(
IN PUCHAR pOutBuf,
IN PNDIS_BUFFER pNdisBuf,
IN ULONG Accm)
{
PUCHAR pData;
int DataLen;
USHORT Fcs = 0xFFFF;
PUCHAR pBuf = pOutBuf;
PUCHAR pEndBuf = pOutBuf + ASYNC_BUF_SIZE;
NdisQueryBufferSafe(pNdisBuf, &pData, &DataLen, NormalPagePriority);
if (pData == NULL)
{
return 0;
}
ASSERT(DataLen);
*pBuf++ = AF_FLAG_CHAR;
while (DataLen != 0)
{
int i;
for (i = 0; i < DataLen; i++)
{
Fcs = CALC_FCS(Fcs, pData[i]);
STUFF_BYTE(pBuf, pData[i], Accm);
}
NdisGetNextBuffer(pNdisBuf, &pNdisBuf);
if (pNdisBuf)
{
NdisQueryBufferSafe(pNdisBuf, &pData, &DataLen, NormalPagePriority);
if (pData == NULL)
{
return 0;
}
}
else
{
break;
}
if (pBuf > pEndBuf)
{
return 0;
}
}
Fcs = ~(Fcs);
STUFF_BYTE(pBuf, ((CHAR) (Fcs & 0xFF)), Accm);
STUFF_BYTE(pBuf, ((CHAR) (Fcs >> 8)), Accm);
*pBuf++ = AF_FLAG_CHAR;
return (UINT)((UINT_PTR)pBuf - (UINT_PTR) pOutBuf);
}
VOID
RasIrCoSendPackets(
IN NDIS_HANDLE MiniportVcContext,
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets )
{
PRASIR_VC pVc = MiniportVcContext;
UINT i;
PNDIS_BUFFER pNdisBuf;
UINT PacketLen;
NTSTATUS Status = NDIS_STATUS_SUCCESS;
BOOLEAN VcDown = FALSE;
PASYNC_BUFFER pAsyncBuf;
PMDL pSendNdisBuf;
GOODVC(pVc);
for (i = 0; i < NumberOfPackets; i++)
{
Status = NDIS_STATUS_SUCCESS;
NdisQueryPacket(PacketArray[i], NULL, NULL, &pNdisBuf, &PacketLen);
ASSERT(PacketLen <= IRDA_MAX_DATA_SIZE);
*((PVOID *) &PacketArray[i]->MiniportReserved[0]) = NULL;
NdisAcquireSpinLock(&pVc->pAdapter->SpinLock);
REFADD(&pVc->RefCnt, 'DNES');
pVc->OutstandingSends += 1;
if (!(pVc->Flags & VCF_IRDA_OPEN))
{
DEBUGMSG(DBG_ERROR, ("RASIR: Not sending on Vc %X, Irda is closed\n", pVc));
Status = NDIS_STATUS_CLOSED;
}
NdisReleaseSpinLock(&pVc->pAdapter->SpinLock);
if (Status == NDIS_STATUS_SUCCESS)
{
if (!pVc->AsyncFraming)
{
pSendNdisBuf = pNdisBuf;
}
else
{
pAsyncBuf = NdisAllocateFromNPagedLookasideList(
&pVc->pAdapter->AsyncBufLList);
*((PVOID *) &PacketArray[i]->MiniportReserved[0]) = pAsyncBuf;
if (!pAsyncBuf)
{
Status = NDIS_STATUS_RESOURCES;
}
else
{
UINT FrameLen;
pAsyncBuf->pNdisBuf = NULL;
FrameLen = AddAsyncFraming(pAsyncBuf->Buf, pNdisBuf,
pVc->LinkInfo.SendACCM);
if (!FrameLen)
{
DEBUGMSG(DBG_ERROR, ("RASIR: not sending, AsyncFraming failed\n"));
IrdaSendComplete(pVc, PacketArray[i], Status);
continue;
}
NdisAllocateBuffer(&Status, &pAsyncBuf->pNdisBuf,
pVc->TxBufferPool, pAsyncBuf->Buf, FrameLen);
if (Status == NDIS_STATUS_SUCCESS)
{
pSendNdisBuf = pAsyncBuf->pNdisBuf;
}
else
{
DEBUGMSG(DBG_ERROR, ("RASIR: NdisAllocateBuffer failed %X\n", Status));
}
}
}
}
if (Status == NDIS_STATUS_SUCCESS)
{
IrdaSend(pVc->IrdaConnContext, pSendNdisBuf, PacketArray[i]);
}
else
{
IrdaSendComplete(pVc, PacketArray[i], Status);
continue;
}
DEBUGMSG(DBG_SEND, ("RASIR: IrdaSend %X len %d pending\n",
PacketArray[i], PacketLen));
}
}
VOID
RasIrReceiveComplete(
PRASIR_VC pVc,
PVOID pRxBuf)
{
if (pVc->AsyncFraming)
{
// Async frames where already completed in
// ProcessAsyncRxPacket() so just return the
// buffer owned by rasir to the BufList
NdisFreeToNPagedLookasideList(
&pVc->pAdapter->AsyncBufLList,
pRxBuf);
}
else
{
IrdaReceiveComplete(pVc->IrdaConnContext,
(PIRDA_RECVBUF) pRxBuf);
}
}
VOID
RasIrReturnPacket(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET pNdisPacket)
{
PVOID pRxBuf;
PRASIR_VC pVc;
PNDIS_BUFFER pNdisBuf;
pVc = *((PRASIR_VC *) &pNdisPacket->MiniportReserved[0]);
pRxBuf = *((PVOID *) &pNdisPacket->MiniportReserved[sizeof(PUCHAR)]);
GOODVC(pVc);
DEBUGMSG(DBG_RECV, ("RASIR: ReturnPacket %X\n", pRxBuf));
RasIrReceiveComplete(pVc, pRxBuf);
NdisUnchainBufferAtFront(pNdisPacket, &pNdisBuf);
NdisFreeBuffer(pNdisBuf);
NdisFreePacket(pNdisPacket);
REFDEL(&pVc->RefCnt, 'VCER');
return;
}
NDIS_STATUS
RasIrCoRequest(
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_HANDLE MiniportVcContext,
IN OUT PNDIS_REQUEST NdisRequest)
{
NDIS_STATUS Status;
PRASIR_ADAPTER pAdapter = MiniportAdapterContext;
PRASIR_VC pVc = MiniportVcContext;
DEBUGMSG(DBG_CONFIG, ("RASIR: RasIrCoRequest() type %X\n",
NdisRequest->RequestType));
switch (NdisRequest->RequestType)
{
case NdisRequestQueryInformation:
{
Status = QueryInformation(
pAdapter,
pVc,
NdisRequest->DATA.QUERY_INFORMATION.Oid,
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
&NdisRequest->DATA.QUERY_INFORMATION.BytesWritten,
&NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded );
break;
}
case NdisRequestSetInformation:
{
Status = SetInformation(
pAdapter,
pVc,
NdisRequest->DATA.SET_INFORMATION.Oid,
NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
NdisRequest->DATA.SET_INFORMATION.InformationBufferLength,
&NdisRequest->DATA.SET_INFORMATION.BytesRead,
&NdisRequest->DATA.SET_INFORMATION.BytesNeeded );
break;
}
default:
{
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
}
return Status;
}
NDIS_STATUS
QueryInformation(
IN PRASIR_ADAPTER pAdapter,
IN PRASIR_VC pVc,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG BytesWritten,
OUT PULONG BytesNeeded)
{
NDIS_STATUS status;
ULONG ulInfo;
VOID* pInfo;
ULONG ulInfoLen;
status = NDIS_STATUS_SUCCESS;
// The cases in this switch statement find or create a buffer containing
// the requested information and point 'pInfo' at it, noting it's length
// in 'ulInfoLen'. Since many of the OIDs return a ULONG, a 'ulInfo'
// buffer is set up as the default.
//
ulInfo = 0;
pInfo = &ulInfo;
ulInfoLen = sizeof(ulInfo);
DEBUGMSG(DBG_CONFIG, ("RASIR: QueryInformation oid:%X\n", Oid));
switch (Oid)
{
case OID_GEN_MAXIMUM_LOOKAHEAD:
{
DEBUGMSG(DBG_CONFIG, (" OID_GET_MAXIMUM_LOOKAHEAD = %d\n",
IRDA_MAX_DATA_SIZE));
ulInfo = IRDA_MAX_DATA_SIZE;
break;
}
case OID_GEN_MAC_OPTIONS:
{
// Report a bitmask defining optional properties of the driver.
//
// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA promises that our receive
// buffer is not on a device-specific card.
//
// NDIS_MAC_OPTION_TRANSFERS_NOT_PEND promises we won't return
// NDIS_STATUS_PENDING from our TransferData handler which is true
// since we don't have one.
//
ulInfo = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA
| NDIS_MAC_OPTION_TRANSFERS_NOT_PEND;
DEBUGMSG(DBG_CONFIG, (" OID_GEN_MAC_OPTIONS = %d\n",ulInfo));
break;
}
case OID_WAN_MEDIUM_SUBTYPE:
{
// Report the media subtype we support. NDISWAN may use this in
// the future (doesn't now) to provide framing differences for
// different media.
//
DEBUGMSG(DBG_CONFIG, (" OID_WAN_MEDIUM_SUBTYPE\n"));
if (pAdapter->ModemPort)
{
ulInfo = NdisWanMediumSerial;
}
else
{
ulInfo = NdisWanMediumIrda;
}
break;
}
case OID_WAN_CO_GET_INFO:
{
// Report the capabilities of the adapter.
//
DEBUGMSG(DBG_CONFIG, (" OID_WAN_CO_GET_INFO\n"));
pInfo = &pAdapter->Info;
ulInfoLen = sizeof(NDIS_WAN_CO_INFO);
break;
}
case OID_WAN_CO_GET_LINK_INFO:
{
// Report the current state of the link.
//
DEBUGMSG(DBG_CONFIG, (" OID_WAN_CO_GET_LINK_INFO\n"));
if (!pVc)
return NDIS_STATUS_INVALID_DATA;
pInfo = &pVc->LinkInfo;
ulInfoLen = sizeof(NDIS_WAN_CO_GET_LINK_INFO);
break;
}
case OID_WAN_CO_GET_COMP_INFO:
{
// Report the type of compression we provide, which is none.
//
DEBUGMSG(DBG_CONFIG, (" OID_WAN_CO_GET_COMP_INFO\n"));
status = NDIS_STATUS_NOT_SUPPORTED;
ulInfoLen = 0;
break;
}
case OID_WAN_CO_GET_STATS_INFO:
{
// Because L2TP doesn't do compression, NDISWAN will use it's own
// statistics and not query ours.
//
ASSERT( !"OID_WAN_CO_GET_STATS_INFO?" );
status = NDIS_STATUS_NOT_SUPPORTED;
ulInfoLen = 0;
break;
}
case OID_PNP_QUERY_POWER:
DEBUGMSG(DBG_CONFIG, (" OID_PNP_QUERY_POWER\n"));
status = NDIS_STATUS_NOT_SUPPORTED;
ulInfoLen = 0;
break;
case OID_PNP_CAPABILITIES:
DEBUGMSG(DBG_CONFIG, (" OID_PNP_CAP\n"));
status = NDIS_STATUS_NOT_SUPPORTED;
ulInfoLen = 0;
break;
case OID_PNP_SET_POWER:
DEBUGMSG(DBG_CONFIG, (" OID_PNP_SET_POWER\n"));
status = NDIS_STATUS_NOT_SUPPORTED;
ulInfoLen = 0;
break;
default:
{
DEBUGMSG(DBG_CONFIG, ( " Oid $%08x?\n", Oid));
status = NDIS_STATUS_INVALID_OID;
ulInfoLen = 0;
break;
}
}
if (ulInfoLen > InformationBufferLength)
{
// Caller's buffer is too small. Tell him what he needs.
//
*BytesNeeded = ulInfoLen;
status = NDIS_STATUS_INVALID_LENGTH;
}
else
{
// Copy the found result to caller's buffer.
//
if (ulInfoLen > 0)
{
NdisMoveMemory( InformationBuffer, pInfo, ulInfoLen );
}
*BytesNeeded = *BytesWritten = ulInfoLen;
}
return status;
}
NDIS_STATUS
SetInformation(
IN PRASIR_ADAPTER pAdapter,
IN PRASIR_VC pVc,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG BytesRead,
OUT PULONG BytesNeeded)
{
NDIS_STATUS Status;
DEBUGMSG(DBG_CONFIG, ("RASIR: SetInformation oid:%X\n", Oid));
Status = NDIS_STATUS_SUCCESS;
switch (Oid)
{
case OID_WAN_CO_SET_LINK_INFO:
{
// Read new link state settings.
//
DEBUGMSG(DBG_CONFIG, (" OID_WAN_CO_SET_LINK_INFO\n"));
if (InformationBufferLength < sizeof(NDIS_WAN_CO_SET_LINK_INFO))
{
Status = NDIS_STATUS_INVALID_LENGTH;
*BytesRead = 0;
}
else
{
if (!pVc)
return NDIS_STATUS_INVALID_DATA;
ASSERT( sizeof(pVc->LinkInfo)
== sizeof(NDIS_WAN_CO_SET_LINK_INFO) );
NdisMoveMemory(&pVc->LinkInfo, InformationBuffer,
sizeof(pVc->LinkInfo) );
DEBUGMSG(DBG_CONFIG, (" MaxSend %d MaxRecv %d SendAccm %X RecvAccm %X\n",
pVc->LinkInfo.MaxSendFrameSize,
pVc->LinkInfo.MaxRecvFrameSize,
pVc->LinkInfo.SendACCM,
pVc->LinkInfo.RecvACCM));
*BytesRead = sizeof(NDIS_WAN_CO_SET_LINK_INFO);
}
*BytesNeeded = sizeof(NDIS_WAN_CO_SET_LINK_INFO);
}
break;
case OID_WAN_CO_SET_COMP_INFO:
{
// L2TP doesn't provide compression. Neither does IrDA
//
DEBUGMSG(DBG_CONFIG, (" OID_WAN_CO_SET_COMP_INFO\n"));
Status = NDIS_STATUS_NOT_SUPPORTED;
*BytesRead = *BytesNeeded = 0;
break;
}
case OID_PNP_QUERY_POWER:
DEBUGMSG(DBG_CONFIG, (" OID_PNP_QUERY_POWER\n"));
Status = NDIS_STATUS_NOT_SUPPORTED;
*BytesRead = *BytesNeeded = 0;
break;
case OID_PNP_CAPABILITIES:
DEBUGMSG(DBG_CONFIG, (" OID_PNP_CAP\n"));
Status = NDIS_STATUS_NOT_SUPPORTED;
*BytesRead = *BytesNeeded = 0;
break;
case OID_PNP_SET_POWER:
DEBUGMSG(DBG_CONFIG, (" OID_PNP_SET_POWER\n"));
Status = NDIS_STATUS_NOT_SUPPORTED;
*BytesRead = *BytesNeeded = 0;
break;
#if 0
// These OIDs are mandatory according to current doc, but since
// NDISWAN never requests them they are omitted.
//
case OID_GEN_CURRENT_PACKET_FILTER:
case OID_GEN_CURRENT_LOOKAHEAD:
case OID_GEN_PROTOCOL_OPTIONS:
case OID_WAN_PROTOCOL_TYPE:
case OID_WAN_HEADER_FORMAT:
#endif
default:
{
DEBUGMSG(DBG_CONFIG, ("Oid $%08x?\n", Oid ));
Status = NDIS_STATUS_INVALID_OID;
*BytesRead = *BytesNeeded = 0;
break;
}
}
return Status;
}
VOID
ProcessAsyncRxPacket(
PRASIR_VC pVc,
PIRDA_RECVBUF pIrdaRxBuf)
{
PASYNC_BUFFER pReturnRxBuf = NULL;
BOOLEAN EndOfFrame = FALSE;
PASYNC_BUFFER pCurrAsyncBuf;
UINT i;
CHAR Byte;
//DbgMsgBuf(pIrdaRxBuf->Buf, pIrdaRxBuf->BufLen);
for (i = 0; i < pIrdaRxBuf->BufLen; i++)
{
//
// If we are not currently reasembling a frame
// in pCurrAsyncBuf then get a new one
//
if (pVc->pCurrAsyncBuf == NULL)
{
pVc->AsyncFramingState = RX_READY;
if (!(pCurrAsyncBuf = NdisAllocateFromNPagedLookasideList(
&pVc->pAdapter->AsyncBufLList)))
{
DEBUGMSG(DBG_ERROR, ("RASIR: Failed to allocate AsyncBuf\n"));
return;
}
pCurrAsyncBuf->BufLen = 0;
pVc->pCurrAsyncBuf = pCurrAsyncBuf;
}
else
{
pCurrAsyncBuf = pVc->pCurrAsyncBuf;
}
Byte = pIrdaRxBuf->Buf[i];
switch (pVc->AsyncFramingState)
{
case RX_READY:
if (Byte == AF_FLAG_CHAR)
{
pVc->AsyncFramingState = RX_RX;
}
break;
case RX_RX:
switch (Byte)
{
case AF_FLAG_CHAR:
// We have a complete frame, put it on the completed
// list
pVc->AsyncFramingState = RX_READY;
if (pCurrAsyncBuf->BufLen > 2)
{
// remove FCS, IrDA is reliable so I don't look at it
pCurrAsyncBuf->BufLen -= 2;
NdisInterlockedInsertTailList(
&pVc->CompletedAsyncBufList,
&pCurrAsyncBuf->Linkage,
&pVc->pAdapter->SpinLock);
DEBUGMSG(DBG_RECV, ("RASIR: Complete async frame %d, %d of %d\n",
pVc->pCurrAsyncBuf->BufLen, i, pIrdaRxBuf->BufLen));
pVc->pCurrAsyncBuf = NULL;
}
else
{
// frame too small, we'll just ignore it
pCurrAsyncBuf->BufLen = 0;
DEBUGMSG(DBG_ERROR, ("RASIR: Async failure 1\n"));
}
break;
case AF_ESC_CHAR:
pVc->AsyncFramingState = RX_ESC;
break;
default:
if (pCurrAsyncBuf->BufLen >= ASYNC_BUF_SIZE)
{
pCurrAsyncBuf->BufLen = 0;
pVc->AsyncFramingState = RX_READY;
DEBUGMSG(DBG_ERROR, ("RASIR: Async buffer overflow\n"));
}
else
{
pCurrAsyncBuf->Buf[pCurrAsyncBuf->BufLen] = Byte;
pCurrAsyncBuf->BufLen += 1;
}
}
break;
case RX_ESC:
if (pCurrAsyncBuf->BufLen >= ASYNC_BUF_SIZE)
{
pCurrAsyncBuf->BufLen = 0;
pVc->AsyncFramingState = RX_READY;
DEBUGMSG(DBG_ERROR, ("RASIR: Async failure 2\n"));
}
else
{
pCurrAsyncBuf->Buf[pCurrAsyncBuf->BufLen] = (Byte ^= AF_COMP_BIT);
pCurrAsyncBuf->BufLen += 1;
pVc->AsyncFramingState = RX_RX;
break;
}
}
}
}
VOID
IndicateReceive(
PRASIR_VC pVc,
PIRDA_RECVBUF pRecvBuf,
PASYNC_BUFFER pAsyncBuf,
BOOLEAN LastBuf)
{
PNDIS_PACKET pNdisPacket;
PNDIS_BUFFER pNdisBuf;
NDIS_STATUS Status;
KIRQL OldIrql;
PVOID pRecvOrAsyncBuf = NULL;
int Len;
REFADD(&pVc->RefCnt, 'VCER');
if (pVc->AsyncFraming)
{
ASSERT(pAsyncBuf && !pRecvBuf);
pRecvOrAsyncBuf = pAsyncBuf;
Len = pAsyncBuf->BufLen;
}
else
{
ASSERT(pRecvBuf && !pAsyncBuf);
pRecvOrAsyncBuf = pRecvBuf;
Len = pRecvBuf->BufLen;
}
if (!(pVc->Flags & VCF_OPEN))
{
DEBUGMSG(DBG_ERROR, ("RASIR: VC not open yet, dropping packet\n"));
goto error1;
}
NdisAllocatePacket(&Status, &pNdisPacket, pVc->RxPacketPool);
if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("RASIR: NdisAllocatePacket failed, %X\n",
Status));
goto error1;
}
if (pVc->AsyncFraming)
{
NdisAllocateBuffer(&Status, &pNdisBuf, pVc->RxBufferPool,
pAsyncBuf->Buf, pAsyncBuf->BufLen);
}
else
{
NdisAllocateBuffer(&Status, &pNdisBuf, pVc->RxBufferPool,
pRecvBuf->Buf, pRecvBuf->BufLen);
}
if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("RASIR: NdisAllocateBuffer failed, %X\n",
Status));
goto error2;
}
NdisChainBufferAtFront(pNdisPacket, pNdisBuf);
*((PRASIR_VC *) &pNdisPacket->MiniportReserved[0]) = pVc;
*((PVOID *) &pNdisPacket->MiniportReserved[sizeof(PUCHAR)]) = pRecvOrAsyncBuf;
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
if (LastBuf)
{
NDIS_SET_PACKET_STATUS(pNdisPacket, NDIS_STATUS_RESOURCES);
DEBUGMSG(DBG_RECV, ("RASIR: Irtdi out of buffers\n"));
}
else
{
NDIS_SET_PACKET_STATUS(pNdisPacket, NDIS_STATUS_SUCCESS);
}
Status = NDIS_GET_PACKET_STATUS(pNdisPacket);
DEBUGMSG(DBG_RECV, ("RASIR: ->NdisMCoIndicateReceive %d\n", Len));
NdisMCoIndicateReceivePacket(pVc->NdisVcHandle, &pNdisPacket, 1);
NdisMCoReceiveComplete(pVc->pAdapter->MiniportAdapterHandle);
KeLowerIrql(OldIrql);
if (Status == NDIS_STATUS_SUCCESS) {
//
// the packets will be returned later
//
return;
}
NdisUnchainBufferAtFront(pNdisPacket, &pNdisBuf);
NdisFreeBuffer(pNdisBuf);
error2:
NdisFreePacket(pNdisPacket);
error1:
DEBUGMSG(DBG_RECV, ("RASIR: RecvIndication completed synchronously for %X\n",
pRecvOrAsyncBuf));
RasIrReceiveComplete(pVc, pRecvOrAsyncBuf);
REFDEL(&pVc->RefCnt, 'VCER');
}
VOID
IrdaReceiveIndication(
PVOID ConnectionContext,
PIRDA_RECVBUF pRecvBuf,
BOOLEAN LastBuf)
{
PRASIR_VC pVc = ConnectionContext;
PASYNC_BUFFER pAsyncRxBuf;
DEBUGMSG(DBG_RECV, ("RASIR: IrdaReceiveIndication %X, %d bytes\n",
pRecvBuf, pRecvBuf->BufLen));
if (!pVc)
{
DEBUGMSG(DBG_ERROR, ("RASIR: IrdaReceiveIndication NULL vc\n"));
ASSERT(0);
return;
}
GOODVC(pVc);
GOODADAPTER(pVc->pAdapter);
if (pVc->IrModemCall && pVc->ModemState < MS_ONLINE)
{
ProcessOfflineRxBuf(pVc, pRecvBuf);
IrdaReceiveComplete(pVc->IrdaConnContext, pRecvBuf);
return;
}
if (pVc->AsyncFraming)
{
ProcessAsyncRxPacket(pVc, pRecvBuf);
// We are done with pRecvBuf. The async framing has
// been removed and the data is now contained in a buffer
// on the CompletedAsyncBufList or if not a full frame
// then in pCurrAsyncBuf
IrdaReceiveComplete(pVc->IrdaConnContext, pRecvBuf);
while ((pAsyncRxBuf = (PASYNC_BUFFER) NdisInterlockedRemoveHeadList(
&pVc->CompletedAsyncBufList,
&pVc->pAdapter->SpinLock)) != NULL)
{
IndicateReceive(pVc, NULL, pAsyncRxBuf, LastBuf);
}
}
else
{
IndicateReceive(pVc, pRecvBuf, NULL, LastBuf);
}
return;
}
VOID
IrdaSendComplete(
PVOID ConnectContext,
PVOID SendContext,
NTSTATUS Status)
{
PRASIR_VC pVc = ConnectContext;
PNDIS_PACKET pNdisPacket = (PNDIS_PACKET) SendContext;
DEBUGMSG(DBG_SEND, ("RASIR: IrdaSendComplete vc:%X, Packet %X\n", pVc, SendContext));
GOODVC(pVc);
if (SendContext == RASIR_INTERNAL_SEND)
{
ASSERT(pVc->pOfflineNdisBuf);
NdisFreeBuffer(pVc->pOfflineNdisBuf);
pVc->pOfflineNdisBuf = NULL;
goto EXIT;
}
if (pVc->AsyncFraming)
{
PASYNC_BUFFER pAsyncBuf;
pAsyncBuf = *((PASYNC_BUFFER *) &pNdisPacket->MiniportReserved[0]);
if (pAsyncBuf)
{
if (pAsyncBuf->pNdisBuf)
{
NdisFreeBuffer(pAsyncBuf->pNdisBuf);
}
NdisFreeToNPagedLookasideList(&pVc->pAdapter->AsyncBufLList,
pAsyncBuf);
}
}
NdisMCoSendComplete(Status, pVc->NdisVcHandle, pNdisPacket);
NdisAcquireSpinLock(&pVc->pAdapter->SpinLock);
pVc->OutstandingSends -= 1; // do interlockedDec dork
NdisReleaseSpinLock(&pVc->pAdapter->SpinLock);
if ((pVc->Flags & VCF_CLOSE_PEND) && (pVc->OutstandingSends == 0))
{
DEBUGMSG(DBG_CONNECT, ("RASIR: Outstanding send to 0, CompleteClose\n"));
CompleteClose(pVc);
}
EXIT:
REFDEL(&pVc->RefCnt, 'DNES');
}
NDIS_STATUS
ScheduleWork(
IN PRASIR_ADAPTER pAdapter,
IN NDIS_PROC pProc,
IN PVOID pContext )
// Schedules a PASSIVE IRQL callback to routine 'pProc' which will be
// passed 'pContext'. 'PAdapter' is the adapter control block from which
// the work item is allocated.
//
// Returns NDIS_STATUS_SUCCESS or an error code.
//
{
NDIS_STATUS status;
NDIS_WORK_ITEM* pWork;
pWork = NdisAllocateFromNPagedLookasideList(&pAdapter->WorkItemsLList);
if (!pWork)
{
ASSERT( !"Alloc work?" );
return NDIS_STATUS_RESOURCES;
}
NdisInitializeWorkItem( pWork, pProc, pContext );
status = NdisScheduleWorkItem( pWork );
if (status != NDIS_STATUS_SUCCESS)
{
ASSERT( !"SchedWork?" );
NdisFreeToNPagedLookasideList(&pAdapter->WorkItemsLList, pWork);
}
return status;
}
#if DBG
NTSTATUS
DbgDispatch(
PDEVICE_OBJECT pDeviceObject,
PIRP pIrp)
{
PIO_STACK_LOCATION pIrpSp;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
if (pIrpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return STATUS_SUCCESS;
}
ASSERT(pIrpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
switch(pIrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_IRDA_GET_DBG_MSGS:
{
NTSTATUS Status;
if ((Status = DbgMsgIrp(pIrp, pIrpSp)) == STATUS_PENDING)
{
return STATUS_PENDING;
}
break;
}
case IOCTL_IRDA_GET_DBG_SETTINGS:
{
UINT *Settings = pIrp->AssociatedIrp.SystemBuffer;
Settings[0] = DbgSettings;
Settings[1] = DbgOutput;
pIrp->IoStatus.Information = sizeof(UINT)*2;
pIrp->IoStatus.Status = STATUS_SUCCESS;
break;
}
case IOCTL_IRDA_SET_DBG_SETTINGS:
{
UINT *Settings = pIrp->AssociatedIrp.SystemBuffer;
DbgSettings = Settings[0];
DbgOutput = Settings[1];
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_SUCCESS;
break;
}
default:
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_SUCCESS;
}
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
return STATUS_SUCCESS;
}
#endif