< Route: Routing Table, Add & Delete | IP Helper Functions Main | Change IP & IPConfig Examples >
What do we have in this chapter 13 part 4?
|
ARP
The ARP.EXE utility is used to view and manipulate the ARP cache. The Platform SDK sample that emulates ARP.EXE by using the IP Helper functions is named IPARP.EXE.
|
ARP (which, as you'll recall, stands for address resolution protocol) is responsible for resolving an IPv4 address to a physical MAC address. Machines cache this information for performance reasons, and it is possible to access it through the ARP.EXE utility. Using this utility, you can display the ARP table with the -a option, delete an entry with the -d option, or add an entry with the -s option. In the next section, we will describe how to print the ARP cache, add an entry to the ARP table, and delete ARP entries.
All of the IP Helper functions discussed in this section are available in Windows 98, Windows Me, and Windows NT 4.0 (Service Pack 4 or later).
The simplest function is obtaining the ARP table. The IP Helper function that obtains this table is GetIpNetTable(), which is defined as:
DWORD GetIpNetTable (
PMIB_IPNETTABLE pIpNetTable,
PULONG pdwSize,
BOOL bOrder
);
The first parameter, pIpNetTable, is a pointer to an MIB_IPNETTABLE structure that returns the ARP information. You must supply a sufficiently large buffer when calling this function. As with most other IP Helper functions, passing NULL for this parameter will return the buffer size needed as the parameter pdwSize and the error ERROR_INSUFFICIENT_BUFFER. Otherwise, pdwSize indicates the size of the buffer passed as pIpNetTable. The last parameter, bOrder, indicates whether the returned IPv4 entries should be sorted in ascending IPv4 order.
The MIB_IPNETTABLE structure is a wrapper for an array of MIB_IPNETROW structures and is defined as:
typedef struct _MIB_IPNETTABLE
{
DWORD dwNumEntries;
MIB_IPNETROW table[ANY_SIZE];
} MIB_IPNETTABLE, *PMIB_IPNETTABLE;
The dwNumEntries field indicates the number of array entries present in the table field. The MIB_IPNETROW structure contains the actual ARP entry information and is defined as:
typedef struct _MIB_IPNETROW {
DWORD dwIndex;
DWORD dwPhysAddrLen;
BYTE bPhysAddr[MAXLEN_PHYSADDR];
DWORD dwAddr;
DWORD dwType;
} MIB_IPNETROW, *PMIB_IPNETROW;
The fields of this structure are as follows:
Table 16-12 Possible ARP Entry Types
|
|
ARP Type |
Meaning |
MIB_IPNET_TYPE_STATIC |
Static entry |
MIB_IPNET_TYPE_DYNAMIC |
Dynamic entry |
MIB_IPNET_TYPE_INVALID |
Invalid entry |
MIB_IPNET_TYPE_OTHER |
Other entry |
The next function of ARP is adding an entry to the ARP cache, which is another relatively simple operation. The IP Helper function to add an ARP entry is SetIpNetEntry() and is defined as:
DWORD SetIpNetEntry (PMIB_IPNETROW pArpEntry);
The only argument is the MIB_IPNETROW structure, which we covered in the previous section. To add an ARP entry, simply fill in the structure with the new ARP information. First, you need to set the dwIndex field to the index of a local IPv4 address that indicates the network on which the ARP entry applies. Remember that if you are given the IP address, you can map the IP to the index with the GetIpAddrTable() function. The next field, dwPhysAddrLen, is typically set to 6. (Most physical addresses, such as ETHERNET MAC addresses, are 6 bytes long.) The bPhysAddr byte array must be set to the physical address. Most MAC addresses are represented as 12 characters - for example, 00-A0-C9-A7-86-E8. These characters need to be encoded into the proper byte array locations of the bPhysAddr field. For example, the sample MAC address would be encoded into the following bytes:
00000000 10100000 11001001 10100111 10000110 11101000
The encoding method is the same used for encoding IPX and ATM addresses. The dwAddr field must be set to the IP address that belongs to the remote host and the specified MAC address. The last field, dwType, is set to one of the ARP entry types listed in Table 16-12. Once the structure is filled, call SetIpNetEntry() to add the ARP entry to the cache. Upon success, NO_ERROR is returned.
Deleting an ARP entry is similar to adding one except that the only information required is the interface index, dwIndex, and the IPv4 address of the ARP entry to delete, dwAddr. The function to remove an ARP entry is DeleteIpNetEntry(), which is defined as:
DWORD DeleteIpNetEntry (PMIB_IPNETROW pArpEntry);
Again, the only parameter is an MIB_IPNETROW structure, and the only information necessary for removing an ARP entry is the local IPv4 index and the IPv4 address of the entry to delete. Remember that the index number to a local IPv4 interface can be obtained with the function GetIpAddrTable(). Upon success, NO_ERROR is returned.
It is sometimes useful to send an ARP request to populate the ARP cache with the physical address of a destination. For example, sending a UDP datagram larger than the link MTU to a destination that is not in the ARP cache will always fail; on IPv4 it will fail silently and IPv6 will indicate an error. The SendArp() function will attempt to resolve the given IPv4 address to its MAC address. There is no IPv6 equivalent function but at least IPv6 will indicate that an error has occurred so that the application can retransmit the packet once the physical address has been resolved. The function is declared as:
DWORD SendArp(
IPAddr DestIP,
IPAddr SrcIP,
PULONG pMacAddr,
PULONG PhyAddrLen
);
The DestIP indicates the IPv4 destination address that ARP will attempt to resolve. SrcIP is the optional local IPv4 interface to send the ARP request on. If zero, the routing table will determine which local interface to use. pMacAddr is a data buffer that receives the destination's physical address. Lastly, PHyAddrLen will indicate the length of the physical address returned in the pMacAddr buffer.
Create a new empty Win32 console mode application and add the project/solution name.
Add the following source code.
/*---------------------------------------------------------------------------
Copyright (c) 1998 Microsoft Corporation
---------------------------------------------------------------------------*/
#include <windows.h>
// Link to ws2_32.lib
#include <winsock.h>
// http://msdn.microsoft.com/en-us/library/aa365872(VS.85).aspx
// Link to Iphlpapi.lib
#include <iphlpapi.h>
#include <assert.h>
#include <stdlib.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <iptypes.h>
// Prototypes
void PrintIpNetTable(PMIB_IPNETTABLE pIpNetTable);
// Custom made - http://msdn.microsoft.com/en-us/library/aa365956.aspx
DWORD MyGetIpNetTable(PMIB_IPNETTABLE pIpArpTab, BOOL fOrder);
// Custom made - http://msdn.microsoft.com/en-us/library/aa365949.aspx
DWORD MyGetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, BOOL fOrder);
void PrintIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable);
void DoGetIpNetTable();
void DoSetIpNetEntry(char* pszDottedInetAddr, char* pszPhysAddr, char* pszInterface);
void DoDeleteIpNetEntry(char* pszInetAddr, char* pszInterface);
BOOL PhysAddrToString(BYTE PhysAddr[], DWORD PhysAddrLen, char str[]);
int StringToPhysAddr(char* szInEther, char* szOutEther);
BOOL InterfaceIdxToInterfaceIp(PMIB_IPADDRTABLE pIpAddrTable, DWORD dwIndex, char str[]);
void Usage(char * pszProgramName)
{
printf("%s -s inet_addr eth_addr [if_addr]\n", pszProgramName);
printf("%s -d inet_addr [if_addr]\n", pszProgramName);
printf("%s -a\n", pszProgramName);
printf("-a Displays current ARP entries by interrogating the current\n");
printf(" protocol data.\n");
printf("-d Deletes the host specified by inet_addr.\n");
printf("-s Adds the host and associates the Internet address inet_addr\n");
printf(" with the Physical address eth_addr. The Physical address is\n");
printf(" given as 6 hexadecimal bytes separated by hyphens. The entry\n");
printf(" is permanent.\n");
printf("eth_addr Specifies a physical address.\n");
printf("if_addr If present, this specifies the Internet address of the\n");
printf(" interface whose address translation table should be modified.\n");
printf(" If not present, the first applicable interface will be used.\n");
printf("Example:\n");
printf(" >IpArp -s 157.55.85.212 00-aa-bb-cc-dd-ee 0x2000003 .... Add a static\n");
printf(" arp entry on interface number 0x2000003.\n");
printf(" >IpArp -a ....Displays the arp table.\n");
printf(" >IpArp -d 157.55.85.212 ....Delete an entry.\n");
WSACleanup();
exit(1);
}
int main(int argc, char **argv)
{
WSADATA wsaData;
if ((argc < 2) || (argv[1][0] != '-'))
Usage(argv[0]);
if (strlen(argv[1]) > 2)
Usage(argv[0]);
if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
printf("WSAStartup() is OK!\n");
return -1;
}
else
printf("WSAStartup() is OK!\n");
switch(argv[1][1])
{
case 'a':
// Print arp table
DoGetIpNetTable();
break;
case 's':
//Update or add an ARP Internet/Ethernet Address entry
if (argc == 4)
DoSetIpNetEntry(argv[2], argv[3], NULL);
else if (argc == 5)
DoSetIpNetEntry(argv[2], argv[3], argv[4]);
else
Usage(argv[0]);
break;
case 'd':
//Delete an Internet/Ethernet Address pair from the ARP table
if (argc == 3)
DoDeleteIpNetEntry(argv[2], NULL);
else if (argc == 4)
DoDeleteIpNetEntry(argv[2], argv[3]);
else
Usage(argv[0]);
break;
default:
// help
Usage(argv[0]);
break;
}
if(WSACleanup() == 0)
printf("WSACleanup() is pretty fine!\n");
else
printf("WSACleanup() failed with error code %d\n", WSAGetLastError());
}
void DoGetIpNetTable()
{
DWORD dwStatus;
PMIB_IPNETTABLE pIpArpTab = NULL;
if ( (dwStatus = MyGetIpNetTable(pIpArpTab, TRUE)) == NO_ERROR)
{
printf("Some entries in arp cache...\n");
PrintIpNetTable(pIpArpTab);
free(pIpArpTab);
return;
}
else if ( dwStatus == ERROR_NO_DATA)
{
printf("No entries in arp cache...\n");
if (pIpArpTab)
free (pIpArpTab);
return;
}
else
{
if (pIpArpTab)
free (pIpArpTab);
printf("IpArp returned 0x%x\n", dwStatus);
return;
}
}
//----------------------------------------------------------------------------
// Add an arp entry with ip dotted decimal address of "pszDottedInetAddr" and
// physical address of "pszPhysAddr" in 00-aa-bb-cc-dd-ee format on interface
// index of "pszInterface" in hex form.
//----------------------------------------------------------------------------
void DoSetIpNetEntry(char* pszDottedInetAddr, char* pszPhysAddr, char* pszInterface)
{
DWORD dwInetAddr = 0; // ip address
DWORD dwStatus;
BYTE bPhysAddr[MAXLEN_PHYSADDR];
MIB_IPNETROW arpEntry; // an arp entry
PMIB_IPADDRTABLE pIpAddrTable;
pszInterface = NULL;
if (pszDottedInetAddr == NULL || pszPhysAddr == NULL)
{
printf("Bad Argument!\n");
return;
}
dwInetAddr = inet_addr(pszDottedInetAddr); // convert dotted ip addr. to ip addr.
if (dwInetAddr == INADDR_NONE)
{
printf("Bad Argument %s!\n", pszDottedInetAddr);
return;
}
if (StringToPhysAddr(pszPhysAddr, (char*)bPhysAddr ) != 0)
{
printf("Bad Argument %s!\n", pszPhysAddr);
return;
}
if (pszInterface)
{
// User provides a interface index number
sscanf_s(pszInterface, "%X",&(arpEntry.dwIndex));
}
else
{
// add this to the first available interface
pIpAddrTable = NULL;
if ( (dwStatus = MyGetIpAddrTable(pIpAddrTable, FALSE)) != NO_ERROR)
{
printf("Couldn't find a interface number to add your arp entry\n");
return;
}
else
printf("MyGetIpAddrTable() is OK!\n");
arpEntry.dwIndex = pIpAddrTable->table[0].dwIndex;
free(pIpAddrTable);
}
arpEntry.dwPhysAddrLen = 6;
memcpy(arpEntry.bPhysAddr, bPhysAddr, 6);
arpEntry.dwAddr = dwInetAddr;
arpEntry.dwType = MIB_IPNET_TYPE_STATIC; //static arp entry
dwStatus = SetIpNetEntry(&arpEntry);
if (dwStatus != NO_ERROR)
{
printf("Couldn't add (%s, %s), dwStatus = %lu.\n", pszDottedInetAddr, pszPhysAddr, dwStatus);
}
}
//----------------------------------------------------------------------------
// Delete an arp entry with ip dotted decimal address of "pszDottedInetAddr"
// and interface index of "pszInterface" in hex form.
//----------------------------------------------------------------------------
void DoDeleteIpNetEntry(char* pszDottedInetAddr, char* pszInterface)
{
DWORD dwInetAddr = 0; // ip address
DWORD dwStatus;
MIB_IPNETROW arpEntry; // an arp entry
pszInterface = NULL;
if (pszDottedInetAddr == NULL)
{
printf("Bad Argument!\n");
return;
}
dwInetAddr = inet_addr(pszDottedInetAddr); // convert dotted ip addr. to ip addr.
if (dwInetAddr == INADDR_NONE)
{
printf("Bad Argument %s!\n", pszDottedInetAddr);
return;
}
if (pszInterface)
{
// User provides a interface index number
sscanf_s(pszInterface, "%X",&(arpEntry.dwIndex));
}
else
{
// try to delete this from first available interface
PMIB_IPADDRTABLE pIpAddrTable = NULL;
if ( (dwStatus = MyGetIpAddrTable(pIpAddrTable, FALSE)) != NO_ERROR)
{
printf("Couldn't find a interface number to add your arp entry\n");
return;
}
else
printf("MyGetIpAddrTable() is OK!\n");
arpEntry.dwIndex = pIpAddrTable->table[0].dwIndex;
free(pIpAddrTable);
}
arpEntry.dwAddr = dwInetAddr;
dwStatus = DeleteIpNetEntry(&arpEntry);
if (dwStatus != NO_ERROR)
{
printf("Couldn't delete (%s), dwStatus = %lu.\n", pszDottedInetAddr, dwStatus);
}
}
//----------------------------------------------------------------------------
// Inputs: pIpAddrTable is the IP address table dwIndex is the Interface Number
// Output: If it returns TRUE, str contains the ip address of the interface
//----------------------------------------------------------------------------
BOOL InterfaceIdxToInterfaceIp(PMIB_IPADDRTABLE pIpAddrTable, DWORD dwIndex, char str[])
{
struct in_addr inadTmp;
char* szIpAddr;
DWORD dwIdx;
if (pIpAddrTable == NULL || str == NULL)
return FALSE;
str[0] = '\0';
for (dwIdx = 0; dwIdx < pIpAddrTable->dwNumEntries; dwIdx++)
{
if (dwIndex == pIpAddrTable->table[dwIdx].dwIndex)
{
inadTmp.s_addr = pIpAddrTable->table[dwIdx].dwAddr;
szIpAddr = inet_ntoa(inadTmp);
if (szIpAddr)
{
strcpy_s(str, sizeof(str), szIpAddr);
return TRUE;
}
else
return FALSE;
}
}
return FALSE;
}
//-------------------------------------------------------------------------
// Input: str points to an Ethernet address of the form 00-aa-bb-cc-dd-ee
// If it returns 0, ret contains the 6 bytes Ethernet address.
//-------------------------------------------------------------------------
int StringToPhysAddr(char* szInEther, char* szOutEther)
{
const char DASH = '-';
register char c;
register int val;
int i;
// check szInEther for the correct format
if (strlen(szInEther) != 17)
return (-1);
if (szInEther[2] != DASH || szInEther[5] != DASH || szInEther[8] != DASH ||
szInEther[8] != DASH || szInEther[14] != DASH)
return (-1);
if (!isxdigit(szInEther[0]) || !isxdigit(szInEther[1]) ||
!isxdigit(szInEther[3]) || !isxdigit(szInEther[4]) ||
!isxdigit(szInEther[6]) || !isxdigit(szInEther[7]) ||
!isxdigit(szInEther[9]) || !isxdigit(szInEther[10]) ||
!isxdigit(szInEther[12]) || !isxdigit(szInEther[13]) ||
!isxdigit(szInEther[15]) || !isxdigit(szInEther[16]))
return (-1);
// convert the 12 hex decimals back to 6 digit decimals
for (i = 0; i < 6; i++)
{
val = 0;
c = toupper(szInEther[i*3]);
c = c - (isdigit(c) ? '0' : ('A' - 10)); //offset adjustment
val += c;
val = (val << 4); // val * 16
c = toupper(szInEther[i*3 + 1]);
c = c - (isdigit(c) ? '0' : ('A' - 10)); // offset adjustment
val += c;
szOutEther[i] = val;
}
return (0);
}
//------------------------------------------------------------------------------------
// Inputs: PhysAddr is the hardware address in bytes
// PhysAddrLen is the length of the PhysAddr
// Outputs: if it returns TRUE, str is the hex formatted string of the hardware address.
// NOTE: make sure str is TRIPLE as big as PhysAddrLen
//-------------------------------------------------------------------------------------
BOOL PhysAddrToString(BYTE PhysAddr[], DWORD PhysAddrLen, char str[])
{
DWORD dwIdx;
if (PhysAddr == NULL || PhysAddrLen == 0 || str == NULL)
return FALSE;
str[0] = '\0';
for (dwIdx = 0; dwIdx < PhysAddrLen; dwIdx++)
{
if (dwIdx == PhysAddrLen-1)
sprintf_s(str+(dwIdx*3), sizeof(str+(dwIdx*3)), "%02X", ((int)PhysAddr[dwIdx])&0xff);
else
sprintf_s(str+(dwIdx*3), sizeof(str+(dwIdx*3)), "%02X-", ((int)PhysAddr[dwIdx])&0xff);
}
return TRUE;
}
//----------------------------------------------------------------------------
// arp table format to be printed:
// Interface: 157.61.239.34 on Interface 2
// Internet Address Physical Address Type
// 159.61.230.39 00-aa-00-61-5d-a4 dynamic
//
// Interface: 157.54.178.219 on Interface 3
// Internet Address Physical Address Type
// 159.54.170.1 00-10-54-42-c0-88 dynamic
// 159.54.170.113 00-aa-00-c0-80-2e dynamic
//----------------------------------------------------------------------------
void PrintIpNetTable(PMIB_IPNETTABLE pIpNetTable)
{
DWORD i, dwStatus, dwCurrIndex;
struct in_addr inadTmp;
char szPrintablePhysAddr[256];
char szType[128];
char szIpAddr[128];
PMIB_IPADDRTABLE pIpAddrTable = NULL;
if (pIpNetTable == NULL)
{
printf( "pIpNetTable == NULL in line %d\n", __LINE__);
return;
}
// get IP Address Table for mapping interface index number to ip address
if ( (dwStatus = MyGetIpAddrTable(pIpAddrTable, FALSE)) != NO_ERROR)
{
printf("GetIpAddrTable() returned 0x%x\n", dwStatus);
if (pIpAddrTable)
free(pIpAddrTable);
return;
}
assert(pIpAddrTable);
// Note: the ARP table should be sorted in interface index
dwCurrIndex = pIpNetTable->table[0].dwIndex;
if (InterfaceIdxToInterfaceIp(pIpAddrTable, dwCurrIndex, szIpAddr))
{
printf("\nInterface: %s on Interface 0x%X\n", szIpAddr, dwCurrIndex);
printf(" Internet Address Physical Address Type\n");
}
else
{
printf("Error: Could not convert Interface number 0x%X to IP address.\n", pIpNetTable->table[0].dwIndex);
return;
}
for (i = 0; i < pIpNetTable->dwNumEntries; ++i)
{
if (pIpNetTable->table[i].dwIndex != dwCurrIndex)
{
dwCurrIndex = pIpNetTable->table[i].dwIndex;
if (InterfaceIdxToInterfaceIp(pIpAddrTable, dwCurrIndex, szIpAddr))
{
printf("Interface: %s on Interface 0x%X\n", szIpAddr, dwCurrIndex);
printf(" Internet Address Physical Address Type\n");
}
else
{
printf("Error: Could not convert Interface number 0x%X to IP address.\n",
pIpNetTable->table[0].dwIndex);
return;
}
}
PhysAddrToString(pIpNetTable->table[i].bPhysAddr, pIpNetTable->table[i].dwPhysAddrLen, szPrintablePhysAddr);
inadTmp.s_addr = pIpNetTable->table[i].dwAddr;
switch (pIpNetTable->table[i].dwType)
{
case 1:
strcpy_s(szType, sizeof(szType), "Other");
break;
case 2:
strcpy_s(szType,sizeof(szType), "Invalidated");
break;
case 3:
strcpy_s(szType,sizeof(szType), "Dynamic");
break;
case 4:
strcpy_s(szType,sizeof(szType), "Static");
break;
default:
strcpy_s(szType, sizeof(szType), "InvalidType");
}
printf(" %-16s %-17s %-11s\n", inet_ntoa(inadTmp), szPrintablePhysAddr, szType);
}
if (pIpAddrTable)
free(pIpAddrTable);
}
//--------------------------------------------------------------------------------------
// Format of IP Address Table:
// ipAdEntAddr ifAdEntIfIndex ipAdEntNetMask ipAdEntBcastAddr ipAdEntReasmMaxSize
//--------------------------------------------------------------------------------------
void PrintIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable)
{
DWORD i;
struct in_addr inadTmp1;
struct in_addr inadTmp2;
char szAddr[128];
char szMask[128];
if (pIpAddrTable == NULL)
{
printf("pIpAddrTable == NULL in line %d\n", __LINE__);
return;
}
printf("ipAdEntAddr\t ifAdEntIfIndex\t ipAdEntNetMask\t ipAdEntBcastAddr\t ipAdEntReasmMaxSize\n");
for (i = 0; i < pIpAddrTable->dwNumEntries; ++i)
{
inadTmp1.s_addr = pIpAddrTable->table[i].dwAddr;
strcpy_s(szAddr, sizeof(szAddr), inet_ntoa(inadTmp1));
inadTmp2.s_addr = pIpAddrTable->table[i].dwMask;
strcpy_s(szMask, sizeof(szMask), inet_ntoa(inadTmp2));
printf(" %s\t 0x%X\t %s\t %s\t %u\n",
szAddr,
pIpAddrTable->table[i].dwIndex,
szMask,
(pIpAddrTable->table[i].dwBCastAddr ? "255.255.255.255" : "0.0.0.0"),
pIpAddrTable->table[i].dwReasmSize);
}
}
//----------------------------------------------------------------------------
// Input : fOrder -- sorts the output IP Addr Table
// Output: If it returns NO_ERROR, pIpAddrTable points to the IP Addr Table
//----------------------------------------------------------------------------
// Redundant - http://msdn.microsoft.com/en-us/library/aa365949.aspx
DWORD MyGetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, BOOL fOrder)
{
DWORD status = NO_ERROR;
DWORD statusRetry = NO_ERROR;
DWORD dwActualSize = 0;
fOrder = FALSE;
// query for buffer size needed
status = GetIpAddrTable(pIpAddrTable, &dwActualSize, fOrder);
if (status == NO_ERROR)
{
printf("No error!\n");
return status;
}
else if (status == ERROR_INSUFFICIENT_BUFFER)
{
// need more space
pIpAddrTable = (PMIB_IPADDRTABLE) malloc(dwActualSize);
assert(pIpAddrTable);
statusRetry = GetIpAddrTable(pIpAddrTable, &dwActualSize, fOrder);
return statusRetry;
}
else
{
return status;
}
}
//----------------------------------------------------------------------------
// Input : fOrder -- sorts the output IP Net Table
// Output: If it returns NO_ERROR, pIpNetTable points to the IP Net Table
//----------------------------------------------------------------------------
// Redundant: http://msdn.microsoft.com/en-us/library/aa365956.aspx
DWORD MyGetIpNetTable(PMIB_IPNETTABLE pIpNetTable, BOOL fOrder)
{
DWORD status = NO_ERROR;
DWORD statusRetry = NO_ERROR;
DWORD dwActualSize = 0;
fOrder = FALSE;
// query for buffer size needed
dwActualSize = 0;
status = GetIpNetTable(pIpNetTable, &dwActualSize, fOrder);
if (status == NO_ERROR)
{
return status;
}
else if (status == ERROR_INSUFFICIENT_BUFFER)
{
// need more space
pIpNetTable = (PMIB_IPNETTABLE) malloc(dwActualSize);
assert(pIpNetTable);
statusRetry = GetIpNetTable(pIpNetTable, &dwActualSize, fOrder);
if (statusRetry != NO_ERROR)
{
#ifdef _DEBUG
printf("Retry failed...\n");
#endif
return statusRetry;
}
else
{
return statusRetry;
}
}
else
{
#ifdef _DEBUG
printf("First getipnettable() call failed!\n");
#endif
return status;
}
}
Build and run the project.
< Route: Routing Table, Add & Delete | IP Helper Functions Main | Change IP & IPConfig Examples >