2014-01-04 17:00:08 +04:00
|
|
|
// SoftEther VPN Source Code
|
|
|
|
// Kernel Device Driver
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
|
|
// NDIS6.c
|
|
|
|
// Windows NDIS 6.2 Routine
|
|
|
|
|
|
|
|
#include <GlobalConst.h>
|
|
|
|
|
|
|
|
#define NEO_DEVICE_DRIVER
|
|
|
|
|
|
|
|
#include "Neo6.h"
|
|
|
|
|
|
|
|
static UINT64 max_speed = NEO_MAX_SPEED_DEFAULT;
|
|
|
|
static bool keep_link = false;
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
PsGetVersion(
|
|
|
|
PULONG MajorVersion OPTIONAL,
|
|
|
|
PULONG MinorVersion OPTIONAL,
|
|
|
|
PULONG BuildNumber OPTIONAL,
|
|
|
|
PUNICODE_STRING CSDVersion OPTIONAL
|
|
|
|
);
|
|
|
|
|
|
|
|
// Memory related
|
|
|
|
static NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
|
|
|
|
NDIS_HANDLE ndis_miniport_driver_handle = NULL;
|
|
|
|
|
|
|
|
// Flag for whether Windows 8
|
|
|
|
bool g_is_win8 = false;
|
|
|
|
|
|
|
|
// Win32 driver entry point
|
|
|
|
NDIS_STATUS DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath)
|
|
|
|
{
|
|
|
|
NDIS_MINIPORT_DRIVER_CHARACTERISTICS miniport;
|
|
|
|
ULONG os_major_ver = 0, os_minor_ver = 0;
|
|
|
|
NDIS_STATUS ret;
|
|
|
|
|
|
|
|
// Initialize the Neo library
|
|
|
|
if (NeoInit() == FALSE)
|
|
|
|
{
|
|
|
|
// Initialization Failed
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_is_win8 = false;
|
|
|
|
|
|
|
|
// Get the OS version
|
|
|
|
PsGetVersion(&os_major_ver, &os_minor_ver, NULL, NULL);
|
|
|
|
|
|
|
|
if (os_major_ver >= 7 || (os_major_ver == 6 && os_minor_ver >= 2))
|
|
|
|
{
|
|
|
|
// Windows 8
|
|
|
|
g_is_win8 = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register a NDIS miniport driver
|
|
|
|
NeoZero(&miniport, sizeof(NDIS_MINIPORT_DRIVER_CHARACTERISTICS));
|
|
|
|
|
|
|
|
miniport.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
|
|
|
|
miniport.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
|
|
|
|
miniport.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
|
|
|
|
|
|
|
|
miniport.MajorNdisVersion = NEO_NDIS_MAJOR_VERSION;
|
|
|
|
miniport.MinorNdisVersion = NEO_NDIS_MINOR_VERSION;
|
|
|
|
|
|
|
|
// Register the handler
|
|
|
|
miniport.InitializeHandlerEx = NeoNdisInitEx;
|
|
|
|
miniport.HaltHandlerEx = NeoNdisHaltEx;
|
|
|
|
miniport.OidRequestHandler = NeoNdisOidRequest;
|
|
|
|
miniport.ResetHandlerEx = NeoNdisResetEx;
|
|
|
|
miniport.CheckForHangHandlerEx = NeoNdisCheckForHangEx;
|
|
|
|
miniport.UnloadHandler = NeoNdisDriverUnload;
|
|
|
|
miniport.SendNetBufferListsHandler = NeoNdisSendNetBufferLists;
|
|
|
|
|
|
|
|
miniport.SetOptionsHandler = NeoNdisSetOptions;
|
|
|
|
miniport.PauseHandler = NeoNdisPause;
|
|
|
|
miniport.RestartHandler = NeoNdisRestart;
|
|
|
|
miniport.ReturnNetBufferListsHandler = NeoNdisReturnNetBufferLists;
|
|
|
|
miniport.CancelSendHandler = NeoNdisCancelSend;
|
|
|
|
miniport.DevicePnPEventNotifyHandler = NeoNdisDevicePnPEventNotify;
|
|
|
|
miniport.ShutdownHandlerEx = NeoNdisShutdownEx;
|
|
|
|
miniport.CancelOidRequestHandler = NeoNdisCancelOidRequest;
|
|
|
|
|
|
|
|
ret = NdisMRegisterMiniportDriver(DriverObject, RegistryPath,
|
|
|
|
NULL, &miniport, &ndis_miniport_driver_handle);
|
|
|
|
|
|
|
|
if (NG(ret))
|
|
|
|
{
|
|
|
|
// Registration failure
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialization success
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS NeoNdisSetOptions(NDIS_HANDLE NdisDriverHandle, NDIS_HANDLE DriverContext)
|
|
|
|
{
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS NeoNdisPause(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters)
|
|
|
|
{
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS NeoNdisRestart(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters)
|
|
|
|
{
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NeoNdisReturnNetBufferLists(NDIS_HANDLE MiniportAdapterContext, PNET_BUFFER_LIST NetBufferLists, ULONG ReturnFlags)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void NeoNdisCancelSend(NDIS_HANDLE MiniportAdapterContext, PVOID CancelId)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void NeoNdisDevicePnPEventNotify(NDIS_HANDLE MiniportAdapterContext, PNET_DEVICE_PNP_EVENT NetDevicePnPEvent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void NeoNdisShutdownEx(NDIS_HANDLE MiniportAdapterContext, NDIS_SHUTDOWN_ACTION ShutdownAction)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void NeoNdisCancelOidRequest(NDIS_HANDLE MiniportAdapterContext, PVOID RequestId)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialization handler of adapter
|
|
|
|
NDIS_STATUS NeoNdisInitEx(NDIS_HANDLE MiniportAdapterHandle,
|
|
|
|
NDIS_HANDLE MiniportDriverContext,
|
|
|
|
PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters)
|
|
|
|
{
|
|
|
|
NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES attr;
|
|
|
|
NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES gen;
|
|
|
|
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->NdisMiniportDriverHandle == NULL)
|
|
|
|
{
|
|
|
|
ctx->NdisMiniportDriverHandle = ndis_miniport_driver_handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prevention of multiple start
|
|
|
|
if (ctx->Initing != FALSE)
|
|
|
|
{
|
|
|
|
// Multiple started
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
ctx->Initing = TRUE;
|
|
|
|
|
|
|
|
// Examine whether it has already been initialized
|
|
|
|
if (ctx->Inited != FALSE)
|
|
|
|
{
|
|
|
|
// Driver is started on another instance already.
|
|
|
|
// VPN driver can start only one instance per one service.
|
|
|
|
// User can start multiple drivers with different instance ID
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Current value of the packet filter
|
|
|
|
ctx->CurrentPacketFilter = NDIS_PACKET_TYPE_ALL_LOCAL | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_ALL_FUNCTIONAL;
|
|
|
|
|
|
|
|
// Initialize the adapter information
|
|
|
|
ctx->NdisMiniport = MiniportAdapterHandle;
|
|
|
|
ctx->NdisContext = ctx;
|
|
|
|
ctx->HardwareStatus = NdisHardwareStatusReady;
|
|
|
|
ctx->Halting = FALSE;
|
|
|
|
ctx->Connected = ctx->ConnectedOld = FALSE;
|
|
|
|
|
|
|
|
if (keep_link == false)
|
|
|
|
{
|
|
|
|
ctx->ConnectedForce = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the information from the registry
|
|
|
|
if (NeoLoadRegistory() == FALSE)
|
|
|
|
{
|
|
|
|
// Failure
|
|
|
|
ctx->Initing = FALSE;
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register the device attributes
|
|
|
|
NeoZero(&attr, sizeof(attr));
|
|
|
|
attr.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
|
|
|
|
attr.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
|
|
|
|
attr.Header.Size = sizeof(NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES);
|
|
|
|
attr.AttributeFlags = NDIS_MINIPORT_ATTRIBUTES_NO_HALT_ON_SUSPEND;
|
|
|
|
attr.InterfaceType = NdisInterfaceInternal;
|
|
|
|
attr.MiniportAdapterContext = ctx->NdisContext;
|
|
|
|
|
|
|
|
NdisMSetMiniportAttributes(ctx->NdisMiniport, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&attr);
|
|
|
|
|
|
|
|
NeoZero(&gen, sizeof(gen));
|
|
|
|
gen.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
|
|
|
|
gen.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2;
|
|
|
|
gen.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2;
|
|
|
|
gen.MediaType = NdisMedium802_3;
|
|
|
|
gen.PhysicalMediumType = NdisPhysicalMedium802_3;
|
|
|
|
gen.MtuSize = NEO_MAX_PACKET_SIZE_ANNOUNCE - NEO_MIN_PACKET_SIZE;
|
|
|
|
gen.MaxXmitLinkSpeed = gen.MaxRcvLinkSpeed = max_speed;
|
|
|
|
gen.RcvLinkSpeed = gen.XmitLinkSpeed = max_speed;
|
|
|
|
gen.MediaConnectState = MediaConnectStateDisconnected;
|
|
|
|
gen.LookaheadSize = NEO_MAX_PACKET_SIZE_ANNOUNCE - NEO_MIN_PACKET_SIZE;
|
|
|
|
gen.MacOptions = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_NO_LOOPBACK;
|
|
|
|
gen.SupportedPacketFilters = NDIS_PACKET_TYPE_ALL_LOCAL | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_ALL_FUNCTIONAL;
|
|
|
|
gen.MaxMulticastListSize = NEO_MAX_MULTICASE;
|
|
|
|
gen.MacAddressLength = NEO_MAC_ADDRESS_SIZE;
|
|
|
|
NeoCopy(gen.PermanentMacAddress, ctx->MacAddress, NEO_MAC_ADDRESS_SIZE);
|
|
|
|
NeoCopy(gen.CurrentMacAddress, ctx->MacAddress, NEO_MAC_ADDRESS_SIZE);
|
|
|
|
gen.AccessType = NET_IF_ACCESS_BROADCAST;
|
|
|
|
gen.DirectionType = NET_IF_DIRECTION_SENDRECEIVE;
|
|
|
|
gen.ConnectionType = NET_IF_CONNECTION_DEDICATED;
|
|
|
|
gen.IfType = IF_TYPE_ETHERNET_CSMACD;
|
|
|
|
gen.IfConnectorPresent = TRUE;
|
|
|
|
gen.SupportedStatistics =
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT;
|
|
|
|
gen.SupportedPauseFunctions = NdisPauseFunctionsUnsupported;
|
|
|
|
gen.AutoNegotiationFlags = NDIS_LINK_STATE_XMIT_LINK_SPEED_AUTO_NEGOTIATED |
|
|
|
|
NDIS_LINK_STATE_RCV_LINK_SPEED_AUTO_NEGOTIATED |
|
|
|
|
NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED |
|
|
|
|
NDIS_LINK_STATE_PAUSE_FUNCTIONS_AUTO_NEGOTIATED;
|
|
|
|
gen.SupportedOidList = SupportedOids;
|
|
|
|
gen.SupportedOidListLength = sizeof(SupportedOids);
|
|
|
|
|
|
|
|
NdisMSetMiniportAttributes(ctx->NdisMiniport, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&gen);
|
|
|
|
|
|
|
|
// Initialize the received packet array
|
|
|
|
NeoInitPacketArray();
|
|
|
|
|
|
|
|
// Initialize the control device
|
|
|
|
NeoInitControlDevice();
|
|
|
|
|
|
|
|
// Start the adapter
|
|
|
|
NeoStartAdapter();
|
|
|
|
|
|
|
|
// Flag setting
|
|
|
|
ctx->Initing = FALSE;
|
|
|
|
ctx->Inited = TRUE;
|
|
|
|
|
|
|
|
// Notify the connection state
|
|
|
|
NeoSetConnectState(FALSE);
|
|
|
|
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open the device
|
|
|
|
BOOL NeoNdisOnOpen(IRP *irp, IO_STACK_LOCATION *stack)
|
|
|
|
{
|
|
|
|
char name[MAX_SIZE];
|
|
|
|
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->Opened != FALSE)
|
|
|
|
{
|
|
|
|
// Another client is connected already
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
ctx->Opened = TRUE;
|
|
|
|
|
|
|
|
// Initialize the event name
|
|
|
|
sprintf(name, NDIS_NEO_EVENT_NAME, ctx->HardwareID);
|
|
|
|
|
|
|
|
// Register a Event
|
|
|
|
ctx->Event = NeoNewEvent(name);
|
|
|
|
if (ctx->Event == NULL)
|
|
|
|
{
|
|
|
|
ctx->Opened = FALSE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the connection state
|
|
|
|
NeoSetConnectState(TRUE);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close the device
|
|
|
|
BOOL NeoNdisOnClose(IRP *irp, IO_STACK_LOCATION *stack)
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->Opened == FALSE)
|
|
|
|
{
|
|
|
|
// Client is not connected
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
ctx->Opened = FALSE;
|
|
|
|
|
|
|
|
// Release the event
|
|
|
|
NeoFreeEvent(ctx->Event);
|
|
|
|
ctx->Event = NULL;
|
|
|
|
|
|
|
|
// Release all packets
|
|
|
|
NeoClearPacketQueue();
|
|
|
|
|
|
|
|
NeoSetConnectState(FALSE);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Crash 2
|
|
|
|
void NeoNdisCrash2(UINT a, UINT b, UINT c, UINT d)
|
|
|
|
{
|
|
|
|
KeBugCheckEx(0x00000061, (ULONG_PTR)a, (ULONG_PTR)b, (ULONG_PTR)c, (ULONG_PTR)d);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Crash
|
|
|
|
void NeoNdisCrash()
|
|
|
|
{
|
|
|
|
NEO_QUEUE *q;
|
|
|
|
q = (NEO_QUEUE *)0xACACACAC;
|
|
|
|
q->Size = 128;
|
|
|
|
NeoCopy(q->Buf, "ABCDEFG", 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dispatch table for control
|
|
|
|
NTSTATUS NeoNdisDispatch(DEVICE_OBJECT *DeviceObject, IRP *Irp)
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
|
|
IO_STACK_LOCATION *stack;
|
|
|
|
void *buf;
|
|
|
|
BOOL ok;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the IRP stack
|
|
|
|
stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
|
|
|
|
// Initialize the number of bytes
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
buf = Irp->UserBuffer;
|
|
|
|
|
|
|
|
if (ctx->Halting != FALSE)
|
|
|
|
{
|
|
|
|
// Device driver is terminating
|
|
|
|
Irp->IoStatus.Information = STATUS_UNSUCCESSFUL;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Branch to each operation
|
|
|
|
switch (stack->MajorFunction)
|
|
|
|
{
|
|
|
|
case IRP_MJ_CREATE:
|
|
|
|
// Device is opened
|
|
|
|
if (NeoNdisOnOpen(Irp, stack) == FALSE)
|
|
|
|
{
|
|
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IRP_MJ_CLOSE:
|
|
|
|
// Device is closed
|
|
|
|
if (NeoNdisOnClose(Irp, stack) == FALSE)
|
|
|
|
{
|
|
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IRP_MJ_READ:
|
|
|
|
// Read (Reading of the received packet)
|
|
|
|
ok = false;
|
|
|
|
if (buf != NULL)
|
|
|
|
{
|
|
|
|
if (ctx->Opened && ctx->Inited)
|
|
|
|
{
|
|
|
|
if (stack->Parameters.Read.Length == NEO_EXCHANGE_BUFFER_SIZE)
|
|
|
|
{
|
|
|
|
// Address check
|
|
|
|
MDL *mdl = IoAllocateMdl(buf, NEO_EXCHANGE_BUFFER_SIZE, false, false, NULL);
|
|
|
|
|
|
|
|
if (mdl != NULL)
|
|
|
|
{
|
|
|
|
MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NeoIsKernelAddress(buf) == FALSE)
|
|
|
|
{
|
|
|
|
// Read
|
|
|
|
NeoRead(buf);
|
|
|
|
Irp->IoStatus.Information = NEO_EXCHANGE_BUFFER_SIZE;
|
|
|
|
ok = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mdl != NULL)
|
|
|
|
{
|
|
|
|
MmUnlockPages(mdl);
|
|
|
|
IoFreeMdl(mdl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ok == FALSE)
|
|
|
|
{
|
|
|
|
// An error occurred
|
|
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IRP_MJ_WRITE:
|
|
|
|
// Write (Writing of a transmission packet)
|
|
|
|
ok = false;
|
|
|
|
if (buf != NULL)
|
|
|
|
{
|
|
|
|
if (ctx->Opened && ctx->Inited)
|
|
|
|
{
|
|
|
|
if (stack->Parameters.Write.Length == NEO_EXCHANGE_BUFFER_SIZE)
|
|
|
|
{
|
|
|
|
// Address check
|
|
|
|
MDL *mdl = IoAllocateMdl(buf, NEO_EXCHANGE_BUFFER_SIZE, false, false, NULL);
|
|
|
|
|
|
|
|
if (mdl != NULL)
|
|
|
|
{
|
|
|
|
MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NeoIsKernelAddress(buf) == FALSE)
|
|
|
|
{
|
|
|
|
// Write
|
|
|
|
NeoWrite(buf);
|
|
|
|
Irp->IoStatus.Information = stack->Parameters.Write.Length;
|
|
|
|
ok = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mdl != NULL)
|
|
|
|
{
|
|
|
|
MmUnlockPages(mdl);
|
|
|
|
IoFreeMdl(mdl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ok == FALSE)
|
|
|
|
{
|
|
|
|
// An error occurred
|
|
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the control device
|
|
|
|
void NeoInitControlDevice()
|
|
|
|
{
|
|
|
|
char name_kernel[MAX_SIZE];
|
|
|
|
char name_win32[MAX_SIZE];
|
|
|
|
UNICODE *unicode_kernel, *unicode_win32;
|
|
|
|
DEVICE_OBJECT *control_device_object;
|
|
|
|
NDIS_HANDLE ndis_control_handle;
|
|
|
|
NDIS_DEVICE_OBJECT_ATTRIBUTES t;
|
|
|
|
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the dispatch table
|
|
|
|
NeoZero(ctx->DispatchTable, sizeof(PDRIVER_DISPATCH) * IRP_MJ_MAXIMUM_FUNCTION);
|
|
|
|
|
|
|
|
// Register the handler
|
|
|
|
ctx->DispatchTable[IRP_MJ_CREATE] =
|
|
|
|
ctx->DispatchTable[IRP_MJ_CLOSE] =
|
|
|
|
ctx->DispatchTable[IRP_MJ_READ] =
|
|
|
|
ctx->DispatchTable[IRP_MJ_WRITE] =
|
|
|
|
ctx->DispatchTable[IRP_MJ_DEVICE_CONTROL] = NeoNdisDispatch;
|
|
|
|
ctx->Opened = FALSE;
|
|
|
|
|
|
|
|
// Generate the device name
|
|
|
|
sprintf(name_kernel, NDIS_NEO_DEVICE_NAME, ctx->HardwareID);
|
|
|
|
unicode_kernel = NewUnicode(name_kernel);
|
|
|
|
sprintf(name_win32, NDIS_NEO_DEVICE_NAME_WIN32, ctx->HardwareID);
|
|
|
|
unicode_win32 = NewUnicode(name_win32);
|
|
|
|
|
|
|
|
// Register the device
|
|
|
|
NeoZero(&t, sizeof(t));
|
|
|
|
t.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
|
|
|
|
t.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
|
|
|
|
t.Header.Size = NDIS_SIZEOF_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
|
|
|
|
t.DeviceName = GetUnicode(unicode_kernel);
|
|
|
|
t.SymbolicName = GetUnicode(unicode_win32);
|
|
|
|
t.MajorFunctions = ctx->DispatchTable;
|
|
|
|
|
|
|
|
NdisRegisterDeviceEx(ndis_miniport_driver_handle, &t,
|
|
|
|
&control_device_object,
|
|
|
|
&ndis_control_handle);
|
|
|
|
|
|
|
|
ctx->NdisControlDevice = control_device_object;
|
|
|
|
ctx->NdisControl = ndis_control_handle;
|
|
|
|
|
|
|
|
// Initialize the display name
|
|
|
|
if (strlen(ctx->HardwareID) > 11)
|
|
|
|
{
|
|
|
|
sprintf(ctx->HardwarePrintableID, NDIS_NEO_HARDWARE_ID, ctx->HardwareID_Raw + 11);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf(ctx->HardwarePrintableID, NDIS_NEO_HARDWARE_ID, ctx->HardwareID_Raw);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the control device
|
|
|
|
void NeoFreeControlDevice()
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->Opened != FALSE)
|
|
|
|
{
|
|
|
|
// Delete the event
|
|
|
|
NeoSet(ctx->Event);
|
|
|
|
NeoFreeEvent(ctx->Event);
|
|
|
|
ctx->Event = NULL;
|
|
|
|
ctx->Opened = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete the device
|
|
|
|
NdisDeregisterDeviceEx(ctx->NdisControl);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Read the information from the registry
|
|
|
|
BOOL NeoLoadRegistory()
|
|
|
|
{
|
|
|
|
void *buf;
|
|
|
|
NDIS_STATUS ret;
|
|
|
|
UINT size;
|
|
|
|
NDIS_HANDLE config;
|
|
|
|
NDIS_CONFIGURATION_PARAMETER *param;
|
|
|
|
UNICODE *name;
|
|
|
|
ANSI_STRING ansi;
|
|
|
|
UNICODE_STRING *unicode;
|
|
|
|
UINT64 speed;
|
|
|
|
BOOL keep;
|
|
|
|
NDIS_CONFIGURATION_OBJECT config_obj;
|
|
|
|
|
|
|
|
// Get the Config handle
|
|
|
|
NeoZero(&config_obj, sizeof(config_obj));
|
|
|
|
config_obj.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
|
|
|
|
config_obj.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
|
|
|
|
config_obj.Header.Size = NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1;
|
|
|
|
config_obj.NdisHandle = ctx->NdisMiniport;
|
|
|
|
|
|
|
|
ret = NdisOpenConfigurationEx(&config_obj, &config);
|
|
|
|
if (NG(ret))
|
|
|
|
{
|
|
|
|
// Failure
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the MAC address
|
|
|
|
NdisReadNetworkAddress(&ret, &buf, &size, config);
|
|
|
|
if (NG(ret))
|
|
|
|
{
|
|
|
|
// Failure
|
|
|
|
NdisCloseConfiguration(config);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the MAC address
|
|
|
|
if (size != NEO_MAC_ADDRESS_SIZE)
|
|
|
|
{
|
|
|
|
// Invalid size
|
|
|
|
NdisCloseConfiguration(config);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
NeoCopy(ctx->MacAddress, buf, NEO_MAC_ADDRESS_SIZE);
|
|
|
|
|
|
|
|
if (ctx->MacAddress[0] == 0x00 &&
|
|
|
|
ctx->MacAddress[1] == 0x00 &&
|
|
|
|
ctx->MacAddress[2] == 0x01 &&
|
|
|
|
ctx->MacAddress[3] == 0x00 &&
|
|
|
|
ctx->MacAddress[4] == 0x00 &&
|
|
|
|
ctx->MacAddress[5] == 0x01)
|
|
|
|
{
|
|
|
|
// Special MAC address
|
|
|
|
UINT ptr32 = (UINT)((UINT64)ctx);
|
|
|
|
|
|
|
|
ctx->MacAddress[0] = 0x00;
|
|
|
|
ctx->MacAddress[1] = 0xAD;
|
|
|
|
ctx->MacAddress[2] = ((UCHAR *)(&ptr32))[0];
|
|
|
|
ctx->MacAddress[3] = ((UCHAR *)(&ptr32))[1];
|
|
|
|
ctx->MacAddress[4] = ((UCHAR *)(&ptr32))[2];
|
|
|
|
ctx->MacAddress[5] = ((UCHAR *)(&ptr32))[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the key name of the device name
|
|
|
|
name = NewUnicode("MatchingDeviceId");
|
|
|
|
|
|
|
|
// Read the hardware ID
|
|
|
|
NdisReadConfiguration(&ret, ¶m, config, GetUnicode(name), NdisParameterString);
|
|
|
|
FreeUnicode(name);
|
|
|
|
if (NG(ret))
|
|
|
|
{
|
|
|
|
// Failure
|
|
|
|
NdisCloseConfiguration(config);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
// Type checking
|
|
|
|
if (param->ParameterType != NdisParameterString)
|
|
|
|
{
|
|
|
|
// Failure
|
|
|
|
NdisCloseConfiguration(config);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
unicode = ¶m->ParameterData.StringData;
|
|
|
|
|
|
|
|
// Prepare a buffer for ANSI string
|
|
|
|
NeoZero(&ansi, sizeof(ANSI_STRING));
|
|
|
|
ansi.MaximumLength = MAX_SIZE - 1;
|
|
|
|
ansi.Buffer = NeoZeroMalloc(MAX_SIZE);
|
|
|
|
|
|
|
|
// Convert to ANSI string
|
|
|
|
NdisUnicodeStringToAnsiString(&ansi, unicode);
|
|
|
|
// Copy
|
|
|
|
strcpy(ctx->HardwareID, ansi.Buffer);
|
|
|
|
strcpy(ctx->HardwareID_Raw, ctx->HardwareID);
|
|
|
|
// Convert to upper case
|
|
|
|
_strupr(ctx->HardwareID);
|
|
|
|
// Release the memory
|
|
|
|
NeoFree(ansi.Buffer);
|
|
|
|
|
|
|
|
// Read the bit rate
|
|
|
|
name = NewUnicode("MaxSpeed");
|
|
|
|
NdisReadConfiguration(&ret, ¶m, config, GetUnicode(name), NdisParameterInteger);
|
|
|
|
FreeUnicode(name);
|
|
|
|
|
|
|
|
if (NG(ret) || param->ParameterType != NdisParameterInteger)
|
|
|
|
{
|
|
|
|
speed = NEO_MAX_SPEED_DEFAULT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
speed = (UINT64)param->ParameterData.IntegerData * 1000000ULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
max_speed = speed;
|
|
|
|
|
|
|
|
// Read the link keeping flag
|
|
|
|
name = NewUnicode("KeepLink");
|
|
|
|
NdisReadConfiguration(&ret, ¶m, config, GetUnicode(name), NdisParameterInteger);
|
|
|
|
FreeUnicode(name);
|
|
|
|
|
|
|
|
if (NG(ret) || param->ParameterType != NdisParameterInteger)
|
|
|
|
{
|
|
|
|
keep = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
keep = (param->ParameterData.IntegerData == 0 ? false : true);
|
|
|
|
}
|
|
|
|
|
|
|
|
keep_link = keep;
|
|
|
|
|
|
|
|
// Close the config handle
|
|
|
|
NdisCloseConfiguration(config);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unload the driver
|
|
|
|
VOID NeoNdisDriverUnload(PDRIVER_OBJECT DriverObject)
|
|
|
|
{
|
|
|
|
NdisMDeregisterMiniportDriver(ndis_miniport_driver_handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop handler of adapter
|
|
|
|
void NeoNdisHaltEx(NDIS_HANDLE MiniportAdapterContext, NDIS_HALT_ACTION HaltAction)
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->Halting != FALSE)
|
|
|
|
{
|
|
|
|
// That has already been stopped
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ctx->Halting = TRUE;
|
|
|
|
|
|
|
|
// Stop the adapter
|
|
|
|
NeoStopAdapter();
|
|
|
|
|
|
|
|
// Release the packet array
|
|
|
|
NeoFreePacketArray();
|
|
|
|
|
|
|
|
// Delete the control device
|
|
|
|
NeoFreeControlDevice();
|
|
|
|
|
|
|
|
// Complete to stop
|
|
|
|
ctx->Initing = ctx->Inited = FALSE;
|
|
|
|
ctx->Connected = ctx->ConnectedForce = ctx->ConnectedOld = FALSE;
|
|
|
|
ctx->Halting = FALSE;
|
|
|
|
|
|
|
|
// Shutdown of Neo
|
|
|
|
NeoShutdown();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset handler of adapter
|
|
|
|
NDIS_STATUS NeoNdisResetEx(NDIS_HANDLE MiniportAdapterContext, PBOOLEAN AddressingReset)
|
|
|
|
{
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hang-up check handler of adapter
|
|
|
|
BOOLEAN NeoNdisCheckForHangEx(NDIS_HANDLE MiniportAdapterContext)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// OID request handler
|
|
|
|
NDIS_STATUS NeoNdisOidRequest(NDIS_HANDLE MiniportAdapterContext,
|
|
|
|
PNDIS_OID_REQUEST OidRequest)
|
|
|
|
{
|
|
|
|
NDIS_STATUS ret = STATUS_UNSUCCESSFUL;
|
|
|
|
ULONG dummy = 0;
|
|
|
|
|
|
|
|
switch (OidRequest->RequestType)
|
|
|
|
{
|
|
|
|
case NdisRequestQueryInformation:
|
|
|
|
case NdisRequestQueryStatistics:
|
|
|
|
ret = NeoNdisQuery(MiniportAdapterContext,
|
|
|
|
OidRequest->DATA.QUERY_INFORMATION.Oid,
|
|
|
|
OidRequest->DATA.QUERY_INFORMATION.InformationBuffer,
|
|
|
|
OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
|
|
|
|
&OidRequest->DATA.QUERY_INFORMATION.BytesWritten,
|
|
|
|
&OidRequest->DATA.QUERY_INFORMATION.BytesNeeded);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NdisRequestSetInformation:
|
|
|
|
ret = NeoNdisSet(MiniportAdapterContext,
|
|
|
|
OidRequest->DATA.SET_INFORMATION.Oid,
|
|
|
|
OidRequest->DATA.SET_INFORMATION.InformationBuffer,
|
|
|
|
OidRequest->DATA.SET_INFORMATION.InformationBufferLength,
|
|
|
|
&dummy,
|
|
|
|
&OidRequest->DATA.SET_INFORMATION.BytesNeeded);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ret = NDIS_STATUS_NOT_SUPPORTED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Information acquisition handler of adapter
|
|
|
|
NDIS_STATUS NeoNdisQuery(NDIS_HANDLE MiniportAdapterContext,
|
|
|
|
NDIS_OID Oid,
|
|
|
|
void *InformationBuffer,
|
|
|
|
ULONG InformationBufferLength,
|
|
|
|
ULONG *BytesWritten,
|
|
|
|
ULONG *BytesNeeded)
|
|
|
|
{
|
|
|
|
NDIS_MEDIUM media;
|
|
|
|
void *buf;
|
|
|
|
UINT value32;
|
|
|
|
USHORT value16;
|
|
|
|
UINT size;
|
|
|
|
NDIS_STATISTICS_INFO stat;
|
|
|
|
NDIS_INTERRUPT_MODERATION_PARAMETERS intp;
|
|
|
|
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialization
|
|
|
|
size = sizeof(UINT);
|
|
|
|
value32 = value16 = 0;
|
|
|
|
buf = &value32;
|
|
|
|
|
|
|
|
// Branch processing
|
|
|
|
switch (Oid)
|
|
|
|
{
|
|
|
|
case OID_GEN_SUPPORTED_LIST:
|
|
|
|
// Return a list of supported OID
|
|
|
|
buf = SupportedOids;
|
|
|
|
size = sizeof(SupportedOids);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_MAC_OPTIONS:
|
|
|
|
// Ethernet option
|
|
|
|
value32 = NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
|
|
|
|
NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_NO_LOOPBACK;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_HARDWARE_STATUS:
|
|
|
|
// Hardware state
|
|
|
|
buf = &ctx->HardwareStatus;
|
|
|
|
size = sizeof(NDIS_HARDWARE_STATUS);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_MEDIA_SUPPORTED:
|
|
|
|
case OID_GEN_MEDIA_IN_USE:
|
|
|
|
// Type of media
|
|
|
|
media = NdisMedium802_3;
|
|
|
|
buf = &media;
|
|
|
|
size = sizeof(NDIS_MEDIUM);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
|
|
case OID_GEN_MAXIMUM_LOOKAHEAD:
|
|
|
|
// Read-ahead available size
|
|
|
|
value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE - NEO_MIN_PACKET_SIZE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
|
|
// Maximum frame size
|
|
|
|
value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE - NEO_MIN_PACKET_SIZE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
|
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
|
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
|
|
// Maximum packet size
|
|
|
|
value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_TRANSMIT_BUFFER_SPACE:
|
|
|
|
case OID_GEN_RECEIVE_BUFFER_SPACE:
|
|
|
|
// Buffer size
|
|
|
|
value32 = NEO_MAX_PACKET_SIZE_ANNOUNCE * NEO_MAX_PACKET_EXCHANGE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_LINK_SPEED:
|
|
|
|
// Communication speed
|
|
|
|
value32 = (UINT)(max_speed / 100);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_VENDOR_ID:
|
|
|
|
// Vendor ID
|
|
|
|
NeoCopy(&value32, ctx->MacAddress, 3);
|
|
|
|
value32 &= 0xFFFFFF00;
|
|
|
|
value32 |= 0x01;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
|
|
|
// Hardware ID
|
|
|
|
buf = ctx->HardwarePrintableID;
|
|
|
|
size = (UINT)strlen(ctx->HardwarePrintableID) + 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_DRIVER_VERSION:
|
|
|
|
// Driver version
|
|
|
|
value16 = ((USHORT)NEO_NDIS_MAJOR_VERSION << 8) | NEO_NDIS_MINOR_VERSION;
|
|
|
|
buf = &value16;
|
|
|
|
size = sizeof(USHORT);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_VENDOR_DRIVER_VERSION:
|
|
|
|
// Vendor driver version
|
|
|
|
value16 = ((USHORT)NEO_NDIS_MAJOR_VERSION << 8) | NEO_NDIS_MINOR_VERSION;
|
|
|
|
buf = &value16;
|
|
|
|
size = sizeof(USHORT);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
|
|
|
case OID_802_3_CURRENT_ADDRESS:
|
|
|
|
// MAC address
|
|
|
|
buf = ctx->MacAddress;
|
|
|
|
size = NEO_MAC_ADDRESS_SIZE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
|
|
|
// Number of multicast
|
|
|
|
value32 = NEO_MAX_MULTICASE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_MAXIMUM_SEND_PACKETS:
|
|
|
|
// Number of packets that can be sent at a time
|
|
|
|
value32 = NEO_MAX_PACKET_EXCHANGE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_XMIT_OK:
|
|
|
|
// Number of packets sent
|
|
|
|
value32 = ctx->Status.NumPacketSend;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_RCV_OK:
|
|
|
|
// Number of received packets
|
|
|
|
value32 = ctx->Status.NumPacketRecv;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_XMIT_ERROR:
|
|
|
|
// Number of transmission error packets
|
|
|
|
value32 = ctx->Status.NumPacketSendError;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_RCV_ERROR:
|
|
|
|
// Number of error packets received
|
|
|
|
value32 = ctx->Status.NumPacketRecvError;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_RCV_NO_BUFFER:
|
|
|
|
// Number of reception buffer shortage occurrences
|
|
|
|
value32 = ctx->Status.NumPacketRecvNoBuffer;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
|
|
// Number of errors
|
|
|
|
value32 = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_MEDIA_CONNECT_STATUS:
|
|
|
|
// Cable connection state
|
|
|
|
NeoCheckConnectState();
|
|
|
|
if (keep_link == false)
|
|
|
|
{
|
|
|
|
value32 = ctx->Connected ? NdisMediaStateConnected : NdisMediaStateDisconnected;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value32 = NdisMediaStateConnected;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
|
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
|
|
// Number of collisions
|
|
|
|
value32 = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
|
|
// Current settings of the packet filter
|
|
|
|
value32 = ctx->CurrentPacketFilter;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* case OID_GEN_PROTOCOL_OPTIONS:
|
|
|
|
// Current value of the protocol option
|
|
|
|
value32 = ctx->CurrentProtocolOptions;
|
|
|
|
break;*/
|
|
|
|
|
|
|
|
case OID_GEN_STATISTICS:
|
|
|
|
// Statistics (NDIS 6.0)
|
|
|
|
NeoZero(&stat, sizeof(stat));
|
|
|
|
buf = &stat;
|
|
|
|
size = sizeof(stat);
|
|
|
|
|
|
|
|
stat.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
|
|
|
|
stat.Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
|
|
|
|
stat.Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
|
|
|
|
stat.SupportedStatistics =
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT |
|
|
|
|
NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT;
|
|
|
|
|
|
|
|
stat.ifInErrors = ctx->Status.Int64NumRecvError;
|
|
|
|
stat.ifHCInOctets = ctx->Status.Int64BytesRecvTotal;
|
|
|
|
stat.ifHCInUcastPkts = ctx->Status.Int64NumRecvUnicast;
|
|
|
|
stat.ifHCInBroadcastPkts = ctx->Status.Int64NumRecvBroadcast;
|
|
|
|
stat.ifHCOutOctets = ctx->Status.Int64BytesSendTotal;
|
|
|
|
stat.ifHCOutUcastPkts = ctx->Status.Int64NumSendUnicast;
|
|
|
|
stat.ifHCOutBroadcastPkts = ctx->Status.Int64NumSendBroadcast;
|
|
|
|
stat.ifOutErrors = ctx->Status.Int64NumSendError;
|
|
|
|
stat.ifHCInUcastOctets = ctx->Status.Int64BytesRecvUnicast;
|
|
|
|
stat.ifHCInBroadcastOctets = ctx->Status.Int64BytesRecvBroadcast;
|
|
|
|
stat.ifHCOutUcastOctets = ctx->Status.Int64BytesSendUnicast;
|
|
|
|
stat.ifHCOutBroadcastOctets = ctx->Status.Int64BytesSendBroadcast;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OID_GEN_INTERRUPT_MODERATION:
|
|
|
|
// Interrupt Moderation (NDIS 6.0)
|
|
|
|
NeoZero(&intp, sizeof(intp));
|
|
|
|
buf = &intp;
|
|
|
|
size = sizeof(intp);
|
|
|
|
|
|
|
|
intp.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
|
|
|
|
intp.Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
|
|
|
|
intp.Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
|
|
|
|
intp.InterruptModeration = NdisInterruptModerationNotSupported;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Unknown OID
|
|
|
|
*BytesWritten = 0;
|
|
|
|
return NDIS_STATUS_INVALID_OID;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size > InformationBufferLength)
|
|
|
|
{
|
|
|
|
// Undersize
|
|
|
|
*BytesNeeded = size;
|
|
|
|
*BytesWritten = 0;
|
|
|
|
return NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Data copy
|
|
|
|
NeoCopy(InformationBuffer, buf, size);
|
|
|
|
*BytesWritten = size;
|
|
|
|
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the cable connection state
|
|
|
|
void NeoSetConnectState(BOOL connected)
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ctx->Connected = connected;
|
|
|
|
NeoCheckConnectState();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the cable connection state
|
|
|
|
void NeoCheckConnectState()
|
|
|
|
{
|
|
|
|
NDIS_STATUS_INDICATION t;
|
|
|
|
NDIS_LINK_STATE state;
|
|
|
|
if (ctx == NULL || ctx->NdisMiniport == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NeoZero(&t, sizeof(t));
|
|
|
|
t.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
|
|
|
|
t.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
|
|
|
|
t.Header.Size = NDIS_SIZEOF_STATUS_INDICATION_REVISION_1;
|
|
|
|
|
|
|
|
t.SourceHandle = ctx->NdisMiniport;
|
|
|
|
|
|
|
|
NeoZero(&state, sizeof(state));
|
|
|
|
state.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
|
|
|
|
state.Header.Revision = NDIS_LINK_STATE_REVISION_1;
|
|
|
|
state.Header.Size = NDIS_SIZEOF_LINK_STATE_REVISION_1;
|
|
|
|
|
|
|
|
state.MediaDuplexState = NdisPauseFunctionsSendAndReceive;
|
|
|
|
state.XmitLinkSpeed = state.RcvLinkSpeed = max_speed;
|
|
|
|
state.PauseFunctions = NdisPauseFunctionsUnsupported;
|
|
|
|
|
|
|
|
t.StatusCode = NDIS_STATUS_LINK_STATE;
|
|
|
|
t.StatusBuffer = &state;
|
|
|
|
t.StatusBufferSize = sizeof(NDIS_LINK_STATE);
|
|
|
|
|
|
|
|
if (keep_link == false)
|
|
|
|
{
|
|
|
|
if (ctx->ConnectedOld != ctx->Connected || ctx->ConnectedForce)
|
|
|
|
{
|
|
|
|
ctx->ConnectedForce = FALSE;
|
|
|
|
ctx->ConnectedOld = ctx->Connected;
|
|
|
|
if (ctx->Halting == FALSE)
|
|
|
|
{
|
|
|
|
state.MediaConnectState = ctx->Connected ? MediaConnectStateConnected : MediaConnectStateDisconnected;
|
|
|
|
NdisMIndicateStatusEx(ctx->NdisMiniport, &t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (ctx->ConnectedForce)
|
|
|
|
{
|
|
|
|
ctx->ConnectedForce = false;
|
|
|
|
|
|
|
|
if (ctx->Halting == FALSE)
|
|
|
|
{
|
|
|
|
state.MediaConnectState = MediaConnectStateConnected;
|
|
|
|
NdisMIndicateStatusEx(ctx->NdisMiniport, &t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Information setting handler of adapter
|
|
|
|
NDIS_STATUS NeoNdisSet(
|
|
|
|
NDIS_HANDLE MiniportAdapterContext,
|
|
|
|
NDIS_OID Oid,
|
|
|
|
void *InformationBuffer,
|
|
|
|
ULONG InformationBufferLength,
|
|
|
|
ULONG *BytesRead,
|
|
|
|
ULONG *BytesNeeded)
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialization
|
|
|
|
*BytesRead = 0;
|
|
|
|
*BytesNeeded = 0;
|
|
|
|
|
|
|
|
// Branch processing
|
|
|
|
switch (Oid)
|
|
|
|
{
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
|
|
/* Packet filter */
|
|
|
|
if (InformationBufferLength != 4)
|
|
|
|
{
|
|
|
|
*BytesNeeded = 4;
|
|
|
|
return NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
}
|
|
|
|
*BytesRead = 4;
|
|
|
|
ctx->CurrentPacketFilter = *((UINT *)InformationBuffer);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
|
|
// case OID_GEN_PROTOCOL_OPTIONS:
|
|
|
|
/* Current protocol option value */
|
|
|
|
/* if (InformationBufferLength != 4)
|
|
|
|
{
|
|
|
|
*BytesNeeded = 4;
|
|
|
|
return NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
}
|
|
|
|
*BytesRead = 4;
|
|
|
|
ctx->CurrentProtocolOptions = *((UINT *)InformationBuffer);
|
|
|
|
return NDIS_STATUS_SUCCESS;*/
|
|
|
|
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
|
|
/* Look ahead */
|
|
|
|
if (InformationBufferLength != 4)
|
|
|
|
{
|
|
|
|
*BytesNeeded = 4;
|
|
|
|
return NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
}
|
|
|
|
*BytesRead = 4;
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
|
|
case OID_GEN_LINK_PARAMETERS:
|
|
|
|
// NDIS 6.0 Link setting
|
|
|
|
*BytesRead = InformationBufferLength;
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
|
|
|
// Multicast list
|
|
|
|
*BytesRead = InformationBufferLength;
|
|
|
|
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NDIS_STATUS_INVALID_OID;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Packet send handler
|
|
|
|
void NeoNdisSendNetBufferLists(NDIS_HANDLE MiniportAdapterContext,
|
|
|
|
NET_BUFFER_LIST *NetBufferLists,
|
|
|
|
NDIS_PORT_NUMBER PortNumber,
|
|
|
|
ULONG SendFlags)
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the connection state
|
|
|
|
NeoCheckConnectState();
|
|
|
|
|
|
|
|
if (NeoNdisSendPacketsHaltCheck(NetBufferLists) == FALSE)
|
|
|
|
{
|
|
|
|
// Device is stopped
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Operation of the packet queue
|
|
|
|
NeoLockPacketQueue();
|
|
|
|
{
|
|
|
|
NET_BUFFER_LIST *nbl;
|
|
|
|
if (NeoNdisSendPacketsHaltCheck(NetBufferLists) == FALSE)
|
|
|
|
{
|
|
|
|
// Device is stopped
|
|
|
|
NeoUnlockPacketQueue();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nbl = NetBufferLists;
|
|
|
|
|
|
|
|
while (nbl != NULL)
|
|
|
|
{
|
|
|
|
NET_BUFFER *nb = NET_BUFFER_LIST_FIRST_NB(nbl);
|
|
|
|
|
|
|
|
while (nb != NULL)
|
|
|
|
{
|
|
|
|
UINT size = NET_BUFFER_DATA_LENGTH(nb);
|
|
|
|
|
|
|
|
if (size >= NEO_MIN_PACKET_SIZE && size <= NEO_MAX_PACKET_SIZE)
|
|
|
|
{
|
|
|
|
UCHAR *buf = NeoMalloc(size);
|
|
|
|
void *ptr;
|
|
|
|
|
|
|
|
ptr = NdisGetDataBuffer(nb, size, buf, 1, 0);
|
|
|
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
{
|
|
|
|
ctx->Status.NumPacketSendError++;
|
|
|
|
ctx->Status.Int64NumSendError++;
|
|
|
|
NeoFree(buf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (ptr != buf)
|
|
|
|
{
|
|
|
|
NeoCopy(buf, ptr, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
NeoInsertQueue(buf, size);
|
|
|
|
ctx->Status.NumPacketSend++;
|
|
|
|
|
|
|
|
if (buf[0] & 0x40)
|
|
|
|
{
|
|
|
|
ctx->Status.Int64NumSendBroadcast++;
|
|
|
|
ctx->Status.Int64BytesSendBroadcast += (UINT64)size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ctx->Status.Int64NumSendUnicast++;
|
|
|
|
ctx->Status.Int64BytesSendUnicast += (UINT64)size;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->Status.Int64BytesSendTotal += (UINT64)size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ctx->Status.NumPacketSendError++;
|
|
|
|
ctx->Status.Int64NumSendError++;
|
|
|
|
}
|
|
|
|
|
|
|
|
nb = NET_BUFFER_NEXT_NB(nb);
|
|
|
|
}
|
|
|
|
|
|
|
|
nbl = NET_BUFFER_LIST_NEXT_NBL(nbl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NeoUnlockPacketQueue();
|
|
|
|
|
|
|
|
// Notify the transmission completion
|
|
|
|
NdisMSendNetBufferListsComplete(ctx->NdisMiniport, NetBufferLists, NDIS_STATUS_SUCCESS);
|
|
|
|
|
|
|
|
// Reception event
|
|
|
|
NeoSet(ctx->Event);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop check of packet transmission
|
|
|
|
BOOL NeoNdisSendPacketsHaltCheck(NET_BUFFER_LIST *NetBufferLists)
|
|
|
|
{
|
|
|
|
if (ctx == NULL)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->Halting != FALSE || ctx->Opened == FALSE)
|
|
|
|
{
|
|
|
|
// Halting
|
|
|
|
NdisMSendNetBufferListsComplete(ctx->NdisMiniport, NetBufferLists, NDIS_STATUS_FAILURE);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the packet array
|
|
|
|
void NeoInitPacketArray()
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
// Create a packet buffer
|
|
|
|
for (i = 0;i < NEO_MAX_PACKET_EXCHANGE;i++)
|
|
|
|
{
|
|
|
|
ctx->PacketBuffer[i] = NeoNewPacketBuffer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the packet array
|
|
|
|
void NeoFreePacketArray()
|
|
|
|
{
|
|
|
|
UINT i;
|
|
|
|
for (i = 0;i < NEO_MAX_PACKET_EXCHANGE;i++)
|
|
|
|
{
|
|
|
|
NeoFreePacketBuffer(ctx->PacketBuffer[i]);
|
|
|
|
ctx->PacketBuffer[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the packet buffer
|
|
|
|
void NeoFreePacketBuffer(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
|
|
|
|
NeoFree(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a packet buffer
|
|
|
|
PACKET_BUFFER *NeoNewPacketBuffer()
|
|
|
|
{
|
|
|
|
PACKET_BUFFER *p;
|
|
|
|
NET_BUFFER_LIST_POOL_PARAMETERS p1;
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
p = NeoZeroMalloc(sizeof(PACKET_BUFFER));
|
|
|
|
|
|
|
|
// Create a NET_BUFFER_LIST pool
|
|
|
|
NeoZero(&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 = NEO_MAX_PACKET_SIZE;
|
|
|
|
p->NetBufferListPool = NdisAllocateNetBufferListPool(NULL, &p1);
|
|
|
|
|
|
|
|
// Create a NET_BUFFER_LIST
|
|
|
|
p->NetBufferList = NdisAllocateNetBufferList(p->NetBufferListPool, 0, 0);
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether the specified address is kernel memory
|
|
|
|
BOOL NeoIsKernelAddress(void *addr)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
if ((ULONG)addr >= (ULONG)0x80000000)
|
|
|
|
{
|
|
|
|
// Kernel memory
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#endif // CPU_64
|
|
|
|
// User memory
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset the event
|
|
|
|
void NeoReset(NEO_EVENT *event)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (event == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeResetEvent(event->event);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the event
|
|
|
|
void NeoSet(NEO_EVENT *event)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (event == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeSetEvent(event->event, 0, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the event
|
|
|
|
void NeoFreeEvent(NEO_EVENT *event)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (event == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZwClose(event->event_handle);
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
NeoFree(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new event
|
|
|
|
NEO_EVENT *NeoNewEvent(char *name)
|
|
|
|
{
|
|
|
|
UNICODE *unicode_name;
|
|
|
|
NEO_EVENT *event;
|
|
|
|
// Validate arguments
|
|
|
|
if (name == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert the name to Unicode
|
|
|
|
unicode_name = NewUnicode(name);
|
|
|
|
if (unicode_name == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
event = NeoZeroMalloc(sizeof(NEO_EVENT));
|
|
|
|
if (event == NULL)
|
|
|
|
{
|
|
|
|
FreeUnicode(unicode_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an Event
|
|
|
|
event->event = IoCreateNotificationEvent(GetUnicode(unicode_name), &event->event_handle);
|
|
|
|
if (event->event == NULL)
|
|
|
|
{
|
|
|
|
NeoFree(event);
|
|
|
|
FreeUnicode(unicode_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the event
|
|
|
|
KeInitializeEvent(event->event, NotificationEvent, FALSE);
|
|
|
|
KeClearEvent(event->event);
|
|
|
|
|
|
|
|
// Release a string
|
|
|
|
FreeUnicode(unicode_name);
|
|
|
|
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the Unicode string
|
|
|
|
NDIS_STRING *GetUnicode(UNICODE *u)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (u == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &u->String;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the Unicode strings
|
|
|
|
void FreeUnicode(UNICODE *u)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (u == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release a string
|
|
|
|
NdisFreeString(u->String);
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
NeoFree(u);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new Unicode string
|
|
|
|
UNICODE *NewUnicode(char *str)
|
|
|
|
{
|
|
|
|
UNICODE *u;
|
|
|
|
// Validate arguments
|
|
|
|
if (str == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
u = NeoZeroMalloc(sizeof(UNICODE));
|
|
|
|
if (u == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// String initialization
|
|
|
|
NdisInitializeString(&u->String, str);
|
|
|
|
|
|
|
|
return u;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the lock
|
|
|
|
void NeoFreeLock(NEO_LOCK *lock)
|
|
|
|
{
|
|
|
|
NDIS_SPIN_LOCK *spin_lock;
|
|
|
|
// Validate arguments
|
|
|
|
if (lock == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock = &lock->spin_lock;
|
|
|
|
NdisFreeSpinLock(spin_lock);
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
NeoFree(lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unlock
|
|
|
|
void NeoUnlock(NEO_LOCK *lock)
|
|
|
|
{
|
|
|
|
NDIS_SPIN_LOCK *spin_lock;
|
|
|
|
// Validate arguments
|
|
|
|
if (lock == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock = &lock->spin_lock;
|
|
|
|
NdisReleaseSpinLock(spin_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lock
|
|
|
|
void NeoLock(NEO_LOCK *lock)
|
|
|
|
{
|
|
|
|
NDIS_SPIN_LOCK *spin_lock;
|
|
|
|
// Validate arguments
|
|
|
|
if (lock == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock = &lock->spin_lock;
|
|
|
|
NdisAcquireSpinLock(spin_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Creating a new lock
|
|
|
|
NEO_LOCK *NeoNewLock()
|
|
|
|
{
|
|
|
|
NDIS_SPIN_LOCK *spin_lock;
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
NEO_LOCK *lock = NeoZeroMalloc(sizeof(NEO_LOCK));
|
|
|
|
if (lock == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize spin lock
|
|
|
|
spin_lock = &lock->spin_lock;
|
|
|
|
|
|
|
|
NdisAllocateSpinLock(spin_lock);
|
|
|
|
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory copy
|
|
|
|
void NeoCopy(void *dst, void *src, UINT size)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (dst == NULL || src == NULL || size == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy
|
|
|
|
NdisMoveMemory(dst, src, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory clear
|
|
|
|
void NeoZero(void *dst, UINT size)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (dst == NULL || size == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear
|
|
|
|
NdisZeroMemory(dst, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear to zero by memory allocation
|
|
|
|
void *NeoZeroMalloc(UINT size)
|
|
|
|
{
|
|
|
|
void *p = NeoMalloc(size);
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
// Memory allocation failure
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
// Clear to zero
|
|
|
|
NeoZero(p, size);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Memory allocation
|
|
|
|
void *NeoMalloc(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
void NeoFree(void *p)
|
|
|
|
{
|
|
|
|
// Validate arguments
|
|
|
|
if (p == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the memory
|
|
|
|
NdisFreeMemory(p, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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/
|