⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ifenum_reactos.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (C) 2003 Art Yerkes
 * A reimplementation of ifenum.c by Juan Lang
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Implementation notes
 * - Our bretheren use IOCTL_TCP_QUERY_INFORMATION_EX to get information
 *   from tcpip.sys and IOCTL_TCP_SET_INFORMATION_EX to set info (such as
 *   the route table).  These ioctls mirror WsControl exactly in usage.
 * - This iphlpapi does not rely on any reactos-only features.
 * - This implementation is meant to be largely correct.  I am not, however,
 *   paying any attention to performance.  It can be done faster, and
 *   someone should definately optimize this code when speed is more of a 
 *   priority than it is now.
 * 
 * Edited implementation notes from the original -- Basically edited to add
 *   information and prune things which are not accurate about this file.
 * Interface index fun:
 * - Windows may rely on an index being cleared in the topmost 8 bits in some
 *   APIs; see GetFriendlyIfIndex and the mention of "backward compatible"
 *   indexes.  It isn't clear which APIs might fail with non-backward-compatible
 *   indexes, but I'll keep them bits clear just in case.
 * FIXME:
 * - We don't support IPv6 addresses here yet -- I moved the upper edge
 *   functions into iphlpv6.c (arty)
 */
#include "iphlpapi_private.h"
#include "ifenum.h"
#include <assert.h>

//#define NDEBUG
#include "debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);

/* Globals */
const PWCHAR TcpFileName = L"\\Device\\Tcp";

/* Functions */

/* I'm a bit skittish about maintaining this info in memory, as I'd rather
 * not add any mutex or critical section blockers to these functions.  I've
 * encountered far too many windows functions that contribute to deadlock
 * by not announcing themselves. */
void interfaceMapInit(void)
{
    /* For now, nothing */
}

void interfaceMapFree(void)
{
    /* Ditto. */
}

NTSTATUS openTcpFile(PHANDLE tcpFile) {
    UNICODE_STRING fileName;
    OBJECT_ATTRIBUTES objectAttributes;
    IO_STATUS_BLOCK ioStatusBlock;
    NTSTATUS status;

    TRACE("called.\n");

    /* Shamelessly ripped from CreateFileW */
    RtlInitUnicodeString( &fileName, TcpFileName );

    InitializeObjectAttributes( &objectAttributes,
                                &fileName,
                                OBJ_CASE_INSENSITIVE,
                                NULL,
                                NULL );

    status = ZwCreateFile( tcpFile,
                           SYNCHRONIZE | GENERIC_EXECUTE | 
                           GENERIC_READ | GENERIC_WRITE,
                           &objectAttributes,
                           &ioStatusBlock,
                           NULL,
                           FILE_ATTRIBUTE_NORMAL,
                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                           FILE_OPEN_IF,
                           FILE_SYNCHRONOUS_IO_NONALERT,
                           0,
                           0 );

    /* String does not need to be freed: it points to the constant
     * string we provided */

    if (!NT_SUCCESS(status)) {
        ERR("openTcpFile for <%wZ> failed: 0x%lx\n", &fileName, status);
    }

    return status;
}

void closeTcpFile( HANDLE h ) {
    TRACE("called.\n");
    NtClose( h );
}

/* A generic thing-getting function which interacts in the right way with
 * TDI.  This may seem oblique, but I'm using it to reduce code and hopefully
 * make this thing easier to debug.
 *
 * The things returned can be any of:
 *   TDIEntityID
 *   TDIObjectID
 *   IFEntry
 *   IPSNMPInfo
 *   IPAddrEntry
 *   IPInterfaceInfo
 */
NTSTATUS tdiGetSetOfThings( HANDLE tcpFile, 
                            DWORD toiClass,
                            DWORD toiType,
                            DWORD toiId,
                            DWORD teiEntity,
			    DWORD teiInstance,
                            DWORD fixedPart,
                            DWORD entrySize,
                            PVOID *tdiEntitySet,
                            PDWORD numEntries ) {
    TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
    PVOID entitySet = 0;
    NTSTATUS status = STATUS_SUCCESS;
    DWORD allocationSizeForEntityArray = entrySize * MAX_TDI_ENTITIES, 
        arraySize = entrySize * MAX_TDI_ENTITIES;

    TRACE("TdiGetSetOfThings(tcpFile %x,toiClass %x,toiType %x,toiId %x,"
          "teiEntity %x,fixedPart %d,entrySize %d)\n",
          (int)tcpFile, 
          (int)toiClass, 
          (int)toiType, 
          (int)toiId, 
          (int)teiEntity,
          (int)fixedPart, 
          (int)entrySize );

    req.ID.toi_class                = toiClass;
    req.ID.toi_type                 = toiType;
    req.ID.toi_id                   = toiId;
    req.ID.toi_entity.tei_entity    = teiEntity;
    req.ID.toi_entity.tei_instance  = teiInstance;

    /* There's a subtle problem here...
     * If an interface is added at this exact instant, (as if by a PCMCIA
     * card insertion), the array will still not have enough entries after
     * have allocated it after the first DeviceIoControl call.
     *
     * We'll get around this by repeating until the number of interfaces
     * stabilizes.
     */
    do {
        assert( !entitySet ); /* We must not have an entity set allocated */
        status = DeviceIoControl( tcpFile,
                                  IOCTL_TCP_QUERY_INFORMATION_EX,
                                  &req,
                                  sizeof(req),
                                  0,
                                  0,
                                  &allocationSizeForEntityArray,
                                  NULL );

        if(!NT_SUCCESS(status))
        {
            ERR("IOCTL Failed\n");
            return STATUS_UNSUCCESSFUL;
        }
        
        arraySize = allocationSizeForEntityArray;
        entitySet = HeapAlloc( GetProcessHeap(), 0, arraySize );
                                              
        if( !entitySet ) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            WARN("TdiGetSetOfThings() => %08x\n", (int)status);
            return status;
        }

        status = DeviceIoControl( tcpFile,
                                  IOCTL_TCP_QUERY_INFORMATION_EX,
                                  &req,
                                  sizeof(req),
                                  entitySet,
                                  arraySize,
                                  &allocationSizeForEntityArray,
                                  NULL );
        
        /* This is why we have the loop -- we might have added an adapter */
        if( arraySize == allocationSizeForEntityArray )
            break;

        HeapFree( GetProcessHeap(), 0, entitySet );
        entitySet = 0;

        if(!status)
        {
            WARN("IOCTL Failed\n");
            return STATUS_UNSUCCESSFUL;
        }

        WARN("TdiGetSetOfThings(): Array changed size: %d -> %d.\n",
               arraySize, allocationSizeForEntityArray );
    } while( TRUE ); /* We break if the array we received was the size we 
                      * expected.  Therefore, we got here because it wasn't */
    
    *numEntries = (arraySize - fixedPart) / entrySize;
    *tdiEntitySet = entitySet;

    WARN("TdiGetSetOfThings() => Success: %d things @ %08x\n", 
           (int)*numEntries, (int)entitySet);

    return STATUS_SUCCESS;
}

VOID tdiFreeThingSet( PVOID things ) {
    HeapFree( GetProcessHeap(), 0, things );
}

NTSTATUS tdiGetMibForIfEntity
( HANDLE tcpFile, TDIEntityID *ent, IFEntrySafelySized *entry ) {
    TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
    NTSTATUS status = STATUS_SUCCESS;
    DWORD returnSize;

    WARN("TdiGetMibForIfEntity(tcpFile %x,entityId %x)\n",
           (int)tcpFile, (int)ent->tei_instance);

    req.ID.toi_class                = INFO_CLASS_PROTOCOL;
    req.ID.toi_type                 = INFO_TYPE_PROVIDER;
    req.ID.toi_id                   = IF_MIB_STATS_ID;
    req.ID.toi_entity               = *ent;

    status = DeviceIoControl( tcpFile,
                              IOCTL_TCP_QUERY_INFORMATION_EX,
                              &req,
                              sizeof(req),
                              entry,
                              sizeof(*entry),
                              &returnSize,
                              NULL );

    if(!status)
    {
            WARN("IOCTL Failed\n");
            return STATUS_UNSUCCESSFUL;
    }

    TRACE("TdiGetMibForIfEntity() => {\n"
           "  if_index ....................... %x\n"
           "  if_type ........................ %x\n"
           "  if_mtu ......................... %d\n"
           "  if_speed ....................... %x\n"
           "  if_physaddrlen ................. %d\n",
           entry->ent.if_index,
           entry->ent.if_type,
           entry->ent.if_mtu,
           entry->ent.if_speed,
           entry->ent.if_physaddrlen);
    TRACE("  if_physaddr .................... %02x:%02x:%02x:%02x:%02x:%02x\n"
           "  if_descr ....................... %s\n",
           entry->ent.if_physaddr[0] & 0xff,
           entry->ent.if_physaddr[1] & 0xff,
           entry->ent.if_physaddr[2] & 0xff,
           entry->ent.if_physaddr[3] & 0xff,
           entry->ent.if_physaddr[4] & 0xff,
           entry->ent.if_physaddr[5] & 0xff,
           entry->ent.if_descr);
    TRACE("} status %08x\n",status);
        
    return status;    
}

NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile,
                            TDIEntityID **entitySet, 
                            PDWORD numEntities ) {
    NTSTATUS status = tdiGetSetOfThings( tcpFile,
                                         INFO_CLASS_GENERIC,
                                         INFO_TYPE_PROVIDER,
                                         ENTITY_LIST_ID,
                                         GENERIC_ENTITY,
					 0,
                                         0,
                                         sizeof(TDIEntityID),
                                         (PVOID *)entitySet,
                                         numEntities );
    if( NT_SUCCESS(status) ) {
        int i;

        for( i = 0; i < *numEntities; i++ ) {
            TRACE("%-4d: %04x:%08x\n",
                   i,
                   (*entitySet)[i].tei_entity, 
                   (*entitySet)[i].tei_instance );
        }
    }
    
    return status;
}

BOOL isInterface( TDIEntityID *if_maybe ) {
    return 
        if_maybe->tei_entity == IF_ENTITY;
}

static BOOL isLoopback( HANDLE tcpFile, TDIEntityID *loop_maybe ) {
    IFEntrySafelySized entryInfo;
    NTSTATUS status;

    status = tdiGetMibForIfEntity( tcpFile, 
                                   loop_maybe,
                                   &entryInfo );

    return NT_SUCCESS(status) && (!entryInfo.ent.if_type || 
        entryInfo.ent.if_type == IFENT_SOFTWARE_LOOPBACK);
}

NTSTATUS tdiGetEntityType( HANDLE tcpFile, TDIEntityID *ent, PULONG type ) {
    TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
    NTSTATUS status = STATUS_SUCCESS;
    DWORD returnSize;

    TRACE("TdiGetEntityType(tcpFile %x,entityId %x)\n",
           (DWORD)tcpFile, ent->tei_instance);

    req.ID.toi_class                = INFO_CLASS_GENERIC;
    req.ID.toi_type                 = INFO_TYPE_PROVIDER;
    req.ID.toi_id                   = ENTITY_TYPE_ID;
    req.ID.toi_entity.tei_entity    = ent->tei_entity;
    req.ID.toi_entity.tei_instance  = ent->tei_instance;

    status = DeviceIoControl( tcpFile,
                              IOCTL_TCP_QUERY_INFORMATION_EX,
                              &req,
                              sizeof(req),
                              type,
                              sizeof(*type),
                              &returnSize,
                              NULL );

    TRACE("TdiGetEntityType() => %08x %08x\n", *type, status);

    return (status ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}

BOOL hasArp( HANDLE tcpFile, TDIEntityID *arp_maybe ) {
    TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
    NTSTATUS status = STATUS_SUCCESS;
    DWORD returnSize, type;

    req.ID.toi_class                = INFO_CLASS_GENERIC;
    req.ID.toi_type                 = INFO_TYPE_PROVIDER;
    req.ID.toi_id                   = ENTITY_TYPE_ID;
    req.ID.toi_entity.tei_entity    = AT_ENTITY;
    req.ID.toi_entity.tei_instance  = arp_maybe->tei_instance;

    status = DeviceIoControl( tcpFile,
                              IOCTL_TCP_QUERY_INFORMATION_EX,
                              &req,
                              sizeof(req),
                              &type,
                              sizeof(type),
                              &returnSize,
                              NULL );

    if( !NT_SUCCESS(status) ) return FALSE;
    return type == AT_ENTITY;
}

static NTSTATUS getInterfaceInfoSet( HANDLE tcpFile, 
                                     IFInfo **infoSet,
                                     PDWORD numInterfaces ) {
    DWORD numEntities;
    TDIEntityID *entIDSet = 0;
    NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entIDSet, &numEntities );
    IFInfo *infoSetInt = 0;
    BOOL interfaceInfoComplete;
    int curInterf = 0, i;

    if (!NT_SUCCESS(status)) {
        ERR("getInterfaceInfoSet: tdiGetEntityIDSet() failed: 0x%lx\n", status);
        return status;
    }

    infoSetInt = HeapAlloc( GetProcessHeap(), 0, 
                            sizeof(IFInfo) * numEntities );
    
    if( infoSetInt ) {
        for( i = 0; i < numEntities; i++ ) {
            if( isInterface( &entIDSet[i] ) ) {
                infoSetInt[curInterf].entity_id = entIDSet[i];
                status = tdiGetMibForIfEntity
                    ( tcpFile,
                      &entIDSet[i],
                      &infoSetInt[curInterf].if_info );
                TRACE("tdiGetMibForIfEntity: %08x\n", status);
                if( NT_SUCCESS(status) ) {
                    DWORD numAddrs;
                    IPAddrEntry *addrs;
                    TDIEntityID ip_ent;
                    int j;

                    interfaceInfoComplete = FALSE;
		    status = getNthIpEntity( tcpFile, 0, &ip_ent );
		    if( NT_SUCCESS(status) )
			status = tdiGetIpAddrsForIpEntity
			    ( tcpFile, &ip_ent, &addrs, &numAddrs );
		    for( j = 0; j < numAddrs && NT_SUCCESS(status); j++ ) {
			TRACE("ADDR %d: index %d (target %d)\n", j, addrs[j].iae_index, infoSetInt[curInterf].if_info.ent.if_index);
			if( addrs[j].iae_index == 
			    infoSetInt[curInterf].if_info.ent.if_index ) {
			    memcpy( &infoSetInt[curInterf].ip_addr,
				    &addrs[j],
				    sizeof( addrs[j] ) );
			    curInterf++;
			    break;
			}
		    }
                }
            }
        }

        if (NT_SUCCESS(status)) {
            *infoSet = infoSetInt;
            *numInterfaces = curInterf;
        } else {
            HeapFree(GetProcessHeap(), 0, infoSetInt);
        }

        return status;
    } else {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
}

static DWORD getNumInterfacesInt(BOOL onlyNonLoopback)
{
    DWORD numEntities, numInterfaces = 0;
    TDIEntityID *entitySet;
    HANDLE tcpFile;
    NTSTATUS status;
    int i;

    status = openTcpFile( &tcpFile );

    if( !NT_SUCCESS(status) ) {
        WARN("getNumInterfaces: failed %08x\n", status );
        return 0;
    }

    status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );

    if( !NT_SUCCESS(status) ) {
        WARN("getNumInterfaces: failed %08x\n", status );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -