1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-11-25 10:59:53 +03:00
SoftEtherVPN/src/See/Openclos.c

708 lines
18 KiB
C
Raw Normal View History

2021-02-26 10:06:15 +03:00
/*
* Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
* Copyright (c) 2005 CACE Technologies, Davis (California)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Politecnico di Torino, CACE Technologies
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <GlobalConst.h>
#include "ntddk.h"
#include "ntiologc.h"
#include "ndis.h"
#include "debug.h"
#include "packet.h"
static NDIS_MEDIUM MediumArray[] = {
NdisMedium802_3,
// NdisMediumWan,
NdisMediumFddi,
NdisMediumArcnet878_2,
NdisMediumAtm,
NdisMedium802_5
};
#define NUM_NDIS_MEDIA (sizeof MediumArray / sizeof MediumArray[0])
ULONG NamedEventsCounter=0;
//Itoa. Replaces the buggy RtlIntegerToUnicodeString
void PacketItoa(UINT n,PUCHAR buf){
int i;
for(i=0;i<20;i+=2){
buf[18-i]=(n%10)+48;
buf[19-i]=0;
n/=10;
}
}
/// Global start time. Used as an absolute reference for timestamp conversion.
struct time_conv G_Start_Time = {
0,
{0, 0},
};
UINT n_Opened_Instances = 0;
NDIS_SPIN_LOCK Opened_Instances_Lock;
//-------------------------------------------------------------------
NTSTATUS NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension;
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
NDIS_STATUS Status;
NDIS_STATUS ErrorStatus;
UINT i;
PCHAR EvName;
IF_LOUD(DbgPrint("NPF: OpenAdapter\n");)
DeviceExtension = DeviceObject->DeviceExtension;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
// allocate some memory for the open structure
Open=ExAllocatePoolWithTag(NonPagedPool, sizeof(OPEN_INSTANCE), '0OWA');
if (Open==NULL) {
// no memory
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(
Open,
sizeof(OPEN_INSTANCE)
);
EvName=ExAllocatePoolWithTag(NonPagedPool, sizeof(L"\\BaseNamedObjects\\SEE0000000000"), '1OWA');
if (EvName==NULL) {
// no memory
ExFreePool(Open);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
// Save or open here
IrpSp->FileObject->FsContext=Open;
Open->DeviceExtension=DeviceExtension;
// Save the Irp here for the completion routine to retrieve
Open->OpenCloseIrp=Irp;
// Allocate a packet pool for our xmit and receive packets
NdisAllocatePacketPool(
&Status,
&Open->PacketPool,
TRANSMIT_PACKETS,
sizeof(PACKET_RESERVED));
if (Status != NDIS_STATUS_SUCCESS) {
IF_LOUD(DbgPrint("NPF: Failed to allocate packet pool\n");)
ExFreePool(Open);
ExFreePool(EvName);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyBytes(EvName,L"\\BaseNamedObjects\\SEE0000000000",sizeof(L"\\BaseNamedObjects\\SEE0000000000"));
//Create the string containing the name of the read event
RtlInitUnicodeString(&Open->ReadEventName,(PCWSTR) EvName);
PacketItoa(NamedEventsCounter,(PUCHAR)(Open->ReadEventName.Buffer+21));
InterlockedIncrement(&NamedEventsCounter);
IF_LOUD(DbgPrint("\nCreated the named event for the read; name=%ws, counter=%d\n", Open->ReadEventName.Buffer,NamedEventsCounter-1);)
//allocate the event objects
Open->ReadEvent=IoCreateNotificationEvent(&Open->ReadEventName,&Open->ReadEventHandle);
if(Open->ReadEvent==NULL){
ExFreePool(Open);
ExFreePool(EvName);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
KeInitializeEvent(Open->ReadEvent, NotificationEvent, FALSE);
KeClearEvent(Open->ReadEvent);
NdisInitializeEvent(&Open->WriteEvent);
NdisInitializeEvent(&Open->IOEvent);
NdisInitializeEvent(&Open->DumpEvent);
NdisAllocateSpinLock(&Open->MachineLock);
NdisAllocateSpinLock(&Open->WriteLock);
Open->WriteInProgress = FALSE;
// list to hold irp's want to reset the adapter
InitializeListHead(&Open->ResetIrpList);
// Initialize the request list
KeInitializeSpinLock(&Open->RequestSpinLock);
InitializeListHead(&Open->RequestList);
// Initializes the extended memory of the NPF machine
Open->mem_ex.buffer = ExAllocatePoolWithTag(NonPagedPool, DEFAULT_MEM_EX_SIZE, '2OWA');
if((Open->mem_ex.buffer) == NULL)
{
// no memory
ExFreePool(Open);
ExFreePool(EvName);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
Open->mem_ex.size = DEFAULT_MEM_EX_SIZE;
RtlZeroMemory(Open->mem_ex.buffer, DEFAULT_MEM_EX_SIZE);
//
// Initialize the open instance
//
// Open->BufSize = 0;
// Open->Buffer = NULL;
// Open->Bhead = 0;
// Open->Btail = 0;
// (INT)Open->BLastByte = -1;
// Open->Dropped = 0; //reset the dropped packets counter
// Open->Received = 0; //reset the received packets counter
// Open->Accepted = 0; //reset the accepted packets counter
Open->bpfprogram = NULL; //reset the filter
Open->mode = MODE_CAPT;
Open->Nbytes.QuadPart = 0;
Open->Npackets.QuadPart = 0;
Open->Nwrites = 1;
Open->Multiple_Write_Counter = 0;
Open->MinToCopy = 0;
Open->TimeOut.QuadPart = (LONGLONG)1;
Open->Bound = TRUE;
Open->DumpFileName.Buffer = NULL;
Open->DumpFileHandle = NULL;
Open->tme.active = TME_NONE_ACTIVE;
Open->DumpLimitReached = FALSE;
Open->MaxFrameSize = 0;
Open->WriterSN=0;
Open->ReaderSN=0;
Open->Size=0;
//allocate the spinlock for the statistic counters
NdisAllocateSpinLock(&Open->CountersLock);
//allocate the spinlock for the buffer pointers
// NdisAllocateSpinLock(&Open->BufLock);
//
// link up the request stored in our open block
//
for (i=0;i<MAX_REQUESTS;i++) {
ExInterlockedInsertTailList(
&Open->RequestList,
&Open->Requests[i].ListElement,
&Open->RequestSpinLock);
}
IoMarkIrpPending(Irp);
//
// Try to open the MAC
//
IF_LOUD(DbgPrint("NPF: Opening the device %ws, BindingContext=%d\n",DeviceExtension->AdapterName.Buffer, Open);)
NdisOpenAdapter(
&Status,
&ErrorStatus,
&Open->AdapterHandle,
&Open->Medium,
MediumArray,
NUM_NDIS_MEDIA,
DeviceExtension->NdisProtocolHandle,
Open,
&DeviceExtension->AdapterName,
0,
NULL);
IF_LOUD(DbgPrint("NPF: Opened the device, Status=%x\n",Status);)
if (Status != NDIS_STATUS_PENDING)
{
NPF_OpenAdapterComplete(Open,Status,NDIS_STATUS_SUCCESS);
}
return(STATUS_PENDING);
}
//-------------------------------------------------------------------
VOID NPF_OpenAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus)
{
PIRP Irp;
POPEN_INSTANCE Open;
PLIST_ENTRY RequestListEntry;
PINTERNAL_REQUEST MaxSizeReq;
NDIS_STATUS ReqStatus;
IF_LOUD(DbgPrint("NPF: OpenAdapterComplete\n");)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
//
// get the open irp
//
Irp=Open->OpenCloseIrp;
if (Status != NDIS_STATUS_SUCCESS) {
IF_LOUD(DbgPrint("NPF: OpenAdapterComplete-FAILURE\n");)
NdisFreePacketPool(Open->PacketPool);
//free mem_ex
Open->mem_ex.size = 0;
if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
ExFreePool(Open->ReadEventName.Buffer);
ZwClose(Open->ReadEventHandle);
ExFreePool(Open);
}
else {
NdisAcquireSpinLock(&Opened_Instances_Lock);
n_Opened_Instances++;
NdisReleaseSpinLock(&Opened_Instances_Lock);
IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances);)
// Get the absolute value of the system boot time.
// This is used for timestamp conversion.
TIME_SYNCHRONIZE(&G_Start_Time);
// Extract a request from the list of free ones
RequestListEntry=ExInterlockedRemoveHeadList(&Open->RequestList, &Open->RequestSpinLock);
if (RequestListEntry == NULL)
{
Open->MaxFrameSize = 1600; // Assume Ethernet
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return;
}
MaxSizeReq = CONTAINING_RECORD(RequestListEntry, INTERNAL_REQUEST, ListElement);
MaxSizeReq->Irp = Irp;
MaxSizeReq->Internal = TRUE;
MaxSizeReq->Request.RequestType = NdisRequestQueryInformation;
MaxSizeReq->Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBuffer = &Open->MaxFrameSize;
MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
// submit the request
NdisRequest(
&ReqStatus,
Open->AdapterHandle,
&MaxSizeReq->Request);
if (ReqStatus != NDIS_STATUS_PENDING) {
NPF_RequestComplete(Open, &MaxSizeReq->Request, ReqStatus);
}
return;
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return;
}
//-------------------------------------------------------------------
NTSTATUS
NPF_Close(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
POPEN_INSTANCE Open;
NDIS_STATUS Status;
PIO_STACK_LOCATION IrpSp;
LARGE_INTEGER ThreadDelay;
IF_LOUD(DbgPrint("NPF: CloseAdapter\n");)
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Open=IrpSp->FileObject->FsContext;
// Reset the buffer size. This tells the dump thread to stop.
// Open->BufSize = 0;
if( Open->Bound == FALSE){
NdisWaitEvent(&Open->IOEvent,10000);
// Free the filter if it's present
if(Open->bpfprogram != NULL)
ExFreePool(Open->bpfprogram);
//
// Jitted filters are supported on x86 (32bit) only
//
#ifdef __NPF_x86__
// Free the jitted filter if it's present
if(Open->Filter != NULL)
BPF_Destroy_JIT_Filter(Open->Filter);
#endif
//free the buffer
// Open->BufSize=0;
// if(Open->Buffer != NULL)ExFreePool(Open->Buffer);
if (Open->Size > 0)
ExFreePool(Open->CpuData[0].Buffer);
//free mem_ex
Open->mem_ex.size = 0;
if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
NdisFreePacketPool(Open->PacketPool);
// Free the string with the name of the dump file
if(Open->DumpFileName.Buffer!=NULL)
ExFreePool(Open->DumpFileName.Buffer);
ExFreePool(Open->ReadEventName.Buffer);
ExFreePool(Open);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_SUCCESS);
}
// Unfreeze the consumer
if(Open->mode & MODE_DUMP)
NdisSetEvent(&Open->DumpEvent);
else
KeSetEvent(Open->ReadEvent,0,FALSE);
// Save the IRP
Open->OpenCloseIrp = Irp;
IoMarkIrpPending(Irp);
// If this instance is in dump mode, complete the dump and close the file
if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL){
NTSTATUS wres;
ThreadDelay.QuadPart = -50000000;
// Wait the completion of the thread
wres = KeWaitForSingleObject(Open->DumpThreadObject,
UserRequest,
KernelMode,
TRUE,
&ThreadDelay);
ObDereferenceObject(Open->DumpThreadObject);
// Flush and close the dump file
NPF_CloseDumpFile(Open);
}
// Destroy the read Event
ZwClose(Open->ReadEventHandle);
// Close the adapter
NdisCloseAdapter(
&Status,
Open->AdapterHandle
);
if (Status != NDIS_STATUS_PENDING) {
NPF_CloseAdapterComplete(
Open,
Status
);
return STATUS_SUCCESS;
}
return(STATUS_PENDING);
}
//-------------------------------------------------------------------
VOID
NPF_CloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status)
{
POPEN_INSTANCE Open;
PIRP Irp;
IF_LOUD(DbgPrint("NPF: CloseAdapterComplete\n");)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
// free the allocated structures only if the instance is still bound to the adapter
if(Open->Bound == TRUE){
// Free the filter if it's present
if(Open->bpfprogram != NULL)
ExFreePool(Open->bpfprogram);
//
// Jitted filters are supported on x86 (32bit) only
//
#ifdef __NPF_x86__
// Free the jitted filter if it's present
if(Open->Filter != NULL)
BPF_Destroy_JIT_Filter(Open->Filter);
#endif // __NPF_x86__
//free the buffer
// Open->BufSize = 0;
// if(Open->Buffer!=NULL)ExFreePool(Open->Buffer);
if (Open->Size > 0)
ExFreePool(Open->CpuData[0].Buffer);
//free mem_ex
Open->mem_ex.size = 0;
if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
NdisFreePacketPool(Open->PacketPool);
Irp=Open->OpenCloseIrp;
// Free the string with the name of the dump file
if(Open->DumpFileName.Buffer!=NULL)
ExFreePool(Open->DumpFileName.Buffer);
ExFreePool(Open->ReadEventName.Buffer);
ExFreePool(Open);
// Complete the request only if the instance is still bound to the adapter
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
else
NdisSetEvent(&Open->IOEvent);
// Decrease the counter of open instances
NdisAcquireSpinLock(&Opened_Instances_Lock);
n_Opened_Instances--;
NdisReleaseSpinLock(&Opened_Instances_Lock);
IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances);)
if(n_Opened_Instances == 0){
// Force a synchronization at the next NPF_Open().
// This hopefully avoids the synchronization issues caused by hibernation or standby.
TIME_DESYNCHRONIZE(&G_Start_Time);
}
return;
}
//-------------------------------------------------------------------
#ifdef NDIS50
NDIS_STATUS
NPF_PowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent)
{
IF_LOUD(DbgPrint("NPF: PowerChange\n");)
TIME_DESYNCHRONIZE(&G_Start_Time);
TIME_SYNCHRONIZE(&G_Start_Time);
return STATUS_SUCCESS;
}
#endif
//-------------------------------------------------------------------
VOID
NPF_BindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING DeviceName,
IN PVOID SystemSpecific1,
IN PVOID SystemSpecific2
)
{
IF_LOUD(DbgPrint("NPF: NPF_BindAdapter\n");)
}
//-------------------------------------------------------------------
VOID
NPF_UnbindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE UnbindContext
)
{
POPEN_INSTANCE Open =(POPEN_INSTANCE)ProtocolBindingContext;
NDIS_STATUS lStatus;
IF_LOUD(DbgPrint("NPF: NPF_UnbindAdapter\n");)
// Reset the buffer size. This tells the dump thread to stop.
// Open->BufSize=0;
NdisResetEvent(&Open->IOEvent);
// This open instance is no more bound to the adapter, set Bound to False
InterlockedExchange( (PLONG) &Open->Bound, FALSE );
// Awake a possible pending read on this instance
if(Open->mode & MODE_DUMP)
NdisSetEvent(&Open->DumpEvent);
else
KeSetEvent(Open->ReadEvent,0,FALSE);
// If this instance is in dump mode, complete the dump and close the file
if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL)
NPF_CloseDumpFile(Open);
// Destroy the read Event
ZwClose(Open->ReadEventHandle);
// close the adapter
NdisCloseAdapter(
&lStatus,
Open->AdapterHandle
);
if (lStatus != NDIS_STATUS_PENDING) {
NPF_CloseAdapterComplete(
Open,
lStatus
);
*Status = NDIS_STATUS_SUCCESS;
return;
}
*Status = NDIS_STATUS_SUCCESS;
return;
}
//-------------------------------------------------------------------
VOID
NPF_ResetComplete(IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_STATUS Status)
{
POPEN_INSTANCE Open;
PIRP Irp;
PLIST_ENTRY ResetListEntry;
IF_LOUD(DbgPrint("NPF: PacketResetComplete\n");)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
//
// remove the reset IRP from the list
//
ResetListEntry=ExInterlockedRemoveHeadList(
&Open->ResetIrpList,
&Open->RequestSpinLock
);
#if DBG
if (ResetListEntry == NULL) {
DbgBreakPoint();
return;
}
#endif
Irp=CONTAINING_RECORD(ResetListEntry,IRP,Tail.Overlay.ListEntry);
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
IF_LOUD(DbgPrint("NPF: PacketResetComplete exit\n");)
return;
}