reactos/sdk/lib/drivers/ip/network/interface.c

266 lines
6.7 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: tcpip/interface.c
* PURPOSE: Convenient abstraction for getting and setting information
* in IP_INTERFACE.
* PROGRAMMERS: Art Yerkes
* REVISIONS:
* CSH 01/08-2000 Created
*/
#include "precomp.h"
#include <ntifs.h>
#include <ipifcons.h>
ULONG NextDefaultAdapter = 0;
NTSTATUS GetInterfaceIPv4Address( PIP_INTERFACE Interface,
ULONG TargetType,
PULONG Address ) {
switch( TargetType ) {
case ADE_UNICAST:
*Address = Interface->Unicast.Address.IPv4Address;
break;
case ADE_ADDRMASK:
*Address = Interface->Netmask.Address.IPv4Address;
break;
case ADE_BROADCAST:
*Address = Interface->Broadcast.Address.IPv4Address;
break;
case ADE_POINTOPOINT:
*Address = Interface->PointToPoint.Address.IPv4Address;
break;
default:
return STATUS_UNSUCCESSFUL;
}
return STATUS_SUCCESS;
}
UINT CountInterfaces() {
ULONG Count = 0;
KIRQL OldIrql;
IF_LIST_ITER(CurrentIF);
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
ForEachInterface(CurrentIF) {
Count++;
} EndFor(CurrentIF);
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
return Count;
}
NTSTATUS GetInterfaceSpeed( PIP_INTERFACE Interface, PUINT Speed ) {
PLAN_ADAPTER IF = (PLAN_ADAPTER)Interface->Context;
*Speed = IF->Speed;
return STATUS_SUCCESS;
}
NTSTATUS GetInterfaceName( PIP_INTERFACE Interface,
PCHAR NameBuffer,
UINT Len ) {
ULONG ResultSize = 0;
NTSTATUS Status =
RtlUnicodeToMultiByteN( NameBuffer,
Len,
&ResultSize,
Interface->Name.Buffer,
Interface->Name.Length );
if( NT_SUCCESS(Status) )
NameBuffer[ResultSize] = 0;
else
NameBuffer[0] = 0;
return Status;
}
PIP_INTERFACE AddrLocateInterface(
PIP_ADDRESS MatchAddress)
{
KIRQL OldIrql;
PIP_INTERFACE RetIF = NULL;
IF_LIST_ITER(CurrentIF);
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
ForEachInterface(CurrentIF) {
if( AddrIsEqual( &CurrentIF->Unicast, MatchAddress ) ||
AddrIsEqual( &CurrentIF->Broadcast, MatchAddress ) ) {
RetIF = CurrentIF;
break;
}
} EndFor(CurrentIF);
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
return RetIF;
}
BOOLEAN HasPrefix(
PIP_ADDRESS Address,
PIP_ADDRESS Prefix,
UINT Length)
/*
* FUNCTION: Determines wether an address has an given prefix
* ARGUMENTS:
* Address = Pointer to address to use
* Prefix = Pointer to prefix to check for
* Length = Length of prefix
* RETURNS:
* TRUE if the address has the prefix, FALSE if not
* NOTES:
* The two addresses must be of the same type
*/
{
PUCHAR pAddress = (PUCHAR)&Address->Address;
PUCHAR pPrefix = (PUCHAR)&Prefix->Address;
TI_DbgPrint(DEBUG_ROUTER, ("Called. Address (0x%X) Prefix (0x%X) Length (%d).\n", Address, Prefix, Length));
#if 0
TI_DbgPrint(DEBUG_ROUTER, ("Address (%s) Prefix (%s).\n",
A2S(Address), A2S(Prefix)));
#endif
/* Don't report matches for empty prefixes */
if (Length == 0) {
return FALSE;
}
/* Check that initial integral bytes match */
while (Length > 8) {
if (*pAddress++ != *pPrefix++)
return FALSE;
Length -= 8;
}
/* Check any remaining bits */
if ((Length > 0) && ((*pAddress >> (8 - Length)) != (*pPrefix >> (8 - Length))))
return FALSE;
return TRUE;
}
PIP_INTERFACE GetDefaultInterface(VOID)
{
KIRQL OldIrql;
ULONG Index = 0;
ULONG IfStatus;
IF_LIST_ITER(CurrentIF);
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
/* DHCP hack: Always return the adapter without an IP address */
ForEachInterface(CurrentIF) {
if (CurrentIF->Context && AddrIsUnspecified(&CurrentIF->Unicast)) {
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
GetInterfaceConnectionStatus(CurrentIF, &IfStatus);
if (IfStatus == MIB_IF_OPER_STATUS_OPERATIONAL) {
return CurrentIF;
}
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
}
} EndFor(CurrentIF);
/* Try to continue from the next adapter */
ForEachInterface(CurrentIF) {
if (CurrentIF->Context && (Index++ == NextDefaultAdapter)) {
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
GetInterfaceConnectionStatus(CurrentIF, &IfStatus);
if (IfStatus == MIB_IF_OPER_STATUS_OPERATIONAL) {
NextDefaultAdapter++;
return CurrentIF;
}
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
}
} EndFor(CurrentIF);
/* No luck, so we'll choose the first adapter this time */
Index = 0;
ForEachInterface(CurrentIF) {
if (CurrentIF->Context) {
Index++;
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
GetInterfaceConnectionStatus(CurrentIF, &IfStatus);
if (IfStatus == MIB_IF_OPER_STATUS_OPERATIONAL) {
NextDefaultAdapter = Index;
return CurrentIF;
}
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
}
} EndFor(CurrentIF);
/* Even that didn't work, so we'll just go with loopback */
NextDefaultAdapter = 0;
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
/* There are no physical interfaces on the system
* so we must pick the loopback interface */
return Loopback;
}
PIP_INTERFACE FindOnLinkInterface(PIP_ADDRESS Address)
/*
* FUNCTION: Checks all on-link prefixes to find out if an address is on-link
* ARGUMENTS:
* Address = Pointer to address to check
* RETURNS:
* Pointer to interface if address is on-link, NULL if not
*/
{
KIRQL OldIrql;
IF_LIST_ITER(CurrentIF);
TI_DbgPrint(DEBUG_ROUTER, ("Called. Address (0x%X)\n", Address));
TI_DbgPrint(DEBUG_ROUTER, ("Address (%s)\n", A2S(Address)));
if (AddrIsUnspecified(Address))
return GetDefaultInterface();
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
ForEachInterface(CurrentIF) {
if (HasPrefix(Address, &CurrentIF->Unicast,
AddrCountPrefixBits(&CurrentIF->Netmask))) {
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
return CurrentIF;
}
} EndFor(CurrentIF);
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
return NULL;
}
VOID GetInterfaceConnectionStatus(PIP_INTERFACE Interface, PULONG Result)
{
PLAN_ADAPTER Adapter = Interface->Context;
/* Loopback has no adapter context */
if (Adapter == NULL || Adapter->State == LAN_STATE_STARTED) {
*Result = MIB_IF_OPER_STATUS_OPERATIONAL;
}
else {
*Result = MIB_IF_OPER_STATUS_DISCONNECTED;
}
}