VOID tapReadPermanentAddress(__in PTAP_ADAPTER_CONTEXT Adapter, __in NDIS_HANDLE ConfigurationHandle, __out MACADDR PermanentAddress) { NDIS_STATUS status; NDIS_CONFIGURATION_PARAMETER *configParameter; NDIS_STRING macKey = NDIS_STRING_CONST("MAC"); ANSI_STRING macString; BOOLEAN macFromRegistry = FALSE; // Read MAC parameter from registry. NdisReadConfiguration(&status, &configParameter, ConfigurationHandle, &macKey, NdisParameterString); if (status == NDIS_STATUS_SUCCESS) { if ((configParameter->ParameterType == NdisParameterString) && (configParameter->ParameterData.StringData.Length >= 12)) { if (RtlUnicodeStringToAnsiString(&macString, &configParameter->ParameterData.StringData, TRUE) == STATUS_SUCCESS) { macFromRegistry = ParseMAC(PermanentAddress, macString.Buffer); RtlFreeAnsiString(&macString); } } } if (!macFromRegistry) { // // There is no (valid) address stashed in the registry parameter. // // Make up a dummy mac address based on the ANSI representation of the // NetCfgInstanceId GUID. // GenerateRandomMac(PermanentAddress, MINIPORT_INSTANCE_ID(Adapter)); } }
VOID tapWaitForReceiveNblInFlightCountZeroEvent(__in PTAP_ADAPTER_CONTEXT Adapter) { LONG nblCount; // // Wait until higher-level protocol has returned all NBLs // to the driver. // // Add one NBL "bias" to insure allow event to be reset safely. nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount); ASSERT(nblCount > 0); NdisResetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent); // // Now remove the bias and wait for the ReceiveNblInFlightCountZeroEvent // if the count returned is not zero. // nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount); ASSERT(nblCount >= 0); if (nblCount) { LARGE_INTEGER startTime, currentTime; NdisGetSystemUpTimeEx(&startTime); for (;;) { BOOLEAN waitResult = NdisWaitEvent(&Adapter->ReceiveNblInFlightCountZeroEvent, TAP_WAIT_POLL_LOOP_TIMEOUT); NdisGetSystemUpTimeEx(¤tTime); if (waitResult) { break; } DEBUGP(("[%s] Waiting for %d in-flight receive NBLs to be returned.\n", MINIPORT_INSTANCE_ID(Adapter), Adapter->ReceiveNblInFlightCount)); } DEBUGP(("[%s] Waited %d ms for all in-flight NBLs to be returned.\n", MINIPORT_INSTANCE_ID(Adapter), (currentTime.LowPart - startTime.LowPart))); } }
VOID IndicateReceivePacket( __in PTAP_ADAPTER_CONTEXT Adapter, __in PUCHAR packetData, __in const unsigned int packetLength ) { PUCHAR injectBuffer; // // Handle miniport Pause // --------------------- // NDIS 6 miniports implement a temporary "Pause" state normally followed // by the Restart. While in the Pause state it is forbidden for the miniport // to indicate receive NBLs. // // That is: The device interface may be "up", but the NDIS miniport send/receive // interface may be temporarily "down". // // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas inject path // the code below will simply ignore inject packets passed to the driver while // the miniport is in the Paused state. // // The correct implementation is to go ahead and build the NBLs corresponding // to the inject packet - but queue them. When Restart is entered the // queued NBLs would be dequeued and indicated to the host. // if(tapAdapterSendAndReceiveReady(Adapter) != NDIS_STATUS_SUCCESS) { DEBUGP (("[%s] Lying send in IndicateReceivePacket while adapter paused\n", MINIPORT_INSTANCE_ID (Adapter))); return; } // Allocate flat buffer for packet data. injectBuffer = (PUCHAR )NdisAllocateMemoryWithTagPriority( Adapter->MiniportAdapterHandle, packetLength, TAP_RX_INJECT_BUFFER_TAG, NormalPoolPriority ); if( injectBuffer) { PMDL mdl; // Copy packet data to flat buffer. NdisMoveMemory (injectBuffer, packetData, packetLength); // Allocate MDL for flat buffer. mdl = NdisAllocateMdl( Adapter->MiniportAdapterHandle, injectBuffer, packetLength ); if( mdl ) { PNET_BUFFER_LIST netBufferList; mdl->Next = NULL; // No next MDL // Allocate the NBL and NB. Link MDL chain to NB. netBufferList = NdisAllocateNetBufferAndNetBufferList( Adapter->ReceiveNblPool, 0, // ContextSize 0, // ContextBackFill mdl, // MDL chain 0, packetLength ); if(netBufferList != NULL) { ULONG receiveFlags = 0; LONG nblCount; NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL if(KeGetCurrentIrql() == DISPATCH_LEVEL) { receiveFlags |= NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL; } // Set flag indicating that this is an injected packet TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED); netBufferList->MiniportReserved[0] = NULL; netBufferList->MiniportReserved[1] = NULL; // Increment in-flight receive NBL count. nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount); ASSERT(nblCount > 0 ); netBufferList->SourceHandle = Adapter->MiniportAdapterHandle; // // Indicate the packet // ------------------- // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length // contains the complete packet including Ethernet header and payload. // NdisMIndicateReceiveNetBufferLists( Adapter->MiniportAdapterHandle, netBufferList, NDIS_DEFAULT_PORT_NUMBER, 1, // NumberOfNetBufferLists receiveFlags ); return; } else { DEBUGP (("[%s] NdisAllocateNetBufferAndNetBufferList failed in IndicateReceivePacket\n", MINIPORT_INSTANCE_ID (Adapter))); NOTE_ERROR (); NdisFreeMdl(mdl); NdisFreeMemory(injectBuffer,0,0); } } else { DEBUGP (("[%s] NdisAllocateMdl failed in IndicateReceivePacket\n", MINIPORT_INSTANCE_ID (Adapter))); NOTE_ERROR (); NdisFreeMemory(injectBuffer,0,0); } } else { DEBUGP (("[%s] NdisAllocateMemoryWithTagPriority failed in IndicateReceivePacket\n", MINIPORT_INSTANCE_ID (Adapter))); NOTE_ERROR (); } }
// IRP_MJ_WRITE callback. NTSTATUS TapDeviceWrite( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success PIO_STACK_LOCATION irpSp;// Pointer to current stack location PTAP_ADAPTER_CONTEXT adapter = NULL; ULONG dataLength; 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); // // Sanity checks on state variables // if (!tapAdapterReadAndWriteReady(adapter)) { //DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n", // MINIPORT_INSTANCE_ID (adapter))); //NOTE_ERROR(); Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return ntStatus; } // Save IRP-accessible copy of buffer length Irp->IoStatus.Information = irpSp->Parameters.Write.Length; if (Irp->MdlAddress == NULL) { DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR(); Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return ntStatus; } // // Try to get a virtual address for the MDL. // NdisQueryMdl( Irp->MdlAddress, &Irp->AssociatedIrp.SystemBuffer, &dataLength, NormalPagePriority ); if (Irp->AssociatedIrp.SystemBuffer == NULL) { DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR(); Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Information = 0; IoCompleteRequest (Irp, IO_NO_INCREMENT); return ntStatus; } ASSERT(dataLength == irpSp->Parameters.Write.Length); Irp->IoStatus.Information = irpSp->Parameters.Write.Length; // // Handle miniport Pause // --------------------- // NDIS 6 miniports implement a temporary "Pause" state normally followed // by the Restart. While in the Pause state it is forbidden for the miniport // to indicate receive NBLs. // // That is: The device interface may be "up", but the NDIS miniport send/receive // interface may be temporarily "down". // // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path // the code below will perform a "lying send" for write IRPs passed to the // driver while the miniport is in the Paused state. // // The correct implementation is to go ahead and build the NBLs corresponding // to the user-mode write - but queue them. When Restart is entered the // queued NBLs would be dequeued and indicated to the host. // if(tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS) { if (!adapter->m_tun && ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE)) { PNET_BUFFER_LIST netBufferList; DUMP_PACKET ("IRP_MJ_WRITE ETH", (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length); //===================================================== // If IPv4 packet, check whether or not packet // was truncated. //===================================================== #if PACKET_TRUNCATION_CHECK IPv4PacketSizeVerify ( (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length, FALSE, "RX", &adapter->m_RxTrunc ); #endif (Irp->MdlAddress)->Next = NULL; // No next MDL // Allocate the NBL and NB. Link MDL chain to NB. netBufferList = NdisAllocateNetBufferAndNetBufferList( adapter->ReceiveNblPool, 0, // ContextSize 0, // ContextBackFill Irp->MdlAddress, // MDL chain 0, dataLength ); if(netBufferList != NULL) { LONG nblCount; NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL // Stash IRP pointer in NBL MiniportReserved[0] field. netBufferList->MiniportReserved[0] = Irp; netBufferList->MiniportReserved[1] = NULL; // BUGBUG!!! Setup for IRP cancel!!! TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); // Increment in-flight receive NBL count. nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); ASSERT(nblCount > 0 ); // // Indicate the packet // ------------------- // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length // contains the complete packet including Ethernet header and payload. // NdisMIndicateReceiveNetBufferLists( adapter->MiniportAdapterHandle, netBufferList, NDIS_DEFAULT_PORT_NUMBER, 1, // NumberOfNetBufferLists 0 // ReceiveFlags ); ntStatus = STATUS_PENDING; } else { DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR (); // Fail the IRP Irp->IoStatus.Information = 0; ntStatus = STATUS_INSUFFICIENT_RESOURCES; } } else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE)) { PETH_HEADER p_UserToTap = &adapter->m_UserToTap; PMDL mdl; // Head of MDL chain. // For IPv6, need to use Ethernet header with IPv6 proto if ( IPH_GET_VER( ((IPHDR*) Irp->AssociatedIrp.SystemBuffer)->version_len) == 6 ) { p_UserToTap = &adapter->m_UserToTap_IPv6; } DUMP_PACKET2 ("IRP_MJ_WRITE P2P", p_UserToTap, (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length); //===================================================== // If IPv4 packet, check whether or not packet // was truncated. //===================================================== #if PACKET_TRUNCATION_CHECK IPv4PacketSizeVerify ( (unsigned char *) Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Write.Length, TRUE, "RX", &adapter->m_RxTrunc ); #endif // // Allocate MDL for Ethernet header // -------------------------------- // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length // contains the only the Ethernet payload. Prepend the user-mode provided // payload with the Ethernet header pointed to by p_UserToTap. // mdl = NdisAllocateMdl( adapter->MiniportAdapterHandle, p_UserToTap, sizeof(ETH_HEADER) ); if(mdl != NULL) { PNET_BUFFER_LIST netBufferList; // Chain user's Ethernet payload behind Ethernet header. mdl->Next = Irp->MdlAddress; (Irp->MdlAddress)->Next = NULL; // No next MDL // Allocate the NBL and NB. Link MDL chain to NB. netBufferList = NdisAllocateNetBufferAndNetBufferList( adapter->ReceiveNblPool, 0, // ContextSize 0, // ContextBackFill mdl, // MDL chain 0, sizeof(ETH_HEADER) + dataLength ); if(netBufferList != NULL) { LONG nblCount; NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL // This IRP is pended. IoMarkIrpPending(Irp); // This IRP cannot be cancelled while in-flight. IoSetCancelRoutine(Irp,NULL); // Stash IRP pointer in NBL MiniportReserved[0] field. netBufferList->MiniportReserved[0] = Irp; netBufferList->MiniportReserved[1] = NULL; // Set flag indicating that this is P2P packet TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_P2P); // Increment in-flight receive NBL count. nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); ASSERT(nblCount > 0 ); // // Indicate the packet // NdisMIndicateReceiveNetBufferLists( adapter->MiniportAdapterHandle, netBufferList, NDIS_DEFAULT_PORT_NUMBER, 1, // NumberOfNetBufferLists 0 // ReceiveFlags ); ntStatus = STATUS_PENDING; } else { mdl->Next = NULL; NdisFreeMdl(mdl); DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR (); // Fail the IRP Irp->IoStatus.Information = 0; ntStatus = STATUS_INSUFFICIENT_RESOURCES; } } else { DEBUGP (("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID (adapter))); NOTE_ERROR (); // Fail the IRP Irp->IoStatus.Information = 0; ntStatus = STATUS_INSUFFICIENT_RESOURCES; } } else { DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n", MINIPORT_INSTANCE_ID (adapter), irpSp->Parameters.Write.Length)); NOTE_ERROR (); Irp->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE; Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; } } else { DEBUGP (("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n", MINIPORT_INSTANCE_ID (adapter))); ntStatus = STATUS_SUCCESS; } if (ntStatus != STATUS_PENDING) { Irp->IoStatus.Status = ntStatus; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return ntStatus; }
NDIS_STATUS AdapterCreate(__in NDIS_HANDLE MiniportAdapterHandle, __in NDIS_HANDLE MiniportDriverContext, __in PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters) { PTAP_ADAPTER_CONTEXT adapter = NULL; NDIS_STATUS status; UNREFERENCED_PARAMETER(MiniportDriverContext); UNREFERENCED_PARAMETER(MiniportInitParameters); DEBUGP(("[TAP] --> AdapterCreate\n")); do { NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES regAttributes = {0}; NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES genAttributes = {0}; NDIS_PNP_CAPABILITIES pnpCapabilities = {0}; // // Allocate adapter context structure and initialize all the // memory resources for sending and receiving packets. // // Returns with reference count initialized to one. // adapter = tapAdapterContextAllocate(MiniportAdapterHandle); if (adapter == NULL) { DEBUGP(("[TAP] Couldn't allocate adapter memory\n")); status = NDIS_STATUS_RESOURCES; break; } // Enter the Initializing state. DEBUGP(("[TAP] Miniport State: Initializing\n")); tapAdapterAcquireLock(adapter, FALSE); adapter->Locked.AdapterState = MiniportInitializingState; tapAdapterReleaseLock(adapter, FALSE); // // First read adapter configuration from registry. // ----------------------------------------------- // Subsequent device registration will fail if NetCfgInstanceId // has not been successfully read. // status = tapReadConfiguration(adapter); // // Set the registration attributes. // { C_ASSERT(sizeof(regAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1); } regAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES; regAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; regAttributes.Header.Revision = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; regAttributes.MiniportAdapterContext = adapter; regAttributes.AttributeFlags = TAP_ADAPTER_ATTRIBUTES_FLAGS; regAttributes.CheckForHangTimeInSeconds = TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS; regAttributes.InterfaceType = TAP_INTERFACE_TYPE; // NDIS_DECLARE_MINIPORT_ADAPTER_CONTEXT(TAP_ADAPTER_CONTEXT); status = NdisMSetMiniportAttributes(MiniportAdapterHandle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)®Attributes); if (status != NDIS_STATUS_SUCCESS) { DEBUGP(("[TAP] NdisSetOptionalHandlers failed; Status 0x%08x\n", status)); break; } // // Next, set the general attributes. // { C_ASSERT(sizeof(genAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1); } genAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES; genAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; genAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; // // Specify the medium type that the NIC can support but not // necessarily the medium type that the NIC currently uses. // genAttributes.MediaType = TAP_MEDIUM_TYPE; // // Specifiy medium type that the NIC currently uses. // genAttributes.PhysicalMediumType = TAP_PHYSICAL_MEDIUM; // // Specifiy the maximum network frame size, in bytes, that the NIC // supports excluding the header. // genAttributes.MtuSize = TAP_FRAME_MAX_DATA_SIZE; genAttributes.MaxXmitLinkSpeed = TAP_XMIT_SPEED; genAttributes.XmitLinkSpeed = TAP_XMIT_SPEED; genAttributes.MaxRcvLinkSpeed = TAP_RECV_SPEED; genAttributes.RcvLinkSpeed = TAP_RECV_SPEED; if (adapter->MediaStateAlwaysConnected) { DEBUGP(("[%s] Initial MediaConnectState: Connected\n", MINIPORT_INSTANCE_ID(adapter))); genAttributes.MediaConnectState = MediaConnectStateConnected; } else { DEBUGP(("[%s] Initial MediaConnectState: Disconnected\n", MINIPORT_INSTANCE_ID(adapter))); genAttributes.MediaConnectState = MediaConnectStateDisconnected; } genAttributes.MediaDuplexState = MediaDuplexStateFull; // // The maximum number of bytes the NIC can provide as lookahead data. // If that value is different from the size of the lookahead buffer // supported by bound protocols, NDIS will call MiniportOidRequest to // set the size of the lookahead buffer provided by the miniport driver // to the minimum of the miniport driver and protocol(s) values. If the // driver always indicates up full packets with // NdisMIndicateReceiveNetBufferLists, it should set this value to the // maximum total frame size, which excludes the header. // // Upper-layer drivers examine lookahead data to determine whether a // packet that is associated with the lookahead data is intended for // one or more of their clients. If the underlying driver supports // multipacket receive indications, bound protocols are given full net // packets on every indication. Consequently, this value is identical // to that returned for OID_GEN_RECEIVE_BLOCK_SIZE. // genAttributes.LookaheadSize = TAP_MAX_LOOKAHEAD; genAttributes.MacOptions = TAP_MAC_OPTIONS; genAttributes.SupportedPacketFilters = TAP_SUPPORTED_FILTERS; // // The maximum number of multicast addresses the NIC driver can manage. // This list is global for all protocols bound to (or above) the NIC. // Consequently, a protocol can receive NDIS_STATUS_MULTICAST_FULL from // the NIC driver when attempting to set the multicast address list, // even if the number of elements in the given list is less than the // number originally returned for this query. // genAttributes.MaxMulticastListSize = TAP_MAX_MCAST_LIST; genAttributes.MacAddressLength = MACADDR_SIZE; // // Return the MAC address of the NIC burnt in the hardware. // ETH_COPY_NETWORK_ADDRESS(genAttributes.PermanentMacAddress, adapter->PermanentAddress); // // Return the MAC address the NIC is currently programmed to use. Note // that this address could be different from the permananent address as // the user can override using registry. Read NdisReadNetworkAddress // doc for more info. // ETH_COPY_NETWORK_ADDRESS(genAttributes.CurrentMacAddress, adapter->CurrentAddress); genAttributes.RecvScaleCapabilities = NULL; genAttributes.AccessType = TAP_ACCESS_TYPE; genAttributes.DirectionType = TAP_DIRECTION_TYPE; genAttributes.ConnectionType = TAP_CONNECTION_TYPE; genAttributes.IfType = TAP_IFTYPE; genAttributes.IfConnectorPresent = TAP_HAS_PHYSICAL_CONNECTOR; genAttributes.SupportedStatistics = TAP_SUPPORTED_STATISTICS; genAttributes.SupportedPauseFunctions = NdisPauseFunctionsUnsupported; // IEEE 802.3 pause frames genAttributes.DataBackFillSize = 0; genAttributes.ContextBackFillSize = 0; // // The SupportedOidList is an array of OIDs for objects that the // underlying driver or its NIC supports. Objects include general, // media-specific, and implementation-specific objects. NDIS forwards a // subset of the returned list to protocols that make this query. That // is, NDIS filters any supported statistics OIDs out of the list // because protocols never make statistics queries. // genAttributes.SupportedOidList = TAPSupportedOids; genAttributes.SupportedOidListLength = sizeof(TAPSupportedOids); genAttributes.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED; // // Set power management capabilities // NdisZeroMemory(&pnpCapabilities, sizeof(pnpCapabilities)); pnpCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; pnpCapabilities.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified; genAttributes.PowerManagementCapabilities = &pnpCapabilities; status = NdisMSetMiniportAttributes(MiniportAdapterHandle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&genAttributes); if (status != NDIS_STATUS_SUCCESS) { DEBUGP(("[TAP] NdisMSetMiniportAttributes failed; Status 0x%08x\n", status)); break; } // // Create the Win32 device I/O interface. // status = CreateTapDevice(adapter); if (status == NDIS_STATUS_SUCCESS) { // Add this adapter to the global adapter list. tapAdapterContextAddToGlobalList(adapter); } else { DEBUGP(("[TAP] CreateTapDevice failed; Status 0x%08x\n", status)); break; } } while (FALSE); if (status == NDIS_STATUS_SUCCESS) { // Enter the Paused state if initialization is complete. DEBUGP(("[TAP] Miniport State: Paused\n")); tapAdapterAcquireLock(adapter, FALSE); adapter->Locked.AdapterState = MiniportPausedState; tapAdapterReleaseLock(adapter, FALSE); } else { if (adapter != NULL) { DEBUGP(("[TAP] Miniport State: Halted\n")); // // Remove reference when adapter context was allocated // --------------------------------------------------- // This should result in freeing adapter context memory // and assiciated resources. // tapAdapterContextDereference(adapter); adapter = NULL; } } DEBUGP(("[TAP] <-- AdapterCreate; status = %8.8X\n", status)); return status; }
NDIS_STATUS tapReadConfiguration(__in PTAP_ADAPTER_CONTEXT Adapter) { NDIS_STATUS status = NDIS_STATUS_SUCCESS; NDIS_CONFIGURATION_OBJECT configObject; NDIS_HANDLE configHandle; DEBUGP(("[TAP] --> tapReadConfiguration\n")); // // Setup defaults in case configuration cannot be opened. // Adapter->MtuSize = ETHERNET_MTU; Adapter->MediaStateAlwaysConnected = FALSE; Adapter->LogicalMediaState = FALSE; Adapter->AllowNonAdmin = FALSE; // // Open the registry for this adapter to read advanced // configuration parameters stored by the INF file. // NdisZeroMemory(&configObject, sizeof(configObject)); { C_ASSERT(sizeof(configObject) >= NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1); } configObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT; configObject.Header.Size = NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1; configObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1; configObject.NdisHandle = Adapter->MiniportAdapterHandle; configObject.Flags = 0; status = NdisOpenConfigurationEx(&configObject, &configHandle); // Read on the opened configuration handle. if (status == NDIS_STATUS_SUCCESS) { NDIS_CONFIGURATION_PARAMETER *configParameter; NDIS_STRING mkey = NDIS_STRING_CONST("NetCfgInstanceId"); // // Read NetCfgInstanceId from the registry. // ------------------------------------ // NetCfgInstanceId is required to create device and associated // symbolic link for the adapter device. // // NetCfgInstanceId is a GUID string provided by NDIS that identifies // the adapter instance. An example is: // // NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0} // // Other names are derived from NetCfgInstanceId. For example, MiniportName: // // MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0} // NdisReadConfiguration(&status, &configParameter, configHandle, &mkey, NdisParameterString); if (status == NDIS_STATUS_SUCCESS) { if (configParameter->ParameterType == NdisParameterString && configParameter->ParameterData.StringData.Length <= sizeof(Adapter->NetCfgInstanceIdBuffer) - sizeof(WCHAR)) { DEBUGP(("[TAP] NdisReadConfiguration (NetCfgInstanceId=%wZ)\n", &configParameter->ParameterData.StringData)); // Save NetCfgInstanceId as UNICODE_STRING. Adapter->NetCfgInstanceId.Length = Adapter->NetCfgInstanceId.MaximumLength = configParameter->ParameterData.StringData.Length; Adapter->NetCfgInstanceId.Buffer = Adapter->NetCfgInstanceIdBuffer; NdisMoveMemory(Adapter->NetCfgInstanceId.Buffer, configParameter->ParameterData.StringData.Buffer, Adapter->NetCfgInstanceId.Length); // Save NetCfgInstanceId as ANSI_STRING as well. if (RtlUnicodeStringToAnsiString(&Adapter->NetCfgInstanceIdAnsi, &configParameter->ParameterData.StringData, TRUE) != STATUS_SUCCESS) { DEBUGP(("[TAP] NetCfgInstanceId ANSI name conversion failed\n")); status = NDIS_STATUS_RESOURCES; } } else { DEBUGP(("[TAP] NetCfgInstanceId has invalid type\n")); status = NDIS_STATUS_INVALID_DATA; } } else { DEBUGP(("[TAP] NetCfgInstanceId failed\n")); status = NDIS_STATUS_INVALID_DATA; } if (status == NDIS_STATUS_SUCCESS) { NDIS_STATUS localStatus; // Use default if these fail. NDIS_CONFIGURATION_PARAMETER *configParameter; NDIS_STRING mtuKey = NDIS_STRING_CONST("MTU"); NDIS_STRING mediaStatusKey = NDIS_STRING_CONST("MediaStatus"); #if ENABLE_NONADMIN NDIS_STRING allowNonAdminKey = NDIS_STRING_CONST("AllowNonAdmin"); #endif // Read MTU from the registry. NdisReadConfiguration(&localStatus, &configParameter, configHandle, &mtuKey, NdisParameterInteger); if (localStatus == NDIS_STATUS_SUCCESS) { if (configParameter->ParameterType == NdisParameterInteger) { int mtu = configParameter->ParameterData.IntegerData; if (mtu == 0) { mtu = ETHERNET_MTU; } // Sanity check if (mtu < MINIMUM_MTU) { mtu = MINIMUM_MTU; } else if (mtu > MAXIMUM_MTU) { mtu = MAXIMUM_MTU; } Adapter->MtuSize = mtu; } } DEBUGP(("[%s] Using MTU %d\n", MINIPORT_INSTANCE_ID(Adapter), Adapter->MtuSize)); // Read MediaStatus setting from registry. NdisReadConfiguration(&localStatus, &configParameter, configHandle, &mediaStatusKey, NdisParameterInteger); if (localStatus == NDIS_STATUS_SUCCESS) { if (configParameter->ParameterType == NdisParameterInteger) { if (configParameter->ParameterData.IntegerData == 0) { // Connect state is appplication controlled. DEBUGP(("[%s] Initial MediaConnectState: Application Controlled\n", MINIPORT_INSTANCE_ID(Adapter))); Adapter->MediaStateAlwaysConnected = FALSE; Adapter->LogicalMediaState = FALSE; } else { // Connect state is always connected. DEBUGP(("[%s] Initial MediaConnectState: Always Connected\n", MINIPORT_INSTANCE_ID(Adapter))); Adapter->MediaStateAlwaysConnected = TRUE; Adapter->LogicalMediaState = TRUE; } } } // Read MAC PermanentAddress setting from registry. tapReadPermanentAddress(Adapter, configHandle, Adapter->PermanentAddress); DEBUGP(("[%s] Using MAC PermanentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", MINIPORT_INSTANCE_ID(Adapter), Adapter->PermanentAddress[0], Adapter->PermanentAddress[1], Adapter->PermanentAddress[2], Adapter->PermanentAddress[3], Adapter->PermanentAddress[4], Adapter->PermanentAddress[5])); // Now seed the current MAC address with the permanent address. ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentAddress, Adapter->PermanentAddress); DEBUGP(("[%s] Using MAC CurrentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", MINIPORT_INSTANCE_ID(Adapter), Adapter->CurrentAddress[0], Adapter->CurrentAddress[1], Adapter->CurrentAddress[2], Adapter->CurrentAddress[3], Adapter->CurrentAddress[4], Adapter->CurrentAddress[5])); // Read optional AllowNonAdmin setting from registry. #if ENABLE_NONADMIN NdisReadConfiguration(&localStatus, &configParameter, configHandle, &allowNonAdminKey, NdisParameterInteger); if (localStatus == NDIS_STATUS_SUCCESS) { if (configParameter->ParameterType == NdisParameterInteger) { Adapter->AllowNonAdmin = TRUE; } } #endif } // Close the configuration handle. NdisCloseConfiguration(configHandle); } else { DEBUGP(("[TAP] Couldn't open adapter registry\n")); } DEBUGP(("[TAP] <-- tapReadConfiguration; status = %8.8X\n", status)); return status; }
// 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; }