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