922 lines
25 KiB
C
922 lines
25 KiB
C
|
|
/*++
|
|
|
|
Copyright (c) 2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tunmp.c
|
|
|
|
Abstract:
|
|
Microsoft Tunnel interface Miniport driver
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
alid 10/22/2001
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define __FILENUMBER 'MUNT'
|
|
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
NDIS_STATUS Status;
|
|
NDIS_MINIPORT_CHARACTERISTICS MChars;
|
|
NDIS_STRING Name;
|
|
|
|
DEBUGP(DL_INFO, ("Tunmp: ==>DriverEntry\n"));
|
|
|
|
|
|
//
|
|
// Register the miniport with NDIS.
|
|
//
|
|
NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);
|
|
|
|
if (NdisWrapperHandle == NULL)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
return Status;
|
|
}
|
|
|
|
|
|
TUN_ZERO_MEM(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));
|
|
|
|
MChars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
|
|
MChars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
|
|
|
|
MChars.InitializeHandler = TunMpInitialize;
|
|
MChars.QueryInformationHandler = TunMpQueryInformation;
|
|
MChars.SetInformationHandler = TunMpSetInformation;
|
|
MChars.ResetHandler = NULL;
|
|
MChars.ReturnPacketHandler = TunMpReturnPacket;
|
|
MChars.SendPacketsHandler = TunMpSendPackets;
|
|
MChars.HaltHandler = TunMpHalt;
|
|
MChars.CheckForHangHandler = NULL;
|
|
|
|
MChars.CancelSendPacketsHandler = NULL;
|
|
MChars.PnPEventNotifyHandler = NULL;
|
|
MChars.AdapterShutdownHandler = TunMpShutdown;
|
|
|
|
Status = NdisMRegisterMiniport(NdisWrapperHandle,
|
|
&MChars,
|
|
sizeof(MChars));
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NdisTerminateWrapper(NdisWrapperHandle, NULL);
|
|
}
|
|
|
|
TUN_INIT_LOCK(&TunGlobalLock);
|
|
TUN_INIT_LIST_HEAD(&TunAdapterList);
|
|
|
|
DEBUGP(DL_INFO, ("Tunmp: <==DriverEntry Status %lx\n", Status));
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
TunMpInitialize(
|
|
OUT PNDIS_STATUS OpenErrorStatus,
|
|
OUT PUINT SelectedMediumIndex,
|
|
IN PNDIS_MEDIUM MediumArray,
|
|
IN UINT MediumArraySize,
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE ConfigurationContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the initialize handler.
|
|
|
|
Arguments:
|
|
|
|
OpenErrorStatus Not used by us.
|
|
SelectedMediumIndex Place-holder for what media we are using
|
|
MediumArray Array of ndis media passed down to us to pick from
|
|
MediumArraySize Size of the array
|
|
MiniportAdapterHandle The handle NDIS uses to refer to us
|
|
WrapperConfigurationContext For use by NdisOpenConfiguration
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS unless something goes wrong
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT i, Length;
|
|
PTUN_ADAPTER pAdapter = NULL;
|
|
NDIS_MEDIUM AdapterMedium;
|
|
NDIS_HANDLE ConfigHandle = NULL;
|
|
PNDIS_CONFIGURATION_PARAMETER Parameter;
|
|
PUCHAR NetworkAddress;
|
|
NDIS_STATUS Status;
|
|
NDIS_STRING MiniportNameStr = NDIS_STRING_CONST("MiniportName");
|
|
|
|
|
|
DEBUGP(DL_INFO, ("==>TunMpInitialize: MiniportAdapterHandle %p\n", MiniportAdapterHandle));
|
|
|
|
do
|
|
{
|
|
|
|
TUN_ALLOC_MEM(pAdapter, sizeof(TUN_ADAPTER));
|
|
|
|
if (pAdapter == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
TUN_ZERO_MEM(pAdapter, sizeof(TUN_ADAPTER));
|
|
TUN_SET_SIGNATURE(pAdapter, mc);
|
|
|
|
pAdapter->MiniportHandle = MiniportAdapterHandle;
|
|
|
|
//1 no need to specify NDIS_ATTRIBUTE_IGNORE...
|
|
NdisMSetAttributesEx(MiniportAdapterHandle,
|
|
pAdapter,
|
|
0,
|
|
NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS |
|
|
NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT |
|
|
NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT |
|
|
NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND |
|
|
NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK |
|
|
NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS |
|
|
NDIS_ATTRIBUTE_DESERIALIZE,
|
|
0);
|
|
|
|
NdisOpenConfiguration(&Status,
|
|
&ConfigHandle,
|
|
ConfigurationContext);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGP(DL_ERROR, ("TunMpInitialize: NdisOpenConfiguration failed. Status %lx\n", Status));
|
|
break;
|
|
}
|
|
|
|
AdapterMedium = NdisMedium802_3; // Default
|
|
|
|
TUN_COPY_MEM(pAdapter->PermanentAddress,
|
|
TUN_CARD_ADDRESS,
|
|
TUN_MAC_ADDR_LEN);
|
|
|
|
TUN_COPY_MEM(pAdapter->CurrentAddress,
|
|
TUN_CARD_ADDRESS,
|
|
TUN_MAC_ADDR_LEN);
|
|
|
|
pAdapter->Medium = AdapterMedium;
|
|
pAdapter->MediumLinkSpeed = MediaParams[(UINT)AdapterMedium].LinkSpeed;
|
|
pAdapter->MediumMinPacketLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen;
|
|
pAdapter->MediumMaxPacketLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen+
|
|
MediaParams[(UINT)AdapterMedium].MaxFrameLen;
|
|
pAdapter->MediumMacHeaderLen = MediaParams[(UINT)AdapterMedium].MacHeaderLen;
|
|
pAdapter->MediumMaxFrameLen = MediaParams[(UINT)AdapterMedium].MaxFrameLen;
|
|
|
|
pAdapter->MaxLookAhead = MediaParams[(UINT)AdapterMedium].MaxFrameLen;
|
|
|
|
//Get the software-configurable network address that was stored in the
|
|
//registry when the adapter was installed in the machine.
|
|
NdisReadNetworkAddress(&Status,
|
|
&NetworkAddress,
|
|
&Length,
|
|
ConfigHandle);
|
|
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
#if TUN_ALLOW_ANY_MAC_ADDRESS
|
|
if ((Length == ETH_LENGTH_OF_ADDRESS) &&
|
|
(!ETH_IS_MULTICAST(NetworkAddress)))
|
|
|
|
#else
|
|
if ((Length == ETH_LENGTH_OF_ADDRESS) &&
|
|
(!ETH_IS_MULTICAST(NetworkAddress)) &&
|
|
(NetworkAddress[0] & 0x02))
|
|
#endif
|
|
{
|
|
TUN_COPY_MEM(pAdapter->CurrentAddress,
|
|
NetworkAddress,
|
|
Length);
|
|
}
|
|
}
|
|
|
|
//
|
|
// read the miniport name
|
|
//
|
|
//1 make sure miniport name is really used
|
|
NdisReadConfiguration(&Status,
|
|
&Parameter,
|
|
ConfigHandle,
|
|
&MiniportNameStr,
|
|
NdisParameterString);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
TUN_ALLOC_MEM(pAdapter->MiniportName.Buffer,
|
|
Parameter->ParameterData.StringData.Length);
|
|
|
|
if (pAdapter->MiniportName.Buffer == NULL)
|
|
{
|
|
DEBUGP(DL_ERROR, ("TunMpInitialize: failed to allocate memory for miniport name.\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
pAdapter->MiniportName.Length = pAdapter->MiniportName.MaximumLength =
|
|
Parameter->ParameterData.StringData.Length;
|
|
|
|
TUN_COPY_MEM(pAdapter->MiniportName.Buffer,
|
|
Parameter->ParameterData.StringData.Buffer,
|
|
Parameter->ParameterData.StringData.Length);
|
|
|
|
}
|
|
else
|
|
{
|
|
DEBUGP(DL_ERROR, ("TunMpInitialize: NdisReadConfiguration failed to read miniport name. Status %lx\n", Status));
|
|
break;
|
|
}
|
|
|
|
NdisCloseConfiguration(ConfigHandle);
|
|
ConfigHandle = NULL;
|
|
|
|
//
|
|
//Make sure the medium saved is one of the ones being offered
|
|
//
|
|
for (i = 0; i < MediumArraySize; i++)
|
|
{
|
|
if (MediumArray[i] == AdapterMedium)
|
|
{
|
|
*SelectedMediumIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == MediumArraySize)
|
|
{
|
|
Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
|
|
DEBUGP(DL_ERROR, ("TunMpInitialize: Status %lx, AdapterMedium %lx\n",
|
|
Status, AdapterMedium));
|
|
break;
|
|
}
|
|
|
|
Status = TunMpCreateDevice(pAdapter);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGP(DL_ERROR, ("TunMpInitialize: TunMpCreateDevice failed. Status %lx\n",
|
|
Status));
|
|
break;
|
|
}
|
|
|
|
pAdapter->RefCount = 1;
|
|
|
|
//Initialize the adapter spin lock
|
|
TUN_INIT_LOCK(&pAdapter->Lock);
|
|
|
|
//
|
|
//Get the list heads for the pended read/write IRPS and received
|
|
//packets (from the NDIS) initialized
|
|
//
|
|
InitializeListHead(&pAdapter->PendedReads); //read IRPs
|
|
InitializeListHead(&pAdapter->PendedWrites); //writes IRPs
|
|
InitializeListHead(&pAdapter->RecvPktQueue); //received packets
|
|
|
|
|
|
NdisAllocatePacketPoolEx(&Status,
|
|
&pAdapter->SendPacketPool,
|
|
MIN_SEND_PACKET_POOL_SIZE,
|
|
MAX_SEND_PACKET_POOL_SIZE
|
|
- MIN_SEND_PACKET_POOL_SIZE,
|
|
4 * sizeof(PVOID)
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGP(DL_ERROR, ("TunMpInitialize: NdisAllocatePacketPoolEx for Send failed. Status %lx\n",
|
|
Status));
|
|
break;
|
|
}
|
|
|
|
//
|
|
//Get the adapter listed in the tun global list of adapters
|
|
//
|
|
TUN_ACQUIRE_LOCK(&TunGlobalLock);
|
|
|
|
TUN_INSERT_HEAD_LIST(&TunAdapterList, &pAdapter->Link);
|
|
|
|
TUN_RELEASE_LOCK(&TunGlobalLock);
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (pAdapter != NULL)
|
|
{
|
|
|
|
if (ConfigHandle)
|
|
{
|
|
NdisCloseConfiguration(ConfigHandle);
|
|
}
|
|
|
|
if (pAdapter->NdisDeviceHandle)
|
|
{
|
|
NdisMDeregisterDevice(pAdapter->NdisDeviceHandle);
|
|
}
|
|
|
|
if (pAdapter->SendPacketPool)
|
|
{
|
|
NdisFreePacketPool(pAdapter->SendPacketPool);
|
|
}
|
|
|
|
TUN_FREE_MEM(pAdapter);
|
|
}
|
|
}
|
|
|
|
DEBUGP(DL_INFO, ("<==TunMpInitialize: MiniportAdapterHandle %p, Status\n",
|
|
MiniportAdapterHandle, Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
TunMpCreateDevice(
|
|
IN PTUN_ADAPTER pAdapter
|
|
)
|
|
{
|
|
LONG DeviceInstanceNumber;
|
|
UNICODE_STRING usDeviceID;
|
|
WCHAR TempBuffer[4] = {0};
|
|
WCHAR DeviceNameBuffer[sizeof(DEVICE_NAME)+4] = {0};
|
|
WCHAR SymbolicNameBuffer[sizeof(SYMBOLIC_NAME)+4] = {0};
|
|
UNICODE_STRING DeviceName, SymbolicName;
|
|
PDRIVER_DISPATCH MajorFunctions[IRP_MJ_MAXIMUM_FUNCTION+1];
|
|
NTSTATUS NtStatus;
|
|
NDIS_STATUS Status;
|
|
UINT i;
|
|
PDEVICE_OBJECT DeviceObject = NULL;
|
|
NDIS_HANDLE NdisDeviceHandle = NULL;
|
|
|
|
DEBUGP(DL_INFO, ("==>TunMpCreateDevice, pAdapter %p\n", pAdapter));
|
|
|
|
do
|
|
{
|
|
|
|
DeviceInstanceNumber = InterlockedIncrement(&GlobalDeviceInstanceNumber);
|
|
//
|
|
// for the time being, allow one device only
|
|
//
|
|
|
|
// if (DeviceInstanceNumber > 99)
|
|
if (DeviceInstanceNumber > 0)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
pAdapter->DeviceInstanceNumber = (ULONG)DeviceInstanceNumber;
|
|
|
|
//
|
|
//Initiallize a unicode string
|
|
//
|
|
usDeviceID.Buffer = TempBuffer;
|
|
usDeviceID.Length = 0;
|
|
usDeviceID.MaximumLength = sizeof(TempBuffer);
|
|
|
|
|
|
NtStatus = RtlIntegerToUnicodeString ((ULONG)DeviceInstanceNumber, 10, &usDeviceID);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
//1 GlobalDeviceInstanceNumber is not protected properly
|
|
InterlockedDecrement(&GlobalDeviceInstanceNumber);
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
DEBUGP(DL_ERROR, ("TunMpCreateDevice: RtlIntegerToUnicodeString failed. NtStatus %lx\n",
|
|
NtStatus));
|
|
break;
|
|
}
|
|
|
|
|
|
wcscpy(DeviceNameBuffer, DEVICE_NAME);
|
|
RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
|
|
RtlAppendUnicodeStringToString(&DeviceName, &usDeviceID);
|
|
|
|
|
|
wcscpy(SymbolicNameBuffer, SYMBOLIC_NAME);
|
|
RtlInitUnicodeString(&SymbolicName, SymbolicNameBuffer);
|
|
RtlAppendUnicodeStringToString(&SymbolicName, &usDeviceID);
|
|
|
|
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
|
|
{
|
|
MajorFunctions[i] = NULL;
|
|
}
|
|
|
|
MajorFunctions[IRP_MJ_CREATE] = TunFOpen;
|
|
MajorFunctions[IRP_MJ_CLOSE] = TunFClose;
|
|
MajorFunctions[IRP_MJ_READ] = TunRead;
|
|
MajorFunctions[IRP_MJ_WRITE] = TunWrite;
|
|
MajorFunctions[IRP_MJ_CLEANUP] = TunFCleanup;
|
|
MajorFunctions[IRP_MJ_DEVICE_CONTROL] = TunFIoControl;
|
|
|
|
|
|
Status = NdisMRegisterDevice(
|
|
NdisWrapperHandle,
|
|
&DeviceName,
|
|
&SymbolicName,
|
|
MajorFunctions,
|
|
&DeviceObject,
|
|
&NdisDeviceHandle
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGP(DL_ERROR, ("TunMpCreateDevice: NdisMRegisterDevice failed. Status %lx\n",
|
|
Status));
|
|
|
|
InterlockedDecrement(&GlobalDeviceInstanceNumber);
|
|
break;
|
|
}
|
|
|
|
DeviceObject->Flags |= DO_DIRECT_IO;
|
|
pAdapter->DeviceObject = DeviceObject;
|
|
pAdapter->NdisDeviceHandle = NdisDeviceHandle;
|
|
}while (FALSE);
|
|
|
|
DEBUGP(DL_INFO, ("<==TunMpCreateDevice, pAdapter %p, Status %lx\n", pAdapter, Status));
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
TunMpHalt(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Halt handler. It frees the adapter object and corresponding device object.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to the Adapter
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTUN_ADAPTER pAdapter = (PTUN_ADAPTER)MiniportAdapterContext;
|
|
NDIS_EVENT HaltReadyEvent;
|
|
|
|
DEBUGP(DL_INFO, ("==>TunMpHalt, pAdapter %p\n", pAdapter));
|
|
|
|
NdisInitializeEvent(&HaltReadyEvent);
|
|
//
|
|
// let's wait for the app to close all the handles
|
|
//
|
|
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
|
|
if (TUN_TEST_FLAG(pAdapter, TUN_ADAPTER_CANT_HALT))
|
|
{
|
|
pAdapter->HaltEvent = &HaltReadyEvent;
|
|
}
|
|
TUN_RELEASE_LOCK(&pAdapter->Lock);
|
|
|
|
if (pAdapter->HaltEvent)
|
|
{
|
|
NdisWaitEvent(pAdapter->HaltEvent, 0);
|
|
}
|
|
pAdapter->HaltEvent = 0;
|
|
|
|
//
|
|
// we should not have any pending NDIS sends
|
|
//
|
|
ASSERT(pAdapter->PendedReadCount == 0);
|
|
|
|
//
|
|
// Free the resources now
|
|
//
|
|
|
|
if (pAdapter->NdisDeviceHandle)
|
|
{
|
|
NdisMDeregisterDevice(pAdapter->NdisDeviceHandle);
|
|
}
|
|
|
|
InterlockedDecrement(&GlobalDeviceInstanceNumber);
|
|
|
|
if (pAdapter->SendPacketPool)
|
|
{
|
|
NdisFreePacketPool(pAdapter->SendPacketPool);
|
|
}
|
|
|
|
//
|
|
// remove it from the global queue
|
|
//
|
|
|
|
TUN_ACQUIRE_LOCK(&TunGlobalLock);
|
|
TUN_REMOVE_ENTRY_LIST(&pAdapter->Link);
|
|
TUN_RELEASE_LOCK(&TunGlobalLock);
|
|
|
|
TUN_FREE_MEM(pAdapter);
|
|
|
|
DEBUGP(DL_INFO, ("<==TunMpHalt, pAdapter %p\n", pAdapter));
|
|
|
|
}
|
|
|
|
VOID
|
|
TunMpShutdown(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
{
|
|
DEBUGP(DL_INFO, ("==>TunMpShutdown, pAdapter %p\n", MiniportAdapterContext));
|
|
//
|
|
// nothing to do here
|
|
//
|
|
DEBUGP(DL_INFO, ("<==TunMpShutdown, pAdapter %p\n", MiniportAdapterContext));
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
TunMpSendPackets(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send packets handler. Just queues packets in the list of pended received packets.
|
|
And then calls TunServiceReads to process packets.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext Pointer to the adapter
|
|
Packet Packet to send
|
|
Flags Unused, passed down below
|
|
|
|
Return Value:
|
|
|
|
Return code from NdisSend
|
|
|
|
--*/
|
|
|
|
{
|
|
PTUN_ADAPTER pAdapter = (PTUN_ADAPTER)MiniportAdapterContext;
|
|
NDIS_STATUS NdisStatus;
|
|
UINT Index;
|
|
UINT BytesToSend;
|
|
PLIST_ENTRY pRcvPacketEntry;
|
|
PNDIS_PACKET pOldRcvPacket;
|
|
|
|
DEBUGP(DL_LOUD, ("==>TunMpSendPackets, pAdapter %p, PacketArray %p, NumberOfPackets\n",
|
|
MiniportAdapterContext, PacketArray, NumberOfPackets));
|
|
|
|
TUN_REF_ADAPTER(pAdapter); // queued rcv packet
|
|
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
|
|
|
|
if ((!TUN_TEST_FLAG(pAdapter, TUN_ADAPTER_OPEN)) ||
|
|
TUN_TEST_FLAG(pAdapter, TUN_ADAPTER_OFF))
|
|
|
|
{
|
|
pAdapter->XmitError += NumberOfPackets;
|
|
TUN_RELEASE_LOCK(&pAdapter->Lock);
|
|
|
|
if (!TUN_TEST_FLAG(pAdapter, TUN_ADAPTER_OPEN))
|
|
{
|
|
DEBUGP(DL_WARN, ("TunMpSendPackets, pAdapter %p, Adapter not open\n",
|
|
pAdapter));
|
|
NdisStatus = NDIS_STATUS_NO_CABLE;
|
|
}
|
|
else
|
|
{
|
|
DEBUGP(DL_WARN, ("TunMpSendPackets, pAdapter %p, Adapter off.\n",
|
|
pAdapter));
|
|
|
|
NdisStatus = NDIS_STATUS_ADAPTER_NOT_READY;
|
|
}
|
|
|
|
for(Index = 0; Index < NumberOfPackets; Index++)
|
|
{
|
|
NDIS_SET_PACKET_STATUS(PacketArray[Index], NdisStatus);
|
|
NdisMSendComplete(pAdapter->MiniportHandle,
|
|
PacketArray[Index],
|
|
NdisStatus);
|
|
}
|
|
|
|
TUN_DEREF_ADAPTER(pAdapter);
|
|
DEBUGP(DL_LOUD, ("<==TunMpSendPackets, pAdapter %p\n",
|
|
MiniportAdapterContext));
|
|
return;
|
|
}
|
|
|
|
for(Index = 0; Index < NumberOfPackets; Index++)
|
|
{
|
|
NdisQueryPacket(PacketArray[Index], NULL, NULL, NULL, &BytesToSend);
|
|
|
|
//
|
|
//if the packet size is invalid or no data buffer associated with it,
|
|
//inform NDIS about the invalidity
|
|
//
|
|
if ((BytesToSend == 0) || (BytesToSend > pAdapter->MediumMaxPacketLen))
|
|
{
|
|
NDIS_SET_PACKET_STATUS(PacketArray[Index], NDIS_STATUS_FAILURE);
|
|
pAdapter->XmitError++;
|
|
|
|
TUN_RELEASE_LOCK(&pAdapter->Lock);
|
|
NdisMSendComplete(pAdapter->MiniportHandle,
|
|
PacketArray[Index],
|
|
NDIS_STATUS_FAILURE);
|
|
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
//if there are already MAX_PEND packets in miniport's pended packet queue,
|
|
// refuse the new ones with NDIS_STATUS_RESOURCES
|
|
//
|
|
else if(pAdapter->RecvPktCount >= MAX_RECV_QUEUE_SIZE)
|
|
{
|
|
pAdapter->XmitError += NumberOfPackets - Index;
|
|
pAdapter->XmitErrorNoReadIrps += NumberOfPackets - Index;
|
|
|
|
TUN_RELEASE_LOCK(&pAdapter->Lock);
|
|
|
|
for (;Index < NumberOfPackets; Index++)
|
|
{
|
|
NDIS_SET_PACKET_STATUS(PacketArray[Index], NDIS_STATUS_RESOURCES);
|
|
|
|
|
|
NdisMSendComplete(pAdapter->MiniportHandle,
|
|
PacketArray[Index],
|
|
NDIS_STATUS_RESOURCES);
|
|
}
|
|
|
|
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
//queue the new packet, and set the packet status to pending
|
|
//
|
|
TUN_INSERT_TAIL_LIST(&pAdapter->RecvPktQueue, TUN_RCV_PKT_TO_LIST_ENTRY(PacketArray[Index]));
|
|
|
|
//need to make sure the packet pointer in this statement
|
|
|
|
pAdapter->RecvPktCount++;
|
|
TUN_REF_ADAPTER(pAdapter); // pended send
|
|
|
|
NDIS_SET_PACKET_STATUS(PacketArray[Index], NDIS_STATUS_PENDING);
|
|
}
|
|
|
|
TUN_RELEASE_LOCK(&pAdapter->Lock);
|
|
|
|
//
|
|
// Run the receive queue service routine now.
|
|
//
|
|
TunServiceReads(pAdapter);
|
|
|
|
TUN_DEREF_ADAPTER(pAdapter);
|
|
|
|
DEBUGP(DL_LOUD, ("<==TunMpSendPackets, pAdapter %p\n",
|
|
MiniportAdapterContext));
|
|
return;
|
|
|
|
}
|
|
|
|
VOID
|
|
TunMpReturnPacket(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN PNDIS_PACKET NdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NDIS entry point called to signify completion of a packet send.
|
|
We pick up and complete the Write IRP corresponding to this packet.
|
|
|
|
NDIS 5.1:
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext - pointer to open context
|
|
pNdisPacket - packet that completed send
|
|
Status - status of send
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
PTUN_ADAPTER pAdapter;
|
|
|
|
pAdapter = (PTUN_ADAPTER)MiniportAdapterContext;
|
|
|
|
DEBUGP(DL_LOUD, ("==>TunMpReturnPacket, pAdapter %p\n",
|
|
pAdapter));
|
|
|
|
//1 get rid of this
|
|
TUN_STRUCT_ASSERT(pAdapter, mc);
|
|
|
|
pIrp = TUN_IRP_FROM_SEND_PKT(NdisPacket);
|
|
|
|
//
|
|
// We are done with the NDIS_PACKET:
|
|
//
|
|
TUN_DEREF_SEND_PKT(NdisPacket);
|
|
|
|
//
|
|
// Complete the Write IRP with the right status.
|
|
//
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length;
|
|
pIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
DEBUGP(DL_VERY_LOUD, ("SendComplete: packet %p/IRP %p/Length %d "
|
|
"completed with status %x\n",
|
|
NdisPacket, pIrp, pIrp->IoStatus.Information, pIrp->IoStatus.Status));
|
|
|
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
|
|
|
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
|
|
|
|
pAdapter->PendedSendCount--;
|
|
pAdapter->RcvPackets++;
|
|
|
|
if ((!TUN_TEST_FLAG(pAdapter, TUN_ADAPTER_ACTIVE)) &&
|
|
(pAdapter->PendedSendCount == 0) &&
|
|
(TUN_TEST_FLAG(pAdapter, TUN_COMPLETE_REQUEST)) &&
|
|
((!TUN_TEST_FLAG(pAdapter, TUN_ADAPTER_OFF)) ||
|
|
(pAdapter->PendedReadCount == 0)))
|
|
{
|
|
TUN_CLEAR_FLAG(pAdapter, TUN_COMPLETE_REQUEST);
|
|
TUN_RELEASE_LOCK(&pAdapter->Lock);
|
|
NdisMSetInformationComplete(&pAdapter->MiniportHandle,
|
|
NDIS_STATUS_SUCCESS);
|
|
}
|
|
else
|
|
{
|
|
TUN_RELEASE_LOCK(&pAdapter->Lock);
|
|
}
|
|
|
|
TUN_DEREF_ADAPTER(pAdapter); // send complete - dequeued send IRP
|
|
|
|
DEBUGP(DL_LOUD, ("<==TunMpReturnPacket, pAdapter %p\n",
|
|
pAdapter));
|
|
}
|
|
|
|
VOID
|
|
TunMpRefAdapter(
|
|
IN PTUN_ADAPTER pAdapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reference the given open context.
|
|
|
|
NOTE: Can be called with or without holding the opencontext lock.
|
|
|
|
Arguments:
|
|
|
|
pOpenContext - pointer to open context
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NdisInterlockedIncrement(&pAdapter->RefCount);
|
|
}
|
|
|
|
|
|
VOID
|
|
TunMpDerefAdapter(
|
|
IN PTUN_ADAPTER pAdapter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dereference the given open context. If the ref count goes to zero,
|
|
free it.
|
|
|
|
NOTE: called without holding the opencontext lock
|
|
|
|
Arguments:
|
|
|
|
pAdapter - pointer to open context
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//1 how do we protect against ref count going to zero and back up again?
|
|
if (NdisInterlockedDecrement(&pAdapter->RefCount) == 0)
|
|
{
|
|
DEBUGP(DL_INFO, ("DerefAdapter: Adapter %p, Flags %x, ref count is zero!\n",
|
|
pAdapter, pAdapter->Flags));
|
|
|
|
TUN_ASSERT(pAdapter->MiniportHandle == NULL);
|
|
TUN_ASSERT(pAdapter->RefCount == 0);
|
|
TUN_ASSERT(pAdapter->pFileObject == NULL);
|
|
|
|
pAdapter->mc_sig++;
|
|
|
|
//
|
|
// Free it.
|
|
//
|
|
TUN_FREE_MEM(pAdapter);
|
|
}
|
|
}
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
TunMpDbgRefAdapter(
|
|
IN PTUN_ADAPTER pAdapter,
|
|
IN ULONG FileNumber,
|
|
IN ULONG LineNumber
|
|
)
|
|
{
|
|
DEBUGP(DL_VERY_LOUD, (" RefAdapter: Adapter %p, old ref %d, File %c%c%c%c, line %d\n",
|
|
pAdapter,
|
|
pAdapter->RefCount,
|
|
(CHAR)(FileNumber),
|
|
(CHAR)(FileNumber >> 8),
|
|
(CHAR)(FileNumber >> 16),
|
|
(CHAR)(FileNumber >> 24),
|
|
LineNumber));
|
|
|
|
TunMpRefAdapter(pAdapter);
|
|
}
|
|
|
|
VOID
|
|
TunMpDbgDerefAdapter(
|
|
IN PTUN_ADAPTER pAdapter,
|
|
IN ULONG FileNumber,
|
|
IN ULONG LineNumber
|
|
)
|
|
{
|
|
DEBUGP(DL_VERY_LOUD, ("DerefAdapter: Adapter %p, old ref %d, File %c%c%c%c, line %d\n",
|
|
pAdapter,
|
|
pAdapter->RefCount,
|
|
(CHAR)(FileNumber),
|
|
(CHAR)(FileNumber >> 8),
|
|
(CHAR)(FileNumber >> 16),
|
|
(CHAR)(FileNumber >> 24),
|
|
LineNumber));
|
|
|
|
TunMpDerefAdapter(pAdapter);
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
|