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