diff --git a/reactos/drivers/net/tcpip/datalink/lan.c b/reactos/drivers/net/tcpip/datalink/lan.c index 08169ead95a..fd4aec48218 100644 --- a/reactos/drivers/net/tcpip/datalink/lan.c +++ b/reactos/drivers/net/tcpip/datalink/lan.c @@ -15,7 +15,6 @@ #include #include - NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL; BOOLEAN ProtocolRegistered = FALSE; LIST_ENTRY AdapterListHead; @@ -590,6 +589,72 @@ VOID LANTransmit( } } +static NTSTATUS +OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) { + OBJECT_ATTRIBUTES Attributes; + NTSTATUS Status; + + InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0); + Status = ZwOpenKey(RegHandle, GENERIC_READ, &Attributes); + return Status; +} + +static NTSTATUS ReadIPAddressFromRegistry( HANDLE RegHandle, + PWCHAR RegistryValue, + PIP_ADDRESS *Address ) { + UNICODE_STRING ValueName; + UNICODE_STRING UnicodeAddress; + NTSTATUS Status; + ULONG ResultLength; + UCHAR buf[1024]; + PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf; + ANSI_STRING AnsiAddress; + ULONG AnsiLen; + + RtlInitUnicodeString(&ValueName, RegistryValue); + Status = + ZwQueryValueKey(RegHandle, + &ValueName, + KeyValuePartialInformation, + Information, + sizeof(buf), + &ResultLength); + + if (!NT_SUCCESS(Status)) + return Status; + /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */ + TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength)); + + UnicodeAddress.Buffer = (PWCHAR)&Information->Data; + UnicodeAddress.Length = Information->DataLength; + UnicodeAddress.MaximumLength = Information->DataLength; + + AnsiLen = RtlUnicodeStringToAnsiSize(&UnicodeAddress); + if(!AnsiLen) + return STATUS_NO_MEMORY; + + AnsiAddress.Buffer = ExAllocatePoolWithTag(PagedPool, AnsiLen, 0x01020304); + if(!AnsiAddress.Buffer) + return STATUS_NO_MEMORY; + + AnsiAddress.Length = AnsiLen; + AnsiAddress.MaximumLength = AnsiLen; + + Status = RtlUnicodeStringToAnsiString(&AnsiAddress, &UnicodeAddress, FALSE); + if (!NT_SUCCESS(Status)) { + ExFreePool(AnsiAddress.Buffer); + return STATUS_UNSUCCESSFUL; + } + + AnsiAddress.Buffer[AnsiAddress.Length] = 0; + *Address = AddrBuildIPv4(inet_addr(AnsiAddress.Buffer)); + if (!Address) { + ExFreePool(AnsiAddress.Buffer); + return STATUS_UNSUCCESSFUL; + } + + return *Address ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; +} VOID BindAdapter( PLAN_ADAPTER Adapter, @@ -605,11 +670,14 @@ VOID BindAdapter( { INT i; PIP_INTERFACE IF; - PIP_ADDRESS Address; + PIP_ADDRESS Address = 0; + PIP_ADDRESS Netmask = 0; PNDIS_PACKET Packet; NDIS_STATUS NdisStatus; LLIP_BIND_INFO BindInfo; ULONG Lookahead = LOOKAHEAD_SIZE; + NTSTATUS Status; + HANDLE RegHandle = 0; TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); @@ -655,100 +723,59 @@ VOID BindAdapter( return; } - { - /* - * Query per-adapter configuration from the registry - * In case anyone is curious: there *is* an Ndis configuration api - * for this sort of thing, but it doesn't really support things like - * REG_MULTI_SZ very well, and there is a note in the DDK that says that - * protocol drivers developed for win2k and above just use the native - * services (ZwOpenKey, etc). - */ - - OBJECT_ATTRIBUTES Attributes; - HANDLE RegHandle; - NTSTATUS Status; - UNICODE_STRING ValueName; - UCHAR buf[1024]; - PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf; - ULONG ResultLength; - ANSI_STRING AnsiAddress; - UNICODE_STRING UnicodeAddress; - ULONG AnsiLen; - - InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0); - Status = ZwOpenKey(&RegHandle, GENERIC_READ, &Attributes); - - if(!NT_SUCCESS(Status)) - { - TI_DbgPrint(MIN_TRACE, ("Unable to open protocol-specific registry key: 0x%x\n", Status)); - - /* XXX how do we proceed? No ip address, no parameters... do we guess? */ - FreeTDPackets(Adapter); - IPDestroyInterface(Adapter->Context); - return; - } - - RtlInitUnicodeString(&ValueName, L"IPAddress"); - ZwQueryValueKey(RegHandle, &ValueName, KeyValuePartialInformation, Information, sizeof(buf), &ResultLength); - ZwClose(RegHandle); - - /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */ - TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength)); - - UnicodeAddress.Buffer = (PWCHAR)&Information->Data; - UnicodeAddress.Length = Information->DataLength; - UnicodeAddress.MaximumLength = Information->DataLength; - - AnsiLen = RtlUnicodeStringToAnsiSize(&UnicodeAddress); - if(!AnsiLen) - { - TI_DbgPrint(MIN_TRACE, ("Unable to calculate address length\n")); - FreeTDPackets(Adapter); - IPDestroyInterface(Adapter->Context); - return; - } - - AnsiAddress.Buffer = ExAllocatePoolWithTag(PagedPool, AnsiLen, 0x01020304); - if(!AnsiAddress.Buffer) - { - TI_DbgPrint(MIN_TRACE, ("ExAllocatePoolWithTag() failed.\n")); - FreeTDPackets(Adapter); - IPDestroyInterface(Adapter->Context); - return; - } - AnsiAddress.Length = AnsiLen; - AnsiAddress.MaximumLength = AnsiLen; - - Status = RtlUnicodeStringToAnsiString(&AnsiAddress, &UnicodeAddress, FALSE); - if (!NT_SUCCESS(Status)) - { - TI_DbgPrint(MIN_TRACE, ("RtlUnicodeStringToAnsiString() failed with Status 0x%lx.\n", Status)); - FreeTDPackets(Adapter); - IPDestroyInterface(Adapter->Context); - return; - } - - AnsiAddress.Buffer[AnsiAddress.Length] = 0; - Address = AddrBuildIPv4(inet_addr(AnsiAddress.Buffer)); - if (!Address) { - TI_DbgPrint(MIN_TRACE, ("AddrBuildIPv4() failed.\n")); - FreeTDPackets(Adapter); - IPDestroyInterface(Adapter->Context); - return; - } - - TI_DbgPrint(MID_TRACE, ("--> Our IP address on this interface: '%s'\n", A2S(Address))); - } + /* + * Query per-adapter configuration from the registry + * In case anyone is curious: there *is* an Ndis configuration api + * for this sort of thing, but it doesn't really support things like + * REG_MULTI_SZ very well, and there is a note in the DDK that says that + * protocol drivers developed for win2k and above just use the native + * services (ZwOpenKey, etc). + */ + + Status = OpenRegistryKey( RegistryPath, &RegHandle ); + + if(NT_SUCCESS(Status)) + Status = ReadIPAddressFromRegistry( RegHandle, L"IPAddress", + &Address ); + if(NT_SUCCESS(Status)) + Status = ReadIPAddressFromRegistry( RegHandle, L"SubnetMask", + &Netmask ); + + if(!NT_SUCCESS(Status) || !Address || !Netmask) + { + TI_DbgPrint(MIN_TRACE, ("Unable to open protocol-specific registry key: 0x%x\n", Status)); + + /* XXX how do we proceed? No ip address, no parameters... do we guess? */ + if(RegHandle) + ZwClose(RegHandle); + if(Address) Address->Free(Address); + if(Netmask) Netmask->Free(Netmask); + FreeTDPackets(Adapter); + IPDestroyInterface(IF); + return; + } + + TI_DbgPrint + (MID_TRACE, + ("--> Our IP address on this interface: '%s'\n", + A2S(Address))); + + TI_DbgPrint + (MID_TRACE, + ("--> Our net mask on this interface: '%s'\n", + A2S(Netmask))); /* Create a net table entry for this interface */ - if (!IPCreateNTE(IF, Address, 8)) { + if (!IPCreateNTE(IF, Address, AddrCountPrefixBits(Netmask))) { + Netmask->Free(Netmask); TI_DbgPrint(MIN_TRACE, ("IPCreateNTE() failed.\n")); FreeTDPackets(Adapter); IPDestroyInterface(IF); return; } + Netmask->Free(Netmask); + /* Reference the interface for the NTE. The reference for the address is just passed on to the NTE */ ReferenceObject(IF); diff --git a/reactos/drivers/net/tcpip/include/address.h b/reactos/drivers/net/tcpip/include/address.h index c93b6772115..450f96889c2 100644 --- a/reactos/drivers/net/tcpip/include/address.h +++ b/reactos/drivers/net/tcpip/include/address.h @@ -78,6 +78,10 @@ PADDRESS_FILE AddrSearchNext( unsigned long PASCAL inet_addr(const char*); +ULONG IPv4NToHl( ULONG Address ); + +UINT AddrCountPrefixBits( PIP_ADDRESS Netmask ); + #endif /* __ADDRESS_H */ /* EOF */ diff --git a/reactos/drivers/net/tcpip/include/info.h b/reactos/drivers/net/tcpip/include/info.h index 2e9631bea3e..2ead71a6e88 100644 --- a/reactos/drivers/net/tcpip/include/info.h +++ b/reactos/drivers/net/tcpip/include/info.h @@ -7,6 +7,8 @@ #ifndef __INFO_H #define __INFO_H +#define MAX_PHYSADDR_LEN 8 +#define MAX_IFDESCR_LEN 256 typedef struct IPSNMP_INFO { ULONG Forwarding; @@ -60,7 +62,31 @@ typedef struct IPROUTE_ENTRY { ULONG Info; } IPROUTE_ENTRY, *PIPROUTE_ENTRY; +typedef struct IFENTRY { + ULONG Index; + ULONG Type; + ULONG Mtu; + ULONG Speed; + ULONG PhysAddrLen; + UCHAR PhysAddr[MAX_PHYSADDR_LEN]; + ULONG AdminStatus; + ULONG OperStatus; + ULONG LastChange; + ULONG InOctets; + ULONG InUcastPackets; + ULONG InDiscards; + ULONG InErrors; + ULONG InUnknownProtos; + ULONG OutOctets; + ULONG OutUcastPackets; + ULONG OutDiscards; + ULONG OutErrors; + ULONG OutQLen; + ULONG DescrLen; +} IFENTRY, *PIFENTRY; + #define IP_MIB_STATS_ID 1 +#define IF_MIB_STATS_ID 1 #ifndef IP_MIB_ADDRTABLE_ENTRY_ID #define IP_MIB_ADDRTABLE_ENTRY_ID 0x102 #endif diff --git a/reactos/drivers/net/tcpip/include/ip.h b/reactos/drivers/net/tcpip/include/ip.h index 81670ac507a..6c2b7190861 100644 --- a/reactos/drivers/net/tcpip/include/ip.h +++ b/reactos/drivers/net/tcpip/include/ip.h @@ -264,6 +264,8 @@ NTSTATUS IPStartup( NTSTATUS IPShutdown( VOID); + + #endif /* __IP_H */ /* EOF */ diff --git a/reactos/drivers/net/tcpip/include/tcpip.h b/reactos/drivers/net/tcpip/include/tcpip.h index 69efcd6215a..67a0d16c2e8 100644 --- a/reactos/drivers/net/tcpip/include/tcpip.h +++ b/reactos/drivers/net/tcpip/include/tcpip.h @@ -125,6 +125,7 @@ extern NDIS_HANDLE GlobalBufferPool; extern KSPIN_LOCK EntityListLock; extern TDIEntityID *EntityList; extern ULONG EntityCount; +extern ULONG EntityMax; extern UDP_STATISTICS UDPStats; #endif /* __TCPIP_H */ diff --git a/reactos/drivers/net/tcpip/tcpip/address.c b/reactos/drivers/net/tcpip/tcpip/address.c index 252f6ddd387..5828c36d4da 100644 --- a/reactos/drivers/net/tcpip/tcpip/address.c +++ b/reactos/drivers/net/tcpip/tcpip/address.c @@ -54,6 +54,35 @@ PCHAR A2S( #endif /* DBG */ +ULONG IPv4NToHl( ULONG Address ) { + return + ((Address & 0xff) << 24) | + ((Address & 0xff00) << 8) | + ((Address >> 8) & 0xff00) | + ((Address >> 24) & 0xff); +} + +UINT AddrCountPrefixBits( PIP_ADDRESS Netmask ) { + UINT Prefix = 0; + if( Netmask->Type == IP_ADDRESS_V4 ) { + ULONG BitTest = 0x80000000; + + /* The mask has been read in network order. Put it in host order + * in order to scan it. */ + + ULONG TestMask = IPv4NToHl(Netmask->Address.IPv4Address); + + while( (BitTest & TestMask) == BitTest ) { + Prefix++; + BitTest >>= 1; + } + return Prefix; + } else { + TI_DbgPrint(DEBUG_DATALINK, ("Don't know address type %d\n", + Netmask->Type)); + return 0; + } +} VOID IPAddressFree( PVOID Object) diff --git a/reactos/drivers/net/tcpip/tcpip/info.c b/reactos/drivers/net/tcpip/tcpip/info.c index 04e91815d45..2331821ba4d 100644 --- a/reactos/drivers/net/tcpip/tcpip/info.c +++ b/reactos/drivers/net/tcpip/tcpip/info.c @@ -201,6 +201,127 @@ TDI_STATUS IPTdiQueryInformationEx( return TDI_INVALID_PARAMETER; } +TDI_STATUS InfoTdiQueryListEntities(PNDIS_BUFFER Buffer, + UINT BufSize, + PUINT BufferSize) +{ + UINT Count, Size, Temp; + KIRQL OldIrql; + PLIST_ENTRY CurrentIFEntry; + + /* Count Adapters */ + KeAcquireSpinLock(&InterfaceListLock, &OldIrql); + + CurrentIFEntry = InterfaceListHead.Flink; + Count = EntityCount; + + while( CurrentIFEntry != &InterfaceListHead ) { + Count++; + CurrentIFEntry = CurrentIFEntry->Flink; + } + + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + + Size = Count * sizeof(TDIEntityID); + *BufferSize = Size; + + if (BufSize < Size) + { + /* The buffer is too small to contain requested data */ + return TDI_BUFFER_TOO_SMALL; + } + + DbgPrint("About to copy %d TDIEntityIDs (%d bytes) to user\n", + Count, Size); + + KeAcquireSpinLock(&EntityListLock, &OldIrql); + + /* Update entity list */ + for( Temp = EntityCount; Temp < Count; Temp++ ) { + EntityList[Temp].tei_entity = IF_ENTITY; + EntityList[Temp].tei_instance = Temp - EntityCount; + } + EntityMax = Count; + + /* Return entity list */ + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)EntityList, Size); + + KeReleaseSpinLock(&EntityListLock, OldIrql); + + *BufferSize = Size; + + return TDI_SUCCESS; +} + +TDI_STATUS InfoTdiQueryGetInterfaceMIB(TDIObjectID *ID, + PNDIS_BUFFER Buffer, + UINT BufSize, + PUINT BufferSize) { + PIFENTRY OutData; + UINT ListedIfIndex, Count, Size; + PLIST_ENTRY CurrentADEEntry; + PADDRESS_ENTRY CurrentADE; + PLIST_ENTRY CurrentIFEntry; + PIP_INTERFACE CurrentIF; + PCHAR IFDescr; + KIRQL OldIrql; + + OutData = ExAllocatePool( NonPagedPool, + sizeof(IFENTRY) + MAX_IFDESCR_LEN ); + + if( !OutData ) return STATUS_NO_MEMORY; + + RtlZeroMemory( OutData,sizeof(IFENTRY) + MAX_IFDESCR_LEN ); + + KeAcquireSpinLock(&EntityListLock, &OldIrql); + ListedIfIndex = ID->toi_entity.tei_instance - EntityCount; + if( ListedIfIndex > EntityMax ) { + KeReleaseSpinLock(&EntityListLock,OldIrql); + return TDI_INVALID_REQUEST; + } + + CurrentIFEntry = InterfaceListHead.Flink; + + for( Count = 0; Count < ListedIfIndex; Count++ ) + CurrentIFEntry = CurrentIFEntry->Flink; + + CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); + + CurrentADEEntry = CurrentIF->ADEListHead.Flink; + if( CurrentADEEntry == &CurrentIF->ADEListHead ) { + KeReleaseSpinLock( &EntityListLock, OldIrql ); + return TDI_INVALID_REQUEST; + } + + CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); + + OutData->Index = Count + 1; /* XXX - arty What goes here?? */ + OutData->Type = CurrentADE->Type; + OutData->Mtu = CurrentIF->MTU; + OutData->Speed = 10000000; /* XXX - arty Not sure */ + memcpy(OutData->PhysAddr, + CurrentIF->Address,CurrentIF->AddressLength); + OutData->PhysAddrLen = CurrentIF->AddressLength; + OutData->AdminStatus = TRUE; + OutData->OperStatus = TRUE; + IFDescr = (PCHAR)&OutData[1]; + strcpy(IFDescr,"ethernet adapter"); + OutData->DescrLen = strlen(IFDescr); + IFDescr = IFDescr + strlen(IFDescr); + Size = IFDescr - (PCHAR)OutData; + + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + + *BufferSize = Size; + + if( BufSize < Size ) { + return TDI_BUFFER_TOO_SMALL; + } else { + CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&OutData, Size); + return TDI_SUCCESS; + } +} + TDI_STATUS InfoTdiQueryInformationEx( PTDI_REQUEST Request, TDIObjectID *ID, @@ -250,47 +371,18 @@ TDI_STATUS InfoTdiQueryInformationEx( return TDI_INVALID_PARAMETER; } - /* Count Adapters */ - KeAcquireSpinLock(&InterfaceListLock, &OldIrql); + return InfoTdiQueryListEntities(Buffer, BufSize, BufferSize); + } - CurrentIFEntry = InterfaceListHead.Flink; - Count = EntityCount; + /* Get an IFENTRY */ + if (ID->toi_class == INFO_CLASS_PROTOCOL && + ID->toi_type == INFO_TYPE_PROVIDER && + ID->toi_id == IF_MIB_STATS_ID) + { + if(ID->toi_entity.tei_entity != IF_ENTITY) + return TDI_INVALID_REQUEST; - while( CurrentIFEntry != &InterfaceListHead ) { - Count++; - CurrentIFEntry = CurrentIFEntry->Flink; - } - - KeReleaseSpinLock(&InterfaceListLock, OldIrql); - - Size = Count * sizeof(TDIEntityID); - *BufferSize = Size; - - if (BufSize < Size) - { - /* The buffer is too small to contain requested data */ - return TDI_BUFFER_TOO_SMALL; - } - - DbgPrint("About to copy %d TDIEntityIDs (%d bytes) to user\n", - Count, Size); - - KeAcquireSpinLock(&EntityListLock, &OldIrql); - - /* Update entity list */ - for( Temp = EntityCount; Temp < Count; Temp++ ) { - EntityList[Temp].tei_entity = IF_ENTITY; - EntityList[Temp].tei_instance = Temp - EntityCount; - } - - /* Return entity list */ - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)EntityList, Size); - - KeReleaseSpinLock(&EntityListLock, OldIrql); - - *BufferSize = Size; - - return TDI_SUCCESS; + return InfoTdiQueryGetInterfaceMIB(ID, Buffer, BufSize, BufferSize); } if ((Entity != CL_TL_ENTITY) && (Entity != CO_TL_ENTITY))