123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209 |
- /*
- * TAP-Windows -- A kernel driver to provide virtual tap
- * device functionality on Windows.
- *
- * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
- *
- * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
- * and is released under the GPL version 2 (see below).
- *
- * 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
- * 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
- */
- //
- // Include files.
- //
- #include "tap.h"
- #include <wdmsec.h> // for SDDLs
- //======================================================================
- // TAP Win32 Device I/O Callbacks
- //======================================================================
- #ifdef ALLOC_PRAGMA
- #pragma alloc_text( PAGE, TapDeviceCreate)
- #pragma alloc_text( PAGE, TapDeviceControl)
- #pragma alloc_text( PAGE, TapDeviceCleanup)
- #pragma alloc_text( PAGE, TapDeviceClose)
- #endif // ALLOC_PRAGMA
- //===================================================================
- // Go back to default TAP mode from Point-To-Point mode.
- // Also reset (i.e. disable) DHCP Masq mode.
- //===================================================================
- VOID tapResetAdapterState(
- __in PTAP_ADAPTER_CONTEXT Adapter
- )
- {
- /*
- // Point-To-Point
- Adapter->m_tun = FALSE;
- Adapter->m_localIP = 0;
- Adapter->m_remoteNetwork = 0;
- Adapter->m_remoteNetmask = 0;
- NdisZeroMemory (&Adapter->m_TapToUser, sizeof (Adapter->m_TapToUser));
- NdisZeroMemory (&Adapter->m_UserToTap, sizeof (Adapter->m_UserToTap));
- NdisZeroMemory (&Adapter->m_UserToTap_IPv6, sizeof (Adapter->m_UserToTap_IPv6));
- */
- // DHCP Masq
- /*
- Adapter->m_dhcp_enabled = FALSE;
- Adapter->m_dhcp_server_arp = FALSE;
- Adapter->m_dhcp_user_supplied_options_buffer_len = 0;
- Adapter->m_dhcp_addr = 0;
- Adapter->m_dhcp_netmask = 0;
- Adapter->m_dhcp_server_ip = 0;
- Adapter->m_dhcp_lease_time = 0;
- Adapter->m_dhcp_received_discover = FALSE;
- Adapter->m_dhcp_bad_requests = 0;
- NdisZeroMemory (Adapter->m_dhcp_server_mac, MACADDR_SIZE);
- */
- }
- // IRP_MJ_CREATE
- NTSTATUS
- TapDeviceCreate(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp
- )
- /*++
- Routine Description:
- This routine is called by the I/O system when the device is opened.
- No action is performed other than completing the request successfully.
- Arguments:
- DeviceObject - a pointer to the object that represents the device
- that I/O is to be done on.
- Irp - a pointer to the I/O Request Packet for this request.
- Return Value:
- NT status code
- --*/
- {
- NDIS_STATUS status;
- PIO_STACK_LOCATION irpSp;// Pointer to current stack location
- PTAP_ADAPTER_CONTEXT adapter = NULL;
- PFILE_OBJECT originalFileObject;
- PAGED_CODE();
- DEBUGP (("[TAP] --> TapDeviceCreate\n"));
- irpSp = IoGetCurrentIrpStackLocation(Irp);
- //
- // Invalidate file context
- //
- irpSp->FileObject->FsContext = NULL;
- irpSp->FileObject->FsContext2 = NULL;
- //
- // Find adapter context for this device.
- // -------------------------------------
- // Returns with added reference on adapter context.
- //
- adapter = tapAdapterContextFromDeviceObject(DeviceObject);
- // Insure that adapter exists.
- ASSERT(adapter);
- if(adapter == NULL )
- {
- DEBUGP (("[TAP] release [%d.%d] open request; adapter not found\n",
- TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION
- ));
- Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest( Irp, IO_NO_INCREMENT );
- return STATUS_DEVICE_DOES_NOT_EXIST;
- }
- DEBUGP(("[%s] [TAP] release [%d.%d] open request (TapFileIsOpen=%d)\n",
- MINIPORT_INSTANCE_ID(adapter),
- TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION,
- adapter->TapFileIsOpen
- ));
- // Enforce exclusive access
- originalFileObject = InterlockedCompareExchangePointer(
- &adapter->TapFileObject,
- irpSp->FileObject,
- NULL
- );
- if(originalFileObject == NULL)
- {
- irpSp->FileObject->FsContext = adapter; // Quick reference
- status = STATUS_SUCCESS;
- }
- else
- {
- status = STATUS_UNSUCCESSFUL;
- }
- // Release the lock.
- //tapAdapterReleaseLock(adapter,FALSE);
- if(status == STATUS_SUCCESS)
- {
- // Reset adapter state on successful open.
- tapResetAdapterState(adapter);
- adapter->TapFileIsOpen = 1; // Legacy...
- // NOTE!!! Reference added by tapAdapterContextFromDeviceObject
- // will be removed when file is closed.
- }
- else
- {
- DEBUGP (("[%s] TAP is presently unavailable (TapFileIsOpen=%d)\n",
- MINIPORT_INSTANCE_ID(adapter), adapter->TapFileIsOpen
- ));
- NOTE_ERROR();
- // Remove reference added by tapAdapterContextFromDeviceObject.
- tapAdapterContextDereference(adapter);
- }
- // Complete the IRP.
- Irp->IoStatus.Status = status;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest( Irp, IO_NO_INCREMENT );
- DEBUGP (("[TAP] <-- TapDeviceCreate; status = %8.8X\n",status));
- return status;
- }
- //===================================================
- // Tell Windows whether the TAP device should be
- // considered "connected" or "disconnected".
- //
- // Allows application control of media connect state.
- //===================================================
- VOID
- tapSetMediaConnectStatus(
- __in PTAP_ADAPTER_CONTEXT Adapter,
- __in BOOLEAN LogicalMediaState
- )
- {
- NDIS_STATUS_INDICATION statusIndication;
- NDIS_LINK_STATE linkState;
- NdisZeroMemory(&statusIndication, sizeof(NDIS_STATUS_INDICATION));
- NdisZeroMemory(&linkState, sizeof(NDIS_LINK_STATE));
- //
- // Fill in object headers
- //
- statusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
- statusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
- statusIndication.Header.Size = sizeof(NDIS_STATUS_INDICATION);
- linkState.Header.Revision = NDIS_LINK_STATE_REVISION_1;
- linkState.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
- linkState.Header.Size = sizeof(NDIS_LINK_STATE);
- //
- // Link state buffer
- //
- if(Adapter->LogicalMediaState == TRUE)
- {
- linkState.MediaConnectState = MediaConnectStateConnected;
- }
- linkState.MediaDuplexState = MediaDuplexStateFull;
- linkState.RcvLinkSpeed = TAP_RECV_SPEED;
- linkState.XmitLinkSpeed = TAP_XMIT_SPEED;
- //
- // Fill in the status buffer
- //
- statusIndication.StatusCode = NDIS_STATUS_LINK_STATE;
- statusIndication.SourceHandle = Adapter->MiniportAdapterHandle;
- statusIndication.DestinationHandle = NULL;
- statusIndication.RequestId = 0;
- statusIndication.StatusBuffer = &linkState;
- statusIndication.StatusBufferSize = sizeof(NDIS_LINK_STATE);
- // Fill in new media connect state.
- if ( (Adapter->LogicalMediaState != LogicalMediaState) && !Adapter->MediaStateAlwaysConnected)
- {
- Adapter->LogicalMediaState = LogicalMediaState;
- if (LogicalMediaState == TRUE)
- {
- linkState.MediaConnectState = MediaConnectStateConnected;
- DEBUGP (("[TAP] Set MediaConnectState: Connected.\n"));
- }
- else
- {
- linkState.MediaConnectState = MediaConnectStateDisconnected;
- DEBUGP (("[TAP] Set MediaConnectState: Disconnected.\n"));
- }
- }
- // Make the status indication.
- if(Adapter->Locked.AdapterState != MiniportHaltedState)
- {
- NdisMIndicateStatusEx(Adapter->MiniportAdapterHandle, &statusIndication);
- }
- }
- /*
- //======================================================
- // If DHCP mode is used together with tun
- // mode, consider the fact that the P2P remote subnet
- // might enclose the DHCP masq server address.
- //======================================================
- VOID
- CheckIfDhcpAndTunMode (
- __in PTAP_ADAPTER_CONTEXT Adapter
- )
- {
- if (Adapter->m_tun && Adapter->m_dhcp_enabled)
- {
- if ((Adapter->m_dhcp_server_ip & Adapter->m_remoteNetmask) == Adapter->m_remoteNetwork)
- {
- ETH_COPY_NETWORK_ADDRESS (Adapter->m_dhcp_server_mac, Adapter->m_TapToUser.dest);
- Adapter->m_dhcp_server_arp = FALSE;
- }
- }
- }
- */
- // IRP_MJ_DEVICE_CONTROL callback.
- NTSTATUS
- TapDeviceControl(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp
- )
- /*++
- Routine Description:
- This routine is called by the I/O system to perform a device I/O
- control function.
- Arguments:
- DeviceObject - a pointer to the object that represents the device
- that I/O is to be done on.
- Irp - a pointer to the I/O Request Packet for this request.
- Return Value:
- NT status code
- --*/
- {
- NTSTATUS ntStatus = STATUS_SUCCESS; // Assume success
- PIO_STACK_LOCATION irpSp; // Pointer to current stack location
- PTAP_ADAPTER_CONTEXT adapter = NULL;
- ULONG inBufLength; // Input buffer length
- ULONG outBufLength; // Output buffer length
- PCHAR inBuf, outBuf; // pointer to Input and output buffer
- PMDL mdl = NULL;
- PCHAR buffer = NULL;
- PAGED_CODE();
- irpSp = IoGetCurrentIrpStackLocation( Irp );
- //
- // Fetch adapter context for this device.
- // --------------------------------------
- // Adapter pointer was stashed in FsContext when handle was opened.
- //
- adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
- ASSERT(adapter);
- inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
- outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
- if (!inBufLength || !outBufLength)
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- goto End;
- }
- //
- // Determine which I/O control code was specified.
- //
- switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
- {
- case TAP_WIN_IOCTL_GET_MAC:
- {
- if (outBufLength >= MACADDR_SIZE )
- {
- ETH_COPY_NETWORK_ADDRESS(
- Irp->AssociatedIrp.SystemBuffer,
- adapter->CurrentAddress
- );
- Irp->IoStatus.Information = MACADDR_SIZE;
- }
- else
- {
- NOTE_ERROR();
- Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- }
- break;
- case TAP_WIN_IOCTL_GET_VERSION:
- {
- const ULONG size = sizeof (ULONG) * 3;
- if (outBufLength >= size)
- {
- ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0]
- = TAP_DRIVER_MAJOR_VERSION;
- ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[1]
- = TAP_DRIVER_MINOR_VERSION;
- ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[2]
- #if DBG
- = 1;
- #else
- = 0;
- #endif
- Irp->IoStatus.Information = size;
- }
- else
- {
- NOTE_ERROR();
- Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- }
- break;
- case TAP_WIN_IOCTL_GET_MTU:
- {
- const ULONG size = sizeof (ULONG) * 1;
- if (outBufLength >= size)
- {
- ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0]
- = adapter->MtuSize;
- Irp->IoStatus.Information = size;
- }
- else
- {
- NOTE_ERROR();
- Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- }
- break;
- // Allow ZeroTier One to get multicast memberships at the L2 level in a
- // protocol-neutral manner.
- case TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS:
- {
- if (outBufLength < TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE) {
- /* output buffer too small */
- NOTE_ERROR ();
- Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
- } else {
- char *out = (char *)Irp->AssociatedIrp.SystemBuffer;
- char *end = out + TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE;
- unsigned long i,j;
- for(i=0;i<adapter->ulMCListSize;++i) {
- if (i >= TAP_MAX_MCAST_LIST)
- break;
- for(j=0;j<6;++j)
- *(out++) = adapter->MCList[i][j];
- if (out >= end)
- break;
- }
- while (out < end)
- *(out++) = (char)0;
- Irp->IoStatus.Information = TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE;
- Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS;
- }
- break;
- }
- #if 0
- case TAP_WIN_IOCTL_CONFIG_TUN:
- {
- if(inBufLength >= sizeof(IPADDR)*3)
- {
- MACADDR dest;
- adapter->m_tun = FALSE;
- GenerateRelatedMAC (dest, adapter->CurrentAddress, 1);
- adapter->m_localIP = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0];
- adapter->m_remoteNetwork = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1];
- adapter->m_remoteNetmask = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[2];
- // Sanity check on network/netmask
- if ((adapter->m_remoteNetwork & adapter->m_remoteNetmask) != adapter->m_remoteNetwork)
- {
- NOTE_ERROR();
- Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
- break;
- }
- ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.src, adapter->CurrentAddress);
- ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.dest, dest);
- ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.src, dest);
- ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.dest, adapter->CurrentAddress);
- adapter->m_TapToUser.proto = adapter->m_UserToTap.proto = htons (NDIS_ETH_TYPE_IPV4);
- adapter->m_UserToTap_IPv6 = adapter->m_UserToTap;
- adapter->m_UserToTap_IPv6.proto = htons(NDIS_ETH_TYPE_IPV6);
- adapter->m_tun = TRUE;
- CheckIfDhcpAndTunMode (adapter);
- Irp->IoStatus.Information = 1; // Simple boolean value
- DEBUGP (("[TAP] Set TUN mode.\n"));
- }
- else
- {
- NOTE_ERROR();
- Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- break;
- case TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT:
- {
- if(inBufLength >= sizeof(IPADDR)*2)
- {
- MACADDR dest;
- adapter->m_tun = FALSE;
- GenerateRelatedMAC (dest, adapter->CurrentAddress, 1);
- adapter->m_localIP = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0];
- adapter->m_remoteNetwork = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1];
- adapter->m_remoteNetmask = ~0;
- ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.src, adapter->CurrentAddress);
- ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.dest, dest);
- ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.src, dest);
- ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.dest, adapter->CurrentAddress);
- adapter->m_TapToUser.proto = adapter->m_UserToTap.proto = htons (NDIS_ETH_TYPE_IPV4);
- adapter->m_UserToTap_IPv6 = adapter->m_UserToTap;
- adapter->m_UserToTap_IPv6.proto = htons(NDIS_ETH_TYPE_IPV6);
- adapter->m_tun = TRUE;
- CheckIfDhcpAndTunMode (adapter);
- Irp->IoStatus.Information = 1; // Simple boolean value
- DEBUGP (("[TAP] Set P2P mode.\n"));
- }
- else
- {
- NOTE_ERROR();
- Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- break;
- #endif
- #if 0
- case TAP_WIN_IOCTL_CONFIG_DHCP_MASQ:
- {
- if(inBufLength >= sizeof(IPADDR)*4)
- {
- adapter->m_dhcp_enabled = FALSE;
- adapter->m_dhcp_server_arp = FALSE;
- adapter->m_dhcp_user_supplied_options_buffer_len = 0;
- // Adapter IP addr / netmask
- adapter->m_dhcp_addr =
- ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0];
- adapter->m_dhcp_netmask =
- ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1];
- // IP addr of DHCP masq server
- adapter->m_dhcp_server_ip =
- ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[2];
- // Lease time in seconds
- adapter->m_dhcp_lease_time =
- ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[3];
- GenerateRelatedMAC(
- adapter->m_dhcp_server_mac,
- adapter->CurrentAddress,
- 2
- );
- adapter->m_dhcp_enabled = TRUE;
- adapter->m_dhcp_server_arp = TRUE;
- CheckIfDhcpAndTunMode (adapter);
- Irp->IoStatus.Information = 1; // Simple boolean value
- DEBUGP (("[TAP] Configured DHCP MASQ.\n"));
- }
- else
- {
- NOTE_ERROR();
- Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- break;
- case TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT:
- {
- if (inBufLength <= DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE
- && adapter->m_dhcp_enabled)
- {
- adapter->m_dhcp_user_supplied_options_buffer_len = 0;
- NdisMoveMemory(
- adapter->m_dhcp_user_supplied_options_buffer,
- Irp->AssociatedIrp.SystemBuffer,
- inBufLength
- );
- adapter->m_dhcp_user_supplied_options_buffer_len =
- inBufLength;
- Irp->IoStatus.Information = 1; // Simple boolean value
- DEBUGP (("[TAP] Set DHCP OPT.\n"));
- }
- else
- {
- NOTE_ERROR();
- Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- break;
- #endif
- #if 0
- case TAP_WIN_IOCTL_GET_INFO:
- {
- char state[16];
- // Fetch adapter (miniport) state.
- if (tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS)
- state[0] = 'A';
- else
- state[0] = 'a';
- if (tapAdapterReadAndWriteReady(adapter))
- state[1] = 'T';
- else
- state[1] = 't';
- state[2] = '0' + adapter->CurrentPowerState;
- if (adapter->MediaStateAlwaysConnected)
- state[3] = 'C';
- else
- state[3] = 'c';
- state[4] = '\0';
- // BUGBUG!!! What follows, and is not yet implemented, is a real mess.
- // BUGBUG!!! Tied closely to the NDIS 5 implementation. Need to map
- // as much as possible to the NDIS 6 implementation.
- Irp->IoStatus.Status = ntStatus = RtlStringCchPrintfExA (
- ((LPTSTR) (Irp->AssociatedIrp.SystemBuffer)),
- outBufLength,
- NULL,
- NULL,
- STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
- #if PACKET_TRUNCATION_CHECK
- "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d,%d] Rx=[%d,%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]",
- #else
- "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]",
- #endif
- state,
- g_LastErrorFilename,
- g_LastErrorLineNumber,
- (int)adapter->TapFileOpenCount,
- (int)(adapter->FramesTxDirected + adapter->FramesTxMulticast + adapter->FramesTxBroadcast),
- (int)adapter->TransmitFailuresOther,
- #if PACKET_TRUNCATION_CHECK
- (int)adapter->m_TxTrunc,
- #endif
- (int)adapter->m_Rx,
- (int)adapter->m_RxErr,
- #if PACKET_TRUNCATION_CHECK
- (int)adapter->m_RxTrunc,
- #endif
- (int)adapter->PendingReadIrpQueue.Count,
- (int)adapter->PendingReadIrpQueue.MaxCount,
- (int)IRP_QUEUE_SIZE, // Ignored in NDIS 6 driver...
- (int)adapter->SendPacketQueue.Count,
- (int)adapter->SendPacketQueue.MaxCount,
- (int)PACKET_QUEUE_SIZE,
- (int)0, // adapter->InjectPacketQueue.Count - Unused
- (int)0, // adapter->InjectPacketQueue.MaxCount - Unused
- (int)INJECT_QUEUE_SIZE
- );
- Irp->IoStatus.Information = outBufLength;
- // BUGBUG!!! Fail because this is not completely implemented.
- ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- }
- #endif
- #if DBG
- case TAP_WIN_IOCTL_GET_LOG_LINE:
- {
- if (GetDebugLine( (LPTSTR)Irp->AssociatedIrp.SystemBuffer,outBufLength))
- {
- Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS;
- }
- else
- {
- Irp->IoStatus.Status = ntStatus = STATUS_UNSUCCESSFUL;
- }
- Irp->IoStatus.Information = outBufLength;
- break;
- }
- #endif
- case TAP_WIN_IOCTL_SET_MEDIA_STATUS:
- {
- if(inBufLength >= sizeof(ULONG))
- {
- ULONG parm = ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0];
- tapSetMediaConnectStatus (adapter, (BOOLEAN) parm);
- Irp->IoStatus.Information = 1;
- }
- else
- {
- NOTE_ERROR();
- Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- break;
- default:
- //
- // The specified I/O control code is unrecognized by this driver.
- //
- ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- break;
- }
- End:
- //
- // Finish the I/O operation by simply completing the packet and returning
- // the same status as in the packet itself.
- //
- Irp->IoStatus.Status = ntStatus;
- IoCompleteRequest( Irp, IO_NO_INCREMENT );
- return ntStatus;
- }
- // Flush the pending read IRP queue.
- VOID
- tapFlushIrpQueues(
- __in PTAP_ADAPTER_CONTEXT Adapter
- )
- {
- DEBUGP (("[TAP] tapFlushIrpQueues: Flushing %d pending read IRPs\n",
- Adapter->PendingReadIrpQueue.Count));
- tapIrpCsqFlush(&Adapter->PendingReadIrpQueue);
- }
- // IRP_MJ_CLEANUP
- NTSTATUS
- TapDeviceCleanup(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp
- )
- /*++
- Routine Description:
- Receipt of this request indicates that the last handle for a file
- object that is associated with the target device object has been closed
- (but, due to outstanding I/O requests, might not have been released).
- A driver that holds pending IRPs internally must implement a routine for
- IRP_MJ_CLEANUP. When the routine is called, the driver should cancel all
- the pending IRPs that belong to the file object identified by the IRP_MJ_CLEANUP
- call.
-
- In other words, it should cancel all the IRPs that have the same file-object
- pointer as the one supplied in the current I/O stack location of the IRP for the
- IRP_MJ_CLEANUP call. Of course, IRPs belonging to other file objects should
- not be canceled. Also, if an outstanding IRP is completed immediately, the
- driver does not have to cancel it.
- Arguments:
- DeviceObject - a pointer to the object that represents the device
- to be cleaned up.
- Irp - a pointer to the I/O Request Packet for this request.
- Return Value:
- NT status code
- --*/
- {
- NDIS_STATUS status = NDIS_STATUS_SUCCESS; // Always succeed.
- PIO_STACK_LOCATION irpSp; // Pointer to current stack location
- PTAP_ADAPTER_CONTEXT adapter = NULL;
- PAGED_CODE();
- DEBUGP (("[TAP] --> TapDeviceCleanup\n"));
- irpSp = IoGetCurrentIrpStackLocation(Irp);
- //
- // Fetch adapter context for this device.
- // --------------------------------------
- // Adapter pointer was stashed in FsContext when handle was opened.
- //
- adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
- // Insure that adapter exists.
- ASSERT(adapter);
- if(adapter == NULL )
- {
- DEBUGP (("[TAP] release [%d.%d] cleanup request; adapter not found\n",
- TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION
- ));
- }
- if(adapter != NULL )
- {
- adapter->TapFileIsOpen = 0; // Legacy...
- // Disconnect from media.
- tapSetMediaConnectStatus(adapter,FALSE);
- // Reset adapter state when cleaning up;
- tapResetAdapterState(adapter);
- // BUGBUG!!! Use RemoveLock???
- //
- // Flush pending send TAP packet queue.
- //
- tapFlushSendPacketQueue(adapter);
- ASSERT(adapter->SendPacketQueue.Count == 0);
- //
- // Flush the pending IRP queues
- //
- tapFlushIrpQueues(adapter);
- ASSERT(adapter->PendingReadIrpQueue.Count == 0);
- }
- // Complete the IRP.
- Irp->IoStatus.Status = status;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest( Irp, IO_NO_INCREMENT );
- DEBUGP (("[TAP] <-- TapDeviceCleanup; status = %8.8X\n",status));
- return status;
- }
- // IRP_MJ_CLOSE
- NTSTATUS
- TapDeviceClose(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp
- )
- /*++
- Routine Description:
- Receipt of this request indicates that the last handle of the file
- object that is associated with the target device object has been closed
- and released.
-
- All outstanding I/O requests have been completed or canceled.
- Arguments:
- DeviceObject - a pointer to the object that represents the device
- to be closed.
- Irp - a pointer to the I/O Request Packet for this request.
- Return Value:
- NT status code
- --*/
- {
- NDIS_STATUS status = NDIS_STATUS_SUCCESS; // Always succeed.
- PIO_STACK_LOCATION irpSp; // Pointer to current stack location
- PTAP_ADAPTER_CONTEXT adapter = NULL;
- PAGED_CODE();
- DEBUGP (("[TAP] --> TapDeviceClose\n"));
- irpSp = IoGetCurrentIrpStackLocation(Irp);
- //
- // Fetch adapter context for this device.
- // --------------------------------------
- // Adapter pointer was stashed in FsContext when handle was opened.
- //
- adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
- // Insure that adapter exists.
- ASSERT(adapter);
- if(adapter == NULL )
- {
- DEBUGP (("[TAP] release [%d.%d] close request; adapter not found\n",
- TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION
- ));
- }
- if(adapter != NULL )
- {
- if(adapter->TapFileObject == NULL)
- {
- // Should never happen!!!
- ASSERT(FALSE);
- }
- else
- {
- ASSERT(irpSp->FileObject->FsContext == adapter);
- ASSERT(adapter->TapFileObject == irpSp->FileObject);
- }
- adapter->TapFileObject = NULL;
- irpSp->FileObject = NULL;
- // Remove reference added by when handle was opened.
- tapAdapterContextDereference(adapter);
- }
- // Complete the IRP.
- Irp->IoStatus.Status = status;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest( Irp, IO_NO_INCREMENT );
- DEBUGP (("[TAP] <-- TapDeviceClose; status = %8.8X\n",status));
- return status;
- }
- NTSTATUS
- tapConcatenateNdisStrings(
- __inout PNDIS_STRING DestinationString,
- __in_opt PNDIS_STRING SourceString1,
- __in_opt PNDIS_STRING SourceString2,
- __in_opt PNDIS_STRING SourceString3
- )
- {
- NTSTATUS status;
- ASSERT(SourceString1 && SourceString2 && SourceString3);
- status = RtlAppendUnicodeStringToString(
- DestinationString,
- SourceString1
- );
- if(status == STATUS_SUCCESS)
- {
- status = RtlAppendUnicodeStringToString(
- DestinationString,
- SourceString2
- );
- if(status == STATUS_SUCCESS)
- {
- status = RtlAppendUnicodeStringToString(
- DestinationString,
- SourceString3
- );
- }
- }
- return status;
- }
- NTSTATUS
- tapMakeDeviceNames(
- __in PTAP_ADAPTER_CONTEXT Adapter
- )
- {
- NDIS_STATUS status;
- NDIS_STRING deviceNamePrefix = NDIS_STRING_CONST("\\Device\\");
- NDIS_STRING tapNameSuffix = NDIS_STRING_CONST(".tap");
- // Generate DeviceName from NetCfgInstanceId.
- Adapter->DeviceName.Buffer = Adapter->DeviceNameBuffer;
- Adapter->DeviceName.MaximumLength = sizeof(Adapter->DeviceNameBuffer);
- status = tapConcatenateNdisStrings(
- &Adapter->DeviceName,
- &deviceNamePrefix,
- &Adapter->NetCfgInstanceId,
- &tapNameSuffix
- );
- if(status == STATUS_SUCCESS)
- {
- NDIS_STRING linkNamePrefix = NDIS_STRING_CONST("\\DosDevices\\Global\\");
- Adapter->LinkName.Buffer = Adapter->LinkNameBuffer;
- Adapter->LinkName.MaximumLength = sizeof(Adapter->LinkNameBuffer);
- status = tapConcatenateNdisStrings(
- &Adapter->LinkName,
- &linkNamePrefix,
- &Adapter->NetCfgInstanceId,
- &tapNameSuffix
- );
- }
- return status;
- }
- NDIS_STATUS
- CreateTapDevice(
- __in PTAP_ADAPTER_CONTEXT Adapter
- )
- {
- NDIS_STATUS status;
- NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttribute;
- PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
- DEBUGP (("[TAP] version [%d.%d] creating tap device: %wZ\n",
- TAP_DRIVER_MAJOR_VERSION,
- TAP_DRIVER_MINOR_VERSION,
- &Adapter->NetCfgInstanceId));
- // Generate DeviceName and LinkName from NetCfgInstanceId.
- status = tapMakeDeviceNames(Adapter);
- if (NT_SUCCESS(status))
- {
- DEBUGP (("[TAP] DeviceName: %wZ\n",&Adapter->DeviceName));
- DEBUGP (("[TAP] LinkName: %wZ\n",&Adapter->LinkName));
- // Initialize dispatch table.
- NdisZeroMemory(dispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));
- dispatchTable[IRP_MJ_CREATE] = TapDeviceCreate;
- dispatchTable[IRP_MJ_CLEANUP] = TapDeviceCleanup;
- dispatchTable[IRP_MJ_CLOSE] = TapDeviceClose;
- dispatchTable[IRP_MJ_READ] = TapDeviceRead;
- dispatchTable[IRP_MJ_WRITE] = TapDeviceWrite;
- dispatchTable[IRP_MJ_DEVICE_CONTROL] = TapDeviceControl;
- //
- // Create a device object and register dispatch handlers
- //
- NdisZeroMemory(&deviceAttribute, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES));
- deviceAttribute.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
- deviceAttribute.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
- deviceAttribute.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES);
- deviceAttribute.DeviceName = &Adapter->DeviceName;
- deviceAttribute.SymbolicName = &Adapter->LinkName;
- deviceAttribute.MajorFunctions = &dispatchTable[0];
- //deviceAttribute.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION);
- #if ENABLE_NONADMIN
- if(Adapter->AllowNonAdmin)
- {
- //
- // SDDL_DEVOBJ_SYS_ALL_WORLD_RWX_RES_RWX allows the kernel and system complete
- // control over the device. By default the admin can access the entire device,
- // but cannot change the ACL (the admin must take control of the device first)
- //
- // Everyone else, including "restricted" or "untrusted" code can read or write
- // to the device. Traversal beneath the device is also granted (removing it
- // would only effect storage devices, except if the "bypass-traversal"
- // privilege was revoked).
- //
- deviceAttribute.DefaultSDDLString = &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX;
- }
- #endif
- status = NdisRegisterDeviceEx(
- Adapter->MiniportAdapterHandle,
- &deviceAttribute,
- &Adapter->DeviceObject,
- &Adapter->DeviceHandle
- );
- }
- ASSERT(NT_SUCCESS(status));
- if (NT_SUCCESS(status))
- {
- // Set TAP device flags.
- (Adapter->DeviceObject)->Flags &= ~DO_BUFFERED_IO;
- (Adapter->DeviceObject)->Flags |= DO_DIRECT_IO;;
- //========================
- // Finalize initialization
- //========================
- Adapter->TapDeviceCreated = TRUE;
- DEBUGP (("[%wZ] successfully created TAP device [%wZ]\n",
- &Adapter->NetCfgInstanceId,
- &Adapter->DeviceName
- ));
- }
- DEBUGP (("[TAP] <-- CreateTapDevice; status = %8.8X\n",status));
- return status;
- }
- //
- // DestroyTapDevice is called from AdapterHalt and NDIS miniport
- // is in Halted state. Prior to entering the Halted state the
- // miniport would have passed through the Pausing and Paused
- // states. These miniport states have responsibility for waiting
- // until NDIS network operations have completed.
- //
- VOID
- DestroyTapDevice(
- __in PTAP_ADAPTER_CONTEXT Adapter
- )
- {
- DEBUGP (("[TAP] --> DestroyTapDevice; Adapter: %wZ\n",
- &Adapter->NetCfgInstanceId));
- //
- // Let clients know we are shutting down
- //
- Adapter->TapDeviceCreated = FALSE;
- //
- // Flush pending send TAP packet queue.
- //
- tapFlushSendPacketQueue(Adapter);
- ASSERT(Adapter->SendPacketQueue.Count == 0);
- //
- // Flush IRP queues. Wait for pending I/O. Etc.
- // --------------------------------------------
- // Exhaust IRP and packet queues. Any pending IRPs will
- // be cancelled, causing user-space to get this error
- // on overlapped reads:
- //
- // ERROR_OPERATION_ABORTED, code=995
- //
- // "The I/O operation has been aborted because of either a
- // thread exit or an application request."
- //
- // It's important that user-space close the device handle
- // when this code is returned, so that when we finally
- // do a NdisMDeregisterDeviceEx, the device reference count
- // is 0. Otherwise the driver will not unload even if the
- // the last adapter has been halted.
- //
- // The act of flushing the queues at this point should result in the user-mode
- // application closing the adapter's device handle. Closing the handle will
- // result in the TapDeviceCleanup call being made, followed by the a call to
- // the TapDeviceClose callback.
- //
- tapFlushIrpQueues(Adapter);
- ASSERT(Adapter->PendingReadIrpQueue.Count == 0);
- //
- // Deregister the Win32 device.
- // ----------------------------
- // When a driver calls NdisDeregisterDeviceEx, the I/O manager deletes the
- // target device object if there are no outstanding references to it. However,
- // if any outstanding references remain, the I/O manager marks the device
- // object as "delete pending" and deletes the device object when the references
- // are finally released.
- //
- if(Adapter->DeviceHandle)
- {
- DEBUGP (("[TAP] Calling NdisDeregisterDeviceEx\n"));
- NdisDeregisterDeviceEx(Adapter->DeviceHandle);
- }
- Adapter->DeviceHandle = NULL;
- DEBUGP (("[TAP] <-- DestroyTapDevice\n"));
- }
|