/*++ Copyright (c) 2000-2000 Microsoft Corporation Module Name: PnP.c Abstract: This module contains the various PnP handlers Author: Mohammad Shabbir Alam (MAlam) 3-30-2000 Revision History: --*/ #include "precomp.h" #include // for IPInterfaceInfo #include "ntddip.h" // Needed for IP_INTERFACE_INFO #include // for AO_OPTION_xxx, TCPSocketOption //******************* Pageable Routine Declarations **************** #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, SetTdiHandlers) #endif //******************* Pageable Routine Declarations **************** HANDLE TdiClientHandle = NULL; //---------------------------------------------------------------------------- BOOLEAN SrcIsUs( tIPADDRESS IpAddress ) /*++ Routine Description: This routine determines if the IP address passed in is a local address Arguments: IN IpAddress -- IpAddress to verify Return Value: TRUE if IpAddress is local, FALSE otherwise --*/ { LIST_ENTRY *pEntry; LIST_ENTRY *pEntry2; PGMLockHandle OldIrq; tLOCAL_INTERFACE *pLocalInterface; tADDRESS_ON_INTERFACE *pLocalAddress; PgmLock (&PgmDynamicConfig, OldIrq); pEntry = &PgmDynamicConfig.LocalInterfacesList; while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList) { pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage); pEntry2 = &pLocalInterface->Addresses; while ((pEntry2 = pEntry2->Flink) != &pLocalInterface->Addresses) { pLocalAddress = CONTAINING_RECORD (pEntry2, tADDRESS_ON_INTERFACE, Linkage); if (pLocalAddress->IpAddress == IpAddress) { PgmUnlock (&PgmDynamicConfig, OldIrq); return (TRUE); } } } PgmUnlock (&PgmDynamicConfig, OldIrq); return (FALSE); } //---------------------------------------------------------------------------- NTSTATUS GetIpInterfaceContextFromAddress( IN tIPADDRESS IpAddr, OUT ULONG *pIPInterfaceContext ) /*++ Routine Description: Given an IP address, this routine determines will return the Ip interface context that address is registered on Arguments: IN IpAddress -- IpAddress OUT IpInterfaceContext -- IpInterfaceContext for the IP address passed Return Value: STATUS_SUCCESS if IpAddress was matched to interface, STATUS_UNSUCCESSFUL otherwise The DynamicConfig lock is held on entry and exit from this routine --*/ { LIST_ENTRY *pEntry; LIST_ENTRY *pEntry2; tLOCAL_INTERFACE *pLocalInterface; tADDRESS_ON_INTERFACE *pLocalAddress; ASSERT (IpAddr); pEntry = &PgmDynamicConfig.LocalInterfacesList; while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList) { pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage); pEntry2 = &pLocalInterface->Addresses; while ((pEntry2 = pEntry2->Flink) != &pLocalInterface->Addresses) { pLocalAddress = CONTAINING_RECORD (pEntry2, tADDRESS_ON_INTERFACE, Linkage); if (pLocalAddress->IpAddress == IpAddr) { *pIPInterfaceContext = pLocalInterface->IpInterfaceContext; return (STATUS_SUCCESS); } } } return (STATUS_UNSUCCESSFUL); } //---------------------------------------------------------------------------- NTSTATUS GetIpInterfaceContextFromDeviceName( IN tIPADDRESS NetIpAddr, IN PUNICODE_STRING pucBindString, OUT ULONG *pIPInterfaceContext, IN ULONG BufferLength, OUT UCHAR *pBuffer, IN BOOLEAN fGetInterfaceInfo ) /*++ Routine Description: Given a Unicode device name string, this routine will query Ip and return the IpInterfaceContext for that device Arguments: IN NetIpAddr -- IpAddress on Device IN pucBindString -- Pointer to unicode device name string OUT IpInterfaceContext -- IpInterfaceContext for the device name IN BufferLength -- Length of Output buffer passed OUT pBuffer -- Output buffer passed for Interface properties IN fGetInterfaceInfo -- Whether to return Interface properties or not Return Value: STATUS_SUCCESS if IpInterfaceContext was found, and properties successfully queried, STATUS_UNSUCCESSFUL otherwise --*/ { LONG i; NTSTATUS status; PVOID *pIPInfo; PIP_INTERFACE_INFO pIPIfInfo; UNICODE_STRING ucDeviceName; ULONG BufferLen = 2 * sizeof(IP_ADAPTER_INDEX_MAP); // assume status = PgmProcessIPRequest (IOCTL_IP_INTERFACE_INFO, NULL, // No Input buffer 0, &pIPIfInfo, &BufferLen); if (!NT_SUCCESS(status)) { PgmLog (PGM_LOG_ERROR, DBG_PNP, "GetInterfaceContext", "PgmProcessIPRequest returned status=<%x> for IOCTL_IP_INTERFACE_INFO, pDevice=<%wZ>!\n", status, pucBindString); return (status); } status = STATUS_UNSUCCESSFUL; for (i=0; i < pIPIfInfo->NumAdapters; i++) { ucDeviceName.Buffer = pIPIfInfo->Adapter[i].Name; ucDeviceName.Length = sizeof (WCHAR) * wcslen (pIPIfInfo->Adapter[i].Name); ucDeviceName.MaximumLength = ucDeviceName.Length + sizeof (WCHAR); PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "GetInterfaceContext", "[%d/%d]\t<%wZ>\n", i+1, pIPIfInfo->NumAdapters, &ucDeviceName); if (RtlCompareUnicodeString (&ucDeviceName, pucBindString, TRUE) == 0) { *pIPInterfaceContext = pIPIfInfo->Adapter[i].Index; status = STATUS_SUCCESS; break; } } PgmFreeMem (pIPIfInfo); if (!NT_SUCCESS (status)) { PgmLog (PGM_LOG_ERROR, DBG_PNP, "GetInterfaceContext", "Could not find IPInterfaceContext for Device=<%wZ>\n", pucBindString); return (status); } status = PgmQueryTcpInfo (pgPgmDevice->hControl, IP_INTFC_INFO_ID, &NetIpAddr, sizeof (tIPADDRESS), pBuffer, BufferLength); if (!NT_SUCCESS (status)) { PgmLog (PGM_LOG_ERROR, DBG_PNP, "GetInterfaceContext", "PgmQueryTcpInfo returned <%x>\n", status); return (status); } PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "GetInterfaceContext", "IPInterfaceContext=<%x> for Device=<%wZ>\n", *pIPInterfaceContext, pucBindString); return (status); } //---------------------------------------------------------------------------- ULONG StopListeningOnInterface( #ifdef IP_FIX IN ULONG IpInterfaceContext, #else IN tIPADDRESS IpAddress, // Host format #endif // IP_FIX IN PGMLockHandle *pOldIrqDynamicConfig ) /*++ Routine Description: Given an IPInterfaceContext, this routine traverses the list of all Receivers, and if any are determined to be listening on that interface, stops them from listening on all the addresses on this interface. In the case that the listener is part of an active session, the routine will also change the state of the Receiver to start listening on all interfaces Arguments: IN IpInterfaceContext -- IpInterfaceContext to stop listening on IN pOldIrqDynamicConfig-- OldIrq for DynamicConfig lock held The DynamicConfig lock is held on entry and exit from this routine Return Value: Number of receivers found listening on this interface --*/ { NTSTATUS status; tRECEIVE_SESSION *pReceive; tADDRESS_CONTEXT *pAddress; LIST_ENTRY *pEntry; LIST_ENTRY *pEntry2; PGMLockHandle OldIrq1, OldIrq2; USHORT i; tMCAST_INFO MCastInfo; ULONG NumDisconnected = 0; tADDRESS_CONTEXT *pAddressToDeref = NULL; #ifdef IP_FIX MCastInfo.MCastInIf = IpInterfaceContext; #else MCastInfo.MCastInIf = htonl (IpAddress); #endif // IP_FIX pEntry = &PgmDynamicConfig.ReceiverAddressHead; while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.ReceiverAddressHead) { pAddress = CONTAINING_RECORD (pEntry, tADDRESS_CONTEXT, Linkage); PgmLock (pAddress, OldIrq1); if (!(pAddress->Flags & PGM_ADDRESS_LISTEN_ON_ALL_INTERFACES)) { // // If the app had specified interfaces to listen on, // then don't manage interfaces! // PgmUnlock (pAddress, OldIrq1); continue; } // // See if this address was listening on this interface // for (i=0; iNumReceiveInterfaces; i++) { #ifdef IP_FIX if (pAddress->ReceiverInterfaceList[i] == IpInterfaceContext) #else if (pAddress->ReceiverInterfaceList[i] == IpAddress) #endif // IP_FIX { break; } } if (i >= pAddress->NumReceiveInterfaces) { PgmUnlock (pAddress, OldIrq1); continue; } // // Remove this Interface from the list of listening interfaces // pAddress->NumReceiveInterfaces--; while (i < pAddress->NumReceiveInterfaces) { pAddress->ReceiverInterfaceList[i] = pAddress->ReceiverInterfaceList[i+1]; i++; } PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_STOP_LISTENING, TRUE); // // If this were the only interface we were listening on // for an active session (or waiting for a session), ensure // that we go back into listening mode! // if ((pAddress->Flags & PGM_ADDRESS_LISTEN_ON_ALL_INTERFACES) && (!pAddress->NumReceiveInterfaces)) { pAddress->Flags |= PGM_ADDRESS_WAITING_FOR_NEW_INTERFACE; if (!IsListEmpty (&PgmDynamicConfig.LocalInterfacesList)) { status = ListenOnAllInterfaces (pAddress, pOldIrqDynamicConfig, &OldIrq1); if (NT_SUCCESS (status)) { PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "StopListeningOnInterface", "ListenOnAllInterfaces for pAddress=<%x> succeeded\n", pAddress); } else { PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "StopListeningOnInterface", "ListenOnAllInterfaces for pAddress=<%x> returned <%x>\n", pAddress, status); } } } PgmUnlock (pAddress, OldIrq1); PgmUnlock (&PgmDynamicConfig, *pOldIrqDynamicConfig); if (pAddressToDeref) { PGM_DEREFERENCE_ADDRESS (pAddressToDeref, REF_ADDRESS_STOP_LISTENING); } pAddressToDeref = pAddress; // // So, stop listening on this interface // MCastInfo.MCastIpAddr = htonl (pAddress->ReceiverMCastAddr); #ifdef IP_FIX status = PgmSetTcpInfo (pAddress->FileHandle, AO_OPTION_INDEX_DEL_MCAST, &MCastInfo, sizeof (tMCAST_INFO)); #else status = PgmSetTcpInfo (pAddress->FileHandle, AO_OPTION_DEL_MCAST, &MCastInfo, sizeof (tMCAST_INFO)); #endif // IP_FIX if (NT_SUCCESS (status)) { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "\tStopListeningOnInterface", "Stopped pAddress=<%x> from listening on Interface=<%x>\n", pAddress, MCastInfo.MCastInIf); } else { // // We failed to stop listening on this interface -- don't so anything! // PgmLog (PGM_LOG_ERROR, DBG_PNP, "\tStopListeningOnInterface", "AO_OPTION_INDEX_DEL_MCAST for If=<%x> on Address=<%x> returned <%x>\n", MCastInfo.MCastInIf, pAddress, status); } PgmLock (&PgmDynamicConfig, *pOldIrqDynamicConfig); } if (pAddressToDeref) { PGM_DEREFERENCE_ADDRESS (pAddressToDeref, REF_ADDRESS_STOP_LISTENING); } return (NumDisconnected); } //---------------------------------------------------------------------------- VOID StopListeningOnAllInterfacesExcept( IN tADDRESS_CONTEXT *pAddress, IN PVOID Data1, IN PVOID Unused ) /*++ Routine Description: Given an Address Context and IPInterfaceContext (Data1), this routine stops the Address from listening on all the addresses except on this interface. Arguments: IN pAddress -- Address Context IN Data1 -- IpInterfaceContext to stop listening on Return Value: None --*/ { NTSTATUS status; PGMLockHandle OldIrq; tMCAST_INFO MCastInfo; ULONG InterfacesToStop[MAX_RECEIVE_INTERFACES+1]; USHORT NumInterfaces, i; ULONG InterfaceToKeep = PtrToUlong (Data1); #ifndef IP_FIX PGMLockHandle OldIrq0; LIST_ENTRY *pEntry; tLOCAL_INTERFACE *pLocalInterface; tADDRESS_ON_INTERFACE *pLocalAddress; USHORT j; #endif // !IP_FIX PgmLock (&PgmDynamicConfig, OldIrq0); PgmLock (pAddress, OldIrq); // // pAddress must be referenced before entering this routine // if (!(PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS)) || (pAddress->Flags & PGM_ADDRESS_WAITING_FOR_NEW_INTERFACE)) { // // Out state has changed -- deref and return immediately // PgmUnlock (pAddress, OldIrq); PgmUnlock (&PgmDynamicConfig, OldIrq0); PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_STOP_LISTENING); return; } #ifdef IP_FIX // // If this is the only interface we are listening on, // return success // if ((pAddress->NumReceiveInterfaces == 1) && (pAddress->ReceiverInterfaceList[0] == InterfaceToKeep)) { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "StopListeningOnAllInterfacesExcept", "pAddress=<%x> is only listening on 1 Interface=<%x>\n", pAddress, InterfaceToKeep); PgmUnlock (pAddress, OldIrq); return; } ASSERT (pAddress->NumReceiveInterfaces > 1); // // First, enumerate all interfaces to stop listening on // NumInterfaces = 0; for (i=0; iNumReceiveInterfaces; i++) { if (pAddress->ReceiverInterfaceList[i] != InterfaceToKeep) { InterfacesToStop[NumInterfaces++] = pAddress->ReceiverInterfaceList[i]; } } pAddress->ReceiverInterfaceList[0] = InterfaceToKeep; pAddress->NumReceiveInterfaces = 1; // // Now, remove the remaining interfaces // #else // // First, make a copy of all addresses being listened on // NumInterfaces = 0; for (i=0; iNumReceiveInterfaces; i++) { InterfacesToStop[NumInterfaces++] = pAddress->ReceiverInterfaceList[i]; } // // Zero out the current listening list on the address // pAddress->NumReceiveInterfaces = 0; // // Now, remove the addresses on this interface from this list // pEntry = &PgmDynamicConfig.LocalInterfacesList; while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList) { pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage); if (InterfaceToKeep == pLocalInterface->IpInterfaceContext) { // // Found the interface -- now save these addresses in the Address // list and remove from the stop list // pEntry = &pLocalInterface->Addresses; while ((pEntry = pEntry->Flink) != &pLocalInterface->Addresses) { pLocalAddress = CONTAINING_RECORD (pEntry, tADDRESS_ON_INTERFACE, Linkage); pAddress->ReceiverInterfaceList[pAddress->NumReceiveInterfaces++] = pLocalAddress->IpAddress; i = 0; while (i < NumInterfaces) { if (InterfacesToStop[i] == pLocalAddress->IpAddress) { j = i; NumInterfaces--; while (j < NumInterfaces) { InterfacesToStop[j] = InterfacesToStop[j+1]; j++; } } else { i++; } } } break; } } #endif // IP_FIX PgmUnlock (pAddress, OldIrq); PgmUnlock (&PgmDynamicConfig, OldIrq0); MCastInfo.MCastIpAddr = htonl (pAddress->ReceiverMCastAddr); for (i=0; iFileHandle, AO_OPTION_INDEX_DEL_MCAST, &MCastInfo, sizeof (tMCAST_INFO)); #else MCastInfo.MCastInIf = htonl (InterfacesToStop[i]); status = PgmSetTcpInfo (pAddress->FileHandle, AO_OPTION_DEL_MCAST, &MCastInfo, sizeof (tMCAST_INFO)); #endif // IP_FIX if (NT_SUCCESS (status)) { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "\tStopListeningOnAllInterfacesExcept", "Stopped pAddress=<%x> from listening on Interface=<%x>\n", pAddress, MCastInfo.MCastInIf); } else { // // We failed to stop this interface -- don't so anything! // PgmLog (PGM_LOG_ERROR, DBG_PNP, "\tStopListeningOnAllInterfacesExcept", "AO_OPTION_INDEX_DEL_MCAST for If=<%x> on Address=<%x> returned <%x>\n", MCastInfo.MCastInIf, pAddress, status); } } PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_STOP_LISTENING); return; } //---------------------------------------------------------------------------- NTSTATUS ListenOnAllInterfaces( IN tADDRESS_CONTEXT *pAddress, IN PGMLockHandle *pOldIrqDynamicConfig, IN PGMLockHandle *pOldIrqAddress ) /*++ Routine Description: Given an Address Context, this routine enables the Address to start listening on all interfaces Arguments: IN pAddress -- Address Context IN pOldIrqDynamicConfig-- OldIrq for DynamicConfig lock held IN pOldIrqAddress -- OldIrq for Address lock held The DynamicConfig and Address locks are held on entry and exit from this routine Return Value: STATUS_SUCCESS --*/ { NTSTATUS status; LIST_ENTRY *pEntry; tLOCAL_INTERFACE *pLocalInterface; tMCAST_INFO MCastInfo; ULONG InterfacesToAdd[MAX_RECEIVE_INTERFACES+1]; USHORT NumInterfaces, i, j; #ifndef IP_FIX LIST_ENTRY *pEntry2; tADDRESS_ON_INTERFACE *pLocalAddress; #endif // !IP_FIX // // First, get the list of all active interfaces // NumInterfaces = 0; pEntry = &PgmDynamicConfig.LocalInterfacesList; while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList) { pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage); #ifdef IP_FIX InterfacesToAdd[NumInterfaces++] = pLocalInterface->IpInterfaceContext; #else pEntry2 = &pLocalInterface->Addresses; while ((pEntry2 = pEntry2->Flink) != &pLocalInterface->Addresses) { pLocalAddress = CONTAINING_RECORD (pEntry2, tADDRESS_ON_INTERFACE, Linkage); InterfacesToAdd[NumInterfaces++] = pLocalAddress->IpAddress; if (NumInterfaces >= MAX_RECEIVE_INTERFACES) { break; } } #endif // IP_FIX if (NumInterfaces >= MAX_RECEIVE_INTERFACES) { break; } } // // Remove all the interfaces we are already listening // on from the list of interfaces to be added // for (i=0; iNumReceiveInterfaces; i++) { for (j = 0; j < NumInterfaces; j++) { if (pAddress->ReceiverInterfaceList[i] == InterfacesToAdd[j]) { NumInterfaces--; while (j < NumInterfaces) { InterfacesToAdd[j] = InterfacesToAdd[j+1]; j++; } break; } } } if (!NumInterfaces) { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "ListenOnAllInterfaces", "No new interfaces to listen on for pAddress=<%x>, currently listening on <%x> Ifs\n", pAddress, pAddress->NumReceiveInterfaces); return (STATUS_SUCCESS); } // // Ensure that the complete list will not // exceed the maximum limit // if ((pAddress->NumReceiveInterfaces + NumInterfaces) > MAX_RECEIVE_INTERFACES) { NumInterfaces = MAX_RECEIVE_INTERFACES - pAddress->NumReceiveInterfaces; } // // Now, add the remaining interfaces // PgmUnlock (pAddress, *pOldIrqAddress); PgmUnlock (&PgmDynamicConfig, *pOldIrqDynamicConfig); MCastInfo.MCastIpAddr = htonl (pAddress->ReceiverMCastAddr); i = 0; while (i < NumInterfaces) { #ifdef IP_FIX MCastInfo.MCastInIf = InterfacesToAdd[i]; status = PgmSetTcpInfo (pAddress->FileHandle, AO_OPTION_INDEX_ADD_MCAST, &MCastInfo, sizeof (tMCAST_INFO)); #else MCastInfo.MCastInIf = htonl (InterfacesToAdd[i]); status = PgmSetTcpInfo (pAddress->FileHandle, AO_OPTION_ADD_MCAST, &MCastInfo, sizeof (tMCAST_INFO)); #endif // IP_FIX if (NT_SUCCESS (status)) { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "\tListenOnAllInterfaces", "pAddress=<%x> now also listening on If=<%x>\n", pAddress, MCastInfo.MCastInIf); i++; continue; } // // We failed to add this interface, so remove it from // the list // PgmLog (PGM_LOG_ERROR, DBG_PNP, "\tListenOnAllInterfaces", "pAddress=<%x> could not listen on If=<%x>\n", pAddress, MCastInfo.MCastInIf); j = i; NumInterfaces--; while (j < NumInterfaces) { InterfacesToAdd[j] = InterfacesToAdd[j+1]; j++; } } PgmLock (&PgmDynamicConfig, *pOldIrqDynamicConfig); PgmLock (pAddress, *pOldIrqAddress); // // Now, append the new list to the Address context // for (i=0; iNumReceiveInterfaces > MAX_RECEIVE_INTERFACES) { ASSERT (0); break; } pAddress->ReceiverInterfaceList[pAddress->NumReceiveInterfaces] = InterfacesToAdd[i]; pAddress->NumReceiveInterfaces++; } return (STATUS_SUCCESS); } //---------------------------------------------------------------------------- VOID TdiAddressArrival( PTA_ADDRESS Addr, PUNICODE_STRING pDeviceName, PTDI_PNP_CONTEXT Context ) /*++ Routine Description: PnP TDI_ADD_ADDRESS_HANDLER This routine handles an IP address arriving. It is called by TDI when an address arrives. Arguments: IN Addr -- IP address that's coming. IN pDeviceName -- Unicode string Ptr for Device whose address is changing IN Context -- Tdi PnP context Return Value: Nothing! --*/ { tIPADDRESS IpAddr, NetIpAddr; LIST_ENTRY *pEntry; PGMLockHandle OldIrq, OldIrq1; tLOCAL_INTERFACE *pLocalInterface = NULL; tADDRESS_ON_INTERFACE *pLocalAddress = NULL; ULONG BufferLength = 50; UCHAR pBuffer[50]; IPInterfaceInfo *pIpIfInfo = (IPInterfaceInfo *) pBuffer; NTSTATUS status; tADDRESS_CONTEXT *pAddress; tADDRESS_CONTEXT *pAddressToDeref = NULL; ULONG IpInterfaceContext; BOOLEAN fFound; // // Proceed only if this is an IP address // if (Addr->AddressType != TDI_ADDRESS_TYPE_IP) { return; } // // First, verify that we are not getting unloaded // PgmLock (&PgmDynamicConfig, OldIrq); if (!PGM_VERIFY_HANDLE (pgPgmDevice, PGM_VERIFY_DEVICE)) { // // The driver is most probably being unloaded now // PgmUnlock (&PgmDynamicConfig, OldIrq); return; } PGM_REFERENCE_DEVICE (pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION, FALSE); PgmUnlock (&PgmDynamicConfig, OldIrq); NetIpAddr = ((PTDI_ADDRESS_IP)&Addr->Address[0])->in_addr; IpAddr = ntohl (NetIpAddr); // // Now, get the interface context and other info from TcpIp // status = GetIpInterfaceContextFromDeviceName (NetIpAddr, pDeviceName, &IpInterfaceContext, BufferLength, pBuffer, TRUE); if (!NT_SUCCESS (status)) { PgmLog (PGM_LOG_ERROR, DBG_PNP, "TdiAddressArrival", "GetIpInterfaceContext returned <%x>\n", status); PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION); return; } PgmLock (&PgmDynamicConfig, OldIrq); fFound = FALSE; pEntry = &PgmDynamicConfig.LocalInterfacesList; while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList) { pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage); if (pLocalInterface->IpInterfaceContext == IpInterfaceContext) { fFound = TRUE; break; } } if (fFound) { fFound = FALSE; pEntry = &pLocalInterface->Addresses; while ((pEntry = pEntry->Flink) != &pLocalInterface->Addresses) { pLocalAddress = CONTAINING_RECORD (pEntry, tADDRESS_ON_INTERFACE, Linkage); if (pLocalAddress->IpAddress == IpAddr) { PgmUnlock (&PgmDynamicConfig, OldIrq); PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION); PgmLog (PGM_LOG_ERROR, DBG_PNP, "TdiAddressArrival", "\tDUPLICATE address notification for [%d.%d.%d.%d] on <%wZ>\n", (IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF, pDeviceName); return; } } } else if (pLocalInterface = PgmAllocMem (sizeof(tLOCAL_INTERFACE), PGM_TAG('0'))) { PgmZeroMemory (pLocalInterface, sizeof (tLOCAL_INTERFACE)); InitializeListHead (&pLocalInterface->Addresses); pLocalInterface->IpInterfaceContext = IpInterfaceContext; pLocalInterface->MTU = pIpIfInfo->iii_mtu - (sizeof(IPV4Header) + ROUTER_ALERT_SIZE); pLocalInterface->Flags = pIpIfInfo->iii_flags; BufferLength = pIpIfInfo->iii_addrlength < sizeof(tMAC_ADDRESS) ? pIpIfInfo->iii_addrlength : sizeof(tMAC_ADDRESS); PgmCopyMemory (&pLocalInterface->MacAddress, pIpIfInfo->iii_addr, BufferLength); if (pLocalInterface->MTU > PgmDynamicConfig.MaxMTU) { PgmDynamicConfig.MaxMTU = pLocalInterface->MTU; } InsertTailList (&PgmDynamicConfig.LocalInterfacesList, &pLocalInterface->Linkage); } else { PgmUnlock (&PgmDynamicConfig, OldIrq); PgmLog (PGM_LOG_ERROR, DBG_PNP, "TdiAddressArrival", "STATUS_INSUFFICIENT_RESOURCES[Interface] for IP=<%x>, IfContext=<%x>\n", IpAddr, IpInterfaceContext); PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION); return; } // // Now, add this address to the interface // if (pLocalAddress = PgmAllocMem (sizeof(tADDRESS_ON_INTERFACE), PGM_TAG('0'))) { PgmZeroMemory (pLocalAddress, sizeof (tADDRESS_ON_INTERFACE)); pLocalAddress->IpAddress = IpAddr; InsertTailList (&pLocalInterface->Addresses, &pLocalAddress->Linkage); } else { // // If we had just added the interface, there is no point // in keeping an empty context around! // if (IsListEmpty (&pLocalInterface->Addresses)) { RemoveEntryList (&pLocalInterface->Linkage); PgmFreeMem (pLocalInterface); } PgmUnlock (&PgmDynamicConfig, OldIrq); PgmLog (PGM_LOG_ERROR, DBG_PNP, "TdiAddressArrival", "STATUS_INSUFFICIENT_RESOURCES[Address] -- [%d.%d.%d.%d] on <%wZ>\n", (IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF, pDeviceName); PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION); return; } // // Now, check if we have any receivers waiting for an address // pEntry = &PgmDynamicConfig.ReceiverAddressHead; while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.ReceiverAddressHead) { pAddress = CONTAINING_RECORD (pEntry, tADDRESS_CONTEXT, Linkage); PgmLock (pAddress, OldIrq1); if ((PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS)) && (pAddress->Flags & PGM_ADDRESS_WAITING_FOR_NEW_INTERFACE) && (pAddress->Flags & PGM_ADDRESS_LISTEN_ON_ALL_INTERFACES)) { PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO, TRUE); if (pAddressToDeref) { PgmUnlock (pAddress, OldIrq1); PgmUnlock (&PgmDynamicConfig, OldIrq); PGM_DEREFERENCE_ADDRESS (pAddressToDeref, REF_ADDRESS_SET_INFO); PgmLock (&PgmDynamicConfig, OldIrq); PgmLock (pAddress, OldIrq1); } pAddressToDeref = pAddress; status = ReceiverAddMCastIf (pAddress, IpAddr, &OldIrq, &OldIrq1); if (NT_SUCCESS (status)) { PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "TdiAddressArrival", "ReceiverAddMCastIf for pAddress=<%x> succeeded for IP=<%x>\n", pAddress, IpAddr); } else { PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "TdiAddressArrival", "ReceiverAddMCastIf for pAddress=<%x> returned <%x>, IP=<%x>\n", pAddress, status, IpAddr); } } PgmUnlock (pAddress, OldIrq1); } PgmUnlock (&PgmDynamicConfig, OldIrq); if (pAddressToDeref) { PGM_DEREFERENCE_ADDRESS (pAddressToDeref, REF_ADDRESS_SET_INFO); } PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_ADDRESS_NOTIFICATION); PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiAddressArrival", "\t[%d.%d.%d.%d] on <%wZ>\n", (IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF, pDeviceName); } //---------------------------------------------------------------------------- VOID TdiAddressDeletion( PTA_ADDRESS Addr, PUNICODE_STRING pDeviceName, PTDI_PNP_CONTEXT Context ) /*++ Routine Description: This routine handles an IP address going away. It is called by TDI when an address is deleted. If it's an address we care about we'll clean up appropriately. Arguments: IN Addr -- IP address that's going. IN pDeviceName -- Unicode string Ptr for Device whose address is changing IN Context -- Tdi PnP context Return Value: Nothing! --*/ { tIPADDRESS IpAddr; LIST_ENTRY *pEntry; LIST_ENTRY *pEntry2; PGMLockHandle OldIrq, OldIrq1; tSEND_SESSION *pSend; tADDRESS_CONTEXT *pAddress; NTSTATUS status; BOOLEAN fFound; tADDRESS_CONTEXT *pAddressToDeref = NULL; tLOCAL_INTERFACE *pLocalInterface = NULL; tADDRESS_ON_INTERFACE *pLocalAddress = NULL; ULONG IpInterfaceContext; if (Addr->AddressType != TDI_ADDRESS_TYPE_IP) { return; } IpAddr = ntohl(((PTDI_ADDRESS_IP)&Addr->Address[0])->in_addr); PgmLock (&PgmDynamicConfig, OldIrq); fFound = FALSE; pEntry = &PgmDynamicConfig.LocalInterfacesList; while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.LocalInterfacesList) { pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage); pEntry2 = &pLocalInterface->Addresses; while ((pEntry2 = pEntry2->Flink) != &pLocalInterface->Addresses) { pLocalAddress = CONTAINING_RECORD (pEntry2, tADDRESS_ON_INTERFACE, Linkage); if (pLocalAddress->IpAddress == IpAddr) { IpInterfaceContext = pLocalInterface->IpInterfaceContext; RemoveEntryList (&pLocalAddress->Linkage); PgmFreeMem (pLocalAddress); // // If this is the last address on this interface, clean up! // if (IsListEmpty (&pLocalInterface->Addresses)) { RemoveEntryList (&pLocalInterface->Linkage); PgmFreeMem (pLocalInterface); pLocalInterface = NULL; } fFound = TRUE; break; } } if (fFound) { break; } } if (!fFound) { PgmUnlock (&PgmDynamicConfig, OldIrq); PgmLog (PGM_LOG_ERROR, DBG_PNP, "TdiAddressDeletion", "\tAddress [%d.%d.%d.%d] NOT notified on <%wZ>\n", (IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF, pDeviceName); return; } pEntry = &PgmDynamicConfig.SenderAddressHead; while ((pEntry = pEntry->Flink) != &PgmDynamicConfig.SenderAddressHead) { pAddress = CONTAINING_RECORD (pEntry, tADDRESS_CONTEXT, Linkage); if (pAddress->SenderMCastOutIf == IpAddr) { PgmLock (pAddress, OldIrq1); pAddress->Flags |= PGM_ADDRESS_FLAG_INVALID_OUT_IF; pEntry2 = &pAddress->AssociatedConnections; while ((pEntry2 = pEntry2->Flink) != &pAddress->AssociatedConnections) { pSend = CONTAINING_RECORD (pEntry2, tSEND_SESSION, Linkage); if (!(pSend->SessionFlags & PGM_SESSION_TERMINATED_ABORT)) { pSend->SessionFlags |= PGM_SESSION_TERMINATED_ABORT; if (pAddress->evDisconnect) { PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_DISCONNECT, TRUE); PGM_REFERENCE_SESSION_SEND (pSend, REF_SESSION_DISCONNECT, FALSE); PgmUnlock (pAddress, OldIrq1); PgmUnlock (&PgmDynamicConfig, OldIrq); if (pAddressToDeref) { PGM_DEREFERENCE_ADDRESS (pAddressToDeref, REF_ADDRESS_DISCONNECT); } pAddressToDeref = pAddress; status = (*pAddress->evDisconnect) (pAddress->DiscEvContext, pSend->ClientSessionContext, 0, NULL, 0, NULL, TDI_DISCONNECT_ABORT); PGM_DEREFERENCE_SESSION_SEND (pSend, REF_SESSION_DISCONNECT); PgmLock (&PgmDynamicConfig, OldIrq); PgmLock (pAddress, OldIrq1); pEntry = &PgmDynamicConfig.SenderAddressHead; break; } } } PgmUnlock (pAddress, OldIrq1); } } // // See which receivers were actively listening on this interface // If this was an interface for an active session, then we need to // restart listening on all interfaces if no interface(s) had been // specified by the user. // #ifdef IP_FIX if (!pLocalInterface) { StopListeningOnInterface (IpInterfaceContext, &OldIrq); } #else StopListeningOnInterface (IpAddr, &OldIrq); #endif // IP_FIX PgmUnlock (&PgmDynamicConfig, OldIrq); if (pAddressToDeref) { PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_DISCONNECT); } PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiAddressDeletion", "\t[%d.%d.%d.%d] on <%wZ>\n", (IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF, pDeviceName); } //---------------------------------------------------------------------------- VOID TdiBindHandler( TDI_PNP_OPCODE PnPOpCode, PUNICODE_STRING pDeviceName, PWSTR MultiSZBindList ) /*++ Routine Description: This routine is the handler for TDI to notify clients of bind notifications Arguments: IN PnPOpCode -- Notification code IN pDeviceName -- Unicode string Ptr for Device whose address is changing IN MultiSZBindList -- Current list of bindings Return Value: NTSTATUS - Final status of the set event operation --*/ { PAGED_CODE(); switch (PnPOpCode) { case (TDI_PNP_OP_ADD): { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiBindHandler", "\t[ADD]: Device=<%wZ>\n", pDeviceName); break; } case (TDI_PNP_OP_DEL): { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiBindHandler", "\t[DEL]: Device=<%wZ>\n", pDeviceName); break; } case (TDI_PNP_OP_PROVIDERREADY): { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiBindHandler", "\t[PROVIDERREADY]: Device=<%wZ>\n", pDeviceName); break; } case (TDI_PNP_OP_NETREADY): { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiBindHandler", "\t[NETREADY]: Device=<%wZ>\n", pDeviceName); break; } default: { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiBindHandler", "\t[?=%x]: Device=<%wZ>\n", PnPOpCode, pDeviceName); break; } } } //---------------------------------------------------------------------------- NTSTATUS TdiPnPPowerHandler( IN PUNICODE_STRING pDeviceName, IN PNET_PNP_EVENT pPnPEvent, IN PTDI_PNP_CONTEXT Context1, IN PTDI_PNP_CONTEXT Context2 ) /*++ Routine Description: This routine is the handler called by TDI notify its clients of Power notifications Arguments: IN pDeviceName -- Unicode string Ptr for Device whose address is changing IN PnPEvent -- Event notification IN Context1 -- IN Context2 -- Return Value: NTSTATUS - Final status of the set event operation --*/ { PAGED_CODE(); switch (pPnPEvent->NetEvent) { case (NetEventQueryPower): { PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "TdiPnPPowerHandler", "[QueryPower]: Device=<%wZ>\n", pDeviceName); break; } case (NetEventSetPower): { PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "TdiPnPPowerHandler", "[SetPower]: Device=<%wZ>\n", pDeviceName); break; } case (NetEventQueryRemoveDevice): { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiPnPPowerHandler", "[QueryRemoveDevice]: Device=<%wZ>\n", pDeviceName); break; } case (NetEventCancelRemoveDevice): { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiPnPPowerHandler", "[CancelRemoveDevice]: Device=<%wZ>\n", pDeviceName); break; } case (NetEventReconfigure): { PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "TdiPnPPowerHandler", "[Reconfigure]: Device=<%wZ>\n", pDeviceName); break; } case (NetEventBindList): { PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "TdiPnPPowerHandler", "[BindList]: Device=<%wZ>\n", pDeviceName); break; } case (NetEventPnPCapabilities): { PgmLog (PGM_LOG_INFORM_PATH, DBG_PNP, "TdiPnPPowerHandler", "[PnPCapabilities]: Device=<%wZ>\n", pDeviceName); break; } default: { PgmLog (PGM_LOG_INFORM_STATUS, DBG_PNP, "TdiPnPPowerHandler", "[?=%d]: Device=<%wZ>\n", (ULONG) pPnPEvent->NetEvent, pDeviceName); break; } } return (STATUS_SUCCESS); } //---------------------------------------------------------------------------- NTSTATUS SetTdiHandlers( ) /*++ Routine Description: This routine is called at DriverEntry to register our handlers with TDI Arguments: IN Return Value: NTSTATUS - Final status of the set event operation --*/ { NTSTATUS status; UNICODE_STRING ucPgmClientName; TDI_CLIENT_INTERFACE_INFO TdiClientInterface; PAGED_CODE(); // // Register our Handlers with TDI // RtlInitUnicodeString (&ucPgmClientName, WC_PGM_CLIENT_NAME); ucPgmClientName.MaximumLength = sizeof (WC_PGM_CLIENT_NAME); PgmZeroMemory (&TdiClientInterface, sizeof(TdiClientInterface)); TdiClientInterface.MajorTdiVersion = TDI_CURRENT_MAJOR_VERSION; TdiClientInterface.MinorTdiVersion = TDI_CURRENT_MINOR_VERSION; TdiClientInterface.ClientName = &ucPgmClientName; TdiClientInterface.AddAddressHandlerV2 = TdiAddressArrival; TdiClientInterface.DelAddressHandlerV2 = TdiAddressDeletion; TdiClientInterface.BindingHandler = TdiBindHandler; TdiClientInterface.PnPPowerHandler = TdiPnPPowerHandler; status = TdiRegisterPnPHandlers (&TdiClientInterface, sizeof(TdiClientInterface), &TdiClientHandle); if (!NT_SUCCESS (status)) { PgmLog (PGM_LOG_ERROR, DBG_PNP, "SetTdiHandlers", "TdiRegisterPnPHandlers ==> <%x>\n", status); return (status); } TdiEnumerateAddresses(TdiClientHandle); PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_PNP, "SetTdiHandlers", "\tSUCCEEDed\n"); return (status); }