tapdrvr.c revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/*
* TAP-Win32 -- A kernel driver to provide virtual tap device
* functionality on Windows. Originally derived
* from the CIPE-Win32 project by Damion K. Wilson,
* with extensive modifications by James Yonan.
*
* All source code which derives from the CIPE-Win32 project is
* Copyright (C) Damion K. Wilson, 2003, and is released under the
* GPL version 2 (see below).
*
* All other source code is Copyright (C) 2002-2005 OpenVPN Solutions LLC,
* and is released under the GPL version 2 (see below).
*
* 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
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//======================================================
// This driver is designed to work on Win 2000 or higher
// versions of Windows.
//
// It is SMP-safe and handles NDIS 5 power management.
//
// By default we operate as a "tap" virtual ethernet
// 802.3 interface, but we can emulate a "tun"
// interface (point-to-point IPv4) through the
// TAP_IOCTL_CONFIG_POINT_TO_POINT ioctl.
//======================================================
#define NDIS_MINIPORT_DRIVER
#define BINARY_COMPATIBLE 0
#define NDIS50_MINIPORT 1
#define NDIS_WDM 0
#define NDIS50 1
#define NTSTRSAFE_LIB
// Debug info output
#define ALSO_DBGPRINT 1
#define DEBUGP_AT_DISPATCH 0
#include <ndis.h>
#include <ntstrsafe.h>
#include "lock.h"
#include "constants.h"
#include "common.h"
#include "proto.h"
#include "error.h"
#include "endian.h"
#include "dhcp.h"
#include "types.h"
#include "prototypes.h"
#include "mem.c"
#include "macinfo.c"
#include "error.c"
#include "dhcp.c"
#include "instance.c"
#define INCREMENT_STAT(s) ++(s)
#define NAME_BUFFER_SIZE 80
//========================================================
// Globals
//========================================================
const UINT g_SupportedOIDList[] = {
};
//============================================================
// Driver Entry
//============================================================
#pragma NDIS_INIT_FUNCTION (DriverEntry)
{
//========================================================
// Notify NDIS that a new miniport driver is initializing.
//========================================================
//======================
// Global initialization
//======================
#if DBG
#endif
if (!InitInstanceList ())
{
DEBUGP (("[TAP] Allocation failed for adapter instance list\n"));
goto cleanup;
}
//=======================================
// Set and register miniport entry points
//=======================================
if (l_Properties == NULL)
{
DEBUGP (("[TAP] Allocation failed for miniport entry points\n"));
goto cleanup;
}
switch (l_Status =
sizeof (NDIS_MINIPORT_CHARACTERISTICS)))
{
case NDIS_STATUS_SUCCESS:
{
DEBUGP (("[TAP] version [%d.%d] %s %s registered miniport successfully\n",
__TIME__));
break;
}
{
DEBUGP (("[TAP] Miniport characteristics were badly defined\n"));
break;
}
case NDIS_STATUS_BAD_VERSION:
{
(("[TAP] NDIS Version is wrong for the given characteristics\n"));
break;
}
case NDIS_STATUS_RESOURCES:
{
DEBUGP (("[TAP] Insufficient resources\n"));
break;
}
default:
case NDIS_STATUS_FAILURE:
{
DEBUGP (("[TAP] Unknown fatal registration error\n"));
break;
}
}
if (l_Properties)
if (l_Status == NDIS_STATUS_SUCCESS)
else
return l_Status;
}
//============================================================
// Driver Unload
//============================================================
{
DEBUGP (("[TAP] version [%d.%d] %s %s unloaded, instances=%d, imbs=%d\n",
NInstances(),
FreeInstanceList ();
//==============================
// Free debugging text space
//==============================
#if DBG
MyDebugFree ();
#endif
}
//==========================================================
// Adapter Initialization
//==========================================================
{
//====================================
// Make sure adapter type is supported
//====================================
for (l_Index = 0;
++l_Index);
if (l_Index == p_MediaCount)
{
DEBUGP (("[TAP] Unsupported adapter type [wanted: %d]\n",
return NDIS_STATUS_UNSUPPORTED_MEDIA;
}
*p_MediaIndex = l_Index;
//=========================================
// Allocate memory for TapAdapter structure
//=========================================
{
DEBUGP (("[TAP] Couldn't allocate adapter memory\n"));
return NDIS_STATUS_RESOURCES;
}
//==========================================
// Inform the NDIS library about significant
// features of our virtual NIC.
//==========================================
16,
//=====================================
// Initialize simple Adapter parameters
//=====================================
//==================================
// Allocate spinlock for controlling
// access to multicast address list.
//==================================
//====================================================
// Register a shutdown handler which will be called
//====================================================
//============================================
// Get parameters from registry which were set
// in the adapter advanced properties dialog.
//============================================
{
// set defaults in case our registry query fails
if (status != NDIS_STATUS_SUCCESS)
{
DEBUGP (("[TAP] Couldn't open adapter registry\n"));
return status;
}
//====================================
// Allocate and construct adapter name
//====================================
{
if (status == NDIS_STATUS_SUCCESS)
{
{
DEBUGP (("[TAP] NdisReadConfiguration (MiniportName=%s)\n", parm->ParameterData.StringData.Buffer));
TRUE) != STATUS_SUCCESS)
{
DEBUGP (("[TAP] RtlUnicodeStringToAnsiString MiniportName failed\n"));
}
}
} else {
/* "MiniportName" is available only XP and above. Not on Windows 2000. */
if (status == NDIS_STATUS_SUCCESS)
{
{
/* Fallback for Windows 2000 with NDIS version 5.00.00
Don't use this on Vista, 'NDIS_MINIPORT_BLOCK' was changed! */
TRUE) != STATUS_SUCCESS)
{
DEBUGP (("[TAP] RtlUnicodeStringToAnsiString MiniportName (W2K) failed\n"));
}
}
}
}
}
/* Can't continue without name (see macro 'NAME') */
{
return NDIS_STATUS_RESOURCES;
}
/* Read MTU setting from registry */
{
if (status == NDIS_STATUS_SUCCESS)
{
{
if (mtu < MINIMUM_MTU)
mtu = MINIMUM_MTU;
if (mtu > MAXIMUM_MTU)
mtu = MAXIMUM_MTU;
}
}
}
/* Read Media Status setting from registry */
{
if (status == NDIS_STATUS_SUCCESS)
{
{
{
}
}
}
}
/* Read optional MAC setting from registry */
{
if (status == NDIS_STATUS_SUCCESS)
{
{
if (RtlUnicodeStringToAnsiString (&mac_string, &parm->ParameterData.StringData, TRUE) == STATUS_SUCCESS)
{
}
}
}
}
}
//==================================
// Store and update MAC address info
//==================================
if (!l_MacFromRegistry)
DEBUGP (("[%s] Using MAC %x:%x:%x:%x:%x:%x\n",
//==================
// Set broadcast MAC
//==================
{
int i;
for (i = 0; i < sizeof (MACADDR); ++i)
}
//====================================
// Initialize TAP device
//====================================
{
if (tap_status != NDIS_STATUS_SUCCESS)
{
return tap_status;
}
}
if (!AddAdapterToInstanceList (l_Adapter))
{
NOTE_ERROR ();
return NDIS_STATUS_RESOURCES;
}
return NDIS_STATUS_SUCCESS;
}
{
NOTE_ERROR ();
// Free resources
DEBUGP (("[TAP] version [%d.%d] %s %s AdapterHalt returning\n",
__TIME__));
}
{
if (p_Adapter->m_MCLockAllocated)
}
{
//======================================
// Let clients know we are shutting down
//======================================
p_Extension->m_TapOpens = 0;
//=====================================
// If we are concurrently executing in
// TapDeviceHook or AdapterTransmit,
// give those calls time to finish.
// Note that we must be running at IRQL
// < DISPATCH_LEVEL in order to call
// NdisMSleep.
//=====================================
NdisMSleep (500000);
//===========================================================
// Exhaust IRP and packet queues. Any pending IRPs will
// be cancelled, causing user-space to get this error
// on overlapped reads:
// The I/O operation has been aborted because of either a
// thread exit or an application request. (code=995)
// It's important that user-space close the device handle
// when this code is returned, so that when we finally
// do a NdisMDeregisterDevice, the device reference count
// is 0. Otherwise the driver will not unload even if the
// the last adapter has been halted.
//===========================================================
}
{
if (p_Extension->m_PacketQueue)
if (p_Extension->m_IrpQueue)
//==========================================================
// According to DDK docs, the device is not actually deleted
// until its reference count falls to zero. That means we
// still need to gracefully fail TapDeviceHook requests
// after this point, otherwise ugly things would happen if
// the device was disabled (e.g. in the network connections
// control panel) while a userspace app still held an open
// file handle to it.
//==========================================================
if (p_Extension->m_TapDevice)
{
== NDIS_STATUS_SUCCESS);
}
if (p_Extension->m_TapName)
}
//========================================================================
// Tap Device Initialization
//========================================================================
{
const char *l_UsableName;
DEBUGP (("[TAP] version [%d.%d] creating tap device: %s\n",
p_Name));
//=======================================
// Set TAP device entry points
//=======================================
{
goto cleanup;
}
//==================================
// Find the beginning of the GUID
//==================================
while (*l_UsableName != '{')
{
if (*l_UsableName == '\0')
{
goto cleanup;
}
++l_UsableName;
}
//==================================
// Allocate pool for TAP device name
//==================================
{
goto cleanup;
}
//================================================
// Allocate pool for TAP symbolic link name buffer
//================================================
if ((l_LinkString.Buffer =
{
DEBUGP (("[%s] couldn't alloc TAP symbolic link name buffer\n",
p_Name));
goto cleanup;
}
//=======================================================
// Set TAP device name
//=======================================================
NULL,
NULL,
"%s%s%s",
if (l_Status != STATUS_SUCCESS)
{
DEBUGP (("[%s] couldn't format TAP device name\n",
p_Name));
goto cleanup;
}
//=======================================================
// Set TAP link name
//=======================================================
NULL,
NULL,
"%s%s%s",
if (l_Status != STATUS_SUCCESS)
{
DEBUGP (("[%s] couldn't format TAP device symbolic link\n",
p_Name));
goto cleanup;
}
//==================================================
// Convert strings to unicode
//==================================================
{
DEBUGP (("[%s] couldn't alloc TAP unicode name buffer\n",
p_Name));
goto cleanup;
}
!= STATUS_SUCCESS)
{
(("[%s] Couldn't allocate unicode string for symbolic link name\n",
p_Name));
goto cleanup;
}
//==================================================
// Create new TAP device with symbolic
// link and associate with adapter.
//==================================================
);
if (l_Status != STATUS_SUCCESS)
{
goto cleanup;
}
/* Set TAP device flags */
//========================================================
// Initialize Packet and IRP queues.
//
// The packet queue is used to buffer data which has been
// "transmitted" by the virtual NIC, before user space
// has had a chance to read it.
//
// The IRP queue is used to buffer pending I/O requests
// from userspace, i.e. read requests on the TAP device
// waiting for the system to "transmit" something through
// the virtual NIC.
//
// Basically, packets in the packet queue are used
// to satisfy IRP requests in the IRP queue.
//
// QueueLock is used to lock the packet queue used
// for the TAP-Win32 NIC -> User Space packet flow direction.
//
// All accesses to packet or IRP queues should be
// bracketed by the QueueLock spinlock,
// in order to be SMP-safe.
//========================================================
if (!p_Extension->m_PacketQueue
|| !p_Extension->m_IrpQueue)
{
goto cleanup;
}
//========================
// Finalize initialization
//========================
p_Extension->m_TapName));
if (l_FreeTapUnicode)
if (l_LinkString.Buffer)
if (l_Dispatch)
if (l_Return != NDIS_STATUS_SUCCESS)
return l_Return;
}
//========================================================
// Adapter Control
//========================================================
{
return NDIS_STATUS_SUCCESS;
}
{
return NDIS_STATUS_SUCCESS;
}
//==============================================================
// Adapter Option Query/Modification
//==============================================================
{
switch (p_OID)
{
//===================================================================
// Vendor & Driver version Info
//===================================================================
break;
case OID_GEN_VENDOR_ID:
break;
case OID_GEN_DRIVER_VERSION:
l_QueryLength = sizeof (unsigned short);
break;
break;
//=================================================================
// Statistics
//=================================================================
case OID_GEN_RCV_NO_BUFFER:
break;
break;
break;
break;
case OID_GEN_XMIT_OK:
break;
case OID_GEN_RCV_OK:
break;
case OID_GEN_XMIT_ERROR:
break;
case OID_GEN_RCV_ERROR:
break;
//===================================================================
// Device & Protocol Options
//===================================================================
case OID_GEN_SUPPORTED_LIST:
l_QueryLength = sizeof (g_SupportedOIDList);
break;
case OID_GEN_MAC_OPTIONS:
// This MUST be here !!!
break;
break;
case OID_GEN_PROTOCOL_OPTIONS:
break;
//==================================================================
// Device Info
//==================================================================
break;
case OID_GEN_HARDWARE_STATUS:
l_QueryLength = sizeof (NDIS_HARDWARE_STATUS);
break;
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
l_QueryLength = sizeof (NDIS_MEDIUM);
break;
case OID_GEN_PHYSICAL_MEDIUM:
l_QueryLength = sizeof (NDIS_PHYSICAL_MEDIUM);
break;
case OID_GEN_LINK_SPEED:
break;
l_QueryLength = sizeof (MACADDR);
break;
//==================================================================
// Limits
//==================================================================
break;
break;
break;
break;
break;
case OID_PNP_CAPABILITIES:
do
{
if (p_BufferLength >= sizeof (NDIS_PNP_CAPABILITIES))
{
//
// Setting up the buffer to be returned
// to the Protocol above the Passthru miniport
//
}
l_QueryLength = sizeof (NDIS_PNP_CAPABILITIES);
}
while (FALSE);
break;
case OID_PNP_QUERY_POWER:
break;
// Required OIDs that we don't support
case OID_GEN_SUPPORTED_GUIDS:
case OID_TCP_TASK_OFFLOAD:
case OID_FFP_SUPPORT:
break;
// Optional stats OIDs
break;
//===================================================================
// Not Handled
//===================================================================
default:
break;
}
if (l_Status != NDIS_STATUS_SUCCESS)
;
else if (l_QueryLength > p_BufferLength)
{
}
else
(*p_BytesWritten = l_QueryLength));
return l_Status;
}
{
switch (p_OID)
{
//==================================================================
// Device Info
//==================================================================
case OID_802_3_MULTICAST_LIST:
DEBUGP (("[%s] Setting [OID_802_3_MULTICAST_LIST]\n",
*p_BytesNeeded = sizeof (ETH_ADDR);
if (p_BufferLength % sizeof (ETH_ADDR))
else if (p_BufferLength > sizeof (MC_LIST))
{
*p_BytesNeeded = sizeof (MC_LIST);
}
else
{
}
break;
*p_BytesNeeded = 4;
if (p_BufferLength >= sizeof (ULONG))
{
(("[%s] Setting [OID_GEN_CURRENT_PACKET_FILTER] to [0x%02lx]\n",
*p_BytesRead = sizeof (ULONG);
}
break;
if (p_BufferLength < sizeof (ULONG))
{
*p_BytesNeeded = 4;
}
{
}
else
{
DEBUGP (("[%s] Setting [OID_GEN_CURRENT_LOOKAHEAD] to [%d]\n",
*p_BytesRead = sizeof (ULONG);
}
break;
*p_BytesRead = *p_BytesNeeded = 0;
break;
*p_BytesRead = *p_BytesNeeded = 0;
break;
case OID_PNP_SET_POWER:
do
{
switch (NewDeviceState)
{
case NdisDeviceStateD0:
break;
case NdisDeviceStateD1:
break;
case NdisDeviceStateD2:
break;
case NdisDeviceStateD3:
break;
default:
break;
}
//
// Check for invalid length
//
if (p_BufferLength < sizeof (NDIS_DEVICE_POWER_STATE))
{
break;
}
if (NewDeviceState > NdisDeviceStateD0)
{
DEBUGP (("[%s] Power management device state OFF\n",
}
else
{
DEBUGP (("[%s] Power management device state ON\n",
}
}
while (FALSE);
if (l_Status == NDIS_STATUS_SUCCESS)
{
*p_BytesRead = sizeof (NDIS_DEVICE_POWER_STATE);
*p_BytesNeeded = 0;
}
else
{
*p_BytesRead = 0;
*p_BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
}
break;
*p_BytesRead = *p_BytesNeeded = 0;
break;
default:
p_OID));
*p_BytesRead = *p_BytesNeeded = 0;
break;
}
return l_Status;
}
//====================================================================
// Adapter Transmission
//====================================================================
{
//// DEBUGP(("AdapterTransmit %08x size=%x\n", l_NDIS_Buffer, l_PacketLength));
//====================================================
// Here we abandon the transmission attempt if any of
// the parameters is wrong or memory allocation fails
// but we do not indicate failure. The packet is
// silently dropped.
//====================================================
goto exit_fail;
goto exit_success; // Nothing is bound to the TAP device
'5PAT') != NDIS_STATUS_SUCCESS)
goto exit_no_resources;
if (l_PacketBuffer == NULL)
goto exit_no_resources;
//===========================
// Reassemble packet contents
//===========================
{
{
}
//=====================================================
// Are we running in DHCP server masquerade mode?
//
// If so, catch both DHCP requests and ARP queries
// to resolve the address of our virtual DHCP server.
//=====================================================
if (l_Adapter->m_dhcp_enabled)
{
// ARP packet?
if (l_PacketLength == sizeof (ARP_PACKET)
{
if (ProcessARP (l_Adapter,
goto no_queue;
}
// DHCP packet?
{
+ sizeof (ETH_HEADER)
+ sizeof (IPHDR)
+ sizeof (UDPHDR));
const int optlen = l_PacketLength
- sizeof (ETH_HEADER)
- sizeof (IPHDR)
- sizeof (UDPHDR)
- sizeof (DHCP);
if (optlen > 0) // we must have at least one DHCP option
{
goto no_queue;
}
else
goto no_queue;
}
}
//===============================================
// In Point-To-Point mode, check to see whether
// packet is ARP or IPv4 (if neither, then drop).
//===============================================
if (l_Adapter->m_PointToPoint)
{
ETH_HEADER *e;
goto no_queue;
{
case ETH_P_ARP:
// Make sure that packet is the
// right size for ARP.
if (l_PacketLength != sizeof (ARP_PACKET))
goto no_queue;
default:
goto no_queue;
case ETH_P_IP:
// Make sure that packet is large
// enough to be IPv4.
if (l_PacketLength
goto no_queue;
// Only accept directed packets,
// not broadcasts.
goto no_queue;
// Packet looks like IPv4, queue it.
}
}
//===============================================
// Push packet onto queue to wait for read from
// userspace.
//===============================================
{
// adapter receive overrun
goto no_queue;
}
else
{
}
//============================================================
// Cycle through IRPs and packets, try to satisfy each pending
// IRP with a queued packet.
//============================================================
while (TRUE)
{
{
}
if (l_IRP && l_PacketBuffer)
{
}
else
break;
}
}
{
}
return NDIS_STATUS_SUCCESS;
0);
return NDIS_STATUS_SUCCESS;
return NDIS_STATUS_FAILURE;
return NDIS_STATUS_RESOURCES;
}
//======================================================================
// Hooks for catching TAP device IRP's.
//======================================================================
{
{
DEBUGP (("TapDeviceHook called when TAP device is halted, MajorFunction=%d\n",
(int)l_IrpSp->MajorFunction));
{
return STATUS_SUCCESS;
}
else
{
return STATUS_NO_SUCH_DEVICE;
}
}
switch (l_IrpSp->MajorFunction)
{
//===========================================================
// Ioctl call handlers
//===========================================================
case IRP_MJ_DEVICE_CONTROL:
{
{
case TAP_IOCTL_GET_MAC:
{
>= sizeof (MACADDR))
{
}
else
{
NOTE_ERROR ();
}
break;
}
case TAP_IOCTL_GET_VERSION:
{
>= size)
{
#if DBG
= 1;
#else
= 0;
#endif
}
else
{
NOTE_ERROR ();
}
break;
}
case TAP_IOCTL_GET_MTU:
{
>= size)
{
}
else
{
NOTE_ERROR ();
}
break;
}
case TAP_IOCTL_GET_INFO:
{
char state[16];
state[0] = 'A';
else
state[0] = 'a';
else
else
NULL,
NULL,
"State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d]",
(int)IRP_QUEUE_SIZE,
(int)PACKET_QUEUE_SIZE
);
break;
}
#if DBG
case TAP_IOCTL_GET_LOG_LINE:
{
else
break;
}
#endif
{
(sizeof (IPADDR) * 2))
{
}
else
{
NOTE_ERROR ();
}
break;
}
{
(sizeof (ULONG) * 1))
{
}
else
{
NOTE_ERROR ();
}
break;
}
{
(sizeof (IPADDR) * 4))
{
// Adapter IP addr / netmask
// IP addr of DHCP masq server
// Lease time in seconds
}
else
{
NOTE_ERROR ();
}
break;
}
{
&& l_Adapter->m_dhcp_enabled)
{
}
else
{
NOTE_ERROR ();
}
break;
}
default:
{
NOTE_ERROR ();
break;
}
}
break;
}
//===========================================================
// User mode thread issued a read request on the tap device
// If there are packets waiting to be read, then the request
// will be satisfied here. If not, then the request will be
// queued and satisfied by any packet that is not used to
// satisfy requests ahead of it.
//===========================================================
case IRP_MJ_READ:
{
// Save IRP-accessible copy of buffer length
{
DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_READ\n",
NOTE_ERROR ();
break;
}
{
DEBUGP (("[%s] Could not map address in IRP_MJ_READ\n",
NOTE_ERROR ();
break;
}
else if (!l_Adapter->m_InterfaceIsRunning)
{
DEBUGP (("[%s] Interface is down in IRP_MJ_READ\n",
NOTE_ERROR ();
break;
}
//==================================
// Can we provide immediate service?
//==================================
{
}
if (l_PacketBuffer)
{
break;
}
//=============================
// Attempt to pend read request
//=============================
{
}
if (pending)
break;
// Can't queue anymore IRP's
DEBUGP (("[%s] TAP [%s] read IRP overrun\n",
NOTE_ERROR ();
break;
}
//==============================================================
// User mode issued a WriteFile request on the TAP file handle.
// The request will always get satisfied here. The call may
// fail if there are too many pending packets (queue full).
//==============================================================
case IRP_MJ_WRITE:
{
{
DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n",
NOTE_ERROR ();
}
{
DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n",
NOTE_ERROR ();
}
else if (!l_Adapter->m_InterfaceIsRunning)
{
DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n",
NOTE_ERROR ();
}
else if (!l_Adapter->m_PointToPoint && ((l_IrpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
{
{
////DEBUGP(("IRP_MJ_WRITE %08x %x\n", p_IRP->AssociatedIrp.SystemBuffer, l_IrpSp->Parameters.Write.Length));
DUMP_PACKET ("IRP_MJ_WRITE ETH",
}
{
DEBUGP (("[%s] NdisMEthIndicateReceive failed in IRP_MJ_WRITE\n",
NOTE_ERROR ();
}
}
{
{
DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
(unsigned char *) &l_Adapter->m_UserToTap,
sizeof (l_Adapter->m_UserToTap),
}
{
DEBUGP (("[%s] NdisMEthIndicateReceive failed in IRP_MJ_WRITE (P2P)\n",
NOTE_ERROR ();
}
}
else
{
DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n",
NOTE_ERROR ();
}
if (l_Status == STATUS_SUCCESS)
else
break;
}
//--------------------------------------------------------------
// User mode thread has called CreateFile() on the tap device
//--------------------------------------------------------------
case IRP_MJ_CREATE:
{
(("[%s] [TAP] release [%d.%d] open request (m_TapOpens=%d)\n",
if (mutex_succeeded)
{
{
}
if (succeeded)
{
}
else
{
DEBUGP (("[%s] TAP is presently unavailable (m_TapOpens=%d)\n",
NOTE_ERROR ();
}
}
else
{
DEBUGP (("[%s] TAP is presently locked (m_TapOpens=%d)\n",
NOTE_ERROR ();
}
break;
}
//-----------------------------------------------------------
// User mode thread called CloseHandle() on the tap device
//-----------------------------------------------------------
case IRP_MJ_CLOSE:
{
if (mutex_succeeded)
{
}
else
{
DEBUGP (("[%s] TAP is presently locked (m_TapOpens=%d)\n",
NOTE_ERROR ();
}
break;
}
//------------------
// Strange Request
//------------------
default:
{
//NOTE_ERROR ();
break;
}
}
return l_Status;
}
//=============================================================
// CompleteIRP is normally called with an adapter -> userspace
// network packet and an IRP (Pending I/O request) from userspace.
//
// The IRP will normally represent a queued overlapped read
// operation from userspace that is in a wait state.
//
// Use the ethernet packet to satisfy the IRP.
//=============================================================
{
int offset;
int len;
//-------------------------------------------
// While p_PacketBuffer always contains a
// full ethernet packet, including the
// ethernet header, in point-to-point mode,
// we only want to return the IPv4
// component.
//-------------------------------------------
{
}
else
{
offset = 0;
}
{
NOTE_ERROR ();
}
else
{
{
len);
}
{
NOTE_ERROR ();
}
}
{
0);
}
{
}
if (l_Status == STATUS_SUCCESS)
{
}
else
return l_Status;
}
//==============================================
// IRPs get cancelled for a number of reasons.
//
// The TAP device could be closed by userspace
// when there are still pending read operations.
//
// The user could disable the TAP adapter in the
// network connections control panel, while the
// device is still open by a process.
//==============================================
{
}
{
if (p_Extension)
{
}
else
if (exists)
{
}
if (callback)
if (exists)
}
//====================================
// Exhaust packet and IRP queues.
//====================================
{
while (TRUE)
{
if (l_IRP)
{
++n_IRP;
}
else
break;
}
while (TRUE)
{
if (l_PacketBuffer)
{
++n_Packet;
}
else
break;
}
DEBUGP ((
"[%s] [TAP] FlushQueues n_IRP=[%d,%d,%d] n_Packet=[%d,%d,%d]\n",
));
}
//===================================================
// Tell Windows whether the TAP device should be
// considered "connected" or "disconnected".
//===================================================
{
{
if (state)
else
}
}
//======================================================
// If DHCP mode is used together with Point-to-point
// mode, consider the fact that the P2P remote endpoint
// might be equal to the DHCP masq server address.
//======================================================
{
{
{
}
}
}
//===================================================
// Generate an ARP reply message for specific kinds
// ARP queries.
//===================================================
const PARP_PACKET src,
const IPADDR adapter_ip,
{
//-----------------------------------------------
// Is this the kind of packet we are looking for?
//-----------------------------------------------
{
if (arp)
{
//----------------------------------------------
// Initialize ARP reply fields
//----------------------------------------------
//----------------------------------------------
// ARP addresses
//----------------------------------------------
DUMP_PACKET ("ProcessARP",
(unsigned char *) arp,
sizeof (ARP_PACKET));
}
return TRUE;
}
else
return FALSE;
}
//===============================================================
// Used in cases where internally generated packets such as
// ARP or DHCP replies must be returned to the kernel, to be
// seen as an incoming packet "arriving" on the interface.
//===============================================================
const unsigned int len)
{
{
//------------------------------------------------------------
// NdisMEthIndicateReceive and NdisMEthIndicateReceiveComplete
// could potentially be called reentrantly both here and in
//
// The DDK docs imply that this is okay.
//------------------------------------------------------------
}
{
DEBUGP (("[%s] NdisMEthIndicateReceive failed in InjectPacket\n",
NOTE_ERROR ();
}
}
//===================================================================
// Go back to default TAP mode from Point-To-Point mode.
// Also reset (i.e. disable) DHCP Masq mode.
//===================================================================
{
// Point-To-Point
p_Adapter->m_remoteIP = 0;
// DHCP Masq
p_Adapter->m_dhcp_addr = 0;
p_Adapter->m_dhcp_netmask = 0;
p_Adapter->m_dhcp_server_ip = 0;
p_Adapter->m_dhcp_lease_time = 0;
p_Adapter->m_dhcp_bad_requests = 0;
}
//======================================================================
// End of Source
//======================================================================