2014-01-04 17:00:08 +04:00
|
|
|
// SoftEther VPN Source Code
|
|
|
|
// SeLow: SoftEther Lightweight Network Protocol
|
|
|
|
//
|
|
|
|
// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
|
|
|
|
//
|
|
|
|
// Copyright (c) 2012-2014 Daiyuu Nobori.
|
|
|
|
// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
|
|
|
|
// Copyright (c) 2012-2014 SoftEther Corporation.
|
|
|
|
//
|
|
|
|
// All Rights Reserved.
|
|
|
|
//
|
|
|
|
// http://www.softether.org/
|
|
|
|
//
|
|
|
|
// Author: Daiyuu Nobori
|
|
|
|
// Comments: Tetsuo Sugiyama, Ph.D.
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
|
|
|
// version 2 as published by the Free Software Foundation.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License version 2
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
|
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
|
|
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
//
|
|
|
|
// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
|
|
|
|
// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
|
|
|
|
// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
|
|
|
|
// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
|
|
|
|
// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
|
|
|
|
// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
|
|
|
|
// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
|
|
|
|
// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
|
|
|
|
// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
|
|
|
|
// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
|
|
|
|
// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
|
|
|
|
// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
|
|
|
|
// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
|
|
|
|
// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
|
|
|
|
// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
|
|
|
|
//
|
|
|
|
// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
|
|
|
|
// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
|
|
|
|
// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
|
|
|
|
// COUNTRIES MIGHT BE RESTRICTED.
|
|
|
|
//
|
|
|
|
//
|
2014-01-15 13:01:42 +04:00
|
|
|
// SOURCE CODE CONTRIBUTION
|
|
|
|
// ------------------------
|
|
|
|
//
|
|
|
|
// Your contribution to SoftEther VPN Project is much appreciated.
|
|
|
|
// Please send patches to us through GitHub.
|
|
|
|
// Read the SoftEther VPN Patch Acceptance Policy in advance:
|
|
|
|
// http://www.softether.org/5-download/src/9.patch
|
|
|
|
//
|
|
|
|
//
|
2014-01-04 17:00:08 +04:00
|
|
|
// DEAR SECURITY EXPERTS
|
|
|
|
// ---------------------
|
|
|
|
//
|
|
|
|
// If you find a bug or a security vulnerability please kindly inform us
|
|
|
|
// about the problem immediately so that we can fix the security problem
|
|
|
|
// to protect a lot of users around the world as soon as possible.
|
|
|
|
//
|
|
|
|
// Our e-mail address for security reports is:
|
|
|
|
// softether-vpn-security [at] softether.org
|
|
|
|
//
|
|
|
|
// Please note that the above e-mail address is not a technical support
|
|
|
|
// inquiry address. If you need technical assistance, please visit
|
|
|
|
// http://www.softether.org/ and ask your question on the users forum.
|
|
|
|
//
|
|
|
|
// Thank you for your cooperation.
|
2014-03-20 00:45:05 +04:00
|
|
|
//
|
|
|
|
//
|
|
|
|
// NO MEMORY OR RESOURCE LEAKS
|
|
|
|
// ---------------------------
|
|
|
|
//
|
|
|
|
// The memory-leaks and resource-leaks verification under the stress
|
|
|
|
// test has been passed before release this source code.
|
2014-01-04 17:00:08 +04:00
|
|
|
|
|
|
|
|
|
|
|
// SeLow.c
|
|
|
|
// SeLow Device Driver
|
|
|
|
|
|
|
|
#include <GlobalConst.h>
|
|
|
|
|
|
|
|
#define SELOW_DEVICE_DRIVER
|
|
|
|
|
|
|
|
#include "SeLow.h"
|
|
|
|
|
|
|
|
static SL_CTX sl_ctx = {0};
|
|
|
|
static SL_CTX *sl = &sl_ctx;
|
|
|
|
|
|
|
|
// Win32 driver entry point
|
|
|
|
NDIS_STATUS DriverEntry(DRIVER_OBJECT *driver_object, UNICODE_STRING *registry_path)
|
|
|
|
{
|
|
|
|
NDIS_PROTOCOL_DRIVER_CHARACTERISTICS t;
|
|
|
|
NDIS_STATUS ret = NDIS_STATUS_FAILURE;
|
|
|
|
SL_UNICODE *protocol_name = NULL;
|
|
|
|
NDIS_HANDLE protocol_handle = NULL;
|
|
|
|
SL_CTX *sl_ctx = NULL;
|
|
|
|
DEVICE_OBJECT *device_object = NULL;
|
|
|
|
|
|
|
|
SlZero(sl, sizeof(SL_CTX));
|
|
|
|
|
|
|
|
// Register the NDIS protocol
|
|
|
|
protocol_name = SlNewUnicode(SL_PROTOCOL_NAME);
|
|
|
|
if (protocol_name == NULL)
|
|
|
|
{
|
|
|
|
goto LABEL_CLEANUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
SlZero(&t, sizeof(t));
|
|
|
|
t.Header.Type = NDIS_OBJECT_TYPE_PROTOCOL_DRIVER_CHARACTERISTICS;
|
|
|
|
t.Header.Revision = NDIS_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_2;
|
|
|
|
t.Header.Size = NDIS_SIZEOF_PROTOCOL_DRIVER_CHARACTERISTICS_REVISION_2;
|
|
|
|
t.MajorNdisVersion = 6;
|
|
|
|
t.MinorNdisVersion = 20;
|
|
|
|
t.Name = protocol_name->String;
|
|
|
|
|
|
|
|
t.BindAdapterHandlerEx = SlNdisBindAdapterExProc;
|
|
|
|
t.UnbindAdapterHandlerEx = SlNdisUnbindAdapterExProc;
|
|
|
|
t.OpenAdapterCompleteHandlerEx = SlNdisOpenAdapterCompleteExProc;
|
|
|
|
t.CloseAdapterCompleteHandlerEx = SlNdisCloseAdapterCompleteExProc;
|
|
|
|
t.NetPnPEventHandler = SlNdisNetPnPEventProc;
|
|
|
|
t.UninstallHandler = SlNdisUninstallProc;
|
|
|
|
t.OidRequestCompleteHandler = SlNdisOidRequestCompleteProc;
|
|
|
|
t.StatusHandlerEx = SlNdisStatusExProc;
|
|
|
|
t.ReceiveNetBufferListsHandler = SlNdisReceiveNetBufferListsProc;
|
|
|
|
t.SendNetBufferListsCompleteHandler = SlNdisSendNetBufferListsCompleteProc;
|
|
|
|
|
|
|
|
// Create an adapters list
|
|
|
|
sl->DriverObject = driver_object;
|
|
|
|
sl->AdapterList = SlNewList();
|
|
|
|
|
|
|
|
ret = NdisRegisterProtocolDriver(NULL, &t, &protocol_handle);
|
|
|
|
|
|
|
|
if (NG(ret))
|
|
|
|
{
|
|
|
|
protocol_handle = NULL;
|
|
|
|
goto LABEL_CLEANUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
SlZero(driver_object->MajorFunction, sizeof(driver_object->MajorFunction));
|
|
|
|
driver_object->MajorFunction[IRP_MJ_CREATE] = SlDeviceOpenProc;
|
|
|
|
driver_object->MajorFunction[IRP_MJ_CLOSE] = SlDeviceCloseProc;
|
|
|
|
driver_object->MajorFunction[IRP_MJ_READ] = SlDeviceReadProc;
|
|
|
|
driver_object->MajorFunction[IRP_MJ_WRITE] = SlDeviceWriteProc;
|
|
|
|
driver_object->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SlDeviceIoControlProc;
|
|
|
|
driver_object->DriverUnload = SlUnloadProc;
|
|
|
|
|
|
|
|
// Initialize the SL context
|
|
|
|
sl->ProtocolHandle = protocol_handle;
|
|
|
|
|
|
|
|
// Create a basic device
|
|
|
|
sl->BasicDevice = SlNewDevice(SL_BASIC_DEVICE_NAME, SL_BASIC_DEVICE_NAME_SYMBOLIC);
|
|
|
|
if (sl->BasicDevice == NULL)
|
|
|
|
{
|
|
|
|
ret = NDIS_STATUS_FAILURE;
|
|
|
|
goto LABEL_CLEANUP;
|
|
|
|
}
|
|
|
|
sl->BasicDevice->IsBasicDevice = true;
|
|
|
|
|
|
|
|
LABEL_CLEANUP:
|
|
|
|
|
|
|
|
SlFreeUnicode(protocol_name);
|
|
|
|
|
|
|
|
if (NG(ret))
|
|
|
|
{
|
|
|
|
SlUnloadProc(driver_object);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unloading procedure of the device driver
|
|
|
|
void SlUnloadProc(DRIVER_OBJECT *driver_object)
|
|
|
|
{
|
|
|
|
// Release the protocol
|
|
|
|
if (sl->ProtocolHandle != NULL)
|
|
|
|
{
|
|
|
|
NdisDeregisterProtocolDriver(sl->ProtocolHandle);
|
|
|
|
sl->ProtocolHandle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the basic device
|
|
|
|
SlFreeDevice(sl->BasicDevice);
|
|
|
|
|
|
|
|
// Release the adapter list
|
|
|
|
SlFreeList(sl->AdapterList);
|
|
|
|
|
|
|
|
// Initialize the SL context
|
|
|
|
SlZero(sl, sizeof(SL_CTX));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete a device
|
|
|
|
void SlFreeDevice(SL_DEVICE *dev)
|
|
|
|
{
|
|
|
|
NTSTATUS r;
|
|
|
|
// Validate arguments
|
|
|
|
if (dev == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = IoDeleteSymbolicLink(&dev->SymbolicLinkName->String);
|
|
|
|
if (NG(r))
|
|
|
|
{
|
|
|
|
// May fail due to a bug in Windows Kernel
|
|
|
|
}
|
|
|
|
|
|
|
|
IoDeleteDevice(dev->DeviceObject);
|
|
|
|
|
|
|
|
SlFreeUnicode(dev->DeviceName);
|
|
|
|
SlFreeUnicode(dev->SymbolicLinkName);
|
|
|
|
|
|
|
|
SlFreeLock(dev->OpenCloseLock);
|
|
|
|
|
|
|
|
SlFree(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new device
|
|
|
|
SL_DEVICE *SlNewDevice(char *device_name, char *symbolic_link_name)
|
|
|
|
{
|
|
|
|
SL_UNICODE *u_device_name = SlNewUnicode(device_name);
|
|
|
|
SL_UNICODE *u_sym_name = SlNewUnicode(symbolic_link_name);
|
|
|
|
|
|
|
|
SL_DEVICE *ret = SlNewDeviceUnicode(u_device_name, u_sym_name);
|
|
|
|
|
|
|
|
if (ret == NULL)
|
|
|
|
{
|
|
|
|
SlFreeUnicode(u_device_name);
|
|
|
|
SlFreeUnicode(u_sym_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
SL_DEVICE *SlNewDeviceUnicode(SL_UNICODE *u_device_name, SL_UNICODE *u_sym_name)
|
|
|
|
{
|
|
|
|
SL_DEVICE *ret = NULL;
|
|
|
|
DEVICE_OBJECT *dev_obj = NULL;
|
|
|
|
NTSTATUS r;
|
|
|
|
SL_UNICODE *sddl;
|
|
|
|
|
|
|
|
sddl = SlNewUnicode("D:P(A;;GA;;;SY)(A;;GA;;;BA)");
|
|
|
|
|
|
|
|
/*r = IoCreateDevice(sl->DriverObject, sizeof(SL_DEVICE *),
|
|
|
|
&u_device_name->String, FILE_DEVICE_TRANSPORT, 0, false, &dev_obj);*/
|
|
|
|
|
|
|
|
r = IoCreateDeviceSecure(sl->DriverObject, sizeof(SL_DEVICE *),
|
|
|
|
&u_device_name->String, FILE_DEVICE_TRANSPORT, 0, false, SlGetUnicode(sddl),
|
|
|
|
NULL, &dev_obj);
|
|
|
|
|
|
|
|
SlFreeUnicode(sddl);
|
|
|
|
|
|
|
|
if (NG(r))
|
|
|
|
{
|
|
|
|
dev_obj = NULL;
|
|
|
|
goto LABEL_CLEANUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = IoCreateSymbolicLink(&u_sym_name->String, &u_device_name->String);
|
|
|
|
if (NG(r))
|
|
|
|
{
|
|
|
|
// May fail due to a bug in Windows Kernel
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = SlZeroMalloc(sizeof(SL_DEVICE));
|
|
|
|
if (ret == NULL)
|
|
|
|
{
|
|
|
|
goto LABEL_CLEANUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret->DeviceObject = dev_obj;
|
|
|
|
ret->DeviceName = u_device_name;
|
|
|
|
ret->SymbolicLinkName = u_sym_name;
|
|
|
|
*((SL_DEVICE **)dev_obj->DeviceExtension) = ret;
|
|
|
|
|
|
|
|
dev_obj->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
|
|
|
|
ret->OpenCloseLock = SlNewLock();
|
|
|
|
|
|
|
|
LABEL_CLEANUP:
|
|
|
|
if (ret == NULL)
|
|
|
|
{
|
|
|
|
if (dev_obj != NULL)
|
|
|
|
{
|
|
|
|
IoDeleteDevice(dev_obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Device is opened
|
|
|
|
NTSTATUS SlDeviceOpenProc(DEVICE_OBJECT *device_object, IRP *irp)
|
|
|
|
{
|
|
|
|
SL_DEVICE *dev = *((SL_DEVICE **)device_object->DeviceExtension);
|
|
|
|
NTSTATUS ret = STATUS_UNSUCCESSFUL;
|
|
|
|
IO_STACK_LOCATION *irp_stack = IoGetCurrentIrpStackLocation(irp);
|
|
|
|
|
|
|
|
if (dev->IsBasicDevice)
|
|
|
|
{
|
|
|
|
// Basic device
|
|
|
|
ret = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bool set_promisc = false;
|
|
|
|
volatile UINT *num_pending_oid_requests = NULL;
|
|
|
|
UINT64 v;
|
|
|
|
char event_name[SL_EVENT_NAME_SIZE];
|
|
|
|
char event_name_win32[SL_EVENT_NAME_SIZE];
|
|
|
|
SL_EVENT *event_object = NULL;
|
|
|
|
LARGE_INTEGER count;
|
|
|
|
LARGE_INTEGER freq;
|
|
|
|
|
|
|
|
count = KeQueryPerformanceCounter(&freq);
|
|
|
|
|
|
|
|
InterlockedIncrement(&sl->IntCounter1);
|
|
|
|
|
|
|
|
// Create a new event object
|
|
|
|
v = (UINT64)device_object + (UINT64)(++sl->IntCounter1) + *((UINT64 *)(&count));
|
|
|
|
sprintf(event_name, SL_EVENT_NAME, (UINT)v, (UINT)(v >> 32) + sl->IntCounter1);
|
|
|
|
sprintf(event_name_win32, SL_EVENT_NAME_WIN32, (UINT)v, (UINT)(v >> 32) + sl->IntCounter1);
|
|
|
|
event_object = SlNewEvent(event_name);
|
|
|
|
|
|
|
|
SlLock(dev->OpenCloseLock);
|
|
|
|
{
|
|
|
|
// Add to the opened file list
|
|
|
|
SlLockList(dev->FileList);
|
|
|
|
{
|
|
|
|
if (dev->Halting == false && dev->Adapter != NULL && dev->Adapter->Ready && dev->Adapter->Halt == false)
|
|
|
|
{
|
|
|
|
// Adapter device
|
|
|
|
SL_FILE *f = SlZeroMalloc(sizeof(SL_FILE));
|
|
|
|
NET_BUFFER_LIST_POOL_PARAMETERS p;
|
|
|
|
|
|
|
|
f->Device = dev;
|
|
|
|
f->Adapter = dev->Adapter;
|
|
|
|
f->FileObject = irp_stack->FileObject;
|
|
|
|
|
|
|
|
irp_stack->FileObject->FsContext = f;
|
|
|
|
|
|
|
|
SlAdd(dev->FileList, f);
|
|
|
|
|
|
|
|
ret = STATUS_SUCCESS;
|
|
|
|
set_promisc = true;
|
|
|
|
|
|
|
|
// Event
|
|
|
|
f->Event = event_object;
|
|
|
|
event_object = NULL;
|
|
|
|
strcpy(f->EventNameWin32, event_name_win32);
|
|
|
|
|
|
|
|
// Create a lock
|
|
|
|
f->RecvLock = SlNewLock();
|
|
|
|
|
|
|
|
// Create a NET_BUFFER_LIST pool
|
|
|
|
SlZero(&p, sizeof(p));
|
|
|
|
p.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
|
|
|
|
p.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
|
|
|
|
p.Header.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
|
|
|
|
p.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
|
|
|
|
p.fAllocateNetBuffer = true;
|
|
|
|
p.ContextSize = 32;
|
|
|
|
p.DataSize = SL_MAX_PACKET_SIZE;
|
|
|
|
|
|
|
|
f->NetBufferListPool = NdisAllocateNetBufferListPool(NULL, &p);
|
|
|
|
|
|
|
|
num_pending_oid_requests = &dev->Adapter->NumPendingOidRequests;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SlUnlockList(dev->FileList);
|
|
|
|
}
|
|
|
|
SlUnlock(dev->OpenCloseLock);
|
|
|
|
|
|
|
|
if (event_object != NULL)
|
|
|
|
{
|
|
|
|
SlFreeEvent(event_object);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (set_promisc)
|
|
|
|
{
|
|
|
|
// Enable promiscuous mode
|
|
|
|
UINT filter = NDIS_PACKET_TYPE_PROMISCUOUS;
|
|
|
|
SlSendOidRequest(dev->Adapter, true, OID_GEN_CURRENT_PACKET_FILTER, &filter, sizeof(filter));
|
|
|
|
|
|
|
|
// Wait until the number of OID requests being processed becomes 0
|
|
|
|
while ((*num_pending_oid_requests) != 0)
|
|
|
|
{
|
|
|
|
SlSleep(50);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
irp->IoStatus.Status = ret;
|
|
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send an OID request to the device
|
|
|
|
void SlSendOidRequest(SL_ADAPTER *a, bool set, NDIS_OID oid, void *data, UINT size)
|
|
|
|
{
|
|
|
|
NDIS_OID_REQUEST *t;
|
|
|
|
NDIS_STATUS ret;
|
|
|
|
// Validate arguments
|
|
|
|
if (a == NULL || data == NULL || size == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a->Halt == false)
|
|
|
|
{
|
|
|
|
bool ok = false;
|
|
|
|
|
|
|
|
t = SlZeroMalloc(sizeof(NDIS_OID_REQUEST));
|
|
|
|
|
|
|
|
t->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
|
|
|
|
t->Header.Revision = NDIS_OID_REQUEST_REVISION_1;
|
|
|
|
t->Header.Size = NDIS_SIZEOF_OID_REQUEST_REVISION_1;
|
|
|
|
|
|
|
|
if (set == false)
|
|
|
|
{
|
|
|
|
t->RequestType = NdisRequestQueryInformation;
|
|
|
|
t->DATA.QUERY_INFORMATION.Oid = oid;
|
|
|
|
t->DATA.QUERY_INFORMATION.InformationBuffer = data;
|
|
|
|
t->DATA.QUERY_INFORMATION.InformationBufferLength = size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
t->RequestType = NdisRequestSetInformation;
|
|
|
|
t->DATA.SET_INFORMATION.Oid = oid;
|
|
|
|
t->DATA.SET_INFORMATION.InformationBuffer = SlClone(data, size);
|
|
|
|
t->DATA.SET_INFORMATION.InformationBufferLength = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
SlLock(a->Lock);
|
|
|
|
{
|
|
|
|
if (a->AdapterHandle != NULL && a->Halt == false)
|
|
|
|
{
|
|
|
|
InterlockedIncrement(&a->NumPendingOidRequests);
|
|
|
|
ok = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SlUnlock(a->Lock);
|
|
|
|
|
|
|
|
if (ok)
|
|
|
|
{
|
|
|
|
ret = NdisOidRequest(a->AdapterHandle, t);
|
|
|
|
|
|
|
|
if (ret != NDIS_STATUS_PENDING)
|
|
|
|
{
|
|
|
|
InterlockedDecrement(&a->NumPendingOidRequests);
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
SlFree(t->DATA.SET_INFORMATION.InformationBuffer);
|
|
|
|
}
|
|
|
|
SlFree(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
SlFree(t->DATA.SET_INFORMATION.InformationBuffer);
|
|
|
|
}
|
|
|
|
SlFree(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Device is closed
|
|
|
|
NTSTATUS SlDeviceCloseProc(DEVICE_OBJECT *device_object, IRP *irp)
|
|
|
|
{
|
|
|
|
SL_DEVICE *dev = *((SL_DEVICE **)device_object->DeviceExtension);
|
|
|
|
NTSTATUS ret = STATUS_UNSUCCESSFUL;
|
|
|
|
IO_STACK_LOCATION *irp_stack = IoGetCurrentIrpStackLocation(irp);
|
|
|
|
|
|
|
|
if (dev->IsBasicDevice)
|
|
|
|
{
|
|
|
|
// Basic device
|
|
|
|
ret = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Adapter device
|
|
|
|
SL_FILE *f = irp_stack->FileObject->FsContext;
|
|
|
|
|
|
|
|
if (f != NULL)
|
|
|
|
{
|
|
|
|
bool clear_filter = false;
|
|
|
|
|
|
|
|
// Wait until the number of packet being sent becomes the zero
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
if (f->NumSendingPacketets == 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SlSleep(50);
|
|
|
|
}
|
|
|
|
|
|
|
|
SlLock(dev->OpenCloseLock);
|
|
|
|
{
|
|
|
|
// Delete the file from the list
|
|
|
|
SlLockList(dev->FileList);
|
|
|
|
{
|
|
|
|
SlDelete(dev->FileList, f);
|
|
|
|
|
|
|
|
if (SL_LIST_NUM(dev->FileList) == 0)
|
|
|
|
{
|
|
|
|
// Clear the filter when all files are closed
|
|
|
|
clear_filter = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SlUnlockList(dev->FileList);
|
|
|
|
|
|
|
|
if (dev->Adapter->Halt)
|
|
|
|
{
|
|
|
|
clear_filter = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clear_filter)
|
|
|
|
{
|
|
|
|
InterlockedIncrement(&dev->Adapter->NumPendingOidRequests);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SlUnlock(dev->OpenCloseLock);
|
|
|
|
|
|
|
|
if (clear_filter)
|
|
|
|
{
|
|
|
|
// Clear the filter when all files are closed
|
|
|
|
UINT filter = 0;
|
|
|
|
SlSendOidRequest(dev->Adapter, true, OID_GEN_CURRENT_PACKET_FILTER, &filter, sizeof(filter));
|
|
|
|
InterlockedDecrement(&dev->Adapter->NumPendingOidRequests);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the event
|
|
|
|
SlFreeEvent(f->Event);
|
|
|
|
|
|
|
|
// Release the receive queue
|
|
|
|
if (true)
|
|
|
|
{
|
|
|
|
SL_PACKET *p = f->RecvPacketHead;
|
|
|
|
|
|
|
|
while (p != NULL)
|
|
|
|
{
|
|
|
|
SL_PACKET *p_next = p->Next;
|
|
|
|
|
|
|
|
SlFree(p);
|
|
|
|
|
|
|
|
p = p_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the NET_BUFFER_LIST pool
|
|
|
|
NdisFreeNetBufferListPool(f->NetBufferListPool);
|
|
|
|
|
|
|
|
// Release the lock
|
|
|
|
SlFreeLock(f->RecvLock);
|
|
|
|
|
|
|
|
SlFree(f);
|
|
|
|
|
|
|
|
ret = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
irp->IoStatus.Status = ret;
|
|
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read procedure of the device
|
|
|
|
NTSTATUS SlDeviceReadProc(DEVICE_OBJECT *device_object, IRP *irp)
|
|
|
|
{
|
|
|
|
SL_DEVICE *dev = *((SL_DEVICE **)device_object->DeviceExtension);
|
|
|
|
NTSTATUS ret = STATUS_UNSUCCESSFUL;
|
|
|
|
UINT ret_size = 0;
|
|
|
|
IO_STACK_LOCATION *irp_stack = IoGetCurrentIrpStackLocation(irp);
|
|
|
|
|
|
|
|
if (dev->IsBasicDevice)
|
|
|
|
{
|
|
|
|
// Return the adapter list in the case of basic device
|
|
|
|
if (irp_stack->Parameters.Read.Length >= sizeof(SL_ADAPTER_INFO_LIST))
|
|
|
|
{
|
|
|
|
SL_ADAPTER_INFO_LIST *dst = irp->UserBuffer;
|
|
|
|
|
|
|
|
if (dst != NULL)
|
|
|
|
{
|
|
|
|
MDL *mdl;
|
|
|
|
|
|
|
|
mdl = IoAllocateMdl(dst, irp_stack->Parameters.Read.Length, false, false, NULL);
|
|
|
|
if (mdl != NULL)
|
|
|
|
{
|
|
|
|
MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
SlZero(dst, sizeof(SL_ADAPTER_INFO_LIST));
|
|
|
|
|
|
|
|
dst->Signature = SL_SIGNATURE;
|
|
|
|
dst->SeLowVersion = SL_VER;
|
|
|
|
dst->EnumCompleted = sl->IsEnumCompleted ? 8 : 1;
|
|
|
|
|
|
|
|
SlLockList(sl->AdapterList);
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
|
|
|
|
dst->NumAdapters = MIN(SL_LIST_NUM(sl->AdapterList), SL_MAX_ADAPTER_INFO_LIST_ENTRY);
|
|
|
|
|
|
|
|
for (i = 0;i < dst->NumAdapters;i++)
|
|
|
|
{
|
|
|
|
SL_ADAPTER *a = SL_LIST_DATA(sl->AdapterList, i);
|
|
|
|
SL_ADAPTER_INFO *d = &dst->Adapters[i];
|
|
|
|
|
|
|
|
d->MtuSize = a->MtuSize;
|
|
|
|
SlCopy(d->MacAddress, a->MacAddress, 6);
|
|
|
|
SlCopy(d->AdapterId, a->AdapterId, sizeof(a->AdapterId));
|
|
|
|
strcpy(d->FriendlyName, a->FriendlyName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SlUnlockList(sl->AdapterList);
|
|
|
|
|
|
|
|
ret_size = sizeof(SL_ADAPTER_INFO);
|
|
|
|
ret = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
if (mdl != NULL)
|
|
|
|
{
|
|
|
|
MmUnlockPages(mdl);
|
|
|
|
IoFreeMdl(mdl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Adapter device
|
|
|
|
SL_FILE *f = irp_stack->FileObject->FsContext;
|
|
|
|
|
|
|
|
if (irp_stack->Parameters.Read.Length == SL_EXCHANGE_BUFFER_SIZE)
|
|
|
|
{
|
|
|
|
UCHAR *buf = irp->UserBuffer;
|
|
|
|
|
|
|
|
if (dev->Halting || f->Adapter->Halt || buf == NULL)
|
|
|
|
{
|
|
|
|
// Halting
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
UINT num = 0;
|
|
|
|
bool left = true;
|
|
|
|
MDL *mdl;
|
|
|
|
|
|
|
|
mdl = IoAllocateMdl(buf, SL_EXCHANGE_BUFFER_SIZE, false, false, NULL);
|
|
|
|
if (mdl != NULL)
|
|
|
|
{
|
|
|
|
MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lock the receive queue
|
|
|
|
SlLock(f->RecvLock);
|
|
|
|
{
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
SL_PACKET *q;
|
|
|
|
if (num >= SL_MAX_PACKET_EXCHANGE)
|
|
|
|
{
|
|
|
|
if (f->RecvPacketHead == NULL)
|
|
|
|
{
|
|
|
|
left = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
q = f->RecvPacketHead;
|
|
|
|
if (q != NULL)
|
|
|
|
{
|
|
|
|
f->RecvPacketHead = f->RecvPacketHead->Next;
|
|
|
|
q->Next = NULL;
|
|
|
|
f->NumRecvPackets--;
|
|
|
|
|
|
|
|
if (f->RecvPacketHead == NULL)
|
|
|
|
{
|
|
|
|
f->RecvPacketTail = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
left = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SL_SIZE_OF_PACKET(buf, num) = q->Size;
|
|
|
|
SlCopy(SL_ADDR_OF_PACKET(buf, num), q->Data, q->Size);
|
|
|
|
num++;
|
|
|
|
SlFree(q);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SlUnlock(f->RecvLock);
|
|
|
|
|
|
|
|
if (mdl != NULL)
|
|
|
|
{
|
|
|
|
MmUnlockPages(mdl);
|
|
|
|
IoFreeMdl(mdl);
|
|
|
|
}
|
|
|
|
|
|
|
|
SL_NUM_PACKET(buf) = num;
|
|
|
|
SL_LEFT_FLAG(buf) = left;
|
|
|
|
|
|
|
|
if (left == false)
|
|
|
|
{
|
|
|
|
SlReset(f->Event);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SlSet(f->Event);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = STATUS_SUCCESS;
|
|
|
|
ret_size = SL_EXCHANGE_BUFFER_SIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
irp->IoStatus.Status = ret;
|
|
|
|
irp->IoStatus.Information = ret_size;
|
|
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write procedure of the device
|
|
|
|
NTSTATUS SlDeviceWriteProc(DEVICE_OBJECT *device_object, IRP *irp)
|
|
|
|
{
|
|
|
|
SL_DEVICE *dev = *((SL_DEVICE **)device_object->DeviceExtension);
|
|
|
|
NTSTATUS ret = STATUS_UNSUCCESSFUL;
|
|
|
|
IO_STACK_LOCATION *irp_stack = IoGetCurrentIrpStackLocation(irp);
|
|
|
|
UINT ret_size = 0;
|
|
|
|
|
|
|
|
if (dev->IsBasicDevice == false)
|
|
|
|
{
|
|
|
|
// Adapter device
|
|
|
|
SL_FILE *f = irp_stack->FileObject->FsContext;
|
|
|
|
|
|
|
|
if (irp_stack->Parameters.Write.Length == SL_EXCHANGE_BUFFER_SIZE)
|
|
|
|
{
|
|
|
|
UCHAR *buf = irp->UserBuffer;
|
|
|
|
|
|
|
|
if (dev->Halting || dev->Adapter->Halt || buf == NULL)
|
|
|
|
{
|
|
|
|
// Halting
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Write the packet
|
|
|
|
MDL *mdl;
|
|
|
|
UINT num = SL_NUM_PACKET(buf);
|
|
|
|
|
|
|
|
mdl = IoAllocateMdl(buf, SL_EXCHANGE_BUFFER_SIZE, false, false, NULL);
|
|
|
|
if (mdl != NULL)
|
|
|
|
{
|
|
|
|
MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
ret_size = SL_EXCHANGE_BUFFER_SIZE;
|
|
|
|
|
|
|
|
if (num >= 1 && num <= SL_MAX_PACKET_EXCHANGE)
|
|
|
|
{
|
|
|
|
UINT i, j;
|
|
|
|
NET_BUFFER_LIST *nbl_head = NULL;
|
|
|
|
NET_BUFFER_LIST *nbl_tail = NULL;
|
|
|
|
UINT num_packets = 0;
|
|
|
|
NDIS_HANDLE adapter_handle = NULL;
|
|
|
|
|
|
|
|
SlLock(f->Adapter->Lock);
|
|
|
|
|
|
|
|
if (f->Adapter->NumPendingSendPackets <= SL_MAX_PACKET_QUEUED)
|
|
|
|
{
|
|
|
|
// Admit to send only if the number of packets being transmitted does not exceed the specified limit
|
|
|
|
adapter_handle = f->Adapter->AdapterHandle;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (adapter_handle != NULL)
|
|
|
|
{
|
|
|
|
// Lock the file list which opens the same adapter
|
|
|
|
SlLockList(dev->FileList);
|
|
|
|
for (j = 0;j < SL_LIST_NUM(dev->FileList);j++)
|
|
|
|
{
|
|
|
|
SL_FILE *other = SL_LIST_DATA(dev->FileList, j);
|
|
|
|
|
|
|
|
if (other != f)
|
|
|
|
{
|
|
|
|
// Lock the receive queue of other file lists
|
|
|
|
SlLock(other->RecvLock);
|
|
|
|
|
|
|
|
other->SetEventFlag = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0;i < num;i++)
|
|
|
|
{
|
|
|
|
UINT packet_size = SL_SIZE_OF_PACKET(buf, i);
|
|
|
|
UCHAR *packet_buf;
|
|
|
|
NET_BUFFER_LIST *nbl = NULL;
|
|
|
|
bool ok = false;
|
|
|
|
|
|
|
|
if (packet_size > SL_MAX_PACKET_SIZE)
|
|
|
|
{
|
|
|
|
packet_size = SL_MAX_PACKET_SIZE;
|
|
|
|
}
|
|
|
|
else if (packet_size < SL_PACKET_HEADER_SIZE)
|
|
|
|
{
|
|
|
|
packet_size = SL_PACKET_HEADER_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
packet_buf = (UCHAR *)SL_ADDR_OF_PACKET(buf, i);
|
|
|
|
|
|
|
|
for (j = 0;j < SL_LIST_NUM(dev->FileList);j++)
|
|
|
|
{
|
|
|
|
SL_FILE *other = SL_LIST_DATA(dev->FileList, j);
|
|
|
|
|
|
|
|
if (other != f)
|
|
|
|
{
|
|
|
|
// Insert into the receive queue of the other file lists
|
|
|
|
if (other->NumRecvPackets < SL_MAX_PACKET_QUEUED)
|
|
|
|
{
|
|
|
|
SL_PACKET *q = SlMalloc(sizeof(SL_PACKET));
|
|
|
|
|
|
|
|
SlCopy(q->Data, packet_buf, packet_size);
|
|
|
|
q->Size = packet_size;
|
|
|
|
q->Next = NULL;
|
|
|
|
|
|
|
|
if (other->RecvPacketHead == NULL)
|
|
|
|
{
|
|
|
|
other->RecvPacketHead = q;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
other->RecvPacketTail->Next = q;
|
|
|
|
}
|
|
|
|
|
|
|
|
other->RecvPacketTail = q;
|
|
|
|
|
|
|
|
other->NumRecvPackets++;
|
|
|
|
|
|
|
|
other->SetEventFlag = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate a new NET_BUFFER_LIST
|
|
|
|
if (f->NetBufferListPool != NULL)
|
|
|
|
{
|
|
|
|
nbl = NdisAllocateNetBufferList(f->NetBufferListPool, 16, 0);
|
|
|
|
|
|
|
|
if (nbl != NULL)
|
|
|
|
{
|
|
|
|
nbl->SourceHandle = adapter_handle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nbl != NULL)
|
|
|
|
{
|
|
|
|
// Get the NET_BUFFER from the NET_BUFFER_LIST
|
|
|
|
NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl);
|
|
|
|
|
|
|
|
NET_BUFFER_LIST_NEXT_NBL(nbl) = NULL;
|
|
|
|
|
|
|
|
if (nb != NULL && OK(NdisRetreatNetBufferDataStart(nb, packet_size, 0, NULL)))
|
|
|
|
{
|
|
|
|
// Buffer copy
|
|
|
|
UCHAR *dst = NdisGetDataBuffer(nb, packet_size, NULL, 1, 0);
|
|
|
|
|
|
|
|
if (dst != NULL)
|
|
|
|
{
|
|
|
|
SlCopy(dst, packet_buf, packet_size);
|
|
|
|
|
|
|
|
ok = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NdisAdvanceNetBufferDataStart(nb, packet_size, false, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ok == false)
|
|
|
|
{
|
|
|
|
if (nbl != NULL)
|
|
|
|
{
|
|
|
|
NdisFreeNetBufferList(nbl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (nbl_head == NULL)
|
|
|
|
{
|
|
|
|
nbl_head = nbl;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nbl_tail != NULL)
|
|
|
|
{
|
|
|
|
NET_BUFFER_LIST_NEXT_NBL(nbl_tail) = nbl;
|
|
|
|
}
|
|
|
|
|
|
|
|
nbl_tail = nbl;
|
|
|
|
|
|
|
|
*((void **)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl)) = f;
|
|
|
|
|
|
|
|
num_packets++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0;j < SL_LIST_NUM(dev->FileList);j++)
|
|
|
|
{
|
|
|
|
SL_FILE *other = SL_LIST_DATA(dev->FileList, j);
|
|
|
|
|
|
|
|
if (other != f)
|
|
|
|
{
|
|
|
|
// Release the receive queue of other file lists
|
|
|
|
SlUnlock(other->RecvLock);
|
|
|
|
|
|
|
|
// Set an event
|
|
|
|
if (other->SetEventFlag)
|
|
|
|
{
|
|
|
|
SlSet(other->Event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SlUnlockList(dev->FileList);
|
|
|
|
|
|
|
|
if (nbl_head != NULL)
|
|
|
|
{
|
|
|
|
InterlockedExchangeAdd(&f->NumSendingPacketets, num_packets);
|
|
|
|
InterlockedExchangeAdd(&f->Adapter->NumPendingSendPackets, num_packets);
|
|
|
|
|
|
|
|
SlUnlock(f->Adapter->Lock);
|
|
|
|
|
|
|
|
NdisSendNetBufferLists(adapter_handle, nbl_head, 0, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SlUnlock(f->Adapter->Lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SlUnlock(f->Adapter->Lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mdl != NULL)
|
|
|
|
{
|
|
|
|
MmUnlockPages(mdl);
|
|
|
|
IoFreeMdl(mdl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
irp->IoStatus.Information = ret_size;
|
|
|
|
irp->IoStatus.Status = ret;
|
|
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// IOCTL procedure of the device
|
|
|
|
NTSTATUS SlDeviceIoControlProc(DEVICE_OBJECT *device_object, IRP *irp)
|
|
|
|
{
|
|
|
|
SL_DEVICE *dev = *((SL_DEVICE **)device_object->DeviceExtension);
|
|
|
|
NTSTATUS ret = STATUS_UNSUCCESSFUL;
|
|
|
|
IO_STACK_LOCATION *irp_stack = IoGetCurrentIrpStackLocation(irp);
|
|
|
|
UINT ret_size = 0;
|
|
|
|
|
|
|
|
if (dev->IsBasicDevice == false)
|
|
|
|
{
|
|
|
|
// Adapter device
|
|
|
|
SL_FILE *f = irp_stack->FileObject->FsContext;
|
|
|
|
|
|
|
|
switch (irp_stack->Parameters.DeviceIoControl.IoControlCode)
|
|
|
|
{
|
|
|
|
case SL_IOCTL_GET_EVENT_NAME:
|
|
|
|
if (irp_stack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(SL_IOCTL_EVENT_NAME))
|
|
|
|
{
|
|
|
|
SL_IOCTL_EVENT_NAME *t = irp->UserBuffer;
|
|
|
|
|
|
|
|
if (t != NULL)
|
|
|
|
{
|
|
|
|
strcpy(t->EventNameWin32, f->EventNameWin32);
|
|
|
|
|
|
|
|
ret_size = sizeof(SL_IOCTL_EVENT_NAME);
|
|
|
|
|
|
|
|
ret = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
irp->IoStatus.Status = ret;
|
|
|
|
irp->IoStatus.Information = ret_size;
|
|
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NDIS bind notification procedure
|
|
|
|
NDIS_STATUS SlNdisBindAdapterExProc(NDIS_HANDLE protocol_driver_context, NDIS_HANDLE bind_context, NDIS_BIND_PARAMETERS *bind_parameters)
|
|
|
|
{
|
|
|
|
NDIS_STATUS ret = NDIS_STATUS_FAILURE;
|
|
|
|
|
|
|
|
InterlockedIncrement(&sl->NumBoundAdapters);
|
|
|
|
|
|
|
|
// Check the attributes of the adapter, and process only adapter which should be bound to
|
|
|
|
if (bind_parameters->MediaType == NdisMedium802_3 &&
|
|
|
|
bind_parameters->MacAddressLength == 6 &&
|
|
|
|
// (bind_parameters->PhysicalMediumType == NdisPhysicalMedium802_3 || bind_parameters->PhysicalMediumType == 0) &&
|
|
|
|
bind_parameters->AccessType == NET_IF_ACCESS_BROADCAST &&
|
|
|
|
bind_parameters->DirectionType == NET_IF_DIRECTION_SENDRECEIVE &&
|
|
|
|
bind_parameters->ConnectionType == NET_IF_CONNECTION_DEDICATED)
|
|
|
|
{
|
|
|
|
// Open the adapter
|
|
|
|
NDIS_OPEN_PARAMETERS t;
|
|
|
|
NDIS_MEDIUM medium_array = {NdisMedium802_3};
|
|
|
|
SL_ADAPTER *a;
|
|
|
|
wchar_t adapter_id_tag[] = SL_ADAPTER_ID_PREFIX_W;
|
|
|
|
|
|
|
|
SlZero(&t, sizeof(t));
|
|
|
|
t.Header.Type = NDIS_OBJECT_TYPE_OPEN_PARAMETERS;
|
|
|
|
t.Header.Revision = NDIS_OPEN_PARAMETERS_REVISION_1;
|
|
|
|
t.Header.Size = NDIS_SIZEOF_OPEN_PARAMETERS_REVSION_1;
|
|
|
|
|
|
|
|
t.AdapterName = bind_parameters->AdapterName;
|
|
|
|
t.MediumArray = &medium_array;
|
|
|
|
t.MediumArraySize = 1;
|
|
|
|
t.SelectedMediumIndex = &sl->DummyInt;
|
|
|
|
t.FrameTypeArray = NULL;
|
|
|
|
t.FrameTypeArraySize = 0;
|
|
|
|
|
|
|
|
a = SlZeroMalloc(sizeof(SL_ADAPTER));
|
|
|
|
|
|
|
|
a->Lock = SlNewLock();
|
|
|
|
a->AdapterName = SlNewUnicodeFromUnicodeString(bind_parameters->AdapterName);
|
|
|
|
|
|
|
|
SlCopy(a->AdapterId, a->AdapterName->String.Buffer, MIN(sizeof(a->AdapterId) - sizeof(wchar_t), a->AdapterName->String.Length));
|
|
|
|
SlCopy(a->AdapterId, adapter_id_tag, sizeof(adapter_id_tag) - sizeof(wchar_t));
|
|
|
|
|
|
|
|
SlCopy(a->MacAddress, bind_parameters->CurrentMacAddress, 6);
|
|
|
|
SlCopy(&a->BindParamCopy, bind_parameters, sizeof(NDIS_BIND_PARAMETERS));
|
|
|
|
a->BindingContext = bind_context;
|
|
|
|
a->MtuSize = bind_parameters->MtuSize;
|
|
|
|
|
|
|
|
a->IsOpenPending = true;
|
|
|
|
|
|
|
|
ret = NdisOpenAdapterEx(sl->ProtocolHandle, a, &t, bind_context, &a->AdapterHandle);
|
|
|
|
a->AdapterHandle2 = a->AdapterHandle;
|
|
|
|
|
|
|
|
if (ret != NDIS_STATUS_PENDING)
|
|
|
|
{
|
|
|
|
a->IsOpenPending = false;
|
|
|
|
SlNdisOpenAdapterCompleteExProc(a, ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret != NDIS_STATUS_PENDING)
|
|
|
|
{
|
|
|
|
if (ret != NDIS_STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
InterlockedDecrement(&sl->NumBoundAdapters);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open success notification procedure of NDIS adapter
|
|
|
|
void SlNdisOpenAdapterCompleteExProc(NDIS_HANDLE protocol_binding_context, NDIS_STATUS status)
|
|
|
|
{
|
|
|
|
SL_ADAPTER *a = (SL_ADAPTER *)protocol_binding_context;
|
|
|
|
bool is_pending = a->IsOpenPending;
|
|
|
|
NDIS_HANDLE binding_context = a->BindingContext;
|
|
|
|
|
|
|
|
if (OK(status))
|
|
|
|
{
|
|
|
|
// Create an adapter device
|
|
|
|
SL_UNICODE *device_name = SlNewUnicode(SL_ADAPTER_DEVICE_NAME);
|
|
|
|
SL_UNICODE *symbolic_name = SlNewUnicode(SL_ADAPTER_DEVICE_NAME_SYMBOLIC);
|
|
|
|
SL_DEVICE *dev;
|
|
|
|
|
|
|
|
// Create a device name
|
|
|
|
SlCopy(device_name->String.Buffer + 8, a->AdapterId, sizeof(wchar_t) * 46);
|
|
|
|
SlCopy(symbolic_name->String.Buffer + 19, a->AdapterId, sizeof(wchar_t) * 46);
|
|
|
|
|
|
|
|
dev = SlNewDeviceUnicode(device_name, symbolic_name);
|
|
|
|
|
|
|
|
if (dev == NULL)
|
|
|
|
{
|
|
|
|
// Device creation failed
|
|
|
|
SlFreeUnicode(device_name);
|
|
|
|
SlFreeUnicode(symbolic_name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Create a file list
|
|
|
|
dev->FileList = SlNewList();
|
|
|
|
}
|
|
|
|
if (dev != NULL)
|
|
|
|
{
|
|
|
|
// Get the display name
|
|
|
|
SlSendOidRequest(a, false, OID_GEN_VENDOR_DESCRIPTION, a->FriendlyName,
|
|
|
|
sizeof(a->FriendlyName) - 1);
|
|
|
|
|
|
|
|
dev->Adapter = a;
|
|
|
|
a->Device = dev;
|
|
|
|
|
|
|
|
// Add this adapter to the adapter list
|
|
|
|
SlLockList(sl->AdapterList);
|
|
|
|
{
|
|
|
|
SlAdd(sl->AdapterList, a);
|
|
|
|
}
|
|
|
|
SlUnlockList(sl->AdapterList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Discard the adapter handle
|
|
|
|
a->AdapterHandle = NULL;
|
|
|
|
|
|
|
|
// Release the SL_ADAPTER
|
|
|
|
SlFreeAdapter(a);
|
|
|
|
|
|
|
|
a = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_pending)
|
|
|
|
{
|
|
|
|
NdisCompleteBindAdapterEx(binding_context, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a != NULL)
|
|
|
|
{
|
|
|
|
a->Ready = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_pending)
|
|
|
|
{
|
|
|
|
if (NG(status))
|
|
|
|
{
|
|
|
|
InterlockedDecrement(&sl->NumBoundAdapters);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the SL_ADAPTER
|
|
|
|
void SlFreeAdapter(SL_ADAPTER *a)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (a == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SlFreeUnicode(a->AdapterName);
|
|
|
|
|
|
|
|
SlFreeLock(a->Lock);
|
|
|
|
|
|
|
|
SlFree(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
// NDIS unbind notification procedure
|
|
|
|
NDIS_STATUS SlNdisUnbindAdapterExProc(NDIS_HANDLE unbind_context, NDIS_HANDLE protocol_binding_context)
|
|
|
|
{
|
|
|
|
NDIS_STATUS ret;
|
|
|
|
SL_ADAPTER *a = (SL_ADAPTER *)protocol_binding_context;
|
|
|
|
UINT j;
|
|
|
|
NDIS_HANDLE adapter_handle = NULL;
|
|
|
|
|
|
|
|
if (a->Halt)
|
|
|
|
{
|
|
|
|
//SL_WHERE;
|
|
|
|
}
|
|
|
|
|
|
|
|
adapter_handle = a->AdapterHandle;
|
|
|
|
a->Halt = true;
|
|
|
|
if (a->Device != NULL)
|
|
|
|
{
|
|
|
|
a->Device->Halting = true;
|
|
|
|
}
|
|
|
|
a->AdapterHandle = NULL;
|
|
|
|
|
|
|
|
SlLock(a->Lock);
|
|
|
|
{
|
|
|
|
}
|
|
|
|
SlUnlock(a->Lock);
|
|
|
|
|
|
|
|
a->UnbindContext = unbind_context;
|
|
|
|
a->IsClosePending = true;
|
|
|
|
|
|
|
|
// Delete the adapter from the adapter list
|
|
|
|
SlLockList(sl->AdapterList);
|
|
|
|
{
|
|
|
|
SlDelete(sl->AdapterList, a);
|
|
|
|
}
|
|
|
|
SlUnlockList(sl->AdapterList);
|
|
|
|
|
|
|
|
for (j = 0;j < 32;j++)
|
|
|
|
{
|
|
|
|
// Wait until the number of OID requests of being processed by this adapter becomes zero
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
UINT num;
|
|
|
|
|
|
|
|
num = a->NumPendingOidRequests;
|
|
|
|
|
|
|
|
if (num == 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
j = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//SlSleep(50);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait until the number of packets this adapter is transmitting becomes zero
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
UINT num;
|
|
|
|
|
|
|
|
num = a->NumPendingSendPackets;
|
|
|
|
|
|
|
|
if (num == 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
j = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//SlSleep(50);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = NdisCloseAdapterEx(adapter_handle);
|
|
|
|
|
|
|
|
if (ret != NDIS_STATUS_PENDING)
|
|
|
|
{
|
|
|
|
a->IsClosePending = false;
|
|
|
|
SlNdisCloseAdapterCompleteExProc(a);
|
|
|
|
|
|
|
|
ret = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
|
|
InterlockedDecrement(&sl->NumBoundAdapters);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close success notification procedure of NDIS adapter
|
|
|
|
void SlNdisCloseAdapterCompleteExProc(NDIS_HANDLE protocol_binding_context)
|
|
|
|
{
|
|
|
|
SL_ADAPTER *a = (SL_ADAPTER *)protocol_binding_context;
|
|
|
|
NDIS_HANDLE unbind_context = a->UnbindContext;
|
|
|
|
bool is_pending = a->IsClosePending;
|
|
|
|
UINT j;
|
|
|
|
|
|
|
|
if (is_pending)
|
|
|
|
{
|
|
|
|
NdisCompleteUnbindAdapterEx(unbind_context);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0;j < 32;j++)
|
|
|
|
{
|
|
|
|
if (a->Device != NULL)
|
|
|
|
{
|
|
|
|
a->Device->Halting = true;
|
|
|
|
|
|
|
|
// Wait until the number of file handles that are associated with this device becomes zero
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
UINT num_files = 0;
|
|
|
|
|
|
|
|
SlLock(a->Device->OpenCloseLock);
|
|
|
|
{
|
|
|
|
SlLockList(a->Device->FileList);
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
num_files = SL_LIST_NUM(a->Device->FileList);
|
|
|
|
|
|
|
|
for (i = 0;i < num_files;i++)
|
|
|
|
{
|
|
|
|
// Hit the associated event
|
|
|
|
SL_FILE *f = SL_LIST_DATA(a->Device->FileList, i);
|
|
|
|
|
|
|
|
if (f->FinalWakeUp == false)
|
|
|
|
{
|
|
|
|
SlSet(f->Event);
|
|
|
|
f->FinalWakeUp = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SlUnlockList(a->Device->FileList);
|
|
|
|
}
|
|
|
|
SlUnlock(a->Device->OpenCloseLock);
|
|
|
|
|
|
|
|
if (num_files == 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SlSleep(50);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the device
|
|
|
|
if (a->Device != NULL)
|
|
|
|
{
|
|
|
|
// Delete the file list
|
|
|
|
SlFreeList(a->Device->FileList);
|
|
|
|
|
|
|
|
SlFreeDevice(a->Device);
|
|
|
|
a->Device = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the SL_ADAPTER
|
|
|
|
SlFreeAdapter(a);
|
|
|
|
|
|
|
|
if (is_pending)
|
|
|
|
{
|
|
|
|
InterlockedDecrement(&sl->NumBoundAdapters);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NDIS PnP notification procedure
|
|
|
|
NDIS_STATUS SlNdisNetPnPEventProc(NDIS_HANDLE protocol_binding_context, NET_PNP_EVENT_NOTIFICATION *net_pnp_event)
|
|
|
|
{
|
|
|
|
SL_ADAPTER *a = (SL_ADAPTER *)protocol_binding_context;
|
|
|
|
|
|
|
|
if (net_pnp_event != NULL)
|
|
|
|
{
|
|
|
|
if (net_pnp_event->NetPnPEvent.NetEvent == NetEventBindsComplete)
|
|
|
|
{
|
|
|
|
sl->IsEnumCompleted = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NDIS uninstall procedure
|
|
|
|
void SlNdisUninstallProc(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// NDIS OID request completion notification procedure
|
|
|
|
void SlNdisOidRequestCompleteProc(NDIS_HANDLE protocol_binding_context, NDIS_OID_REQUEST *oid_request, NDIS_STATUS status)
|
|
|
|
{
|
|
|
|
SL_ADAPTER *a = (SL_ADAPTER *)protocol_binding_context;
|
|
|
|
bool no_not_free = false;
|
|
|
|
|
|
|
|
// Check the results
|
|
|
|
if (oid_request->RequestType == NdisRequestQueryInformation)
|
|
|
|
{
|
|
|
|
if (oid_request->DATA.QUERY_INFORMATION.Oid == OID_GEN_VENDOR_DESCRIPTION)
|
|
|
|
{
|
|
|
|
no_not_free = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
if (no_not_free == false)
|
|
|
|
{
|
|
|
|
SlFree(oid_request->DATA.SET_INFORMATION.InformationBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
SlFree(oid_request);
|
|
|
|
|
|
|
|
// Counter subtraction
|
|
|
|
InterlockedDecrement(&a->NumPendingOidRequests);
|
|
|
|
}
|
|
|
|
|
|
|
|
// NDIS status notification procedure
|
|
|
|
void SlNdisStatusExProc(NDIS_HANDLE protocol_binding_context, NDIS_STATUS_INDICATION *status_indication)
|
|
|
|
{
|
|
|
|
SL_ADAPTER *a = (SL_ADAPTER *)protocol_binding_context;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NDIS packet reception notification procedure
|
|
|
|
void SlNdisReceiveNetBufferListsProc(NDIS_HANDLE protocol_binding_context, NET_BUFFER_LIST *net_buffer_lists,
|
|
|
|
NDIS_PORT_NUMBER port_number, ULONG NumberOfNetBufferLists,
|
|
|
|
ULONG receive_flags)
|
|
|
|
{
|
|
|
|
SL_ADAPTER *a = (SL_ADAPTER *)protocol_binding_context;
|
|
|
|
UINT i;
|
|
|
|
UINT return_flags = 0;
|
|
|
|
NET_BUFFER_LIST *nbl;
|
|
|
|
UCHAR *tmp_buffer;
|
|
|
|
UINT tmp_size;
|
|
|
|
|
|
|
|
if (net_buffer_lists == NULL || NumberOfNetBufferLists == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a->AdapterHandle2 == NULL)
|
|
|
|
{
|
|
|
|
a->AdapterHandle2 = a->AdapterHandle;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(receive_flags))
|
|
|
|
{
|
|
|
|
NDIS_SET_RETURN_FLAG(return_flags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a->Halt || a->Device == NULL || a->Device->Halting || a->Ready == false || a->AdapterHandle == NULL)
|
|
|
|
{
|
|
|
|
goto LABEL_CLEANUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp_buffer = a->TmpBuffer;
|
|
|
|
tmp_size = sizeof(a->TmpBuffer);
|
|
|
|
|
|
|
|
nbl = net_buffer_lists;
|
|
|
|
|
|
|
|
SlLockList(a->Device->FileList);
|
|
|
|
{
|
|
|
|
if (a->Halt == false)
|
|
|
|
{
|
|
|
|
for (i = 0;i < SL_LIST_NUM(a->Device->FileList);i++)
|
|
|
|
{
|
|
|
|
// Lock the receive queue
|
|
|
|
SL_FILE *f = SL_LIST_DATA(a->Device->FileList, i);
|
|
|
|
|
|
|
|
SlLock(f->RecvLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (nbl != NULL)
|
|
|
|
{
|
|
|
|
NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl);
|
|
|
|
bool is_vlan = false;
|
|
|
|
UCHAR vlan_tag[2];
|
|
|
|
|
|
|
|
if (NET_BUFFER_LIST_INFO(nbl, Ieee8021QNetBufferListInfo) != 0)
|
|
|
|
{
|
|
|
|
NDIS_NET_BUFFER_LIST_8021Q_INFO qinfo;
|
|
|
|
qinfo.Value = NET_BUFFER_LIST_INFO(nbl, Ieee8021QNetBufferListInfo);
|
|
|
|
if (qinfo.TagHeader.VlanId != 0)
|
|
|
|
{
|
|
|
|
USHORT tag_us;
|
|
|
|
is_vlan = true;
|
|
|
|
|
|
|
|
tag_us = (qinfo.TagHeader.UserPriority & 0x07 << 13) |
|
|
|
|
(qinfo.TagHeader.CanonicalFormatId & 0x01 << 12) |
|
|
|
|
(qinfo.TagHeader.VlanId & 0x0FFF);
|
|
|
|
|
|
|
|
vlan_tag[0] = ((UCHAR *)(&tag_us))[1];
|
|
|
|
vlan_tag[1] = ((UCHAR *)(&tag_us))[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (nb != NULL)
|
|
|
|
{
|
|
|
|
UINT size = NET_BUFFER_DATA_LENGTH(nb);
|
|
|
|
|
|
|
|
if (size >= 14 && size <= tmp_size && size <= (UINT)((is_vlan == false) ? SL_MAX_PACKET_SIZE : (SL_MAX_PACKET_SIZE - 4)))
|
|
|
|
{
|
|
|
|
UCHAR *ptr = NdisGetDataBuffer(nb, size, tmp_buffer, 1, 0);
|
|
|
|
|
|
|
|
if (ptr != NULL)
|
|
|
|
{
|
|
|
|
// Insert the queue to all waiting files
|
|
|
|
for (i = 0;i < SL_LIST_NUM(a->Device->FileList);i++)
|
|
|
|
{
|
|
|
|
SL_FILE *f = SL_LIST_DATA(a->Device->FileList, i);
|
|
|
|
|
|
|
|
if (f->NumRecvPackets < SL_MAX_PACKET_QUEUED)
|
|
|
|
{
|
|
|
|
SL_PACKET *q = SlMalloc(sizeof(SL_PACKET));
|
|
|
|
|
|
|
|
if (is_vlan == false)
|
|
|
|
{
|
|
|
|
// Normal packet
|
|
|
|
SlCopy(q->Data, ptr, size);
|
|
|
|
q->Size = size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Insert a tag in the case of IEEE802.1Q packet
|
|
|
|
SlCopy(q->Data, ptr, 12);
|
|
|
|
q->Data[12] = 0x81;
|
|
|
|
q->Data[13] = 0x00;
|
|
|
|
SlCopy(&q->Data[14], vlan_tag, 2);
|
|
|
|
SlCopy(&q->Data[16], &ptr[12], size - 12);
|
|
|
|
|
|
|
|
q->Size = size + 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
q->Next = NULL;
|
|
|
|
|
|
|
|
if (f->RecvPacketHead == NULL)
|
|
|
|
{
|
|
|
|
f->RecvPacketHead = q;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
f->RecvPacketTail->Next = q;
|
|
|
|
}
|
|
|
|
|
|
|
|
f->RecvPacketTail = q;
|
|
|
|
|
|
|
|
f->NumRecvPackets++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nb = NET_BUFFER_NEXT_NB(nb);
|
|
|
|
}
|
|
|
|
|
|
|
|
nbl = NET_BUFFER_LIST_NEXT_NBL(nbl);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hit the event
|
|
|
|
for (i = 0;i < SL_LIST_NUM(a->Device->FileList);i++)
|
|
|
|
{
|
|
|
|
SL_FILE *f = SL_LIST_DATA(a->Device->FileList, i);
|
|
|
|
|
|
|
|
// Unlock the receive queue
|
|
|
|
SlUnlock(f->RecvLock);
|
|
|
|
|
|
|
|
SlSet(f->Event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SlUnlockList(a->Device->FileList);
|
|
|
|
|
|
|
|
LABEL_CLEANUP:
|
|
|
|
|
|
|
|
if (NDIS_TEST_RECEIVE_CAN_PEND(receive_flags))
|
|
|
|
{
|
|
|
|
NdisReturnNetBufferLists(a->AdapterHandle2, net_buffer_lists, return_flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NDIS packet transmission completion notification procedure
|
|
|
|
void SlNdisSendNetBufferListsCompleteProc(NDIS_HANDLE protocol_binding_context, NET_BUFFER_LIST *net_buffer_lists,
|
|
|
|
ULONG send_complete_flags)
|
|
|
|
{
|
|
|
|
NET_BUFFER_LIST *nbl;
|
|
|
|
|
|
|
|
nbl = net_buffer_lists;
|
|
|
|
|
|
|
|
while (nbl != NULL)
|
|
|
|
{
|
|
|
|
NET_BUFFER_LIST *current_nbl = nbl;
|
|
|
|
SL_FILE *f;
|
|
|
|
NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl);
|
|
|
|
|
|
|
|
if (nb != NULL)
|
|
|
|
{
|
|
|
|
UINT size = NET_BUFFER_DATA_LENGTH(nb);
|
|
|
|
|
|
|
|
NdisAdvanceNetBufferDataStart(nb, size, false, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get a file context
|
|
|
|
f = *((void **)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl));
|
|
|
|
|
|
|
|
nbl = NET_BUFFER_LIST_NEXT_NBL(nbl);
|
|
|
|
NET_BUFFER_LIST_NEXT_NBL(current_nbl) = NULL;
|
|
|
|
|
|
|
|
// Release the NET_BUFFER_LIST
|
|
|
|
NdisFreeNetBufferList(current_nbl);
|
|
|
|
|
|
|
|
// Reduce the number of packets being sent by 1
|
|
|
|
InterlockedExchangeAdd(&f->NumSendingPacketets, (LONG)-1);
|
|
|
|
InterlockedExchangeAdd(&f->Adapter->NumPendingSendPackets, (LONG)-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Crash
|
|
|
|
void SlCrash(UINT a, UINT b, UINT c, UINT d)
|
|
|
|
{
|
|
|
|
KeBugCheckEx(0x00000061, (ULONG_PTR)a, (ULONG_PTR)b, (ULONG_PTR)c, (ULONG_PTR)d);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
void *SlMalloc(UINT size)
|
|
|
|
{
|
|
|
|
NDIS_STATUS r;
|
|
|
|
void *p;
|
|
|
|
if (size == 0)
|
|
|
|
{
|
|
|
|
size = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate the non-paged memory
|
|
|
|
r = NdisAllocateMemoryWithTag(&p, size, 0);
|
|
|
|
|
|
|
|
if (NG(r))
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear to zero by allocating the memory
|
|
|
|
void *SlZeroMalloc(UINT size)
|
|
|
|
{
|
|
|
|
void *p = SlMalloc(size);
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
// Memory allocation failure
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear to zero
|
|
|
|
SlZero(p, size);
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
void SlFree(void *p)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
NdisFreeMemory(p, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory zero clear
|
|
|
|
void SlZero(void *dst, UINT size)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (dst == NULL || size == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear
|
|
|
|
NdisZeroMemory(dst, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy memory
|
|
|
|
void SlCopy(void *dst, void *src, UINT size)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (dst == NULL || src == NULL || size == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy
|
|
|
|
NdisMoveMemory(dst, src, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a lock
|
|
|
|
SL_LOCK *SlNewLock()
|
|
|
|
{
|
|
|
|
NDIS_SPIN_LOCK *spin_lock;
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
SL_LOCK *lock = SlZeroMalloc(sizeof(SL_LOCK));
|
|
|
|
if (lock == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize spin lock
|
|
|
|
spin_lock = &lock->spin_lock;
|
|
|
|
|
|
|
|
NdisAllocateSpinLock(spin_lock);
|
|
|
|
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lock
|
|
|
|
void SlLock(SL_LOCK *lock)
|
|
|
|
{
|
|
|
|
NDIS_SPIN_LOCK *spin_lock;
|
|
|
|
// Validate arguments
|
|
|
|
if (lock == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock = &lock->spin_lock;
|
|
|
|
NdisAcquireSpinLock(spin_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unlock
|
|
|
|
void SlUnlock(SL_LOCK *lock)
|
|
|
|
{
|
|
|
|
NDIS_SPIN_LOCK *spin_lock;
|
|
|
|
// Validate arguments
|
|
|
|
if (lock == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock = &lock->spin_lock;
|
|
|
|
NdisReleaseSpinLock(spin_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the lock
|
|
|
|
void SlFreeLock(SL_LOCK *lock)
|
|
|
|
{
|
|
|
|
NDIS_SPIN_LOCK *spin_lock;
|
|
|
|
// Validate arguments
|
|
|
|
if (lock == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock = &lock->spin_lock;
|
|
|
|
NdisFreeSpinLock(spin_lock);
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
SlFree(lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an event
|
|
|
|
SL_EVENT *SlNewEvent(char *name)
|
|
|
|
{
|
|
|
|
SL_UNICODE *unicode_name;
|
|
|
|
SL_EVENT *event;
|
|
|
|
// Validate arguments
|
|
|
|
if (name == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert to Unicode name
|
|
|
|
unicode_name = SlNewUnicode(name);
|
|
|
|
if (unicode_name == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
event = SlZeroMalloc(sizeof(SL_EVENT));
|
|
|
|
if (event == NULL)
|
|
|
|
{
|
|
|
|
SlFreeUnicode(unicode_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an event
|
|
|
|
event->event = IoCreateNotificationEvent(SlGetUnicode(unicode_name), &event->event_handle);
|
|
|
|
if (event->event == NULL)
|
|
|
|
{
|
|
|
|
SlFree(event);
|
|
|
|
SlFreeUnicode(unicode_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the event
|
|
|
|
KeInitializeEvent(event->event, NotificationEvent, FALSE);
|
|
|
|
KeClearEvent(event->event);
|
|
|
|
|
|
|
|
// Release the string
|
|
|
|
SlFreeUnicode(unicode_name);
|
|
|
|
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the event
|
|
|
|
void SlFreeEvent(SL_EVENT *event)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (event == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZwClose(event->event_handle);
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
SlFree(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the event
|
|
|
|
void SlSet(SL_EVENT *event)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (event == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeSetEvent(event->event, 0, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset the event
|
|
|
|
void SlReset(SL_EVENT *event)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (event == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeResetEvent(event->event);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create by copying the Unicode
|
|
|
|
SL_UNICODE *SlNewUnicodeFromUnicodeString(UNICODE_STRING *src)
|
|
|
|
{
|
|
|
|
SL_UNICODE *u;
|
|
|
|
// Validate arguments
|
|
|
|
if (src == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
u = SlZeroMalloc(sizeof(SL_UNICODE));
|
|
|
|
if (u == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
u->String.Length = u->String.MaximumLength = src->Length;
|
|
|
|
|
|
|
|
u->String.Buffer = SlZeroMalloc(src->Length);
|
|
|
|
SlCopy(u->String.Buffer, src->Buffer, src->Length);
|
|
|
|
|
|
|
|
return u;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a Unicode
|
|
|
|
SL_UNICODE *SlNewUnicode(char *str)
|
|
|
|
{
|
|
|
|
SL_UNICODE *u;
|
|
|
|
// Validate arguments
|
|
|
|
if (str == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
u = SlZeroMalloc(sizeof(SL_UNICODE));
|
|
|
|
if (u == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// String initialization
|
|
|
|
NdisInitializeString(&u->String, str);
|
|
|
|
|
|
|
|
return u;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the Unicode
|
|
|
|
void SlFreeUnicode(SL_UNICODE *u)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (u == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the string
|
|
|
|
NdisFreeString(u->String);
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
SlFree(u);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get an Unicode
|
|
|
|
NDIS_STRING *SlGetUnicode(SL_UNICODE *u)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (u == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &u->String;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a packet buffer
|
|
|
|
SL_PACKET_BUFFER *SlNewPacketBuffer()
|
|
|
|
{
|
|
|
|
SL_PACKET_BUFFER *p;
|
|
|
|
NET_BUFFER_LIST_POOL_PARAMETERS p1;
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
p = SlZeroMalloc(sizeof(SL_PACKET_BUFFER));
|
|
|
|
|
|
|
|
// Create a NET_BUFFER_LIST pool
|
|
|
|
SlZero(&p1, sizeof(p1));
|
|
|
|
p1.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
|
|
|
|
p1.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
|
|
|
|
p1.Header.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
|
|
|
|
p1.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
|
|
|
|
p1.fAllocateNetBuffer = TRUE;
|
|
|
|
p1.DataSize = SL_MAX_PACKET_SIZE;
|
|
|
|
|
|
|
|
p->NetBufferListPool = NdisAllocateNetBufferListPool(NULL, &p1);
|
|
|
|
|
|
|
|
// Create a NET_BUFFER_LIST
|
|
|
|
p->NetBufferList = NdisAllocateNetBufferList(p->NetBufferListPool, 0, 0);
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the packet buffer
|
|
|
|
void SlFreePacketBuffer(SL_PACKET_BUFFER *p)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the NET_BUFFER_LIST
|
|
|
|
NdisFreeNetBufferList(p->NetBufferList);
|
|
|
|
|
|
|
|
// Release the NET_BUFFER_LIST pool
|
|
|
|
NdisFreeNetBufferListPool(p->NetBufferListPool);
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
SlFree(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a list
|
|
|
|
SL_LIST *SlNewList()
|
|
|
|
{
|
|
|
|
SL_LIST *o;
|
|
|
|
|
|
|
|
o = (SL_LIST *)SlZeroMalloc(sizeof(SL_LIST));
|
|
|
|
|
|
|
|
o->lock = SlNewLock();
|
|
|
|
|
|
|
|
o->num_item = 0;
|
|
|
|
o->num_reserved = SL_INIT_NUM_RESERVED;
|
|
|
|
|
|
|
|
o->p = (void **)SlZeroMalloc(sizeof(void *) * o->num_reserved);
|
|
|
|
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add an element to the list
|
|
|
|
void SlAdd(SL_LIST *o, void *p)
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
// Validate arguments
|
|
|
|
if (o == NULL || p == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = o->num_item;
|
|
|
|
o->num_item++;
|
|
|
|
|
|
|
|
if (o->num_item > o->num_reserved)
|
|
|
|
{
|
|
|
|
UINT old_num_reserved = o->num_reserved;
|
|
|
|
void *p_old = o->p;
|
|
|
|
|
|
|
|
o->num_reserved = o->num_reserved * 2;
|
|
|
|
|
|
|
|
o->p = SlZeroMalloc(sizeof(void *) * o->num_reserved);
|
|
|
|
SlCopy(o->p, p_old, sizeof(void *) * old_num_reserved);
|
|
|
|
SlFree(p_old);
|
|
|
|
}
|
|
|
|
|
|
|
|
o->p[i] = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete the element from the list
|
|
|
|
bool SlDelete(SL_LIST *o, void *p)
|
|
|
|
{
|
|
|
|
UINT i, n;
|
|
|
|
// Validate arguments
|
|
|
|
if (o == NULL || p == NULL)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0;i < o->num_item;i++)
|
|
|
|
{
|
|
|
|
if (o->p[i] == p)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == o->num_item)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = i;
|
|
|
|
for (i = n;i < (o->num_item - 1);i++)
|
|
|
|
{
|
|
|
|
o->p[i] = o->p[i + 1];
|
|
|
|
}
|
|
|
|
o->num_item--;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete all elements from the list
|
|
|
|
void SlDeleteAll(SL_LIST *o)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (o == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
o->num_item = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lock the list
|
|
|
|
void SlLockList(SL_LIST *o)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (o == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SlLock(o->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unlock the list
|
|
|
|
void SlUnlockList(SL_LIST *o)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (o == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SlUnlock(o->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the list
|
|
|
|
void SlFreeList(SL_LIST *o)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (o == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SlFree(o->p);
|
|
|
|
SlFreeLock(o->lock);
|
|
|
|
|
|
|
|
SlFree(o);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clone the memory
|
|
|
|
void *SlClone(void *p, UINT size)
|
|
|
|
{
|
|
|
|
void *ret;
|
|
|
|
// Validate arguments
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = SlMalloc(size);
|
|
|
|
SlCopy(ret, p, size);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Sleep
|
|
|
|
void SlSleep(int milliSeconds)
|
|
|
|
{
|
|
|
|
PKTIMER timer = SlMalloc(sizeof(KTIMER));
|
|
|
|
LARGE_INTEGER duetime;
|
|
|
|
|
|
|
|
duetime.QuadPart = (__int64)milliSeconds * -10000;
|
|
|
|
KeInitializeTimerEx(timer, NotificationTimer);
|
|
|
|
KeSetTimerEx(timer, duetime, 0, NULL);
|
|
|
|
|
|
|
|
KeWaitForSingleObject(timer, Executive, KernelMode, FALSE, NULL);
|
|
|
|
|
|
|
|
SlFree(timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
|
|
|
|
// Department of Computer Science has dozens of overly-enthusiastic geeks.
|
|
|
|
// Join us: http://www.tsukuba.ac.jp/english/admission/
|