다음을 통해 공유


IOCTL_TCP_QUERY_INFORMATION_EX IOCTL(tcpioctl.h)

[이 제어 코드는 이후 버전의 Windows에서 변경되거나 사용할 수 없습니다. 이 제어 코드 대신 인터넷 프로토콜 도우미 API를 사용합니다.]

TCP/IP 드라이버에서 정보를 검색합니다.

IOCTL_TCP_QUERY_INFORMATION_EX 작업을 수행하려면 다음 매개 변수를 사용하여 DeviceIoControl 함수를 호출합니다.

BOOL DeviceIoControl(
  (HANDLE) hDevice,                  // Open handle to the TCP driver
  IOCTL_TCP_QUERY_INFORMATION_EX,    // dwIoControlCode
  NULL,                              // lpInBuffer (the output buffer is used for input too)
  0,                                 // nInBufferSize
  (LPVOID) lpOutBuffer,              // Pointer to the output buffer
  (DWORD) nOutBufferSize,            // Size of the output buffer
  (LPDWORD) lpBytesReturned,         // Number of bytes returned (if called synchronously)
  (LPOVERLAPPED) lpOverlapped        // OVERLAPPED structure (if called asynchronously)
);

발언

IOCTL_TCP_QUERY_INFORMATION_EX사용하려면 WDK(Windows 드라이버 키트), 특히 TDI(전송 드라이버 인터페이스) 드라이버에 설명된 대로 Windows 드라이버 개발에 익숙해야 합니다.

참고 이 컨트롤 코드를 사용하려면 Windows.h 헤더 파일을 포함합니다. 또한 IOCTL_TCP_QUERY_INFORMATION_EX사용하기 위해 Windows SDK에 게시된 헤더 파일인 Tcpioctl.h와 TDI 드라이버 개발을 위해 WDK에 게시된 Tdiinfo.h 및 Tdistat.h 헤더 파일도 포함됩니다.
 
IOCTL_TCP_QUERY_INFORMATION_EX 작업에 대한 Tdiinfo.h WDK 헤더 파일에 정의된 다양한 플래그 및 기타 상수에 다음 명명 규칙을 사용합니다.
편지 스탠드 포 코멘트
"AT" 주소 변환 ARP(주소 확인 프로토콜)에서 제공하는 것과 같은 주소 확인입니다.
"NL" 네트워크 계층 OSI(Open Systems Interconnection) 참조 모델에서와 같이.
"TL" 전송 계층 OSI 참조 모델에서와 같이.
"CL" Connection-Less 브로드캐스트 패킷을 기반으로 하는 연결 없는 프로토콜입니다.
"CO" 연결 지시된 패킷을 기반으로 하는 연결된 프로토콜입니다.
"ER" Echo 요청/회신 Ping에서 TCP/IP 연결을 테스트하는 데 사용하는 패킷 유형입니다.
"IF" 인터페이스 SNMP에서 사용되는 의미의 인터페이스입니다.
 
 
IOCTL_TCP_QUERY_INFORMATION_EX 작업은 다음 단락 및 예제 코드에 설명된 대로 lpInBuffer 매개 변수가 가리키는 TCP_REQUEST_QUERY_INFORMATION_EX 구조에 따라 다양한 종류의 정보를 검색합니다.
  1. TDI 엔터티를 열거합니다.

컴퓨터의 모든 TCP 엔터티를 식별하는 TDIEntityID 구조체의 배열을 검색하려면 입력 구조체의 ID.toi_entity.tei_entity 멤버를 GENERIC_ENTITY설정합니다. 그런 다음 ID.toi_classINFO_CLASS_GENERIC, ID.toi_typeINFO_TYPE_PROVIDER설정해야 하며, ID.toi_idENTITY_LIST_ID설정해야 합니다. 그렇지 않으면 TDI_INVALID_PARAMETER 오류 코드로 작업이 실패합니다. 목록이 요청되면 입력 구조의 Context 멤버가 무시됩니다. 이 경우 출력은 TDIEntityID 구조의 배열입니다. 아래 첫 번째 코드 예제의 GetEntityArray 함수는 이러한 배열을 검색하는 방법을 보여줍니다.

  1. 특정 TDI 엔터티에 대한 형식 정보를 가져옵니다.

입력 구조의 ID.toi_entity 멤버가 특정 엔터티를 식별하는 경우(위의 열거형 요청에서 반환된 TDIEntityID 구조의 경우와 같이) ID.toi_classINFO_CLASS_GENERIC, ID.toi_typeINFO_TYPE_PROVIDER, ENTITY_TYPE_IDID.toi_id 하나 이상의 플래그 값이 발생합니다. 는 lpOutBuffer 매개 변수가 가리키는 서명되지 않은 긴 반환됩니다. 이러한 플래그 값은 지정된 엔터티의 형식을 식별합니다. 다시 한 번 입력 구조의 Context 멤버는 무시됩니다.

반환할 수 있는 가능한 형식 플래그 값은 다음 표에 나와 있습니다.

중요성
AT_ARP 엔터티는 ARP(주소 확인 프로토콜)를 구현합니다.
AT_NULL 엔터티는 주소 변환을 수행하지 않습니다.
CL_NL_IP 엔터티는 네트워크 계층에서 연결이 없는 IP(인터넷 프로토콜)를 구현합니다.
CL_NL_IPX 엔터티는 네트워크 계층에서 연결 없이 IPX(Internetwork Packet Exchange 프로토콜)를 구현합니다.
CL_TL_NBF 엔터티는 전송 계층에서 연결이 없는 NBF(NetBEUI Frame 프로토콜)를 구현합니다.
CL_TL_UDP 엔터티는 전송 계층에서 UDP(사용자 데이터그램 프로토콜) 연결을 구현합니다.
CO_TL_NBF 엔터티는 전송 계층에서 NBF(NetBEUI Frame 프로토콜) 지시 패킷을 구현합니다.
CO_TL_SPP 엔터티는 전송 계층에서 SPP(시퀀스 패킷 프로토콜) 지시 패킷을 구현합니다.
CO_TL_SPX 엔터티는 전송 계층에서 SPX(시퀀스 패킷 교환 프로토콜) 지시 패킷을 구현합니다.
CO_TL_TCP 엔터티는 전송 계층에서 TCP(전송 제어 프로토콜) 지시 패킷을 구현합니다.
ER_ICMP 엔터티는 Echo Request/Reply에 대한 ICMP(인터넷 제어 메시지 프로토콜)를 구현합니다.
IF_GENERIC 엔터티는 제네릭 인터페이스를 구현합니다.
IF_MIB 엔터티는 SNMP MIB-II 지원을 사용하여 인터페이스를 구현합니다.
 
  1. 인터페이스 엔터티에 대한 MIB-II 정보를 가져옵니다.

엔터티 형식이 IF_MIB 경우 MIB 요청을 전송하여 IFEntry 구조가 반환될 수 있습니다. 입력 구조의 ID.toi_entity 멤버를 설정하여 엔터티, INFO_CLASS_PROTOCOLID.toi_class, INFO_TYPE_PROVIDERID.toi_typeIF_MIB_STATS_IDID.toi_id 식별합니다.

IFEntry 가변 길이 구조이므로 출력 버퍼는 "sizeof(IFEntry)"가 아니라 "sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1"로 할당되어야 합니다.

  1. 특정 IP 엔터티에 대한 MIB-II 정보를 가져옵니다.

엔터티를 식별하도록 ID.toi_entity 멤버, INFO_CLASS_PROTOCOLID.toi_class, INFO_TYPE_PROVIDERID.toi_typeIP_MIB_STATS_IDID.toi_id 설정하여 IP 엔터티(형식이 CL_NL_ENTITY)에서 MIB 정보를 검색할 수도 있습니다. 이 경우 IPSNMPInfo 구조가 반환되고 출력 버퍼를 "sizeof(IPSNMPInfo)"에 할당할 수 있습니다.

  1. 특정 IP 엔터티에 대한 주소 정보를 가져옵니다.

특정 IP 엔터티에 대해 반환된 IPSNMPInfo 구조체의 ipsi_numaddr 멤버가 0이 아니면 ID.toi_entity 멤버를 설정하여 IPAddrEntry 구조의 배열을 검색할 수 있습니다. ID.toi_classINFO_CLASS_PROTOCOLID.toi_typeINFO_TYPE_PROVIDERIP_MIB_ADDRTABLE_ENTRY_IDID.toi_id . 이 경우 출력 버퍼를 할당하여 크기 배열을 보유해야 합니다.

sizeof(IPAddrEntry) * pIpSnmpInfoReturned->ipsi_numaddr

  1. 특정 IP 주소에 대한 인터페이스 정보를 가져옵니다.

위의 IPAddrEntry 배열에서 반환된 지정된 IP 주소에 대해 IP 엔터티를 식별하도록 ID.toi_entity 멤버 집합, INFO_CLASS_PROTOCOL설정된 ID.toi_class, ID.toi_typeINFO_TYPE_PROVIDER설정하여 추가 인터페이스 정보를 검색할 수 있습니다. 그런 다음 ID.toi_idIP_INTFC_INFO_ID 설정하고 TCP_REQUEST_QUERY_INFORMATION_EX 구조의 Context 멤버를 해당 IPv4 또는 IPv6 주소로 설정합니다.

sizeof(IPINTERFACEINFO) + MAX_PHYSADDR_SIZE포함할 수 있을 만큼 큰 출력 버퍼를 할당합니다.

반환되는 출력 버퍼에는 채워진 IPInterfaceInfo 구조체가 포함됩니다.

예제

다음 예제에서는 현재 컴퓨터의 TCP 어댑터에 있는 엔터티 목록을 가져오는 방법을 보여 줍니다.

#define  UNICODE
#define  _WIN32_WINNT  0x0500

#include <stdio.h>
#include <windows.h>
#include <iptypes.h>
#include "winternl.h"
#include "tdiinfo.h"
#include "tdistat.h"
#include "tcpioctl.h"


/*  Function:              GetTCPHandle
    Description:
      Opens a handle to the TCP driver
    Parameters:
      pTCPDriverHandle --  Pointer to a handle variable.
    Return Value (DWORD):  Returns TRUE if successful, and places 
                           a valid handle to the TCP driver in the
                           handle pointed to by pTCPDriverHandle, or
                           returns FALSE otherwise, and sets the
                           handle to INVALID_HANDLE_VALUE.
*/
DWORD GetTCPHandle( PHANDLE pTCPDriverHandle )
{
#define FILE_OPEN_IF                    0x00000003
#define FILE_SYNCHRONOUS_IO_NONALERT    0x00000020
#define OBJ_CASE_INSENSITIVE            0x00000040L

typedef NTSTATUS (NTAPI *P_NT_CREATE_FILE)(
    OUT PHANDLE              FileHandle,
    IN  ACCESS_MASK          DesiredAccess,
    IN  POBJECT_ATTRIBUTES   ObjectAttributes,
    OUT PIO_STATUS_BLOCK     IoStatusBlock,
    IN  PLARGE_INTEGER       AllocationSize OPTIONAL,
    IN  ULONG                FileAttributes,
    IN  ULONG                ShareAccess,
    IN  ULONG                CreateDisposition,
    IN  ULONG                CreateOptions,
    IN  PVOID                EaBuffer OPTIONAL,
    IN  ULONG                EaLength );

  HINSTANCE hNtDLL;
  P_NT_CREATE_FILE pNtCreateFile;
  NTSTATUS rVal;
  WCHAR TCPDriverName[] = DD_TCP_DEVICE_NAME;

  OBJECT_ATTRIBUTES  objectAttributes;
  IO_STATUS_BLOCK    ioStatusBlock;
  UNICODE_STRING     UnicodeStr;

  *pTCPDriverHandle = INVALID_HANDLE_VALUE;

  if( ( hNtDLL = LoadLibrary( L"ntdll" ) ) == NULL )
    return( FALSE );

  pNtCreateFile = (P_NT_CREATE_FILE) GetProcAddress( hNtDLL, 
            "NtCreateFile" );
  if( pNtCreateFile == NULL )
    return( FALSE );

  UnicodeStr.Buffer = TCPDriverName;
  UnicodeStr.Length = (USHORT)(wcslen(TCPDriverName) * sizeof(WCHAR));
  UnicodeStr.MaximumLength = UnicodeStr.Length + sizeof(UNICODE_NULL);

  objectAttributes.Length = sizeof( OBJECT_ATTRIBUTES );
  objectAttributes.ObjectName = &UnicodeStr;
  objectAttributes.Attributes = OBJ_CASE_INSENSITIVE;
  objectAttributes.RootDirectory = NULL;
  objectAttributes.SecurityDescriptor = NULL;
  objectAttributes.SecurityQualityOfService = NULL;

  rVal = pNtCreateFile( pTCPDriverHandle,
                       SYNCHRONIZE | GENERIC_EXECUTE,
                       &objectAttributes,
                       &ioStatusBlock,
                       NULL,
                       FILE_ATTRIBUTE_NORMAL,
                       FILE_SHARE_READ | FILE_SHARE_WRITE,
                       FILE_OPEN_IF,
                       FILE_SYNCHRONOUS_IO_NONALERT,
                       NULL,
                       0 );

  if( rVal < 0 )
  {
    printf( "\nFailed to create TCP Driver handle; NT status code = %d.", rVal );
    *pTCPDriverHandle = INVALID_HANDLE_VALUE;
    return( FALSE );
  }
  return( TRUE );
}


/*  Function:              GetEntityList
    Description:
      Allocates a buffer for and retrieves an array of TDIEntityID 
    structures that identifies the entities supported by 
    the TCP/IP device driver.
    Parameters:
      TCPDriverHandle  --  An open handle to the TCP Driver; if 
            no such handle is available, 
            may be INVALID_HANDLE_VALUE.
      lplpEntities     --  Pointer to a buffer that contains 
            the array of TDIEntityID structures. 
            Must be freed by the calling process 
            using LocalFree( ).
    Return Value:
      DWORD  --  the number of entity structures in the returned array
*/
DWORD GetEntityArray( IN HANDLE TCPDriverHandle, 
    OUT TDIEntityID **lplpEntities )
{
  TCP_REQUEST_QUERY_INFORMATION_EX  req;
  DWORD arrayLen = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
  DWORD bufferLen = arrayLen;
  TDIEntityID * pEntity = NULL;
  NTSTATUS status = TDI_SUCCESS;
  DWORD temporaryHandle = 0;
  int i;


// First, if the handle passed in is not valid, try to obtain one.
  if( TCPDriverHandle == INVALID_HANDLE_VALUE )
  {
    if( GetTCPHandle( &TCPDriverHandle ) == FALSE )
    {
      *lplpEntities = NULL;
      return( 0 );
    }
    temporaryHandle = TRUE;
  }

// Next, set up the input structure for the IOCTL operation.
  req.ID.toi_entity.tei_entity    = GENERIC_ENTITY;
  req.ID.toi_entity.tei_instance  = 0;
  req.ID.toi_class                = INFO_CLASS_GENERIC;
  req.ID.toi_type                 = INFO_TYPE_PROVIDER;
  req.ID.toi_id                   = ENTITY_LIST_ID;


// The loop below is defensively engineered:
// (1)  In the first place, it is unlikely that more 
//     than MAX_TDI_ENTITIES of TCP/IP entities exist, 
//     so the loop should execute only once.
// (2)  Execution is limited to 4 iterations to rule out 
//     infinite looping in case of parameter corruption. Only 2
//     iterations should ever be necessary unless entities are 
//     being added while the loop is running.
  for( i = 0; i < 4; ++i )
  {
    if( pEntity != NULL )
    {
      LocalFree( pEntity );
      pEntity = NULL;
      bufferLen = arrayLen;
    }

    if( arrayLen == 0 )
      break;

    pEntity = (TDIEntityID *) LocalAlloc( LMEM_FIXED, bufferLen );
    if( pEntity == NULL )
    {
      arrayLen = 0;
      break;
    }

    if( !DeviceIoControl( TCPDriverHandle, // Handle to TCP driver
                          IOCTL_TCP_QUERY_INFORMATION_EX, // Cmd code
                          &req,            // Pointer to input buffer
                          sizeof(req),     // Size of ipt buffer
                          pEntity,         // Ptr to output buffer
                          bufferLen,       // Size of output buffer
                          &arrayLen,       // Actual size of array
                          NULL ) )
      status = GetLastError( );

    // Even if the output buffer is too small, the TCP driver 
    // returns a status of TDI_SUCCESS; it is the value returned in
    // arrayLen that indicates whether the entire array was 
    // successfully copied to the output buffer.
    if( status == TDI_SUCCESS )
    {
      if( arrayLen && ( arrayLen <= bufferLen ) )
        break;
    }
    else
      arrayLen = 0;
  }
  if( temporaryHandle )
    CloseHandle( TCPDriverHandle );

  *lplpEntities = pEntity;
  return( (DWORD)( arrayLen / sizeof(TDIEntityID) ) );
}

int main( )
{
  DWORD i;
  DWORD entityCount;
  TDIEntityID
    *entityArray,
    *entityPtr;

  if( !( entityCount = GetEntityArray( INVALID_HANDLE_VALUE, 
    &entityArray ) ) )
    return( 1 );

  entityPtr = entityArray;
  printf( "\n\nList of %d Transport Driver Interface Entities on this machine:\n", entityCount );

  for( i = 0; i < entityCount; ++i )
  {
    printf( "\n  Entity #%d:\n    Category (tei_entity) is ", i );
    switch( entityPtr->tei_entity )
    {
      case GENERIC_ENTITY:
        printf( "Generic." );
        break;
      case CL_NL_ENTITY:
        printf( "Connectionless Network-Layer (CL_NL)" );
        break;
      case CO_NL_ENTITY:
        printf( "Connected Network-Layer (CO_NL)" );
        break;
      case CL_TL_ENTITY:
        printf( "Connectionless Transport-Layer (CL_TL)" );
        break;
      case CO_TL_ENTITY:
        printf( "Connected Transport-Layer (CO_TL)" );
        break;
      case AT_ENTITY:
        printf( "Address Translation (AT)" );
        break;
      case IF_ENTITY:
        printf( "Interface (IF)" );
        break;
      case ER_ENTITY:
        printf( "Echo Request/Response (ER)" );
        break;
      default:
        printf( "[Unidentified Entity Type] = 0x%x", 
        entityPtr->tei_entity );
    }
    printf( "\n Instance (tei_instance) = %d\n", 
        entityPtr->tei_instance );

    ++entityPtr;
  }

//  Free the entity-array buffer before quitting.
    LocalFree( entityArray );

  return( 0 );
}


요구 사항

요구
헤더 tcpioctl.h

참고 항목

DeviceIoControl

인터넷 프로토콜 도우미 API

관리 정보 기본 참조