windows-nt/Source/XPSP1/NT/net/ndis/tunmp/sys/tunf.c
2020-09-26 16:20:57 +08:00

476 lines
11 KiB
C

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
tunf.c
Abstract:
utility routines to handle opening and closing the tunmp device.
Environment:
Kernel mode only.
Revision History:
alid 10/22/2001 modified for tunmp
--*/
#include "precomp.h"
#define __FILENUMBER 'FNUT'
NTSTATUS
TunFOpen(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
Hanndles IRP_MJ_CREATE. Here we set the device status in use, assigns a pointer
from the file object to the adapter object using pIrpSp->FileObject->FsContext,
allocates packet and buffer pools, and returns a success status
Arguments:
pDeviceObject - Pointer to the device object.
pIrp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{
PIO_STACK_LOCATION pIrpSp;
NDIS_STATUS NdisStatus;
NTSTATUS NtStatus = STATUS_SUCCESS;
UINT i;
BOOLEAN Found = FALSE;
PLIST_ENTRY pListEntry;
PTUN_ADAPTER pAdapter = NULL;
BOOLEAN DerefAdapter = FALSE;
DEBUGP(DL_INFO, ("Open: DeviceObject %p\n", DeviceObject));
do
{
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
TUN_ACQUIRE_LOCK(&TunGlobalLock);
for (pListEntry = TunAdapterList.Flink;
pListEntry != &TunAdapterList;
pListEntry = pListEntry->Flink)
{
pAdapter = CONTAINING_RECORD(pListEntry,
TUN_ADAPTER,
Link);
if(pAdapter->DeviceObject == DeviceObject)
{
Found = TRUE;
TUN_REF_ADAPTER(pAdapter);
DerefAdapter = TRUE;
break;
}
}
TUN_RELEASE_LOCK(&TunGlobalLock);
if (Found == FALSE)
{
NtStatus = STATUS_NO_SUCH_DEVICE;
break;
}
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
if (TUN_TEST_FLAG(pAdapter, TUN_ADAPTER_OPEN))
{
//
// adapter is already open by another device. fail
//
TUN_RELEASE_LOCK(&pAdapter->Lock);
NtStatus = STATUS_INVALID_DEVICE_STATE;
break;
}
TUN_SET_FLAG(pAdapter, TUN_ADAPTER_OPEN | TUN_ADAPTER_CANT_HALT);
TUN_RELEASE_LOCK(&pAdapter->Lock);
//Assign a pointer to the adapter object from the file object
pIrpSp->FileObject->FsContext = (PVOID)pAdapter;
//Get the device connected to the network by cable plugging in
NdisMIndicateStatus(pAdapter->MiniportHandle,
NDIS_STATUS_MEDIA_CONNECT,
NULL,
0);
NdisMIndicateStatusComplete(pAdapter->MiniportHandle);
DerefAdapter = FALSE;
} while (FALSE);
//
//Complete the IRP
//
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
if (DerefAdapter)
{
TUN_DEREF_ADAPTER(pAdapter);
}
return (NtStatus);
}
//************************************************************************
NTSTATUS
TunFClose(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
Handles IRP_MJ_CLOSE. Here we change the device state into available (not in
use), free the the file object's pointer to the adapter object, free the
allocated packet/buffer pools, and set the success status.
Arguments:
pDeviceObject - Pointer to the device object.
pIrp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{
//1 this may be moved to clean_up
NTSTATUS NtStatus;
PIO_STACK_LOCATION pIrpSp;
PTUN_ADAPTER pAdapter;
PLIST_ENTRY pRcvPacketEntry;
PNDIS_PACKET pRcvPacket;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pAdapter = (PTUN_ADAPTER)pIrpSp->FileObject->FsContext;
DEBUGP(DL_INFO, ("Close: FileObject %p\n",
IoGetCurrentIrpStackLocation(pIrp)->FileObject));
//If no adapter/device object is associated with the this file object
if (pAdapter == NULL)
{
NtStatus = STATUS_IO_DEVICE_ERROR;
}
else
{
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
TUN_CLEAR_FLAG(pAdapter, TUN_ADAPTER_OPEN);
TUN_RELEASE_LOCK(&pAdapter->Lock);
NdisMIndicateStatus(pAdapter->MiniportHandle,
NDIS_STATUS_MEDIA_DISCONNECT,
NULL,
0);
NdisMIndicateStatusComplete(pAdapter->MiniportHandle);
//Let the adapter object free
pIrpSp->FileObject->FsContext = NULL;
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
//
//Emtpy the received packets queue, and return the packets to NDIS
//with success status
//
while(!IsListEmpty(&pAdapter->RecvPktQueue))
{
//
//Remove the first queued received packet from the entry list
//
pRcvPacketEntry = pAdapter->RecvPktQueue.Flink;
RemoveEntryList(pRcvPacketEntry);
ExInterlockedDecrementLong(&pAdapter->RecvPktCount, &pAdapter->Lock);
//Get the packet from
pRcvPacket = CONTAINING_RECORD(pRcvPacketEntry,
NDIS_PACKET,
MiniportReserved[0]);
TUN_RELEASE_LOCK(&pAdapter->Lock);
//Indicate NDIS about comletion of the packet
NdisMSendComplete(pAdapter->MiniportHandle,
pRcvPacket,
NDIS_STATUS_FAILURE);
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
}
TUN_RELEASE_LOCK(&pAdapter->Lock);
NtStatus = STATUS_SUCCESS;
}
//1 who should do the testing of tunmp
//
//Complete the IRP
//
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
TUN_CLEAR_FLAG(pAdapter, TUN_ADAPTER_CANT_HALT);
if (pAdapter->HaltEvent != NULL)
{
NdisSetEvent(pAdapter->HaltEvent);
}
TUN_RELEASE_LOCK(&pAdapter->Lock);
KdPrint(("\nTunFClose: Exit\n"));
return (NtStatus);
}
//************************************************************************
NTSTATUS
TunFCleanup(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
Handles IRP_MJ_CLEANUP. Here we reset the driver's cancel entry point to NULL
in every IRP currently in the driver's internal queue of read IRPs, cancel
all the queued IRPs, and return a success status.
Arguments:
pDeviceObject - Pointer to the device object.
pIrp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{
PIO_STACK_LOCATION pIrpSp;
NTSTATUS NtStatus;
PTUN_ADAPTER pAdapter;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pAdapter = (PTUN_ADAPTER)pIrpSp->FileObject->FsContext;
DEBUGP(DL_INFO, ("Cleanup: FileObject %p, pAdapter %p\n",
pIrpSp->FileObject, pAdapter));
if (pAdapter != NULL)
{
TUN_STRUCT_ASSERT(pAdapter, mc);
//
// Mark this endpoint.
//
TUN_ACQUIRE_LOCK(&pAdapter->Lock);
TUN_CLEAR_FLAG(pAdapter, TUN_ADAPTER_OPEN);
pAdapter->pFileObject = NULL;
TUN_RELEASE_LOCK(&pAdapter->Lock);
TunCancelPendingReads(pAdapter);
}
NtStatus = STATUS_SUCCESS;
//
//Complete the IRP
//
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
DEBUGP(DL_INFO, ("Cleanup: OpenContext %p\n", pAdapter));
return (NtStatus);
}
//************************************************************************
NTSTATUS
TunFIoControl(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
This is the dispatch routine for handling device IOCTL requests.
Arguments:
pDeviceObject - Pointer to the device object.
pIrp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{
PIO_STACK_LOCATION pIrpSp;
PTUN_ADAPTER pAdapter;
NTSTATUS NtStatus = STATUS_SUCCESS;
ULONG BytesReturned = 0;
PUCHAR OutputBuffer = NULL;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
pAdapter = (PTUN_ADAPTER)pIrpSp->FileObject->FsContext;
// pIrp->IoStatus.Information = 0;
//if no adapter/device object is associated with this file object
if (pAdapter == NULL)
{
pIrp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return NtStatus;
}
//1 check for valid adapter
pIrp->IoStatus.Information = 0;
OutputBuffer = (PUCHAR)pIrp->AssociatedIrp.SystemBuffer;
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_TUN_GET_MEDIUM_TYPE:
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(NDIS_MEDIUM))
{
NtStatus = STATUS_BUFFER_TOO_SMALL;
}
else
{
*((PNDIS_MEDIUM)OutputBuffer) = pAdapter->Medium;
BytesReturned = sizeof(ULONG);
}
break;
case IOCTL_TUN_GET_MTU:
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
{
NtStatus = STATUS_BUFFER_TOO_SMALL;
}
else
{
*((PULONG)OutputBuffer) = pAdapter->MediumMaxPacketLen;
BytesReturned = sizeof(ULONG);
}
break;
case IOCTL_TUN_GET_PACKET_FILTER:
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
{
NtStatus = STATUS_BUFFER_TOO_SMALL;
}
else
{
*((PULONG)OutputBuffer) = pAdapter->PacketFilter;
BytesReturned = sizeof(ULONG);
}
break;
case IOCTL_TUN_GET_MINIPORT_NAME:
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < pAdapter->MiniportName.Length + sizeof(USHORT))
{
NtStatus = STATUS_BUFFER_TOO_SMALL;
}
else
{
*((PUSHORT)OutputBuffer) = pAdapter->MiniportName.Length;
TUN_COPY_MEM(OutputBuffer + sizeof(USHORT),
(PUCHAR)pAdapter->MiniportName.Buffer,
pAdapter->MiniportName.Length);
BytesReturned = pAdapter->MiniportName.Length + sizeof(USHORT);
}
break;
default:
NtStatus = STATUS_NOT_SUPPORTED;
break;
}
pIrp->IoStatus.Information = BytesReturned;
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength = BytesReturned;
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return (NtStatus);
}