ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

iphlpapi_main.c
Go to the documentation of this file.
00001 /*
00002  * iphlpapi dll implementation
00003  *
00004  * Copyright (C) 2003 Juan Lang
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #define DEBUG
00022 
00023 #include "config.h"
00024 #include "iphlpapi_private.h"
00025 
00026 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
00027 
00028 typedef struct _NAME_SERVER_LIST_CONTEXT {
00029     ULONG uSizeAvailable;
00030     ULONG uSizeRequired;
00031     PIP_PER_ADAPTER_INFO pData;
00032     UINT NumServers;
00033     IP_ADDR_STRING *pLastAddr;
00034 } NAME_SERVER_LIST_CONTEXT, *PNAME_SERVER_LIST_CONTEXT;
00035 
00036 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
00037 {
00038   switch (fdwReason) {
00039     case DLL_PROCESS_ATTACH:
00040       DisableThreadLibraryCalls( hinstDLL );
00041       interfaceMapInit();
00042       break;
00043 
00044     case DLL_PROCESS_DETACH:
00045       interfaceMapFree();
00046       break;
00047   }
00048   return TRUE;
00049 }
00050 
00051 /******************************************************************
00052  *    AddIPAddress (IPHLPAPI.@)
00053  *
00054  *
00055  * PARAMS
00056  *
00057  *  Address [In]
00058  *  IpMask [In]
00059  *  IfIndex [In]
00060  *  NTEContext [In/Out]
00061  *  NTEInstance [In/Out]
00062  *
00063  * RETURNS
00064  *
00065  *  DWORD
00066  *
00067  */
00068 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask Netmask, DWORD IfIndex, PULONG NteContext, PULONG NteInstance)
00069 {
00070     return RtlNtStatusToDosError(addIPAddress(Address, Netmask, IfIndex, NteContext, NteInstance));
00071 }
00072 
00073 DWORD getInterfaceGatewayByIndex(DWORD index)
00074 {
00075    DWORD ndx, retVal = 0, numRoutes = getNumRoutes();
00076    RouteTable *table = getRouteTable();
00077    if (!table) return 0;
00078 
00079     for (ndx = 0; ndx < numRoutes; ndx++)
00080     {
00081         if ((table->routes[ndx].ifIndex == (index)) && (table->routes[ndx].dest == 0))
00082             retVal = table->routes[ndx].gateway;
00083     }
00084     HeapFree(GetProcessHeap(), 0, table);
00085     return retVal;
00086 }
00087 
00088 /******************************************************************
00089  *    AllocateAndGetIfTableFromStack (IPHLPAPI.@)
00090  *
00091  *
00092  * PARAMS
00093  *
00094  *  ppIfTable [Out] -- pointer into which the MIB_IFTABLE is
00095  *   allocated and returned.
00096  *  bOrder [In] -- passed to GetIfTable to order the table
00097  *  heap [In] -- heap from which the table is allocated
00098  *  flags [In] -- flags to HeapAlloc
00099  *
00100  * RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
00101  *  GetIfTable returns otherwise
00102  *
00103  */
00104 DWORD WINAPI AllocateAndGetIfTableFromStack(PMIB_IFTABLE *ppIfTable,
00105  BOOL bOrder, HANDLE heap, DWORD flags)
00106 {
00107   DWORD ret;
00108 
00109   TRACE("ppIfTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n", ppIfTable,
00110    (DWORD)bOrder, (DWORD)heap, flags);
00111   if (!ppIfTable)
00112     ret = ERROR_INVALID_PARAMETER;
00113   else {
00114     DWORD dwSize = 0;
00115 
00116     ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
00117     if (ret == ERROR_INSUFFICIENT_BUFFER) {
00118       *ppIfTable = (PMIB_IFTABLE)HeapAlloc(heap, flags, dwSize);
00119       ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
00120     }
00121   }
00122   TRACE("returning %ld\n", ret);
00123   return ret;
00124 }
00125 
00126 
00127 /******************************************************************
00128  *    AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
00129  *
00130  *
00131  * PARAMS
00132  *
00133  *  ppIpAddrTable [Out]
00134  *  bOrder [In] -- passed to GetIpAddrTable to order the table
00135  *  heap [In] -- heap from which the table is allocated
00136  *  flags [In] -- flags to HeapAlloc
00137  *
00138  * RETURNS
00139  *
00140  *  DWORD
00141  *
00142  */
00143 DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
00144  BOOL bOrder, HANDLE heap, DWORD flags)
00145 {
00146   DWORD ret;
00147 
00148   TRACE("ppIpAddrTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n",
00149    ppIpAddrTable, (DWORD)bOrder, (DWORD)heap, flags);
00150   if (!ppIpAddrTable)
00151     ret = ERROR_INVALID_PARAMETER;
00152   else {
00153     DWORD dwSize = 0;
00154 
00155     ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
00156     if (ret == ERROR_INSUFFICIENT_BUFFER) {
00157       *ppIpAddrTable = (PMIB_IPADDRTABLE)HeapAlloc(heap, flags, dwSize);
00158       ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
00159     }
00160   }
00161   TRACE("returning %ld\n", ret);
00162   return ret;
00163 }
00164 
00165 
00166 /******************************************************************
00167  *    AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
00168  *
00169  *
00170  *  ppIpForwardTable [Out] -- pointer into which the MIB_IPFORWARDTABLE is
00171  *   allocated and returned.
00172  *  bOrder [In] -- passed to GetIfTable to order the table
00173  *  heap [In] -- heap from which the table is allocated
00174  *  flags [In] -- flags to HeapAlloc
00175  *
00176  * RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
00177  *  GetIpForwardTable returns otherwise
00178  *
00179  */
00180 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *
00181  ppIpForwardTable, BOOL bOrder, HANDLE heap, DWORD flags)
00182 {
00183   DWORD ret;
00184 
00185   TRACE("ppIpForwardTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n",
00186    ppIpForwardTable, (DWORD)bOrder, (DWORD)heap, flags);
00187   if (!ppIpForwardTable)
00188     ret = ERROR_INVALID_PARAMETER;
00189   else {
00190     DWORD dwSize = 0;
00191 
00192     ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
00193     if (ret == ERROR_INSUFFICIENT_BUFFER) {
00194       *ppIpForwardTable = (PMIB_IPFORWARDTABLE)HeapAlloc(heap, flags, dwSize);
00195       ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
00196     }
00197   }
00198   TRACE("returning %ld\n", ret);
00199   return ret;
00200 }
00201 
00202 
00203 /******************************************************************
00204  *    AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
00205  *
00206  *
00207  * PARAMS
00208  *
00209  *  ppIpNetTable [Out]
00210  *  bOrder [In] -- passed to GetIpNetTable to order the table
00211  *  heap [In] -- heap from which the table is allocated
00212  *  flags [In] -- flags to HeapAlloc
00213  *
00214  * RETURNS
00215  *
00216  *  DWORD
00217  *
00218  */
00219 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable,
00220  BOOL bOrder, HANDLE heap, DWORD flags)
00221 {
00222   DWORD ret;
00223 
00224   TRACE("ppIpNetTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n",
00225    ppIpNetTable, (DWORD)bOrder, (DWORD)heap, flags);
00226   if (!ppIpNetTable)
00227     ret = ERROR_INVALID_PARAMETER;
00228   else {
00229     DWORD dwSize = 0;
00230 
00231     ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
00232     if (ret == ERROR_INSUFFICIENT_BUFFER) {
00233       *ppIpNetTable = (PMIB_IPNETTABLE)HeapAlloc(heap, flags, dwSize);
00234       ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
00235     }
00236   }
00237   TRACE("returning %ld\n", ret);
00238   return ret;
00239 }
00240 
00241 
00242 /******************************************************************
00243  *    AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
00244  *
00245  *
00246  * PARAMS
00247  *
00248  *  ppTcpTable [Out]
00249  *  bOrder [In] -- passed to GetTcpTable to order the table
00250  *  heap [In] -- heap from which the table is allocated
00251  *  flags [In] -- flags to HeapAlloc
00252  *
00253  * RETURNS
00254  *
00255  *  DWORD
00256  *
00257  */
00258 DWORD WINAPI AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE *ppTcpTable,
00259  BOOL bOrder, HANDLE heap, DWORD flags)
00260 {
00261   DWORD ret;
00262 
00263   TRACE("ppTcpTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n",
00264    ppTcpTable, (DWORD)bOrder, (DWORD)heap, flags);
00265   if (!ppTcpTable)
00266     ret = ERROR_INVALID_PARAMETER;
00267   else {
00268     DWORD dwSize = 0;
00269 
00270     ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
00271     if (ret == ERROR_INSUFFICIENT_BUFFER) {
00272       *ppTcpTable = (PMIB_TCPTABLE)HeapAlloc(heap, flags, dwSize);
00273       ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
00274     }
00275   }
00276   TRACE("returning %ld\n", ret);
00277   return ret;
00278 }
00279 
00280 
00281 /******************************************************************
00282  *    AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
00283  *
00284  *
00285  * PARAMS
00286  *
00287  *  ppUdpTable [Out]
00288  *  bOrder [In] -- passed to GetUdpTable to order the table
00289  *  heap [In] -- heap from which the table is allocated
00290  *  flags [In] -- flags to HeapAlloc
00291  *
00292  * RETURNS
00293  *
00294  *  DWORD
00295  *
00296  */
00297 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable,
00298  BOOL bOrder, HANDLE heap, DWORD flags)
00299 {
00300   DWORD ret;
00301 
00302   TRACE("ppUdpTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n",
00303    ppUdpTable, (DWORD)bOrder, (DWORD)heap, flags);
00304   if (!ppUdpTable)
00305     ret = ERROR_INVALID_PARAMETER;
00306   else {
00307     DWORD dwSize = 0;
00308 
00309     ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
00310     if (ret == ERROR_INSUFFICIENT_BUFFER) {
00311       *ppUdpTable = (PMIB_UDPTABLE)HeapAlloc(heap, flags, dwSize);
00312       ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
00313     }
00314   }
00315   TRACE("returning %ld\n", ret);
00316   return ret;
00317 }
00318 
00319 
00320 /******************************************************************
00321  *    CreateIpForwardEntry (IPHLPAPI.@)
00322  *
00323  *
00324  * PARAMS
00325  *
00326  *  pRoute [In/Out]
00327  *
00328  * RETURNS
00329  *
00330  *  DWORD
00331  *
00332  */
00333 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
00334 {
00335     return createIpForwardEntry( pRoute );
00336 }
00337 
00338 
00339 /******************************************************************
00340  *    CreateIpNetEntry (IPHLPAPI.@)
00341  *
00342  *
00343  * PARAMS
00344  *
00345  *  pArpEntry [In/Out]
00346  *
00347  * RETURNS
00348  *
00349  *  DWORD
00350  *
00351  */
00352 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
00353 {
00354   TRACE("pArpEntry %p\n", pArpEntry);
00355   /* could use SIOCSARP on systems that support it, not sure I want to */
00356   FIXME(":stub\n");
00357   return (DWORD) 0;
00358 }
00359 
00360 
00361 /******************************************************************
00362  *    CreateProxyArpEntry (IPHLPAPI.@)
00363  *
00364  *
00365  * PARAMS
00366  *
00367  *  dwAddress [In]
00368  *  dwMask [In]
00369  *  dwIfIndex [In]
00370  *
00371  * RETURNS
00372  *
00373  *  DWORD
00374  *
00375  */
00376 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
00377 {
00378   TRACE("dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx\n", dwAddress,
00379    dwMask, dwIfIndex);
00380   FIXME(":stub\n");
00381   /* marking Win2K+ functions not supported */
00382   return ERROR_NOT_SUPPORTED;
00383 }
00384 
00385 
00386 /******************************************************************
00387  *    DeleteIPAddress (IPHLPAPI.@)
00388  *
00389  *
00390  * PARAMS
00391  *
00392  *  NTEContext [In]
00393  *
00394  * RETURNS
00395  *
00396  *  DWORD
00397  *
00398  */
00399 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
00400 {
00401   TRACE("NTEContext %ld\n", NTEContext);
00402   return RtlNtStatusToDosError(deleteIpAddress(NTEContext));
00403 }
00404 
00405 
00406 /******************************************************************
00407  *    DeleteIpForwardEntry (IPHLPAPI.@)
00408  *
00409  *
00410  * PARAMS
00411  *
00412  *  pRoute [In/Out]
00413  *
00414  * RETURNS
00415  *
00416  *  DWORD
00417  *
00418  */
00419 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
00420 {
00421     return deleteIpForwardEntry( pRoute );
00422 }
00423 
00424 
00425 /******************************************************************
00426  *    DeleteIpNetEntry (IPHLPAPI.@)
00427  *
00428  *
00429  * PARAMS
00430  *
00431  *  pArpEntry [In/Out]
00432  *
00433  * RETURNS
00434  *
00435  *  DWORD
00436  *
00437  */
00438 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
00439 {
00440   TRACE("pArpEntry %p\n", pArpEntry);
00441   /* could use SIOCDARP on systems that support it, not sure I want to */
00442   FIXME(":stub\n");
00443   return (DWORD) 0;
00444 }
00445 
00446 
00447 /******************************************************************
00448  *    DeleteProxyArpEntry (IPHLPAPI.@)
00449  *
00450  *
00451  * PARAMS
00452  *
00453  *  dwAddress [In]
00454  *  dwMask [In]
00455  *  dwIfIndex [In]
00456  *
00457  * RETURNS
00458  *
00459  *  DWORD
00460  *
00461  */
00462 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
00463 {
00464   TRACE("dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx\n", dwAddress,
00465    dwMask, dwIfIndex);
00466   FIXME(":stub\n");
00467   /* marking Win2K+ functions not supported */
00468   return ERROR_NOT_SUPPORTED;
00469 }
00470 
00471 /******************************************************************
00472  *    EnableRouter (IPHLPAPI.@)
00473  *
00474  *
00475  * PARAMS
00476  *
00477  *  pHandle [In/Out]
00478  *  pOverlapped [In/Out]
00479  *
00480  * RETURNS
00481  *
00482  *  DWORD
00483  *
00484  */
00485 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
00486 {
00487   TRACE("pHandle %p, pOverlapped %p\n", pHandle, pOverlapped);
00488   FIXME(":stub\n");
00489   /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
00490      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
00491      marking Win2K+ functions not supported */
00492   return ERROR_NOT_SUPPORTED;
00493 }
00494 
00495 
00496 /******************************************************************
00497  *    FlushIpNetTable (IPHLPAPI.@)
00498  *
00499  *
00500  * PARAMS
00501  *
00502  *  dwIfIndex [In]
00503  *
00504  * RETURNS
00505  *
00506  *  DWORD
00507  *
00508  */
00509 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
00510 {
00511   TRACE("dwIfIndex 0x%08lx\n", dwIfIndex);
00512   FIXME(":stub\n");
00513   /* this flushes the arp cache of the given index
00514      marking Win2K+ functions not supported */
00515   return ERROR_NOT_SUPPORTED;
00516 }
00517 
00518 
00519 /******************************************************************
00520  *    GetAdapterIndex (IPHLPAPI.@)
00521  *
00522  *
00523  * PARAMS
00524  *
00525  *  AdapterName [In/Out]
00526  *  IfIndex [In/Out]
00527  *
00528  * RETURNS
00529  *
00530  *  DWORD
00531  *
00532  */
00533 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
00534 {
00535   TRACE("AdapterName %p, IfIndex %p\n", AdapterName, IfIndex);
00536   FIXME(":stub\n");
00537   /* marking Win2K+ functions not supported */
00538   return ERROR_NOT_SUPPORTED;
00539 }
00540 
00541 
00542 /******************************************************************
00543  *    GetAdaptersInfo (IPHLPAPI.@)
00544  *
00545  *
00546  * PARAMS
00547  *
00548  *  pAdapterInfo [In/Out]
00549  *  pOutBufLen [In/Out]
00550  *
00551  * RETURNS
00552  *
00553  *  DWORD
00554  *
00555  */
00556 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
00557 {
00558   DWORD ret;
00559   BOOL dhcpEnabled;
00560   DWORD dhcpServer;
00561 
00562   TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
00563   if (!pOutBufLen)
00564     ret = ERROR_INVALID_PARAMETER;
00565   else {
00566     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
00567 
00568     if (numNonLoopbackInterfaces > 0) {
00569       /* this calculation assumes only one address in the IP_ADDR_STRING lists.
00570          that's okay, because:
00571          - we don't get multiple addresses per adapter anyway
00572          - we don't know about per-adapter gateways
00573          - DHCP and WINS servers can have max one entry per list */
00574       ULONG size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
00575 
00576       if (!pAdapterInfo || *pOutBufLen < size) {
00577         *pOutBufLen = size;
00578         ret = ERROR_BUFFER_OVERFLOW;
00579       }
00580       else {
00581         InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
00582 
00583         if (table) {
00584           size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
00585           if (*pOutBufLen < size) {
00586             *pOutBufLen = size;
00587             ret = ERROR_INSUFFICIENT_BUFFER;
00588           }
00589           else {
00590             DWORD ndx;
00591             HKEY hKey;
00592             BOOL winsEnabled = FALSE;
00593             IP_ADDRESS_STRING primaryWINS, secondaryWINS;
00594 
00595             memset(pAdapterInfo, 0, size);
00596             if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
00597              "Software\\Wine\\Wine\\Config\\Network", 0, KEY_READ,
00598              &hKey) == ERROR_SUCCESS) {
00599               DWORD size = sizeof(primaryWINS.String);
00600               unsigned long addr;
00601 
00602               RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
00603                (PBYTE)primaryWINS.String, &size);
00604               addr = inet_addr(primaryWINS.String);
00605               if (addr != INADDR_NONE && addr != INADDR_ANY)
00606                 winsEnabled = TRUE;
00607               size = sizeof(secondaryWINS.String);
00608               RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
00609                (PBYTE)secondaryWINS.String, &size);
00610               addr = inet_addr(secondaryWINS.String);
00611               if (addr != INADDR_NONE && addr != INADDR_ANY)
00612                 winsEnabled = TRUE;
00613               RegCloseKey(hKey);
00614             }
00615             TRACE("num of index is %lu\n", table->numIndexes);
00616             for (ndx = 0; ndx < table->numIndexes; ndx++) {
00617               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
00618               DWORD addrLen = sizeof(ptr->Address), type;
00619               const char *ifname =
00620                   getInterfaceNameByIndex(table->indexes[ndx]);
00621               if (!ifname) {
00622                   ret = ERROR_OUTOFMEMORY;
00623                   break;
00624               }
00625 
00626               /* on Win98 this is left empty, but whatever */
00627               strncpy(ptr->AdapterName,ifname,sizeof(ptr->AdapterName));
00628               consumeInterfaceName(ifname);
00629               ptr->AdapterName[MAX_ADAPTER_NAME_LENGTH] = '\0';
00630               getInterfacePhysicalByIndex(table->indexes[ndx], &addrLen,
00631                ptr->Address, &type);
00632               /* MS defines address length and type as UINT in some places and
00633                  DWORD in others, **sigh**.  Don't want to assume that PUINT and
00634                  PDWORD are equiv (64-bit?) */
00635               ptr->AddressLength = addrLen;
00636               ptr->Type = type;
00637               ptr->Index = table->indexes[ndx];
00638               toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
00639                ptr->IpAddressList.IpAddress.String);
00640               toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
00641                ptr->IpAddressList.IpMask.String);
00642               ptr->IpAddressList.Context = ptr->Index;
00643               toIPAddressString(getInterfaceGatewayByIndex(table->indexes[ndx]),
00644                ptr->GatewayList.IpAddress.String);
00645               getDhcpInfoForAdapter(table->indexes[ndx], &dhcpEnabled,
00646                                     &dhcpServer, &ptr->LeaseObtained,
00647                                     &ptr->LeaseExpires);
00648               ptr->DhcpEnabled = (DWORD) dhcpEnabled;
00649               toIPAddressString(dhcpServer,
00650                                 ptr->DhcpServer.IpAddress.String);
00651               if (winsEnabled) {
00652                 ptr->HaveWins = TRUE;
00653                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
00654                  primaryWINS.String, sizeof(primaryWINS.String));
00655                 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
00656                  secondaryWINS.String, sizeof(secondaryWINS.String));
00657               }
00658               if (ndx < table->numIndexes - 1)
00659                 ptr->Next = &pAdapterInfo[ndx + 1];
00660               else
00661                 ptr->Next = NULL;
00662             }
00663             ret = NO_ERROR;
00664           }
00665           free(table);
00666         }
00667         else
00668           ret = ERROR_OUTOFMEMORY;
00669       }
00670     }
00671     else
00672       ret = ERROR_NO_DATA;
00673   }
00674   TRACE("returning %ld\n", ret);
00675   return ret;
00676 }
00677 
00678 
00679 /******************************************************************
00680  *    GetBestInterface (IPHLPAPI.@)
00681  *
00682  *
00683  * PARAMS
00684  *
00685  *  dwDestAddr [In]
00686  *  pdwBestIfIndex [In/Out]
00687  *
00688  * RETURNS
00689  *
00690  *  DWORD
00691  *
00692  */
00693 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
00694 {
00695   DWORD ret;
00696 
00697   TRACE("dwDestAddr 0x%08lx, pdwBestIfIndex %p\n", dwDestAddr, pdwBestIfIndex);
00698   if (!pdwBestIfIndex)
00699     ret = ERROR_INVALID_PARAMETER;
00700   else {
00701     MIB_IPFORWARDROW ipRow;
00702 
00703     ret = GetBestRoute(dwDestAddr, 0, &ipRow);
00704     if (ret == ERROR_SUCCESS)
00705       *pdwBestIfIndex = ipRow.dwForwardIfIndex;
00706   }
00707   TRACE("returning %ld\n", ret);
00708   return ret;
00709 }
00710 
00711 
00712 /******************************************************************
00713  *    GetBestRoute (IPHLPAPI.@)
00714  *
00715  *
00716  * PARAMS
00717  *
00718  *  dwDestAddr [In]
00719  *  dwSourceAddr [In]
00720  *  OUT [In]
00721  *
00722  * RETURNS
00723  *
00724  *  DWORD
00725  *
00726  */
00727 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
00728 {
00729   PMIB_IPFORWARDTABLE table;
00730   DWORD ret;
00731 
00732   TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr,
00733    dwSourceAddr, pBestRoute);
00734   if (!pBestRoute)
00735     return ERROR_INVALID_PARAMETER;
00736 
00737   AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
00738   if (table) {
00739     DWORD ndx, matchedBits, matchedNdx = 0;
00740 
00741     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
00742       if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
00743        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
00744         DWORD numShifts, mask;
00745 
00746         for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
00747          mask && !(mask & 1); mask >>= 1, numShifts++)
00748           ;
00749         if (numShifts > matchedBits) {
00750           matchedBits = numShifts;
00751           matchedNdx = ndx;
00752         }
00753       }
00754     }
00755     memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
00756     HeapFree(GetProcessHeap(), 0, table);
00757     ret = ERROR_SUCCESS;
00758   }
00759   else
00760     ret = ERROR_OUTOFMEMORY;
00761   TRACE("returning %ld\n", ret);
00762   return ret;
00763 }
00764 
00765 /******************************************************************
00766  *    GetExtendedTcpTable (IPHLPAPI.@)
00767  *
00768  * Get the table of TCP endpoints available to the application.
00769  *
00770  * PARAMS
00771  *  pTcpTable [Out]    table struct with the filtered TCP endpoints available to application
00772  *  pdwSize   [In/Out] estimated size of the structure returned in pTcpTable, in bytes
00773  *  bOrder    [In]     whether to order the table
00774  *  ulAf    [in]    version of IP used by the TCP endpoints
00775  *  TableClass [in] type of the TCP table structure from TCP_TABLE_CLASS
00776  *  Reserved [in]   reserved - this value must be zero
00777  *
00778  * RETURNS
00779  *  Success: NO_ERROR
00780  *  Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
00781  *
00782  * NOTES
00783  */
00784 DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
00785 {
00786     DWORD ret = NO_ERROR;
00787     UNIMPLEMENTED;
00788     return ret; 
00789 }
00790 
00791 
00792 /******************************************************************
00793  *    GetFriendlyIfIndex (IPHLPAPI.@)
00794  *
00795  *
00796  * PARAMS
00797  *
00798  *  IfIndex [In]
00799  *
00800  * RETURNS
00801  *
00802  *  DWORD
00803  *
00804  */
00805 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
00806 {
00807   /* windows doesn't validate these, either, just makes sure the top byte is
00808      cleared.  I assume my ifenum module never gives an index with the top
00809      byte set. */
00810   TRACE("returning %ld\n", IfIndex);
00811   return IfIndex;
00812 }
00813 
00814 
00815 /******************************************************************
00816  *    GetIcmpStatistics (IPHLPAPI.@)
00817  *
00818  *
00819  * PARAMS
00820  *
00821  *  pStats [In/Out]
00822  *
00823  * RETURNS
00824  *
00825  *  DWORD
00826  *
00827  */
00828 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
00829 {
00830   DWORD ret;
00831 
00832   TRACE("pStats %p\n", pStats);
00833   ret = getICMPStats(pStats);
00834   TRACE("returning %ld\n", ret);
00835   return ret;
00836 }
00837 
00838 
00839 /******************************************************************
00840  *    GetIfEntry (IPHLPAPI.@)
00841  *
00842  *
00843  * PARAMS
00844  *
00845  *  pIfRow [In/Out]
00846  *
00847  * RETURNS
00848  *
00849  *  DWORD
00850  *
00851  */
00852 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
00853 {
00854   DWORD ret;
00855   const char *name;
00856 
00857   TRACE("pIfRow %p\n", pIfRow);
00858   if (!pIfRow)
00859     return ERROR_INVALID_PARAMETER;
00860 
00861   name = getInterfaceNameByIndex(pIfRow->dwIndex);
00862   if (name) {
00863     ret = getInterfaceEntryByIndex(pIfRow->dwIndex, pIfRow);
00864     if (ret == NO_ERROR)
00865       ret = getInterfaceStatsByName(name, pIfRow);
00866     consumeInterfaceName(name);
00867   }
00868   else
00869     ret = ERROR_INVALID_DATA;
00870   TRACE("returning %ld\n", ret);
00871   return ret;
00872 }
00873 
00874 
00875 static int IfTableSorter(const void *a, const void *b)
00876 {
00877   int ret;
00878 
00879   if (a && b)
00880     ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
00881   else
00882     ret = 0;
00883   return ret;
00884 }
00885 
00886 
00887 /******************************************************************
00888  *    GetIfTable (IPHLPAPI.@)
00889  *
00890  *
00891  * PARAMS
00892  *
00893  *  pIfTable [In/Out]
00894  *  pdwSize [In/Out]
00895  *  bOrder [In]
00896  *
00897  * RETURNS
00898  *
00899  *  DWORD
00900  *
00901  */
00902 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
00903 {
00904   DWORD ret;
00905 
00906   TRACE("pIfTable %p, pdwSize %p, bOrder %ld\n", pdwSize, pdwSize,
00907    (DWORD)bOrder);
00908   if (!pdwSize)
00909     ret = ERROR_INVALID_PARAMETER;
00910   else {
00911     DWORD numInterfaces = getNumInterfaces();
00912     ULONG size;
00913     TRACE("GetIfTable: numInterfaces = %d\n", (int)numInterfaces);
00914     size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
00915 
00916     if (!pIfTable || *pdwSize < size) {
00917       *pdwSize = size;
00918       ret = ERROR_INSUFFICIENT_BUFFER;
00919     }
00920     else {
00921       InterfaceIndexTable *table = getInterfaceIndexTable();
00922 
00923       if (table) {
00924         size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
00925          sizeof(MIB_IFROW);
00926         if (*pdwSize < size) {
00927           *pdwSize = size;
00928           ret = ERROR_INSUFFICIENT_BUFFER;
00929         }
00930         else {
00931           DWORD ndx;
00932 
00933           pIfTable->dwNumEntries = 0;
00934           for (ndx = 0; ndx < table->numIndexes; ndx++) {
00935             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
00936             GetIfEntry(&pIfTable->table[ndx]);
00937             pIfTable->dwNumEntries++;
00938           }
00939           if (bOrder)
00940             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
00941              IfTableSorter);
00942           ret = NO_ERROR;
00943         }
00944         free(table);
00945       }
00946       else
00947         ret = ERROR_OUTOFMEMORY;
00948     }
00949   }
00950   TRACE("returning %ld\n", ret);
00951   return ret;
00952 }
00953 
00954 
00955 /******************************************************************
00956  *    GetInterfaceInfo (IPHLPAPI.@)
00957  *
00958  *
00959  * PARAMS
00960  *
00961  *  pIfTable [In/Out]
00962  *  dwOutBufLen [In/Out]
00963  *
00964  * RETURNS
00965  *
00966  *  DWORD
00967  *
00968  */
00969 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
00970 {
00971   DWORD ret;
00972 
00973   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
00974   if (!dwOutBufLen)
00975     ret = ERROR_INVALID_PARAMETER;
00976   else {
00977     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
00978     ULONG size;
00979     TRACE("numNonLoopbackInterfaces == 0x%x\n", numNonLoopbackInterfaces);
00980     size = sizeof(IP_INTERFACE_INFO) + (numNonLoopbackInterfaces) *
00981      sizeof(IP_ADAPTER_INDEX_MAP);
00982 
00983     if (!pIfTable || *dwOutBufLen < size) {
00984       *dwOutBufLen = size;
00985       ret = ERROR_INSUFFICIENT_BUFFER;
00986     }
00987     else {
00988       InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
00989 
00990       if (table) {
00991         TRACE("table->numIndexes == 0x%x\n", table->numIndexes);
00992         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes) *
00993          sizeof(IP_ADAPTER_INDEX_MAP);
00994         if (*dwOutBufLen < size) {
00995           *dwOutBufLen = size;
00996           ret = ERROR_INSUFFICIENT_BUFFER;
00997         }
00998         else {
00999           DWORD ndx;
01000 
01001           pIfTable->NumAdapters = 0;
01002           for (ndx = 0; ndx < table->numIndexes; ndx++) {
01003             const char *walker, *name;
01004             WCHAR *assigner;
01005 
01006             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
01007             name = getInterfaceNameByIndex(table->indexes[ndx]);
01008             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
01009              walker && *walker &&
01010              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
01011              walker++, assigner++)
01012               *assigner = *walker;
01013             *assigner = 0;
01014             consumeInterfaceName(name);
01015             pIfTable->NumAdapters++;
01016           }
01017           ret = NO_ERROR;
01018         }
01019         free(table);
01020       }
01021       else
01022         ret = ERROR_OUTOFMEMORY;
01023     }
01024   }
01025   TRACE("returning %ld\n", ret);
01026   return ret;
01027 }
01028 
01029 
01030 static int IpAddrTableSorter(const void *a, const void *b)
01031 {
01032   int ret;
01033 
01034   if (a && b)
01035     ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
01036   else
01037     ret = 0;
01038   return ret;
01039 }
01040 
01041 
01042 /******************************************************************
01043  *    GetIpAddrTable (IPHLPAPI.@)
01044  *
01045  *
01046  * PARAMS
01047  *
01048  *  pIpAddrTable [In/Out]
01049  *  pdwSize [In/Out]
01050  *  bOrder [In]
01051  *
01052  * RETURNS
01053  *
01054  *  DWORD
01055  *
01056  */
01057 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
01058 {
01059   DWORD ret;
01060 
01061   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
01062    (DWORD)bOrder);
01063   if (!pdwSize)
01064     ret = ERROR_INVALID_PARAMETER;
01065   else {
01066     DWORD numInterfaces = getNumInterfaces();
01067     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
01068      sizeof(MIB_IPADDRROW);
01069 
01070     if (!pIpAddrTable || *pdwSize < size) {
01071       *pdwSize = size;
01072       ret = ERROR_INSUFFICIENT_BUFFER;
01073     }
01074     else {
01075       InterfaceIndexTable *table = getInterfaceIndexTable();
01076 
01077       if (table) {
01078         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
01079          sizeof(MIB_IPADDRROW);
01080         if (*pdwSize < size) {
01081           *pdwSize = size;
01082           ret = ERROR_INSUFFICIENT_BUFFER;
01083         }
01084         else {
01085           DWORD ndx, bcast;
01086 
01087           pIpAddrTable->dwNumEntries = 0;
01088           for (ndx = 0; ndx < table->numIndexes; ndx++) {
01089             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
01090             pIpAddrTable->table[ndx].dwAddr =
01091              getInterfaceIPAddrByIndex(table->indexes[ndx]);
01092             pIpAddrTable->table[ndx].dwMask =
01093              getInterfaceMaskByIndex(table->indexes[ndx]);
01094             /* the dwBCastAddr member isn't the broadcast address, it indicates
01095              * whether the interface uses the 1's broadcast address (1) or the
01096              * 0's broadcast address (0).
01097              */
01098             bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
01099             pIpAddrTable->table[ndx].dwBCastAddr =
01100              (bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
01101             /* FIXME: hardcoded reasm size, not sure where to get it */
01102             pIpAddrTable->table[ndx].dwReasmSize = 65535;
01103             pIpAddrTable->table[ndx].unused1 = 0;
01104             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
01105             pIpAddrTable->dwNumEntries++;
01106           }
01107           if (bOrder)
01108             qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
01109              sizeof(MIB_IPADDRROW), IpAddrTableSorter);
01110           ret = NO_ERROR;
01111         }
01112         free(table);
01113       }
01114       else
01115         ret = ERROR_OUTOFMEMORY;
01116     }
01117   }
01118   TRACE("returning %ld\n", ret);
01119   return ret;
01120 }
01121 
01122 
01123 static int IpForwardTableSorter(const void *a, const void *b)
01124 {
01125   int ret;
01126 
01127   if (a && b) {
01128     PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
01129 
01130     ret = rowA->dwForwardDest - rowB->dwForwardDest;
01131     if (ret == 0) {
01132       ret = rowA->dwForwardProto - rowB->dwForwardProto;
01133       if (ret == 0) {
01134         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
01135         if (ret == 0)
01136           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
01137       }
01138     }
01139   }
01140   else
01141     ret = 0;
01142   return ret;
01143 }
01144 
01145 
01146 /******************************************************************
01147  *    GetIpForwardTable (IPHLPAPI.@)
01148  *
01149  *
01150  * PARAMS
01151  *
01152  *  pIpForwardTable [In/Out]
01153  *  pdwSize [In/Out]
01154  *  bOrder [In]
01155  *
01156  * RETURNS
01157  *
01158  *  DWORD
01159  *
01160  */
01161 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
01162 {
01163   DWORD ret;
01164 
01165   TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
01166         pdwSize, (DWORD)bOrder);
01167   if (!pdwSize)
01168     ret = ERROR_INVALID_PARAMETER;
01169   else {
01170     DWORD numRoutes = getNumRoutes();
01171     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
01172      sizeof(MIB_IPFORWARDROW);
01173 
01174     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
01175       *pdwSize = sizeNeeded;
01176       ret = ERROR_INSUFFICIENT_BUFFER;
01177     }
01178     else {
01179       RouteTable *table = getRouteTable();
01180       if (table) {
01181         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
01182          sizeof(MIB_IPFORWARDROW);
01183         if (*pdwSize < sizeNeeded) {
01184           *pdwSize = sizeNeeded;
01185           ret = ERROR_INSUFFICIENT_BUFFER;
01186         }
01187         else {
01188           DWORD ndx;
01189 
01190           pIpForwardTable->dwNumEntries = table->numRoutes;
01191           for (ndx = 0; ndx < numRoutes; ndx++) {
01192             pIpForwardTable->table[ndx].dwForwardIfIndex =
01193              table->routes[ndx].ifIndex;
01194             pIpForwardTable->table[ndx].dwForwardDest =
01195              table->routes[ndx].dest;
01196             pIpForwardTable->table[ndx].dwForwardMask =
01197              table->routes[ndx].mask;
01198             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
01199             pIpForwardTable->table[ndx].dwForwardNextHop =
01200              table->routes[ndx].gateway;
01201             /* FIXME: this type is appropriate for local interfaces; may not
01202                always be appropriate */
01203             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
01204             /* FIXME: other protos might be appropriate, e.g. the default route
01205                is typically set with MIB_IPPROTO_NETMGMT instead */
01206             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
01207             /* punt on age and AS */
01208             pIpForwardTable->table[ndx].dwForwardAge = 0;
01209             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
01210             pIpForwardTable->table[ndx].dwForwardMetric1 =
01211              table->routes[ndx].metric;
01212             /* rest of the metrics are 0.. */
01213             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
01214             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
01215             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
01216             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
01217           }
01218           if (bOrder)
01219             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
01220              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
01221           ret = NO_ERROR;
01222         }
01223         HeapFree(GetProcessHeap(), 0, table);
01224       }
01225       else
01226         ret = ERROR_OUTOFMEMORY;
01227     }
01228   }
01229   TRACE("returning %ld\n", ret);
01230   return ret;
01231 }
01232 
01233 
01234 static int IpNetTableSorter(const void *a, const void *b)
01235 {
01236   int ret;
01237 
01238   if (a && b)
01239     ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
01240   else
01241     ret = 0;
01242   return ret;
01243 }
01244 
01245 
01246 /******************************************************************
01247  *    GetIpNetTable (IPHLPAPI.@)
01248  *
01249  *
01250  * PARAMS
01251  *
01252  *  pIpNetTable [In/Out]
01253  *  pdwSize [In/Out]
01254  *  bOrder [In]
01255  *
01256  * RETURNS
01257  *
01258  *  DWORD
01259  *
01260  */
01261 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
01262 {
01263   DWORD ret = NO_ERROR;
01264 
01265   TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize,
01266    (DWORD)bOrder);
01267   if (!pdwSize)
01268     ret = ERROR_INVALID_PARAMETER;
01269   else {
01270     DWORD numEntries = getNumArpEntries();
01271     ULONG size = sizeof(MIB_IPNETTABLE);
01272 
01273     if (numEntries > 1)
01274       size += (numEntries - 1) * sizeof(MIB_IPNETROW);
01275     if (!pIpNetTable || *pdwSize < size) {
01276       *pdwSize = size;
01277       ret = ERROR_INSUFFICIENT_BUFFER;
01278     }
01279     else {
01280       PMIB_IPNETTABLE table = getArpTable();
01281       if (table) {
01282         size = sizeof(MIB_IPNETTABLE);
01283         if (table->dwNumEntries > 1)
01284           size += (table->dwNumEntries - 1) * sizeof(MIB_IPNETROW);
01285         if (*pdwSize < size) {
01286           *pdwSize = size;
01287           ret = ERROR_INSUFFICIENT_BUFFER;
01288         }
01289         else {
01290           *pdwSize = size;
01291           memcpy(pIpNetTable, table, size);
01292           if (bOrder)
01293             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
01294              sizeof(MIB_IPNETROW), IpNetTableSorter);
01295           ret = NO_ERROR;
01296         }
01297         HeapFree(GetProcessHeap(), 0, table);
01298       }
01299     }
01300   }
01301   TRACE("returning %d\n", ret);
01302   return ret;
01303 }
01304 
01305 
01306 /******************************************************************
01307  *    GetIpStatistics (IPHLPAPI.@)
01308  *
01309  *
01310  * PARAMS
01311  *
01312  *  pStats [In/Out]
01313  *
01314  * RETURNS
01315  *
01316  *  DWORD
01317  *
01318  */
01319 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
01320 {
01321     return GetIpStatisticsEx(pStats, PF_INET);
01322 }
01323 
01324 /******************************************************************
01325  *    GetIpStatisticsEx (IPHLPAPI.@)
01326  *
01327  *
01328  * PARAMS
01329  *
01330  *  pStats [In/Out]
01331  *  dwFamily [In]
01332  *
01333  * RETURNS
01334  *
01335  *  DWORD
01336  *
01337  */
01338 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily)
01339 {
01340   DWORD ret;
01341 
01342   TRACE("pStats %p\n", pStats);
01343   ret = getIPStats(pStats, dwFamily);
01344   TRACE("returning %ld\n", ret);
01345   return ret;
01346 }
01347 
01348 /******************************************************************
01349  *    GetNetworkParams (IPHLPAPI.@)
01350  *
01351  *
01352  * PARAMS
01353  *
01354  *  pFixedInfo [In/Out]
01355  *  pOutBufLen [In/Out]
01356  *
01357  * RETURNS
01358  *
01359  *  DWORD
01360  *
01361  */
01362 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
01363 {
01364   DWORD ret, size;
01365   LONG regReturn;
01366   HKEY hKey;
01367   PIPHLP_RES_INFO resInfo;
01368 
01369   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
01370   if (!pOutBufLen)
01371     return ERROR_INVALID_PARAMETER;
01372 
01373   resInfo = getResInfo();
01374   if (!resInfo)
01375     return ERROR_OUTOFMEMORY;
01376 
01377   size = sizeof(FIXED_INFO) + (resInfo->riCount > 1 ? (resInfo->riCount-1) *
01378    sizeof(IP_ADDR_STRING) : 0);
01379   if (!pFixedInfo || *pOutBufLen < size) {
01380     *pOutBufLen = size;
01381     disposeResInfo( resInfo );
01382     return ERROR_BUFFER_OVERFLOW;
01383   }
01384 
01385   memset(pFixedInfo, 0, size);
01386   size = sizeof(pFixedInfo->HostName);
01387   GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
01388   size = sizeof(pFixedInfo->DomainName);
01389   GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
01390 
01391   TRACE("GetComputerNameExA: %s\n", pFixedInfo->DomainName);
01392 
01393   if (resInfo->riCount > 0) 
01394   {
01395     CopyMemory(&pFixedInfo->DnsServerList, resInfo->DnsList, sizeof(IP_ADDR_STRING));
01396     if (resInfo->riCount > 1)
01397     {
01398       IP_ADDR_STRING *pSrc = resInfo->DnsList->Next;
01399       IP_ADDR_STRING *pTarget = (struct _IP_ADDR_STRING*)((char*)pFixedInfo + sizeof(FIXED_INFO));
01400 
01401       pFixedInfo->DnsServerList.Next = pTarget;
01402 
01403       do
01404       {
01405         CopyMemory(pTarget, pSrc, sizeof(IP_ADDR_STRING));
01406         resInfo->riCount--;
01407         if (resInfo->riCount > 1)
01408         {
01409           pTarget->Next = (IP_ADDR_STRING*)((char*)pTarget + sizeof(IP_ADDR_STRING));
01410           pTarget = pTarget->Next;
01411           pSrc = pSrc->Next;
01412         }
01413         else
01414         {
01415           pTarget->Next = NULL;
01416           break;
01417         }
01418       }
01419       while(TRUE);
01420     }
01421     else
01422     {
01423       pFixedInfo->DnsServerList.Next = NULL;
01424     }
01425   }
01426 
01427   pFixedInfo->NodeType = HYBRID_NODETYPE;
01428   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
01429    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
01430   if (regReturn != ERROR_SUCCESS)
01431     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
01432      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
01433      &hKey);
01434   if (regReturn == ERROR_SUCCESS)
01435   {
01436     DWORD size = sizeof(pFixedInfo->ScopeId);
01437 
01438     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (PBYTE)pFixedInfo->ScopeId, &size);
01439     RegCloseKey(hKey);
01440   }
01441 
01442   disposeResInfo( resInfo );
01443   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
01444      I suppose could also check for a listener on port 53 to set EnableDns */
01445   ret = NO_ERROR;
01446   TRACE("returning %ld\n", ret);
01447 
01448   return ret;
01449 }
01450 
01451 
01452 /******************************************************************
01453  *    GetNumberOfInterfaces (IPHLPAPI.@)
01454  *
01455  *
01456  * PARAMS
01457  *
01458  *  pdwNumIf [In/Out]
01459  *
01460  * RETURNS
01461  *
01462  *  DWORD
01463  *
01464  */
01465 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
01466 {
01467   DWORD ret;
01468 
01469   TRACE("pdwNumIf %p\n", pdwNumIf);
01470   if (!pdwNumIf)
01471     ret = ERROR_INVALID_PARAMETER;
01472   else {
01473     *pdwNumIf = getNumInterfaces();
01474     ret = NO_ERROR;
01475   }
01476   TRACE("returning %ld\n", ret);
01477   return ret;
01478 }
01479 
01480 
01481 /******************************************************************
01482  *    GetOwnerModuleFromTcpEntry (IPHLPAPI.@)
01483  *
01484  * Get data about the module that issued the context bind for a specific IPv4 TCP endpoint in a MIB table row
01485  *
01486  * PARAMS
01487  *  pTcpEntry [in]    pointer to a MIB_TCPROW_OWNER_MODULE structure
01488  *  Class [in]      TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
01489  *  Buffer [out]        pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data. 
01490  *  pdwSize [in, out]   estimated size of the structure returned in Buffer, in bytes
01491  *
01492  * RETURNS
01493  *  Success: NO_ERROR
01494  *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
01495  *         ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
01496  *
01497  * NOTES
01498  * The type of data returned in Buffer is indicated by the value of the Class parameter.
01499  */
01500 DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
01501 {
01502     DWORD ret = NO_ERROR;
01503     UNIMPLEMENTED;
01504     return ret; 
01505 }
01506 
01507 
01508 /******************************************************************
01509  *    GetPerAdapterInfo (IPHLPAPI.@)
01510  *
01511  *
01512  * PARAMS
01513  *
01514  *  IfIndex [In]
01515  *  pPerAdapterInfo [In/Out]
01516  *  pOutBufLen [In/Out]
01517  *
01518  * RETURNS
01519  *
01520  *  DWORD
01521  *
01522  */
01523 static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
01524 {
01525   IP_ADDR_STRING *pNext;
01526   PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
01527 
01528   if (!Context->NumServers)
01529   {
01530     if (Context->uSizeAvailable >= Context->uSizeRequired)
01531     {
01532       WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
01533       Context->pData->DnsServerList.IpAddress.String[15] = '\0';
01534       Context->pLastAddr = &Context->pData->DnsServerList;
01535     }
01536   }
01537   else
01538   {
01539      Context->uSizeRequired += sizeof(IP_ADDR_STRING);
01540      if (Context->uSizeAvailable >= Context->uSizeRequired)
01541      {
01542          pNext = (IP_ADDR_STRING*)(((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING));
01543          WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
01544          pNext->IpAddress.String[15] = '\0';
01545          Context->pLastAddr->Next = pNext;
01546          Context->pLastAddr = pNext;
01547          pNext->Next = NULL;
01548      }
01549   }
01550   Context->NumServers++;
01551 }
01552 
01553 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
01554 {
01555   HKEY hkey;
01556   DWORD dwSize = 0;
01557   const char *ifName;
01558   NAME_SERVER_LIST_CONTEXT Context;
01559   WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
01560 
01561   if (!pOutBufLen)
01562     return ERROR_INVALID_PARAMETER;
01563 
01564   if (!pPerAdapterInfo || *pOutBufLen < sizeof(IP_PER_ADAPTER_INFO))
01565   {
01566     *pOutBufLen = sizeof(IP_PER_ADAPTER_INFO);
01567     return ERROR_BUFFER_OVERFLOW;
01568   }
01569 
01570   ifName = getInterfaceNameByIndex(IfIndex);
01571   if (!ifName)
01572     return ERROR_INVALID_PARAMETER;
01573 
01574   MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
01575   HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
01576 
01577   if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
01578   {
01579     return ERROR_NOT_SUPPORTED;
01580   }
01581   Context.NumServers = 0;
01582   Context.uSizeAvailable = *pOutBufLen;
01583   Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
01584   Context.pData = pPerAdapterInfo;
01585 
01586   if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
01587     ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
01588 
01589   EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
01590 
01591   if (Context.uSizeRequired > Context.uSizeAvailable)
01592   {
01593     *pOutBufLen = Context.uSizeRequired;
01594     RegCloseKey(hkey);
01595     return ERROR_BUFFER_OVERFLOW;
01596   }
01597 
01598   if(RegQueryValueExW(hkey, L"NameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
01599   {
01600     pPerAdapterInfo->AutoconfigActive = FALSE;
01601   }
01602   else
01603   {
01604     pPerAdapterInfo->AutoconfigActive = TRUE;
01605   }
01606 
01607   RegCloseKey(hkey);
01608   return NOERROR;
01609 }
01610 
01611 
01612 /******************************************************************
01613  *    GetRTTAndHopCount (IPHLPAPI.@)
01614  *
01615  *
01616  * PARAMS
01617  *
01618  *  DestIpAddress [In]
01619  *  HopCount [In/Out]
01620  *  MaxHops [In]
01621  *  RTT [In/Out]
01622  *
01623  * RETURNS
01624  *
01625  *  BOOL
01626  *
01627  */
01628 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
01629 {
01630   TRACE("DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p\n",
01631    DestIpAddress, HopCount, MaxHops, RTT);
01632   FIXME(":stub\n");
01633   return (BOOL) 0;
01634 }
01635 
01636 
01637 /******************************************************************
01638  *    GetTcpStatisticsEx (IPHLPAPI.@)
01639  *
01640  *
01641  * PARAMS
01642  *
01643  *  pStats [In/Out]
01644  *  dwFamily [In]
01645  *
01646  * RETURNS
01647  *
01648  *  DWORD
01649  *
01650  */
01651 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily)
01652 {
01653   DWORD ret;
01654 
01655   TRACE("pStats %p\n", pStats);
01656   ret = getTCPStats(pStats, dwFamily);
01657   TRACE("returning %ld\n", ret);
01658   return ret;
01659 }
01660 
01661 /******************************************************************
01662  *    GetTcpStatistics (IPHLPAPI.@)
01663  *
01664  *
01665  * PARAMS
01666  *
01667  *  pStats [In/Out]
01668  *
01669  * RETURNS
01670  *
01671  *  DWORD
01672  *
01673  */
01674 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
01675 {
01676     return GetTcpStatisticsEx(pStats, PF_INET);
01677 }
01678 
01679 
01680 static int TcpTableSorter(const void *a, const void *b)
01681 {
01682   int ret;
01683 
01684   if (a && b) {
01685     PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
01686 
01687     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
01688     if (ret == 0) {
01689       ret = rowA->dwLocalPort - rowB->dwLocalPort;
01690       if (ret == 0) {
01691         ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
01692         if (ret == 0)
01693           ret = rowA->dwRemotePort - rowB->dwRemotePort;
01694       }
01695     }
01696   }
01697   else
01698     ret = 0;
01699   return ret;
01700 }
01701 
01702 
01703 /******************************************************************
01704  *    GetTcpTable (IPHLPAPI.@)
01705  *
01706  * Get the table of active TCP connections.
01707  *
01708  * PARAMS
01709  *  pTcpTable [Out]    buffer for TCP connections table
01710  *  pdwSize   [In/Out] length of output buffer
01711  *  bOrder    [In]     whether to order the table
01712  *
01713  * RETURNS
01714  *  Success: NO_ERROR
01715  *  Failure: error code from winerror.h
01716  *
01717  * NOTES
01718  *  If pdwSize is less than required, the function will return 
01719  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to 
01720  *  the required byte size.
01721  *  If bOrder is true, the returned table will be sorted, first by
01722  *  local address and port number, then by remote address and port
01723  *  number.
01724  */
01725 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
01726 {
01727   DWORD ret = ERROR_NO_DATA;
01728 
01729   TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize,
01730    (DWORD)bOrder);
01731   if (!pdwSize)
01732     ret = ERROR_INVALID_PARAMETER;
01733   else {
01734     DWORD numEntries = getNumTcpEntries();
01735     DWORD size = sizeof(MIB_TCPTABLE);
01736 
01737     if (numEntries > 1)
01738       size += (numEntries - 1) * sizeof(MIB_TCPROW);
01739     if (!pTcpTable || *pdwSize < size) {
01740       *pdwSize = size;
01741       ret = ERROR_INSUFFICIENT_BUFFER;
01742     }
01743     else {
01744       PMIB_TCPTABLE pOurTcpTable = getTcpTable();
01745       if (pOurTcpTable)
01746       {
01747         size = sizeof(MIB_TCPTABLE);
01748         if (pOurTcpTable->dwNumEntries > 1)
01749             size += (pOurTcpTable->dwNumEntries - 1) * sizeof(MIB_TCPROW);
01750           
01751         if (*pdwSize < size)
01752         {
01753             *pdwSize = size;
01754 
01755             ret = ERROR_INSUFFICIENT_BUFFER;
01756         }
01757         else
01758         {
01759             memcpy(pTcpTable, pOurTcpTable, size);
01760             
01761             if (bOrder)
01762                 qsort(pTcpTable->table, pTcpTable->dwNumEntries,
01763                       sizeof(MIB_TCPROW), TcpTableSorter);
01764             
01765             ret = NO_ERROR;
01766         }
01767           
01768         free(pOurTcpTable);
01769       }
01770     }
01771   }
01772   TRACE("returning %d\n", ret);
01773   return ret;
01774 }
01775 
01776 
01777 /******************************************************************
01778  *    GetUdpStatisticsEx (IPHLPAPI.@)
01779  *
01780  *
01781  * PARAMS
01782  *
01783  *  pStats [In/Out]
01784  *  dwFamily [In]
01785  *
01786  * RETURNS
01787  *
01788  *  DWORD
01789  *
01790  */
01791 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS pStats, DWORD dwFamily)
01792 {
01793   DWORD ret;
01794 
01795   TRACE("pStats %p\n", pStats);
01796   ret = getUDPStats(pStats, dwFamily);
01797   TRACE("returning %ld\n", ret);
01798   return ret;
01799 }
01800 
01801 /******************************************************************
01802  *    GetUdpStatistics (IPHLPAPI.@)
01803  *
01804  *
01805  * PARAMS
01806  *
01807  *  pStats [In/Out]
01808  *
01809  * RETURNS
01810  *
01811  *  DWORD
01812  *
01813  */
01814 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
01815 {
01816     return GetUdpStatisticsEx(pStats, PF_INET);
01817 }
01818 
01819 
01820 static int UdpTableSorter(const void *a, const void *b)
01821 {
01822   int ret;
01823 
01824   if (a && b) {
01825     PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
01826 
01827     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
01828     if (ret == 0)
01829       ret = rowA->dwLocalPort - rowB->dwLocalPort;
01830   }
01831   else
01832     ret = 0;
01833   return ret;
01834 }
01835 
01836 
01837 /******************************************************************
01838  *    GetUdpTable (IPHLPAPI.@)
01839  *
01840  *
01841  * PARAMS
01842  *
01843  *  pUdpTable [In/Out]
01844  *  pdwSize [In/Out]
01845  *  bOrder [In]
01846  *
01847  * RETURNS
01848  *
01849  *  DWORD
01850  *
01851  */
01852 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
01853 {
01854   DWORD ret;
01855 
01856   TRACE("pUdpTable %p, pdwSize %p, bOrder %ld\n", pUdpTable, pdwSize,
01857    (DWORD)bOrder);
01858   if (!pdwSize)
01859     ret = ERROR_INVALID_PARAMETER;
01860   else {
01861     DWORD numEntries = getNumUdpEntries();
01862     ULONG size = sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW);
01863 
01864     if (!pUdpTable || *pdwSize < size) {
01865       *pdwSize = size;
01866       ret = ERROR_INSUFFICIENT_BUFFER;
01867     }
01868     else {
01869       PMIB_UDPTABLE table = getUdpTable();
01870 
01871       if (table) {
01872         size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) *
01873          sizeof(MIB_UDPROW);
01874         if (*pdwSize < size) {
01875           *pdwSize = size;
01876           ret = ERROR_INSUFFICIENT_BUFFER;
01877         }
01878         else {
01879           memcpy(pUdpTable, table, size);
01880           if (bOrder)
01881             qsort(pUdpTable->table, pUdpTable->dwNumEntries,
01882              sizeof(MIB_UDPROW), UdpTableSorter);
01883           ret = NO_ERROR;
01884         }
01885         free(table);
01886       }
01887       else
01888         ret = ERROR_OUTOFMEMORY;
01889     }
01890   }
01891   TRACE("returning %ld\n", ret);
01892   return ret;
01893 }
01894 
01895 
01896 /******************************************************************
01897  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
01898  *
01899  * This is a Win98-only function to get information on "unidirectional"
01900  * adapters.  Since this is pretty nonsensical in other contexts, it
01901  * never returns anything.
01902  *
01903  * PARAMS
01904  *  pIPIfInfo   [Out] buffer for adapter infos
01905  *  dwOutBufLen [Out] length of the output buffer
01906  *
01907  * RETURNS
01908  *  Success: NO_ERROR
01909  *  Failure: error code from winerror.h
01910  *
01911  * FIXME
01912  *  Stub, returns ERROR_NOT_SUPPORTED.
01913  */
01914 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
01915 {
01916   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
01917   /* a unidirectional adapter?? not bloody likely! */
01918   return ERROR_NOT_SUPPORTED;
01919 }
01920 
01921 
01922 /******************************************************************
01923  *    IpReleaseAddress (IPHLPAPI.@)
01924  *
01925  * Release an IP obtained through DHCP,
01926  *
01927  * PARAMS
01928  *  AdapterInfo [In] adapter to release IP address
01929  *
01930  * RETURNS
01931  *  Success: NO_ERROR
01932  *  Failure: error code from winerror.h
01933  *
01934  */
01935 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
01936 {
01937   DWORD Status, Version = 0;
01938 
01939   if (!AdapterInfo || !AdapterInfo->Name)
01940       return ERROR_INVALID_PARAMETER;
01941 
01942   /* Maybe we should do this in DllMain */
01943   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
01944       return ERROR_PROC_NOT_FOUND;
01945 
01946   if (DhcpReleaseIpAddressLease(AdapterInfo->Index))
01947       Status = ERROR_SUCCESS;
01948   else
01949       Status = ERROR_PROC_NOT_FOUND;
01950 
01951   DhcpCApiCleanup();
01952 
01953   return Status;
01954 }
01955 
01956 
01957 /******************************************************************
01958  *    IpRenewAddress (IPHLPAPI.@)
01959  *
01960  * Renew an IP obtained through DHCP.
01961  *
01962  * PARAMS
01963  *  AdapterInfo [In] adapter to renew IP address
01964  *
01965  * RETURNS
01966  *  Success: NO_ERROR
01967  *  Failure: error code from winerror.h
01968  */
01969 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
01970 {
01971   DWORD Status, Version = 0;
01972 
01973   if (!AdapterInfo || !AdapterInfo->Name)
01974       return ERROR_INVALID_PARAMETER;
01975 
01976   /* Maybe we should do this in DllMain */
01977   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
01978       return ERROR_PROC_NOT_FOUND;
01979 
01980   if (DhcpRenewIpAddressLease(AdapterInfo->Index))
01981       Status = ERROR_SUCCESS;
01982   else
01983       Status = ERROR_PROC_NOT_FOUND;
01984 
01985   DhcpCApiCleanup();
01986 
01987   return Status;
01988 }
01989 
01990 
01991 /******************************************************************
01992  *    NotifyAddrChange (IPHLPAPI.@)
01993  *
01994  * Notify caller whenever the ip-interface map is changed.
01995  *
01996  * PARAMS
01997  *  Handle     [Out] handle usable in asynchronous notification
01998  *  overlapped [In]  overlapped structure that notifies the caller
01999  *
02000  * RETURNS
02001  *  Success: NO_ERROR
02002  *  Failure: error code from winerror.h
02003  *
02004  * FIXME
02005  *  Stub, returns ERROR_NOT_SUPPORTED.
02006  */
02007 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
02008 {
02009   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
02010   return ERROR_NOT_SUPPORTED;
02011 }
02012 
02013 
02014 /******************************************************************
02015  *    NotifyRouteChange (IPHLPAPI.@)
02016  *
02017  * Notify caller whenever the ip routing table is changed.
02018  *
02019  * PARAMS
02020  *  Handle     [Out] handle usable in asynchronous notification
02021  *  overlapped [In]  overlapped structure that notifies the caller
02022  *
02023  * RETURNS
02024  *  Success: NO_ERROR
02025  *  Failure: error code from winerror.h
02026  *
02027  * FIXME
02028  *  Stub, returns ERROR_NOT_SUPPORTED.
02029  */
02030 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
02031 {
02032   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
02033   return ERROR_NOT_SUPPORTED;
02034 }
02035 
02036 
02037 /******************************************************************
02038  *    SendARP (IPHLPAPI.@)
02039  *
02040  * Send an ARP request.
02041  *
02042  * PARAMS
02043  *  DestIP     [In]     attempt to obtain this IP
02044  *  SrcIP      [In]     optional sender IP address
02045  *  pMacAddr   [Out]    buffer for the mac address
02046  *  PhyAddrLen [In/Out] length of the output buffer
02047  *
02048  * RETURNS
02049  *  Success: NO_ERROR
02050  *  Failure: error code from winerror.h
02051  *
02052  * FIXME
02053  *  Stub, returns ERROR_NOT_SUPPORTED.
02054  */
02055 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
02056 {
02057   FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
02058    DestIP, SrcIP, pMacAddr, PhyAddrLen);
02059   return ERROR_NOT_SUPPORTED;
02060 }
02061 
02062 
02063 /******************************************************************
02064  *    SetIfEntry (IPHLPAPI.@)
02065  *
02066  * Set the administrative status of an interface.
02067  *
02068  * PARAMS
02069  *  pIfRow [In] dwAdminStatus member specifies the new status.
02070  *
02071  * RETURNS
02072  *  Success: NO_ERROR
02073  *  Failure: error code from winerror.h
02074  *
02075  * FIXME
02076  *  Stub, returns ERROR_NOT_SUPPORTED.
02077  */
02078 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
02079 {
02080   FIXME("(pIfRow %p): stub\n", pIfRow);
02081   /* this is supposed to set an interface administratively up or down.
02082      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
02083      this sort of down is indistinguishable from other sorts of down (e.g. no
02084      link). */
02085   return ERROR_NOT_SUPPORTED;
02086 }
02087 
02088 
02089 /******************************************************************
02090  *    SetIpForwardEntry (IPHLPAPI.@)
02091  *
02092  * Modify an existing route.
02093  *
02094  * PARAMS
02095  *  pRoute [In] route with the new information
02096  *
02097  * RETURNS
02098  *  Success: NO_ERROR
02099  *  Failure: error code from winerror.h
02100  *
02101  */
02102 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
02103 {
02104     return setIpForwardEntry( pRoute );
02105 }
02106 
02107 
02108 /******************************************************************
02109  *    SetIpNetEntry (IPHLPAPI.@)
02110  *
02111  * Modify an existing ARP entry.
02112  *
02113  * PARAMS
02114  *  pArpEntry [In] ARP entry with the new information
02115  *
02116  * RETURNS
02117  *  Success: NO_ERROR
02118  *  Failure: error code from winerror.h
02119  */
02120 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
02121 {
02122   HANDLE tcpFile;
02123   NTSTATUS status;
02124   TCP_REQUEST_SET_INFORMATION_EX_ARP_ENTRY req =
02125       TCP_REQUEST_SET_INFORMATION_INIT;
02126   TDIEntityID id;
02127   DWORD returnSize;
02128   PMIB_IPNETROW arpBuff;
02129 
02130   if (!pArpEntry)
02131       return ERROR_INVALID_PARAMETER;
02132 
02133   if (!NT_SUCCESS(openTcpFile( &tcpFile )))
02134       return ERROR_NOT_SUPPORTED;
02135 
02136   if (!NT_SUCCESS(getNthIpEntity( tcpFile, pArpEntry->dwIndex, &id )))
02137   {
02138       closeTcpFile(tcpFile);
02139       return ERROR_INVALID_PARAMETER;
02140   }
02141 
02142   req.Req.ID.toi_class = INFO_CLASS_PROTOCOL;
02143   req.Req.ID.toi_type = INFO_TYPE_PROVIDER;
02144   req.Req.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
02145   req.Req.ID.toi_entity.tei_instance = id.tei_instance;
02146   req.Req.ID.toi_entity.tei_entity = AT_ENTITY;
02147   req.Req.BufferSize = sizeof(MIB_IPNETROW);
02148   arpBuff = (PMIB_IPNETROW)&req.Req.Buffer[0];
02149 
02150   RtlCopyMemory(arpBuff, pArpEntry, sizeof(MIB_IPNETROW));
02151 
02152   status = DeviceIoControl( tcpFile,
02153                             IOCTL_TCP_SET_INFORMATION_EX,
02154                             &req,
02155                             sizeof(req),
02156                             NULL,
02157                             0,
02158                             &returnSize,
02159                             NULL );
02160 
02161   closeTcpFile(tcpFile);
02162 
02163   if (status)
02164      return NO_ERROR;
02165   else
02166      return ERROR_INVALID_PARAMETER;
02167 }
02168 
02169 
02170 /******************************************************************
02171  *    SetIpStatistics (IPHLPAPI.@)
02172  *
02173  * Toggle IP forwarding and det the default TTL value.
02174  *
02175  * PARAMS
02176  *  pIpStats [In] IP statistics with the new information
02177  *
02178  * RETURNS
02179  *  Success: NO_ERROR
02180  *  Failure: error code from winerror.h
02181  *
02182  * FIXME
02183  *  Stub, returns NO_ERROR.
02184  */
02185 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
02186 {
02187   FIXME("(pIpStats %p): stub\n", pIpStats);
02188   return 0;
02189 }
02190 
02191 
02192 /******************************************************************
02193  *    SetIpTTL (IPHLPAPI.@)
02194  *
02195  * Set the default TTL value.
02196  *
02197  * PARAMS
02198  *  nTTL [In] new TTL value
02199  *
02200  * RETURNS
02201  *  Success: NO_ERROR
02202  *  Failure: error code from winerror.h
02203  *
02204  * FIXME
02205  *  Stub, returns NO_ERROR.
02206  */
02207 DWORD WINAPI SetIpTTL(UINT nTTL)
02208 {
02209   FIXME("(nTTL %d): stub\n", nTTL);
02210   return 0;
02211 }
02212 
02213 
02214 /******************************************************************
02215  *    SetTcpEntry (IPHLPAPI.@)
02216  *
02217  * Set the state of a TCP connection.
02218  *
02219  * PARAMS
02220  *  pTcpRow [In] specifies connection with new state
02221  *
02222  * RETURNS
02223  *  Success: NO_ERROR
02224  *  Failure: error code from winerror.h
02225  *
02226  * FIXME
02227  *  Stub, returns NO_ERROR.
02228  */
02229 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
02230 {
02231   FIXME("(pTcpRow %p): stub\n", pTcpRow);
02232   return 0;
02233 }
02234 
02235 
02236 /******************************************************************
02237  *    UnenableRouter (IPHLPAPI.@)
02238  *
02239  * Decrement the IP-forwarding reference count. Turn off IP-forwarding
02240  * if it reaches zero.
02241  *
02242  * PARAMS
02243  *  pOverlapped     [In/Out] should be the same as in EnableRouter()
02244  *  lpdwEnableCount [Out]    optional, receives reference count
02245  *
02246  * RETURNS
02247  *  Success: NO_ERROR
02248  *  Failure: error code from winerror.h
02249  *
02250  * FIXME
02251  *  Stub, returns ERROR_NOT_SUPPORTED.
02252  */
02253 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
02254 {
02255   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
02256    lpdwEnableCount);
02257   return ERROR_NOT_SUPPORTED;
02258 }
02259 
02260 /*
02261  * @unimplemented
02262  */
02263 DWORD WINAPI GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)
02264 {
02265     FIXME(":stub\n");
02266     return 0L;
02267 }
02268 
02269 
02270 /*
02271  * @unimplemented
02272  */
02273 PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
02274 {
02275     FIXME(":stub\n");
02276     return 0L;
02277 }
02278 
02279 /*
02280  * @implemented
02281  */
02282 DWORD WINAPI GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
02283 {
02284 #if 0
02285     InterfaceIndexTable *indexTable;
02286     IFInfo ifInfo;
02287     int i;
02288     ULONG ret, requiredSize = 0;
02289     PIP_ADAPTER_ADDRESSES currentAddress;
02290     PUCHAR currentLocation;
02291     HANDLE tcpFile;
02292 
02293     if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
02294     if (Reserved) return ERROR_INVALID_PARAMETER;
02295 
02296     indexTable = getNonLoopbackInterfaceIndexTable(); //I think we want non-loopback here
02297     if (!indexTable)
02298         return ERROR_NOT_ENOUGH_MEMORY;
02299 
02300     ret = openTcpFile(&tcpFile);
02301     if (!NT_SUCCESS(ret))
02302         return ERROR_NO_DATA;
02303 
02304     for (i = indexTable->numIndexes; i >= 0; i--)
02305     {
02306         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
02307                                            NULL,
02308                                            indexTable->indexes[i],
02309                                            &ifInfo)))
02310         {
02311             /* The whole struct */
02312             requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
02313 
02314             /* Friendly name */
02315             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
02316                 requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1; //FIXME
02317 
02318             /* Adapter name */
02319             requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
02320 
02321             /* Unicast address */
02322             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
02323                 requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
02324 
02325             /* FIXME: Implement multicast, anycast, and dns server stuff */
02326 
02327             /* FIXME: Implement dns suffix and description */
02328             requiredSize += 2 * sizeof(WCHAR);
02329 
02330             /* We're only going to implement what's required for XP SP0 */
02331         }
02332     }
02333 
02334     if (*pOutBufLen < requiredSize)
02335     {
02336         *pOutBufLen = requiredSize;
02337         closeTcpFile(tcpFile);
02338         free(indexTable);
02339         return ERROR_BUFFER_OVERFLOW;
02340     }
02341 
02342     RtlZeroMemory(pAdapterAddresses, requiredSize);
02343 
02344     /* Let's set up the pointers */
02345     currentAddress = pAdapterAddresses;
02346     for (i = indexTable->numIndexes; i >= 0; i--)
02347     {
02348         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
02349                                            NULL,
02350                                            indexTable->indexes[i],
02351                                            &ifInfo)))
02352         {
02353             currentLocation = (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
02354 
02355             /* FIXME: Friendly name */
02356             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
02357             {
02358                 currentAddress->FriendlyName = (PVOID)currentLocation;
02359                 currentLocation += sizeof(WCHAR);
02360             }
02361 
02362             /* Adapter name */
02363             currentAddress->AdapterName = (PVOID)currentLocation;
02364             currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
02365 
02366             /* Unicast address */
02367             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
02368             {
02369                 currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
02370                 currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
02371                 currentAddress->FirstUnicastAddress->Address.lpSockaddr = (PVOID)currentLocation;
02372                 currentLocation += sizeof(struct sockaddr);
02373             }
02374 
02375             /* FIXME: Implement multicast, anycast, and dns server stuff */
02376 
02377             /* FIXME: Implement dns suffix and description */
02378             currentAddress->DnsSuffix = (PVOID)currentLocation;
02379             currentLocation += sizeof(WCHAR);
02380 
02381             currentAddress->Description = (PVOID)currentLocation;
02382             currentLocation += sizeof(WCHAR);
02383 
02384             currentAddress->Next = (PVOID)currentLocation;
02385 
02386             /* We're only going to implement what's required for XP SP0 */
02387 
02388             currentAddress = currentAddress->Next;
02389         }
02390     }
02391 
02392     /* Terminate the last address correctly */
02393     if (currentAddress)
02394         currentAddress->Next = NULL;
02395 
02396     /* Now again, for real this time */
02397 
02398     currentAddress = pAdapterAddresses;
02399     for (i = indexTable->numIndexes; i >= 0; i--)
02400     {
02401         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
02402                                            NULL,
02403                                            indexTable->indexes[i],
02404                                            &ifInfo)))
02405         {
02406             /* Make sure we're not looping more than we hoped for */
02407             ASSERT(currentAddress);
02408 
02409             /* Alignment information */
02410             currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
02411             currentAddress->IfIndex = indexTable->indexes[i];
02412 
02413             /* Adapter name */
02414             strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr);
02415 
02416             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
02417             {
02418                 currentAddress->FirstUnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
02419                 currentAddress->FirstUnicastAddress->Flags = 0; //FIXME
02420                 currentAddress->FirstUnicastAddress->Next = NULL; //FIXME: Support more than one address per adapter
02421                 currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
02422                 memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
02423                        &ifInfo.ip_addr.iae_addr,
02424                        sizeof(ifInfo.ip_addr.iae_addr));
02425                 currentAddress->FirstUnicastAddress->Address.iSockaddrLength = sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
02426                 currentAddress->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; //FIXME
02427                 currentAddress->FirstUnicastAddress->SuffixOrigin = IpPrefixOriginOther; //FIXME
02428                 currentAddress->FirstUnicastAddress->DadState = IpDadStatePreferred; //FIXME
02429                 currentAddress->FirstUnicastAddress->ValidLifetime = 0xFFFFFFFF; //FIXME
02430                 currentAddress->FirstUnicastAddress->PreferredLifetime = 0xFFFFFFFF; //FIXME
02431                 currentAddress->FirstUnicastAddress->LeaseLifetime = 0xFFFFFFFF; //FIXME
02432             }
02433 
02434             /* FIXME: Implement multicast, anycast, and dns server stuff */
02435             currentAddress->FirstAnycastAddress = NULL;
02436             currentAddress->FirstMulticastAddress = NULL;
02437             currentAddress->FirstDnsServerAddress = NULL;
02438 
02439             /* FIXME: Implement dns suffix, description, and friendly name */
02440             currentAddress->DnsSuffix[0] = UNICODE_NULL;
02441             currentAddress->Description[0] = UNICODE_NULL;
02442             currentAddress->FriendlyName[0] = UNICODE_NULL;
02443 
02444             /* Physical Address */
02445             memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, ifInfo.if_info.ent.if_physaddrlen);
02446             currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
02447 
02448             /* Flags */
02449             currentAddress->Flags = 0; //FIXME
02450 
02451             /* MTU */
02452             currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
02453 
02454             /* Interface type */
02455             currentAddress->IfType = ifInfo.if_info.ent.if_type;
02456 
02457             /* Operational status */
02458             currentAddress->OperStatus = ifInfo.if_info.ent.if_operstatus;
02459 
02460             /* We're only going to implement what's required for XP SP0 */
02461 
02462             /* Move to the next address */
02463             currentAddress = currentAddress->Next;
02464         }
02465     }
02466 
02467     closeTcpFile(tcpFile);
02468     free(indexTable);
02469 
02470     return NO_ERROR;
02471 #else
02472     if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
02473     if (!pAdapterAddresses || *pOutBufLen == 0)
02474       return ERROR_BUFFER_OVERFLOW;
02475     if (Reserved) return ERROR_INVALID_PARAMETER;
02476 
02477     FIXME(":stub\n");
02478     return ERROR_NO_DATA;
02479 #endif
02480 }
02481 
02482 /*
02483  * @unimplemented
02484  */
02485 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)
02486 {
02487     FIXME(":stub\n");
02488     return 0L;
02489 }
02490 
02491 /*
02492  * @unimplemented
02493  */
02494 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex)
02495 {
02496     FIXME(":stub\n");
02497     return 0L;
02498 }
02499 
02500 /*
02501  * @unimplemented
02502  */
02503 DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)
02504 {
02505     FIXME(":stub\n");
02506     return 0L;
02507 }
02508 
02509 /*
02510  * @unimplemented
02511  */
02512 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
02513 {
02514     FIXME(":stub\n");
02515     return 0L;
02516 }
02517 
02518 /******************************************************************
02519  *    GetIfTable2 (IPHLPAPI.@)
02520  *
02521  * PARAMS
02522  *  pIfTable [In/Out]
02523  */
02524  
02525 NETIOAPI_API WINAPI GetIfTable2(PMIB_IF_TABLE2 *pIfTable)
02526 {
02527     UNIMPLEMENTED;
02528     return ERROR_NOT_SUPPORTED;
02529 }
02530 
02531 /******************************************************************
02532  *    GetIfEntry2 (IPHLPAPI.@)
02533  *
02534  * PARAMS
02535  *  pIfRow [In/Out]
02536  */
02537 NETIOAPI_API WINAPI GetIfEntry2(IN OUT PMIB_IF_ROW2 pIfRow)
02538 {
02539   TRACE("pIfRow %p\n", pIfRow);
02540   if (!pIfRow)
02541     return ERROR_INVALID_PARAMETER;
02542     
02543   UNIMPLEMENTED;
02544   return ERROR_NOT_SUPPORTED;
02545 }
02546 
02547 DWORD WINAPI
02548 SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)
02549 {
02550     FIXME("SetIpForwardEntryToStack() stub\n");
02551     return 0L;
02552 }
02553 
02554 DWORD WINAPI
02555 NhGetInterfaceNameFromDeviceGuid(DWORD dwUnknown1,
02556                                  DWORD dwUnknown2,
02557                                  DWORD dwUnknown3,
02558                                  DWORD dwUnknown4,
02559                                  DWORD dwUnknown5)
02560 {
02561     FIXME("NhGetInterfaceNameFromDeviceGuid() stub\n");
02562     return 0L;
02563 }

Generated on Sat May 26 2012 04:22:42 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.