dmsynth: Dump data passed to Download method.
[wine] / dlls / iphlpapi / iphlpapi_main.c
1 /*
2  * iphlpapi dll implementation
3  *
4  * Copyright (C) 2003,2006 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #ifdef HAVE_NETINET_IN_H
27 # include <netinet/in.h>
28 #endif
29 #ifdef HAVE_ARPA_INET_H
30 # include <arpa/inet.h>
31 #endif
32 #ifdef HAVE_ARPA_NAMESER_H
33 # include <arpa/nameser.h>
34 #endif
35 #ifdef HAVE_RESOLV_H
36 # include <resolv.h>
37 #endif
38
39 #define NONAMELESSUNION
40 #define NONAMELESSSTRUCT
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winreg.h"
44 #define USE_WS_PREFIX
45 #include "winsock2.h"
46 #include "winternl.h"
47 #include "ws2ipdef.h"
48 #include "iphlpapi.h"
49 #include "ifenum.h"
50 #include "ipstats.h"
51 #include "ipifcons.h"
52 #include "fltdefs.h"
53
54 #include "wine/debug.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
57
58 #ifndef IF_NAMESIZE
59 #define IF_NAMESIZE 16
60 #endif
61
62 #ifndef INADDR_NONE
63 #define INADDR_NONE ~0UL
64 #endif
65
66 /* call res_init() just once because of a bug in Mac OS X 10.4 */
67 /* Call once per thread on systems that have per-thread _res. */
68 static void initialise_resolver(void)
69 {
70     if ((_res.options & RES_INIT) == 0)
71         res_init();
72 }
73
74 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
75 {
76   switch (fdwReason) {
77     case DLL_PROCESS_ATTACH:
78       DisableThreadLibraryCalls( hinstDLL );
79       break;
80
81     case DLL_PROCESS_DETACH:
82       break;
83   }
84   return TRUE;
85 }
86
87 /******************************************************************
88  *    AddIPAddress (IPHLPAPI.@)
89  *
90  * Add an IP address to an adapter.
91  *
92  * PARAMS
93  *  Address     [In]  IP address to add to the adapter
94  *  IpMask      [In]  subnet mask for the IP address
95  *  IfIndex     [In]  adapter index to add the address
96  *  NTEContext  [Out] Net Table Entry (NTE) context for the IP address
97  *  NTEInstance [Out] NTE instance for the IP address
98  *
99  * RETURNS
100  *  Success: NO_ERROR
101  *  Failure: error code from winerror.h
102  *
103  * FIXME
104  *  Stub. Currently returns ERROR_NOT_SUPPORTED.
105  */
106 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG NTEContext, PULONG NTEInstance)
107 {
108   FIXME(":stub\n");
109   return ERROR_NOT_SUPPORTED;
110 }
111
112
113 /******************************************************************
114  *    AllocateAndGetIfTableFromStack (IPHLPAPI.@)
115  *
116  * Get table of local interfaces.
117  * Like GetIfTable(), but allocate the returned table from heap.
118  *
119  * PARAMS
120  *  ppIfTable [Out] pointer into which the MIB_IFTABLE is
121  *                  allocated and returned.
122  *  bOrder    [In]  whether to sort the table
123  *  heap      [In]  heap from which the table is allocated
124  *  flags     [In]  flags to HeapAlloc
125  *
126  * RETURNS
127  *  ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
128  *  GetIfTable() returns otherwise.
129  */
130 DWORD WINAPI AllocateAndGetIfTableFromStack(PMIB_IFTABLE *ppIfTable,
131  BOOL bOrder, HANDLE heap, DWORD flags)
132 {
133   DWORD ret;
134
135   TRACE("ppIfTable %p, bOrder %d, heap %p, flags 0x%08x\n", ppIfTable,
136         bOrder, heap, flags);
137   if (!ppIfTable)
138     ret = ERROR_INVALID_PARAMETER;
139   else {
140     DWORD dwSize = 0;
141
142     ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
143     if (ret == ERROR_INSUFFICIENT_BUFFER) {
144       *ppIfTable = HeapAlloc(heap, flags, dwSize);
145       ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
146     }
147   }
148   TRACE("returning %d\n", ret);
149   return ret;
150 }
151
152
153 static int IpAddrTableSorter(const void *a, const void *b)
154 {
155   int ret;
156
157   if (a && b)
158     ret = ((const MIB_IPADDRROW*)a)->dwAddr - ((const MIB_IPADDRROW*)b)->dwAddr;
159   else
160     ret = 0;
161   return ret;
162 }
163
164
165 /******************************************************************
166  *    AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
167  *
168  * Get interface-to-IP address mapping table. 
169  * Like GetIpAddrTable(), but allocate the returned table from heap.
170  *
171  * PARAMS
172  *  ppIpAddrTable [Out] pointer into which the MIB_IPADDRTABLE is
173  *                      allocated and returned.
174  *  bOrder        [In]  whether to sort the table
175  *  heap          [In]  heap from which the table is allocated
176  *  flags         [In]  flags to HeapAlloc
177  *
178  * RETURNS
179  *  ERROR_INVALID_PARAMETER if ppIpAddrTable is NULL, other error codes on
180  *  failure, NO_ERROR on success.
181  */
182 DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
183  BOOL bOrder, HANDLE heap, DWORD flags)
184 {
185   DWORD ret;
186
187   TRACE("ppIpAddrTable %p, bOrder %d, heap %p, flags 0x%08x\n",
188    ppIpAddrTable, bOrder, heap, flags);
189   ret = getIPAddrTable(ppIpAddrTable, heap, flags);
190   if (!ret && bOrder)
191     qsort((*ppIpAddrTable)->table, (*ppIpAddrTable)->dwNumEntries,
192      sizeof(MIB_IPADDRROW), IpAddrTableSorter);
193   TRACE("returning %d\n", ret);
194   return ret;
195 }
196
197
198 /******************************************************************
199  *    CancelIPChangeNotify (IPHLPAPI.@)
200  *
201  * Cancel a previous notification created by NotifyAddrChange or
202  * NotifyRouteChange.
203  *
204  * PARAMS
205  *  overlapped [In]  overlapped structure that notifies the caller
206  *
207  * RETURNS
208  *  Success: TRUE
209  *  Failure: FALSE
210  *
211  * FIXME
212  *  Stub, returns FALSE.
213  */
214 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED overlapped)
215 {
216   FIXME("(overlapped %p): stub\n", overlapped);
217   return FALSE;
218 }
219
220
221
222 /******************************************************************
223  *    CreateIpForwardEntry (IPHLPAPI.@)
224  *
225  * Create a route in the local computer's IP table.
226  *
227  * PARAMS
228  *  pRoute [In] new route information
229  *
230  * RETURNS
231  *  Success: NO_ERROR
232  *  Failure: error code from winerror.h
233  *
234  * FIXME
235  *  Stub, always returns NO_ERROR.
236  */
237 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
238 {
239   FIXME("(pRoute %p): stub\n", pRoute);
240   /* could use SIOCADDRT, not sure I want to */
241   return 0;
242 }
243
244
245 /******************************************************************
246  *    CreateIpNetEntry (IPHLPAPI.@)
247  *
248  * Create entry in the ARP table.
249  *
250  * PARAMS
251  *  pArpEntry [In] new ARP entry
252  *
253  * RETURNS
254  *  Success: NO_ERROR
255  *  Failure: error code from winerror.h
256  *
257  * FIXME
258  *  Stub, always returns NO_ERROR.
259  */
260 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
261 {
262   FIXME("(pArpEntry %p)\n", pArpEntry);
263   /* could use SIOCSARP on systems that support it, not sure I want to */
264   return 0;
265 }
266
267
268 /******************************************************************
269  *    CreateProxyArpEntry (IPHLPAPI.@)
270  *
271  * Create a Proxy ARP (PARP) entry for an IP address.
272  *
273  * PARAMS
274  *  dwAddress [In] IP address for which this computer acts as a proxy. 
275  *  dwMask    [In] subnet mask for dwAddress
276  *  dwIfIndex [In] interface index
277  *
278  * RETURNS
279  *  Success: NO_ERROR
280  *  Failure: error code from winerror.h
281  *
282  * FIXME
283  *  Stub, returns ERROR_NOT_SUPPORTED.
284  */
285 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
286 {
287   FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
288    dwAddress, dwMask, dwIfIndex);
289   return ERROR_NOT_SUPPORTED;
290 }
291
292
293 /******************************************************************
294  *    DeleteIPAddress (IPHLPAPI.@)
295  *
296  * Delete an IP address added with AddIPAddress().
297  *
298  * PARAMS
299  *  NTEContext [In] NTE context from AddIPAddress();
300  *
301  * RETURNS
302  *  Success: NO_ERROR
303  *  Failure: error code from winerror.h
304  *
305  * FIXME
306  *  Stub, returns ERROR_NOT_SUPPORTED.
307  */
308 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
309 {
310   FIXME("(NTEContext %d): stub\n", NTEContext);
311   return ERROR_NOT_SUPPORTED;
312 }
313
314
315 /******************************************************************
316  *    DeleteIpForwardEntry (IPHLPAPI.@)
317  *
318  * Delete a route.
319  *
320  * PARAMS
321  *  pRoute [In] route to delete
322  *
323  * RETURNS
324  *  Success: NO_ERROR
325  *  Failure: error code from winerror.h
326  *
327  * FIXME
328  *  Stub, returns NO_ERROR.
329  */
330 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
331 {
332   FIXME("(pRoute %p): stub\n", pRoute);
333   /* could use SIOCDELRT, not sure I want to */
334   return 0;
335 }
336
337
338 /******************************************************************
339  *    DeleteIpNetEntry (IPHLPAPI.@)
340  *
341  * Delete an ARP entry.
342  *
343  * PARAMS
344  *  pArpEntry [In] ARP entry to delete
345  *
346  * RETURNS
347  *  Success: NO_ERROR
348  *  Failure: error code from winerror.h
349  *
350  * FIXME
351  *  Stub, returns NO_ERROR.
352  */
353 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
354 {
355   FIXME("(pArpEntry %p): stub\n", pArpEntry);
356   /* could use SIOCDARP on systems that support it, not sure I want to */
357   return 0;
358 }
359
360
361 /******************************************************************
362  *    DeleteProxyArpEntry (IPHLPAPI.@)
363  *
364  * Delete a Proxy ARP entry.
365  *
366  * PARAMS
367  *  dwAddress [In] IP address for which this computer acts as a proxy. 
368  *  dwMask    [In] subnet mask for dwAddress
369  *  dwIfIndex [In] interface index
370  *
371  * RETURNS
372  *  Success: NO_ERROR
373  *  Failure: error code from winerror.h
374  *
375  * FIXME
376  *  Stub, returns ERROR_NOT_SUPPORTED.
377  */
378 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
379 {
380   FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
381    dwAddress, dwMask, dwIfIndex);
382   return ERROR_NOT_SUPPORTED;
383 }
384
385
386 /******************************************************************
387  *    EnableRouter (IPHLPAPI.@)
388  *
389  * Turn on ip forwarding.
390  *
391  * PARAMS
392  *  pHandle     [In/Out]
393  *  pOverlapped [In/Out] hEvent member should contain a valid handle.
394  *
395  * RETURNS
396  *  Success: ERROR_IO_PENDING
397  *  Failure: error code from winerror.h
398  *
399  * FIXME
400  *  Stub, returns ERROR_NOT_SUPPORTED.
401  */
402 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
403 {
404   FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle, pOverlapped);
405   /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
406      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
407    */
408   return ERROR_NOT_SUPPORTED;
409 }
410
411
412 /******************************************************************
413  *    FlushIpNetTable (IPHLPAPI.@)
414  *
415  * Delete all ARP entries of an interface
416  *
417  * PARAMS
418  *  dwIfIndex [In] interface index
419  *
420  * RETURNS
421  *  Success: NO_ERROR
422  *  Failure: error code from winerror.h
423  *
424  * FIXME
425  *  Stub, returns ERROR_NOT_SUPPORTED.
426  */
427 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
428 {
429   FIXME("(dwIfIndex 0x%08x): stub\n", dwIfIndex);
430   /* this flushes the arp cache of the given index */
431   return ERROR_NOT_SUPPORTED;
432 }
433
434
435 /******************************************************************
436  *    GetAdapterIndex (IPHLPAPI.@)
437  *
438  * Get interface index from its name.
439  *
440  * PARAMS
441  *  AdapterName [In]  unicode string with the adapter name
442  *  IfIndex     [Out] returns found interface index
443  *
444  * RETURNS
445  *  Success: NO_ERROR
446  *  Failure: error code from winerror.h
447  */
448 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
449 {
450   char adapterName[MAX_ADAPTER_NAME];
451   unsigned int i;
452   DWORD ret;
453
454   TRACE("(AdapterName %p, IfIndex %p)\n", AdapterName, IfIndex);
455   /* The adapter name is guaranteed not to have any unicode characters, so
456    * this translation is never lossy */
457   for (i = 0; i < sizeof(adapterName) - 1 && AdapterName[i]; i++)
458     adapterName[i] = (char)AdapterName[i];
459   adapterName[i] = '\0';
460   ret = getInterfaceIndexByName(adapterName, IfIndex);
461   TRACE("returning %d\n", ret);
462   return ret;
463 }
464
465
466 /******************************************************************
467  *    GetAdaptersInfo (IPHLPAPI.@)
468  *
469  * Get information about adapters.
470  *
471  * PARAMS
472  *  pAdapterInfo [Out] buffer for adapter infos
473  *  pOutBufLen   [In]  length of output buffer
474  *
475  * RETURNS
476  *  Success: NO_ERROR
477  *  Failure: error code from winerror.h
478  */
479 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
480 {
481   DWORD ret;
482
483   TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
484   if (!pOutBufLen)
485     ret = ERROR_INVALID_PARAMETER;
486   else {
487     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
488
489     if (numNonLoopbackInterfaces > 0) {
490       DWORD numIPAddresses = getNumIPAddresses();
491       ULONG size;
492
493       /* This may slightly overestimate the amount of space needed, because
494        * the IP addresses include the loopback address, but it's easier
495        * to make sure there's more than enough space than to make sure there's
496        * precisely enough space.
497        */
498       size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
499       size += numIPAddresses  * sizeof(IP_ADDR_STRING); 
500       if (!pAdapterInfo || *pOutBufLen < size) {
501         *pOutBufLen = size;
502         ret = ERROR_BUFFER_OVERFLOW;
503       }
504       else {
505         InterfaceIndexTable *table = NULL;
506         PMIB_IPADDRTABLE ipAddrTable = NULL;
507         PMIB_IPFORWARDTABLE routeTable = NULL;
508
509         ret = getIPAddrTable(&ipAddrTable, GetProcessHeap(), 0);
510         if (!ret)
511           ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
512         if (!ret)
513           table = getNonLoopbackInterfaceIndexTable();
514         if (table) {
515           size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
516           size += ipAddrTable->dwNumEntries * sizeof(IP_ADDR_STRING); 
517           if (*pOutBufLen < size) {
518             *pOutBufLen = size;
519             ret = ERROR_INSUFFICIENT_BUFFER;
520           }
521           else {
522             DWORD ndx;
523             HKEY hKey;
524             BOOL winsEnabled = FALSE;
525             IP_ADDRESS_STRING primaryWINS, secondaryWINS;
526             PIP_ADDR_STRING nextIPAddr = (PIP_ADDR_STRING)((LPBYTE)pAdapterInfo
527              + numNonLoopbackInterfaces * sizeof(IP_ADAPTER_INFO));
528
529             memset(pAdapterInfo, 0, size);
530             /* @@ Wine registry key: HKCU\Software\Wine\Network */
531             if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Network",
532              &hKey) == ERROR_SUCCESS) {
533               DWORD size = sizeof(primaryWINS.String);
534               unsigned long addr;
535
536               RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
537                (LPBYTE)primaryWINS.String, &size);
538               addr = inet_addr(primaryWINS.String);
539               if (addr != INADDR_NONE && addr != INADDR_ANY)
540                 winsEnabled = TRUE;
541               size = sizeof(secondaryWINS.String);
542               RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
543                (LPBYTE)secondaryWINS.String, &size);
544               addr = inet_addr(secondaryWINS.String);
545               if (addr != INADDR_NONE && addr != INADDR_ANY)
546                 winsEnabled = TRUE;
547               RegCloseKey(hKey);
548             }
549             for (ndx = 0; ndx < table->numIndexes; ndx++) {
550               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
551               DWORD i;
552               PIP_ADDR_STRING currentIPAddr = &ptr->IpAddressList;
553               BOOL firstIPAddr = TRUE;
554
555               /* on Win98 this is left empty, but whatever */
556               getInterfaceNameByIndex(table->indexes[ndx], ptr->AdapterName);
557               getInterfaceNameByIndex(table->indexes[ndx], ptr->Description);
558               ptr->AddressLength = sizeof(ptr->Address);
559               getInterfacePhysicalByIndex(table->indexes[ndx],
560                &ptr->AddressLength, ptr->Address, &ptr->Type);
561               ptr->Index = table->indexes[ndx];
562               for (i = 0; i < ipAddrTable->dwNumEntries; i++) {
563                 if (ipAddrTable->table[i].dwIndex == ptr->Index) {
564                   if (firstIPAddr) {
565                     toIPAddressString(ipAddrTable->table[i].dwAddr,
566                      ptr->IpAddressList.IpAddress.String);
567                     toIPAddressString(ipAddrTable->table[i].dwMask,
568                      ptr->IpAddressList.IpMask.String);
569                     firstIPAddr = FALSE;
570                   }
571                   else {
572                     currentIPAddr->Next = nextIPAddr;
573                     currentIPAddr = nextIPAddr;
574                     toIPAddressString(ipAddrTable->table[i].dwAddr,
575                      currentIPAddr->IpAddress.String);
576                     toIPAddressString(ipAddrTable->table[i].dwMask,
577                      currentIPAddr->IpMask.String);
578                     nextIPAddr++;
579                   }
580                 }
581               }
582               /* Find first router through this interface, which we'll assume
583                * is the default gateway for this adapter */
584               for (i = 0; i < routeTable->dwNumEntries; i++)
585                 if (routeTable->table[i].dwForwardIfIndex == ptr->Index
586                  && routeTable->table[i].u1.ForwardType ==
587                  MIB_IPROUTE_TYPE_INDIRECT)
588                   toIPAddressString(routeTable->table[i].dwForwardNextHop,
589                    ptr->GatewayList.IpAddress.String);
590               if (winsEnabled) {
591                 ptr->HaveWins = TRUE;
592                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
593                  primaryWINS.String, sizeof(primaryWINS.String));
594                 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
595                  secondaryWINS.String, sizeof(secondaryWINS.String));
596               }
597               if (ndx < table->numIndexes - 1)
598                 ptr->Next = &pAdapterInfo[ndx + 1];
599               else
600                 ptr->Next = NULL;
601
602               ptr->DhcpEnabled = TRUE;
603             }
604             ret = NO_ERROR;
605           }
606           HeapFree(GetProcessHeap(), 0, table);
607         }
608         else
609           ret = ERROR_OUTOFMEMORY;
610         HeapFree(GetProcessHeap(), 0, routeTable);
611         HeapFree(GetProcessHeap(), 0, ipAddrTable);
612       }
613     }
614     else
615       ret = ERROR_NO_DATA;
616   }
617   TRACE("returning %d\n", ret);
618   return ret;
619 }
620
621 static DWORD typeFromMibType(DWORD mib_type)
622 {
623     switch (mib_type)
624     {
625     case MIB_IF_TYPE_ETHERNET:  return IF_TYPE_ETHERNET_CSMACD;
626     case MIB_IF_TYPE_TOKENRING: return IF_TYPE_ISO88025_TOKENRING;
627     case MIB_IF_TYPE_PPP:       return IF_TYPE_PPP;
628     case MIB_IF_TYPE_LOOPBACK:  return IF_TYPE_SOFTWARE_LOOPBACK;
629     default:                    return IF_TYPE_OTHER;
630     }
631 }
632
633 static NET_IF_CONNECTION_TYPE connectionTypeFromMibType(DWORD mib_type)
634 {
635     switch (mib_type)
636     {
637     case MIB_IF_TYPE_PPP:       return NET_IF_CONNECTION_DEMAND;
638     case MIB_IF_TYPE_SLIP:      return NET_IF_CONNECTION_DEMAND;
639     default:                    return NET_IF_CONNECTION_DEDICATED;
640     }
641 }
642
643 static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addrs)
644 {
645     ULONG ret, i, j;
646     MIB_IPADDRTABLE *at;
647
648     *num_addrs = 0;
649     if ((ret = getIPAddrTable(&at, GetProcessHeap(), 0))) return ret;
650     for (i = 0; i < at->dwNumEntries; i++)
651     {
652         if (at->table[i].dwIndex == index) (*num_addrs)++;
653     }
654     if (!(*addrs = HeapAlloc(GetProcessHeap(), 0, *num_addrs * sizeof(DWORD))))
655     {
656         HeapFree(GetProcessHeap(), 0, at);
657         return ERROR_OUTOFMEMORY;
658     }
659     for (i = 0, j = 0; i < at->dwNumEntries; i++)
660     {
661         if (at->table[i].dwIndex == index) (*addrs)[j++] = at->table[i].dwAddr;
662     }
663     HeapFree(GetProcessHeap(), 0, at);
664     return ERROR_SUCCESS;
665 }
666
667 static char *debugstr_ipv4(const in_addr_t *in_addr, char *buf)
668 {
669     const BYTE *addrp;
670     char *p = buf;
671
672     for (addrp = (const BYTE *)in_addr;
673      addrp - (const BYTE *)in_addr < sizeof(*in_addr);
674      addrp++)
675     {
676         if (addrp == (const BYTE *)in_addr + sizeof(*in_addr) - 1)
677             sprintf(p, "%d", *addrp);
678         else
679             p += sprintf(p, "%d.", *addrp);
680     }
681     return buf;
682 }
683
684 static char *debugstr_ipv6(const struct WS_sockaddr_in6 *sin, char *buf)
685 {
686     const IN6_ADDR *addr = &sin->sin6_addr;
687     char *p = buf;
688     int i;
689     BOOL in_zero = FALSE;
690
691     for (i = 0; i < 7; i++)
692     {
693         if (!addr->u.Word[i])
694         {
695             if (i == 0)
696                 *p++ = ':';
697             if (!in_zero)
698             {
699                 *p++ = ':';
700                 in_zero = TRUE;
701             }
702         }
703         else
704         {
705             p += sprintf(p, "%x:", ntohs(addr->u.Word[i]));
706             in_zero = FALSE;
707         }
708     }
709     sprintf(p, "%x", ntohs(addr->u.Word[7]));
710     return buf;
711 }
712
713 static ULONG count_v4_gateways(DWORD index, PMIB_IPFORWARDTABLE routeTable)
714 {
715     DWORD i, num_gateways = 0;
716
717     for (i = 0; i < routeTable->dwNumEntries; i++)
718     {
719         if (routeTable->table[i].dwForwardIfIndex == index &&
720             routeTable->table[i].u1.ForwardType == MIB_IPROUTE_TYPE_INDIRECT)
721             num_gateways++;
722     }
723     return num_gateways;
724 }
725
726 static PMIB_IPFORWARDROW findIPv4Gateway(DWORD index,
727                                          PMIB_IPFORWARDTABLE routeTable)
728 {
729     DWORD i;
730     PMIB_IPFORWARDROW row = NULL;
731
732     for (i = 0; !row && i < routeTable->dwNumEntries; i++)
733     {
734         if (routeTable->table[i].dwForwardIfIndex == index &&
735             routeTable->table[i].u1.ForwardType == MIB_IPROUTE_TYPE_INDIRECT)
736             row = &routeTable->table[i];
737     }
738     return row;
739 }
740
741 static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index,
742                                        IP_ADAPTER_ADDRESSES *aa, ULONG *size)
743 {
744     ULONG ret = ERROR_SUCCESS, i, num_v4addrs = 0, num_v4_gateways = 0, num_v6addrs = 0, total_size;
745     DWORD *v4addrs = NULL;
746     SOCKET_ADDRESS *v6addrs = NULL;
747     PMIB_IPFORWARDTABLE routeTable = NULL;
748
749     if (family == WS_AF_INET)
750     {
751         if (!(flags & GAA_FLAG_SKIP_UNICAST))
752             ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs);
753         if (!ret && flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
754         {
755             ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE,
756                                                         GetProcessHeap(), 0);
757             if (!ret)
758                 num_v4_gateways = count_v4_gateways(index, routeTable);
759         }
760     }
761     else if (family == WS_AF_INET6)
762     {
763         if (!(flags & GAA_FLAG_SKIP_UNICAST))
764             ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs);
765     }
766     else if (family == WS_AF_UNSPEC)
767     {
768         if (!(flags & GAA_FLAG_SKIP_UNICAST))
769             ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs);
770         if (!ret && flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
771         {
772             ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE,
773                                                         GetProcessHeap(), 0);
774             if (!ret)
775                 num_v4_gateways = count_v4_gateways(index, routeTable);
776         }
777         if (!ret && !(flags & GAA_FLAG_SKIP_UNICAST))
778             ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs);
779     }
780     else
781     {
782         FIXME("address family %u unsupported\n", family);
783         ret = ERROR_NO_DATA;
784     }
785     if (ret)
786     {
787         HeapFree(GetProcessHeap(), 0, v4addrs);
788         HeapFree(GetProcessHeap(), 0, routeTable);
789         return ret;
790     }
791
792     total_size = sizeof(IP_ADAPTER_ADDRESSES);
793     total_size += IF_NAMESIZE;
794     total_size += IF_NAMESIZE * sizeof(WCHAR);
795     if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
796         total_size += IF_NAMESIZE * sizeof(WCHAR);
797     total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v4addrs;
798     total_size += sizeof(struct sockaddr_in) * num_v4addrs;
799     total_size += (sizeof(IP_ADAPTER_GATEWAY_ADDRESS) + sizeof(SOCKADDR_IN)) * num_v4_gateways;
800     total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v6addrs;
801     total_size += sizeof(SOCKET_ADDRESS) * num_v6addrs;
802     for (i = 0; i < num_v6addrs; i++)
803         total_size += v6addrs[i].iSockaddrLength;
804
805     if (aa && *size >= total_size)
806     {
807         char name[IF_NAMESIZE], *ptr = (char *)aa + sizeof(IP_ADAPTER_ADDRESSES), *src;
808         WCHAR *dst;
809         DWORD buflen, type;
810         INTERNAL_IF_OPER_STATUS status;
811
812         memset(aa, 0, sizeof(IP_ADAPTER_ADDRESSES));
813         aa->u.s.Length  = sizeof(IP_ADAPTER_ADDRESSES);
814         aa->u.s.IfIndex = index;
815
816         getInterfaceNameByIndex(index, name);
817         memcpy(ptr, name, IF_NAMESIZE);
818         aa->AdapterName = ptr;
819         ptr += IF_NAMESIZE;
820         if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
821         {
822             aa->FriendlyName = (WCHAR *)ptr;
823             for (src = name, dst = (WCHAR *)ptr; *src; src++, dst++)
824                 *dst = *src;
825             *dst++ = 0;
826             ptr = (char *)dst;
827         }
828         aa->Description = (WCHAR *)ptr;
829         for (src = name, dst = (WCHAR *)ptr; *src; src++, dst++)
830             *dst = *src;
831         *dst++ = 0;
832         ptr = (char *)dst;
833
834         TRACE("%s: %d IPv4 addresses, %d IPv6 addresses:\n", name, num_v4addrs,
835               num_v6addrs);
836         if (num_v4_gateways)
837         {
838             PMIB_IPFORWARDROW adapterRow;
839
840             if ((adapterRow = findIPv4Gateway(index, routeTable)))
841             {
842                 PIP_ADAPTER_GATEWAY_ADDRESS gw;
843                 PSOCKADDR_IN sin;
844
845                 gw = (PIP_ADAPTER_GATEWAY_ADDRESS)ptr;
846                 aa->FirstGatewayAddress = gw;
847
848                 gw->u.s.Length = sizeof(IP_ADAPTER_GATEWAY_ADDRESS);
849                 ptr += sizeof(IP_ADAPTER_GATEWAY_ADDRESS);
850                 sin = (PSOCKADDR_IN)ptr;
851                 sin->sin_family = AF_INET;
852                 sin->sin_port = 0;
853                 memcpy(&sin->sin_addr, &adapterRow->dwForwardNextHop,
854                        sizeof(DWORD));
855                 gw->Address.lpSockaddr = (LPSOCKADDR)sin;
856                 gw->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
857                 gw->Next = NULL;
858                 ptr += sizeof(SOCKADDR_IN);
859             }
860         }
861         if (num_v4addrs)
862         {
863             IP_ADAPTER_UNICAST_ADDRESS *ua;
864             struct sockaddr_in *sa;
865             aa->Flags |= IP_ADAPTER_IPV4_ENABLED;
866             ua = aa->FirstUnicastAddress = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
867             for (i = 0; i < num_v4addrs; i++)
868             {
869                 char addr_buf[16];
870
871                 memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
872                 ua->u.s.Length              = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
873                 ua->Address.iSockaddrLength = sizeof(struct sockaddr_in);
874                 ua->Address.lpSockaddr      = (SOCKADDR *)((char *)ua + ua->u.s.Length);
875
876                 sa = (struct sockaddr_in *)ua->Address.lpSockaddr;
877                 sa->sin_family      = AF_INET;
878                 sa->sin_addr.s_addr = v4addrs[i];
879                 sa->sin_port        = 0;
880                 TRACE("IPv4 %d/%d: %s\n", i + 1, num_v4addrs,
881                       debugstr_ipv4(&sa->sin_addr.s_addr, addr_buf));
882
883                 ptr += ua->u.s.Length + ua->Address.iSockaddrLength;
884                 if (i < num_v4addrs - 1)
885                 {
886                     ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
887                     ua = ua->Next;
888                 }
889             }
890         }
891         if (num_v6addrs)
892         {
893             IP_ADAPTER_UNICAST_ADDRESS *ua;
894             struct WS_sockaddr_in6 *sa;
895
896             aa->Flags |= IP_ADAPTER_IPV6_ENABLED;
897             if (aa->FirstUnicastAddress)
898             {
899                 for (ua = aa->FirstUnicastAddress; ua->Next; ua = ua->Next)
900                     ;
901                 ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
902                 ua = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
903             }
904             else
905                 ua = aa->FirstUnicastAddress = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
906             for (i = 0; i < num_v6addrs; i++)
907             {
908                 char addr_buf[46];
909
910                 memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
911                 ua->u.s.Length              = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
912                 ua->Address.iSockaddrLength = v6addrs[i].iSockaddrLength;
913                 ua->Address.lpSockaddr      = (SOCKADDR *)((char *)ua + ua->u.s.Length);
914
915                 sa = (struct WS_sockaddr_in6 *)ua->Address.lpSockaddr;
916                 memcpy(sa, v6addrs[i].lpSockaddr, sizeof(*sa));
917                 TRACE("IPv6 %d/%d: %s\n", i + 1, num_v6addrs,
918                       debugstr_ipv6(sa, addr_buf));
919
920                 ptr += ua->u.s.Length + ua->Address.iSockaddrLength;
921                 if (i < num_v6addrs - 1)
922                 {
923                     ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
924                     ua = ua->Next;
925                 }
926             }
927         }
928
929         buflen = MAX_INTERFACE_PHYSADDR;
930         getInterfacePhysicalByIndex(index, &buflen, aa->PhysicalAddress, &type);
931         aa->PhysicalAddressLength = buflen;
932         aa->IfType = typeFromMibType(type);
933         aa->ConnectionType = connectionTypeFromMibType(type);
934
935         getInterfaceMtuByName(name, &aa->Mtu);
936
937         getInterfaceStatusByName(name, &status);
938         if (status == MIB_IF_OPER_STATUS_OPERATIONAL) aa->OperStatus = IfOperStatusUp;
939         else if (status == MIB_IF_OPER_STATUS_NON_OPERATIONAL) aa->OperStatus = IfOperStatusDown;
940         else aa->OperStatus = IfOperStatusUnknown;
941     }
942     *size = total_size;
943     HeapFree(GetProcessHeap(), 0, routeTable);
944     HeapFree(GetProcessHeap(), 0, v6addrs);
945     HeapFree(GetProcessHeap(), 0, v4addrs);
946     return ERROR_SUCCESS;
947 }
948
949 static ULONG get_dns_server_addresses(PIP_ADAPTER_DNS_SERVER_ADDRESS address, ULONG *len)
950 {
951     DWORD size;
952
953     initialise_resolver();
954     /* FIXME: no support for IPv6 DNS server addresses.  Doing so requires
955      * sizeof SOCKADDR_STORAGE instead, and using _res._u._ext.nsaddrs when
956      * available.
957      */
958     size = _res.nscount * (sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + sizeof(SOCKADDR));
959     if (!address || *len < size)
960     {
961         *len = size;
962         return ERROR_BUFFER_OVERFLOW;
963     }
964     *len = size;
965     if (_res.nscount > 0)
966     {
967         PIP_ADAPTER_DNS_SERVER_ADDRESS addr;
968         int i;
969
970         for (i = 0, addr = address; i < _res.nscount && addr;
971              i++, addr = addr->Next)
972         {
973             SOCKADDR_IN *sin;
974
975             addr->Address.iSockaddrLength = sizeof(SOCKADDR);
976             addr->Address.lpSockaddr =
977              (LPSOCKADDR)((PBYTE)addr + sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS));
978             sin = (SOCKADDR_IN *)addr->Address.lpSockaddr;
979             sin->sin_family = WS_AF_INET;
980             sin->sin_port = _res.nsaddr_list[i].sin_port;
981             memcpy(&sin->sin_addr, &_res.nsaddr_list[i].sin_addr, sizeof(sin->sin_addr));
982             if (i == _res.nscount - 1)
983                 addr->Next = NULL;
984             else
985                 addr->Next =
986                  (PIP_ADAPTER_DNS_SERVER_ADDRESS)((PBYTE)addr +
987                  sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + sizeof(SOCKADDR));
988         }
989     }
990     return ERROR_SUCCESS;
991 }
992
993 static BOOL is_ip_address_string(const char *str)
994 {
995     struct in_addr in;
996     int ret;
997
998     ret = inet_aton(str, &in);
999     return ret != 0;
1000 }
1001
1002 static ULONG get_dns_suffix(WCHAR *suffix, ULONG *len)
1003 {
1004     ULONG size, i;
1005     char *found_suffix = NULL;
1006
1007     initialise_resolver();
1008     /* Always return a NULL-terminated string, even if it's empty. */
1009     size = sizeof(WCHAR);
1010     for (i = 0, found_suffix = NULL;
1011          !found_suffix && i < MAXDNSRCH + 1 && _res.dnsrch[i]; i++)
1012     {
1013         /* This uses a heuristic to select a DNS suffix:
1014          * the first, non-IP address string is selected.
1015          */
1016         if (!is_ip_address_string(_res.dnsrch[i]))
1017             found_suffix = _res.dnsrch[i];
1018     }
1019     if (found_suffix)
1020         size += strlen(found_suffix) * sizeof(WCHAR);
1021     if (!suffix || *len < size)
1022     {
1023         *len = size;
1024         return ERROR_BUFFER_OVERFLOW;
1025     }
1026     *len = size;
1027     if (found_suffix)
1028     {
1029         char *p;
1030
1031         for (p = found_suffix; *p; p++)
1032             *suffix++ = *p;
1033     }
1034     *suffix = 0;
1035     return ERROR_SUCCESS;
1036 }
1037
1038 ULONG WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG family, ULONG flags, PVOID reserved,
1039                                                     PIP_ADAPTER_ADDRESSES aa, PULONG buflen)
1040 {
1041     InterfaceIndexTable *table;
1042     ULONG i, size, dns_server_size, dns_suffix_size, total_size, ret = ERROR_NO_DATA;
1043
1044     TRACE("(%d, %08x, %p, %p, %p)\n", family, flags, reserved, aa, buflen);
1045
1046     if (!buflen) return ERROR_INVALID_PARAMETER;
1047
1048     table = getInterfaceIndexTable();
1049     if (!table || !table->numIndexes)
1050     {
1051         HeapFree(GetProcessHeap(), 0, table);
1052         return ERROR_NO_DATA;
1053     }
1054     total_size = 0;
1055     for (i = 0; i < table->numIndexes; i++)
1056     {
1057         size = 0;
1058         if ((ret = adapterAddressesFromIndex(family, flags, table->indexes[i], NULL, &size)))
1059         {
1060             HeapFree(GetProcessHeap(), 0, table);
1061             return ret;
1062         }
1063         total_size += size;
1064     }
1065     if (!(flags & GAA_FLAG_SKIP_DNS_SERVER))
1066     {
1067         /* Since DNS servers aren't really per adapter, get enough space for a
1068          * single copy of them.
1069          */
1070         get_dns_server_addresses(NULL, &dns_server_size);
1071         total_size += dns_server_size;
1072     }
1073     /* Since DNS suffix also isn't really per adapter, get enough space for a
1074      * single copy of it.
1075      */
1076     get_dns_suffix(NULL, &dns_suffix_size);
1077     total_size += dns_suffix_size;
1078     if (aa && *buflen >= total_size)
1079     {
1080         ULONG bytes_left = size = total_size;
1081         PIP_ADAPTER_ADDRESSES first_aa = aa;
1082         PIP_ADAPTER_DNS_SERVER_ADDRESS firstDns;
1083         WCHAR *dnsSuffix;
1084
1085         for (i = 0; i < table->numIndexes; i++)
1086         {
1087             if ((ret = adapterAddressesFromIndex(family, flags, table->indexes[i], aa, &size)))
1088             {
1089                 HeapFree(GetProcessHeap(), 0, table);
1090                 return ret;
1091             }
1092             if (i < table->numIndexes - 1)
1093             {
1094                 aa->Next = (IP_ADAPTER_ADDRESSES *)((char *)aa + size);
1095                 aa = aa->Next;
1096                 size = bytes_left -= size;
1097             }
1098         }
1099         if (!(flags & GAA_FLAG_SKIP_DNS_SERVER))
1100         {
1101             firstDns = (PIP_ADAPTER_DNS_SERVER_ADDRESS)((BYTE *)first_aa + total_size - dns_server_size - dns_suffix_size);
1102             get_dns_server_addresses(firstDns, &dns_server_size);
1103             for (aa = first_aa; aa; aa = aa->Next)
1104             {
1105                 if (aa->IfType != IF_TYPE_SOFTWARE_LOOPBACK && aa->OperStatus == IfOperStatusUp)
1106                     aa->FirstDnsServerAddress = firstDns;
1107             }
1108         }
1109         aa = first_aa;
1110         dnsSuffix = (WCHAR *)((BYTE *)aa + total_size - dns_suffix_size);
1111         get_dns_suffix(dnsSuffix, &dns_suffix_size);
1112         for (; aa; aa = aa->Next)
1113         {
1114             if (aa->IfType != IF_TYPE_SOFTWARE_LOOPBACK && aa->OperStatus == IfOperStatusUp)
1115                 aa->DnsSuffix = dnsSuffix;
1116             else
1117                 aa->DnsSuffix = (WCHAR *)((BYTE*)dnsSuffix + dns_suffix_size - 2);
1118         }
1119         ret = ERROR_SUCCESS;
1120     }
1121     else
1122         ret = ERROR_BUFFER_OVERFLOW;
1123     *buflen = total_size;
1124
1125     TRACE("num adapters %u\n", table->numIndexes);
1126     HeapFree(GetProcessHeap(), 0, table);
1127     return ret;
1128 }
1129
1130 /******************************************************************
1131  *    GetBestInterface (IPHLPAPI.@)
1132  *
1133  * Get the interface, with the best route for the given IP address.
1134  *
1135  * PARAMS
1136  *  dwDestAddr     [In]  IP address to search the interface for
1137  *  pdwBestIfIndex [Out] found best interface
1138  *
1139  * RETURNS
1140  *  Success: NO_ERROR
1141  *  Failure: error code from winerror.h
1142  */
1143 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
1144 {
1145     struct WS_sockaddr_in sa_in;
1146     memset(&sa_in, 0, sizeof(sa_in));
1147     sa_in.sin_family = AF_INET;
1148     sa_in.sin_addr.S_un.S_addr = dwDestAddr;
1149     return GetBestInterfaceEx((struct WS_sockaddr *)&sa_in, pdwBestIfIndex);
1150 }
1151
1152 /******************************************************************
1153  *    GetBestInterfaceEx (IPHLPAPI.@)
1154  *
1155  * Get the interface, with the best route for the given IP address.
1156  *
1157  * PARAMS
1158  *  dwDestAddr     [In]  IP address to search the interface for
1159  *  pdwBestIfIndex [Out] found best interface
1160  *
1161  * RETURNS
1162  *  Success: NO_ERROR
1163  *  Failure: error code from winerror.h
1164  */
1165 DWORD WINAPI GetBestInterfaceEx(struct WS_sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
1166 {
1167   DWORD ret;
1168
1169   TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
1170   if (!pDestAddr || !pdwBestIfIndex)
1171     ret = ERROR_INVALID_PARAMETER;
1172   else {
1173     MIB_IPFORWARDROW ipRow;
1174
1175     if (pDestAddr->sa_family == AF_INET) {
1176       ret = GetBestRoute(((struct WS_sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
1177       if (ret == ERROR_SUCCESS)
1178         *pdwBestIfIndex = ipRow.dwForwardIfIndex;
1179     } else {
1180       FIXME("address family %d not supported\n", pDestAddr->sa_family);
1181       ret = ERROR_NOT_SUPPORTED;
1182     }
1183   }
1184   TRACE("returning %d\n", ret);
1185   return ret;
1186 }
1187
1188
1189 /******************************************************************
1190  *    GetBestRoute (IPHLPAPI.@)
1191  *
1192  * Get the best route for the given IP address.
1193  *
1194  * PARAMS
1195  *  dwDestAddr   [In]  IP address to search the best route for
1196  *  dwSourceAddr [In]  optional source IP address
1197  *  pBestRoute   [Out] found best route
1198  *
1199  * RETURNS
1200  *  Success: NO_ERROR
1201  *  Failure: error code from winerror.h
1202  */
1203 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
1204 {
1205   PMIB_IPFORWARDTABLE table;
1206   DWORD ret;
1207
1208   TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr,
1209    dwSourceAddr, pBestRoute);
1210   if (!pBestRoute)
1211     return ERROR_INVALID_PARAMETER;
1212
1213   ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
1214   if (!ret) {
1215     DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
1216
1217     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
1218       if (table->table[ndx].u1.ForwardType != MIB_IPROUTE_TYPE_INVALID &&
1219        (dwDestAddr & table->table[ndx].dwForwardMask) ==
1220        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
1221         DWORD numShifts, mask;
1222
1223         for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
1224          mask && mask & 1; mask >>= 1, numShifts++)
1225           ;
1226         if (numShifts > matchedBits) {
1227           matchedBits = numShifts;
1228           matchedNdx = ndx;
1229         }
1230         else if (!matchedBits) {
1231           matchedNdx = ndx;
1232         }
1233       }
1234     }
1235     if (matchedNdx < table->dwNumEntries) {
1236       memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
1237       ret = ERROR_SUCCESS;
1238     }
1239     else {
1240       /* No route matches, which can happen if there's no default route. */
1241       ret = ERROR_HOST_UNREACHABLE;
1242     }
1243     HeapFree(GetProcessHeap(), 0, table);
1244   }
1245   TRACE("returning %d\n", ret);
1246   return ret;
1247 }
1248
1249
1250 /******************************************************************
1251  *    GetFriendlyIfIndex (IPHLPAPI.@)
1252  *
1253  * Get a "friendly" version of IfIndex, which is one that doesn't
1254  * have the top byte set.  Doesn't validate whether IfIndex is a valid
1255  * adapter index.
1256  *
1257  * PARAMS
1258  *  IfIndex [In] interface index to get the friendly one for
1259  *
1260  * RETURNS
1261  *  A friendly version of IfIndex.
1262  */
1263 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1264 {
1265   /* windows doesn't validate these, either, just makes sure the top byte is
1266      cleared.  I assume my ifenum module never gives an index with the top
1267      byte set. */
1268   TRACE("returning %d\n", IfIndex);
1269   return IfIndex;
1270 }
1271
1272
1273 /******************************************************************
1274  *    GetIfEntry (IPHLPAPI.@)
1275  *
1276  * Get information about an interface.
1277  *
1278  * PARAMS
1279  *  pIfRow [In/Out] In:  dwIndex of MIB_IFROW selects the interface.
1280  *                  Out: interface information
1281  *
1282  * RETURNS
1283  *  Success: NO_ERROR
1284  *  Failure: error code from winerror.h
1285  */
1286 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
1287 {
1288   DWORD ret;
1289   char nameBuf[MAX_ADAPTER_NAME];
1290   char *name;
1291
1292   TRACE("pIfRow %p\n", pIfRow);
1293   if (!pIfRow)
1294     return ERROR_INVALID_PARAMETER;
1295
1296   name = getInterfaceNameByIndex(pIfRow->dwIndex, nameBuf);
1297   if (name) {
1298     ret = getInterfaceEntryByName(name, pIfRow);
1299     if (ret == NO_ERROR)
1300       ret = getInterfaceStatsByName(name, pIfRow);
1301   }
1302   else
1303     ret = ERROR_INVALID_DATA;
1304   TRACE("returning %d\n", ret);
1305   return ret;
1306 }
1307
1308
1309 static int IfTableSorter(const void *a, const void *b)
1310 {
1311   int ret;
1312
1313   if (a && b)
1314     ret = ((const MIB_IFROW*)a)->dwIndex - ((const MIB_IFROW*)b)->dwIndex;
1315   else
1316     ret = 0;
1317   return ret;
1318 }
1319
1320
1321 /******************************************************************
1322  *    GetIfTable (IPHLPAPI.@)
1323  *
1324  * Get a table of local interfaces.
1325  *
1326  * PARAMS
1327  *  pIfTable [Out]    buffer for local interfaces table
1328  *  pdwSize  [In/Out] length of output buffer
1329  *  bOrder   [In]     whether to sort the table
1330  *
1331  * RETURNS
1332  *  Success: NO_ERROR
1333  *  Failure: error code from winerror.h
1334  *
1335  * NOTES
1336  *  If pdwSize is less than required, the function will return
1337  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1338  *  size.
1339  *  If bOrder is true, the returned table will be sorted by interface index.
1340  */
1341 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
1342 {
1343   DWORD ret;
1344
1345   TRACE("pIfTable %p, pdwSize %p, bOrder %d\n", pdwSize, pdwSize,
1346    (DWORD)bOrder);
1347   if (!pdwSize)
1348     ret = ERROR_INVALID_PARAMETER;
1349   else {
1350     DWORD numInterfaces = getNumInterfaces();
1351     ULONG size = sizeof(MIB_IFTABLE);
1352
1353     if (numInterfaces > 1)
1354       size += (numInterfaces - 1) * sizeof(MIB_IFROW);
1355     if (!pIfTable || *pdwSize < size) {
1356       *pdwSize = size;
1357       ret = ERROR_INSUFFICIENT_BUFFER;
1358     }
1359     else {
1360       InterfaceIndexTable *table = getInterfaceIndexTable();
1361
1362       if (table) {
1363         size = sizeof(MIB_IFTABLE);
1364         if (table->numIndexes > 1)
1365           size += (table->numIndexes - 1) * sizeof(MIB_IFROW);
1366         if (*pdwSize < size) {
1367           *pdwSize = size;
1368           ret = ERROR_INSUFFICIENT_BUFFER;
1369         }
1370         else {
1371           DWORD ndx;
1372
1373           *pdwSize = size;
1374           pIfTable->dwNumEntries = 0;
1375           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1376             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
1377             GetIfEntry(&pIfTable->table[ndx]);
1378             pIfTable->dwNumEntries++;
1379           }
1380           if (bOrder)
1381             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
1382              IfTableSorter);
1383           ret = NO_ERROR;
1384         }
1385         HeapFree(GetProcessHeap(), 0, table);
1386       }
1387       else
1388         ret = ERROR_OUTOFMEMORY;
1389     }
1390   }
1391   TRACE("returning %d\n", ret);
1392   return ret;
1393 }
1394
1395
1396 /******************************************************************
1397  *    GetInterfaceInfo (IPHLPAPI.@)
1398  *
1399  * Get a list of network interface adapters.
1400  *
1401  * PARAMS
1402  *  pIfTable    [Out] buffer for interface adapters
1403  *  dwOutBufLen [Out] if buffer is too small, returns required size
1404  *
1405  * RETURNS
1406  *  Success: NO_ERROR
1407  *  Failure: error code from winerror.h
1408  *
1409  * BUGS
1410  *  MSDN states this should return non-loopback interfaces only.
1411  */
1412 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
1413 {
1414   DWORD ret;
1415
1416   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
1417   if (!dwOutBufLen)
1418     ret = ERROR_INVALID_PARAMETER;
1419   else {
1420     DWORD numInterfaces = getNumInterfaces();
1421     ULONG size = sizeof(IP_INTERFACE_INFO);
1422
1423     if (numInterfaces > 1)
1424       size += (numInterfaces - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
1425     if (!pIfTable || *dwOutBufLen < size) {
1426       *dwOutBufLen = size;
1427       ret = ERROR_INSUFFICIENT_BUFFER;
1428     }
1429     else {
1430       InterfaceIndexTable *table = getInterfaceIndexTable();
1431
1432       if (table) {
1433         size = sizeof(IP_INTERFACE_INFO);
1434         if (table->numIndexes > 1)
1435           size += (table->numIndexes - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
1436         if (*dwOutBufLen < size) {
1437           *dwOutBufLen = size;
1438           ret = ERROR_INSUFFICIENT_BUFFER;
1439         }
1440         else {
1441           DWORD ndx;
1442           char nameBuf[MAX_ADAPTER_NAME];
1443
1444           *dwOutBufLen = size;
1445           pIfTable->NumAdapters = 0;
1446           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1447             const char *walker, *name;
1448             WCHAR *assigner;
1449
1450             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
1451             name = getInterfaceNameByIndex(table->indexes[ndx], nameBuf);
1452             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
1453              walker && *walker &&
1454              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
1455              walker++, assigner++)
1456               *assigner = *walker;
1457             *assigner = 0;
1458             pIfTable->NumAdapters++;
1459           }
1460           ret = NO_ERROR;
1461         }
1462         HeapFree(GetProcessHeap(), 0, table);
1463       }
1464       else
1465         ret = ERROR_OUTOFMEMORY;
1466     }
1467   }
1468   TRACE("returning %d\n", ret);
1469   return ret;
1470 }
1471
1472
1473 /******************************************************************
1474  *    GetIpAddrTable (IPHLPAPI.@)
1475  *
1476  * Get interface-to-IP address mapping table. 
1477  *
1478  * PARAMS
1479  *  pIpAddrTable [Out]    buffer for mapping table
1480  *  pdwSize      [In/Out] length of output buffer
1481  *  bOrder       [In]     whether to sort the table
1482  *
1483  * RETURNS
1484  *  Success: NO_ERROR
1485  *  Failure: error code from winerror.h
1486  *
1487  * NOTES
1488  *  If pdwSize is less than required, the function will return
1489  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1490  *  size.
1491  *  If bOrder is true, the returned table will be sorted by the next hop and
1492  *  an assortment of arbitrary parameters.
1493  */
1494 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1495 {
1496   DWORD ret;
1497
1498   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %d\n", pIpAddrTable, pdwSize,
1499    (DWORD)bOrder);
1500   if (!pdwSize)
1501     ret = ERROR_INVALID_PARAMETER;
1502   else {
1503     PMIB_IPADDRTABLE table;
1504
1505     ret = getIPAddrTable(&table, GetProcessHeap(), 0);
1506     if (ret == NO_ERROR)
1507     {
1508       ULONG size = FIELD_OFFSET(MIB_IPADDRTABLE, table[table->dwNumEntries]);
1509
1510       if (!pIpAddrTable || *pdwSize < size) {
1511         *pdwSize = size;
1512         ret = ERROR_INSUFFICIENT_BUFFER;
1513       }
1514       else {
1515         *pdwSize = size;
1516         memcpy(pIpAddrTable, table, size);
1517         if (bOrder)
1518           qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1519            sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1520         ret = NO_ERROR;
1521       }
1522       HeapFree(GetProcessHeap(), 0, table);
1523     }
1524   }
1525   TRACE("returning %d\n", ret);
1526   return ret;
1527 }
1528
1529
1530 /******************************************************************
1531  *    GetIpForwardTable (IPHLPAPI.@)
1532  *
1533  * Get the route table.
1534  *
1535  * PARAMS
1536  *  pIpForwardTable [Out]    buffer for route table
1537  *  pdwSize         [In/Out] length of output buffer
1538  *  bOrder          [In]     whether to sort the table
1539  *
1540  * RETURNS
1541  *  Success: NO_ERROR
1542  *  Failure: error code from winerror.h
1543  *
1544  * NOTES
1545  *  If pdwSize is less than required, the function will return
1546  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1547  *  size.
1548  *  If bOrder is true, the returned table will be sorted by the next hop and
1549  *  an assortment of arbitrary parameters.
1550  */
1551 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1552 {
1553     DWORD ret;
1554     PMIB_IPFORWARDTABLE table;
1555
1556     TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable, pdwSize, bOrder);
1557
1558     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1559
1560     ret = AllocateAndGetIpForwardTableFromStack(&table, bOrder, GetProcessHeap(), 0);
1561     if (!ret) {
1562         DWORD size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[table->dwNumEntries] );
1563         if (!pIpForwardTable || *pdwSize < size) {
1564           *pdwSize = size;
1565           ret = ERROR_INSUFFICIENT_BUFFER;
1566         }
1567         else {
1568           *pdwSize = size;
1569           memcpy(pIpForwardTable, table, size);
1570         }
1571         HeapFree(GetProcessHeap(), 0, table);
1572     }
1573     TRACE("returning %d\n", ret);
1574     return ret;
1575 }
1576
1577
1578 /******************************************************************
1579  *    GetIpNetTable (IPHLPAPI.@)
1580  *
1581  * Get the IP-to-physical address mapping table.
1582  *
1583  * PARAMS
1584  *  pIpNetTable [Out]    buffer for mapping table
1585  *  pdwSize     [In/Out] length of output buffer
1586  *  bOrder      [In]     whether to sort the table
1587  *
1588  * RETURNS
1589  *  Success: NO_ERROR
1590  *  Failure: error code from winerror.h
1591  *
1592  * NOTES
1593  *  If pdwSize is less than required, the function will return
1594  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1595  *  size.
1596  *  If bOrder is true, the returned table will be sorted by IP address.
1597  */
1598 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1599 {
1600     DWORD ret;
1601     PMIB_IPNETTABLE table;
1602
1603     TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize, bOrder);
1604
1605     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1606
1607     ret = AllocateAndGetIpNetTableFromStack( &table, bOrder, GetProcessHeap(), 0 );
1608     if (!ret) {
1609         DWORD size = FIELD_OFFSET( MIB_IPNETTABLE, table[table->dwNumEntries] );
1610         if (!pIpNetTable || *pdwSize < size) {
1611           *pdwSize = size;
1612           ret = ERROR_INSUFFICIENT_BUFFER;
1613         }
1614         else {
1615           *pdwSize = size;
1616           memcpy(pIpNetTable, table, size);
1617         }
1618         HeapFree(GetProcessHeap(), 0, table);
1619     }
1620     TRACE("returning %d\n", ret);
1621     return ret;
1622 }
1623
1624 /* Gets the DNS server list into the list beginning at list.  Assumes that
1625  * a single server address may be placed at list if *len is at least
1626  * sizeof(IP_ADDR_STRING) long.  Otherwise, list->Next is set to firstDynamic,
1627  * and assumes that all remaining DNS servers are contiguously located
1628  * beginning at firstDynamic.  On input, *len is assumed to be the total number
1629  * of bytes available for all DNS servers, and is ignored if list is NULL.
1630  * On return, *len is set to the total number of bytes required for all DNS
1631  * servers.
1632  * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
1633  * ERROR_SUCCESS otherwise.
1634  */
1635 static DWORD get_dns_server_list(PIP_ADDR_STRING list,
1636  PIP_ADDR_STRING firstDynamic, DWORD *len)
1637 {
1638   DWORD size;
1639
1640   initialise_resolver();
1641   size = _res.nscount * sizeof(IP_ADDR_STRING);
1642   if (!list || *len < size) {
1643     *len = size;
1644     return ERROR_BUFFER_OVERFLOW;
1645   }
1646   *len = size;
1647   if (_res.nscount > 0) {
1648     PIP_ADDR_STRING ptr;
1649     int i;
1650
1651     for (i = 0, ptr = list; i < _res.nscount && ptr; i++, ptr = ptr->Next) {
1652       toIPAddressString(_res.nsaddr_list[i].sin_addr.s_addr,
1653        ptr->IpAddress.String);
1654       if (i == _res.nscount - 1)
1655         ptr->Next = NULL;
1656       else if (i == 0)
1657         ptr->Next = firstDynamic;
1658       else
1659         ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
1660     }
1661   }
1662   return ERROR_SUCCESS;
1663 }
1664
1665 /******************************************************************
1666  *    GetNetworkParams (IPHLPAPI.@)
1667  *
1668  * Get the network parameters for the local computer.
1669  *
1670  * PARAMS
1671  *  pFixedInfo [Out]    buffer for network parameters
1672  *  pOutBufLen [In/Out] length of output buffer
1673  *
1674  * RETURNS
1675  *  Success: NO_ERROR
1676  *  Failure: error code from winerror.h
1677  *
1678  * NOTES
1679  *  If pOutBufLen is less than required, the function will return
1680  *  ERROR_INSUFFICIENT_BUFFER, and pOutBufLen will be set to the required byte
1681  *  size.
1682  */
1683 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1684 {
1685   DWORD ret, size, serverListSize;
1686   LONG regReturn;
1687   HKEY hKey;
1688
1689   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
1690   if (!pOutBufLen)
1691     return ERROR_INVALID_PARAMETER;
1692
1693   get_dns_server_list(NULL, NULL, &serverListSize);
1694   size = sizeof(FIXED_INFO) + serverListSize - sizeof(IP_ADDR_STRING);
1695   if (!pFixedInfo || *pOutBufLen < size) {
1696     *pOutBufLen = size;
1697     return ERROR_BUFFER_OVERFLOW;
1698   }
1699
1700   memset(pFixedInfo, 0, size);
1701   size = sizeof(pFixedInfo->HostName);
1702   GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
1703   size = sizeof(pFixedInfo->DomainName);
1704   GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
1705   get_dns_server_list(&pFixedInfo->DnsServerList,
1706    (PIP_ADDR_STRING)((BYTE *)pFixedInfo + sizeof(FIXED_INFO)),
1707    &serverListSize);
1708   /* Assume the first DNS server in the list is the "current" DNS server: */
1709   pFixedInfo->CurrentDnsServer = &pFixedInfo->DnsServerList;
1710   pFixedInfo->NodeType = HYBRID_NODETYPE;
1711   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1712    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
1713   if (regReturn != ERROR_SUCCESS)
1714     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1715      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
1716      &hKey);
1717   if (regReturn == ERROR_SUCCESS)
1718   {
1719     DWORD size = sizeof(pFixedInfo->ScopeId);
1720
1721     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (LPBYTE)pFixedInfo->ScopeId, &size);
1722     RegCloseKey(hKey);
1723   }
1724
1725   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1726      I suppose could also check for a listener on port 53 to set EnableDns */
1727   ret = NO_ERROR;
1728   TRACE("returning %d\n", ret);
1729   return ret;
1730 }
1731
1732
1733 /******************************************************************
1734  *    GetNumberOfInterfaces (IPHLPAPI.@)
1735  *
1736  * Get the number of interfaces.
1737  *
1738  * PARAMS
1739  *  pdwNumIf [Out] number of interfaces
1740  *
1741  * RETURNS
1742  *  NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
1743  */
1744 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1745 {
1746   DWORD ret;
1747
1748   TRACE("pdwNumIf %p\n", pdwNumIf);
1749   if (!pdwNumIf)
1750     ret = ERROR_INVALID_PARAMETER;
1751   else {
1752     *pdwNumIf = getNumInterfaces();
1753     ret = NO_ERROR;
1754   }
1755   TRACE("returning %d\n", ret);
1756   return ret;
1757 }
1758
1759
1760 /******************************************************************
1761  *    GetPerAdapterInfo (IPHLPAPI.@)
1762  *
1763  * Get information about an adapter corresponding to an interface.
1764  *
1765  * PARAMS
1766  *  IfIndex         [In]     interface info
1767  *  pPerAdapterInfo [Out]    buffer for per adapter info
1768  *  pOutBufLen      [In/Out] length of output buffer
1769  *
1770  * RETURNS
1771  *  Success: NO_ERROR
1772  *  Failure: error code from winerror.h
1773  */
1774 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1775 {
1776   ULONG bytesNeeded = sizeof(IP_PER_ADAPTER_INFO), serverListSize = 0;
1777   DWORD ret = NO_ERROR;
1778
1779   TRACE("(IfIndex %d, pPerAdapterInfo %p, pOutBufLen %p)\n", IfIndex, pPerAdapterInfo, pOutBufLen);
1780
1781   if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
1782
1783   if (!isIfIndexLoopback(IfIndex)) {
1784     get_dns_server_list(NULL, NULL, &serverListSize);
1785     if (serverListSize > sizeof(IP_ADDR_STRING))
1786       bytesNeeded += serverListSize - sizeof(IP_ADDR_STRING);
1787   }
1788   if (!pPerAdapterInfo || *pOutBufLen < bytesNeeded)
1789   {
1790     *pOutBufLen = bytesNeeded;
1791     return ERROR_BUFFER_OVERFLOW;
1792   }
1793
1794   memset(pPerAdapterInfo, 0, bytesNeeded);
1795   if (!isIfIndexLoopback(IfIndex)) {
1796     ret = get_dns_server_list(&pPerAdapterInfo->DnsServerList,
1797      (PIP_ADDR_STRING)((PBYTE)pPerAdapterInfo + sizeof(IP_PER_ADAPTER_INFO)),
1798      &serverListSize);
1799     /* Assume the first DNS server in the list is the "current" DNS server: */
1800     pPerAdapterInfo->CurrentDnsServer = &pPerAdapterInfo->DnsServerList;
1801   }
1802   return ret;
1803 }
1804
1805
1806 /******************************************************************
1807  *    GetRTTAndHopCount (IPHLPAPI.@)
1808  *
1809  * Get round-trip time (RTT) and hop count.
1810  *
1811  * PARAMS
1812  *
1813  *  DestIpAddress [In]  destination address to get the info for
1814  *  HopCount      [Out] retrieved hop count
1815  *  MaxHops       [In]  maximum hops to search for the destination
1816  *  RTT           [Out] RTT in milliseconds
1817  *
1818  * RETURNS
1819  *  Success: TRUE
1820  *  Failure: FALSE
1821  *
1822  * FIXME
1823  *  Stub, returns FALSE.
1824  */
1825 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
1826 {
1827   FIXME("(DestIpAddress 0x%08x, HopCount %p, MaxHops %d, RTT %p): stub\n",
1828    DestIpAddress, HopCount, MaxHops, RTT);
1829   return FALSE;
1830 }
1831
1832
1833 /******************************************************************
1834  *    GetTcpTable (IPHLPAPI.@)
1835  *
1836  * Get the table of active TCP connections.
1837  *
1838  * PARAMS
1839  *  pTcpTable [Out]    buffer for TCP connections table
1840  *  pdwSize   [In/Out] length of output buffer
1841  *  bOrder    [In]     whether to order the table
1842  *
1843  * RETURNS
1844  *  Success: NO_ERROR
1845  *  Failure: error code from winerror.h
1846  *
1847  * NOTES
1848  *  If pdwSize is less than required, the function will return 
1849  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to 
1850  *  the required byte size.
1851  *  If bOrder is true, the returned table will be sorted, first by
1852  *  local address and port number, then by remote address and port
1853  *  number.
1854  */
1855 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1856 {
1857     TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize, bOrder);
1858     return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, AF_INET, TCP_TABLE_BASIC_ALL, 0);
1859 }
1860
1861 /******************************************************************
1862  *    GetExtendedTcpTable (IPHLPAPI.@)
1863  */
1864 DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder,
1865                                  ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
1866 {
1867     DWORD ret, size;
1868     void *table;
1869
1870     TRACE("pTcpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
1871            pTcpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
1872
1873     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1874
1875     if (ulAf != AF_INET ||
1876         (TableClass != TCP_TABLE_BASIC_ALL && TableClass != TCP_TABLE_OWNER_PID_ALL))
1877     {
1878         FIXME("ulAf = %u, TableClass = %u not supported\n", ulAf, TableClass);
1879         return ERROR_NOT_SUPPORTED;
1880     }
1881     if ((ret = build_tcp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size)))
1882         return ret;
1883
1884     if (!pTcpTable || *pdwSize < size)
1885     {
1886         *pdwSize = size;
1887         ret = ERROR_INSUFFICIENT_BUFFER;
1888     }
1889     else
1890     {
1891         *pdwSize = size;
1892         memcpy(pTcpTable, table, size);
1893     }
1894     HeapFree(GetProcessHeap(), 0, table);
1895     return ret;
1896 }
1897
1898 /******************************************************************
1899  *    GetUdpTable (IPHLPAPI.@)
1900  *
1901  * Get a table of active UDP connections.
1902  *
1903  * PARAMS
1904  *  pUdpTable [Out]    buffer for UDP connections table
1905  *  pdwSize   [In/Out] length of output buffer
1906  *  bOrder    [In]     whether to order the table
1907  *
1908  * RETURNS
1909  *  Success: NO_ERROR
1910  *  Failure: error code from winerror.h
1911  *
1912  * NOTES
1913  *  If pdwSize is less than required, the function will return 
1914  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
1915  *  required byte size.
1916  *  If bOrder is true, the returned table will be sorted, first by
1917  *  local address, then by local port number.
1918  */
1919 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1920 {
1921     return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, AF_INET, UDP_TABLE_BASIC, 0);
1922 }
1923
1924 /******************************************************************
1925  *    GetExtendedUdpTable (IPHLPAPI.@)
1926  */
1927 DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder,
1928                                  ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved)
1929 {
1930     DWORD ret, size;
1931     void *table;
1932
1933     TRACE("pUdpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
1934            pUdpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
1935
1936     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1937
1938     if (ulAf != AF_INET ||
1939         (TableClass != UDP_TABLE_BASIC && TableClass != UDP_TABLE_OWNER_PID &&
1940          TableClass != UDP_TABLE_OWNER_MODULE))
1941     {
1942         FIXME("ulAf = %u, TableClass = %u not supported\n", ulAf, TableClass);
1943         return ERROR_NOT_SUPPORTED;
1944     }
1945     if (TableClass == UDP_TABLE_OWNER_MODULE)
1946         FIXME("UDP_TABLE_OWNER_MODULE not fully supported\n");
1947
1948     if ((ret = build_udp_table(TableClass, &table, bOrder, GetProcessHeap(), 0, &size)))
1949         return ret;
1950
1951     if (!pUdpTable || *pdwSize < size)
1952     {
1953         *pdwSize = size;
1954         ret = ERROR_INSUFFICIENT_BUFFER;
1955     }
1956     else
1957     {
1958         *pdwSize = size;
1959         memcpy(pUdpTable, table, size);
1960     }
1961     HeapFree(GetProcessHeap(), 0, table);
1962     return ret;
1963 }
1964
1965 /******************************************************************
1966  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1967  *
1968  * This is a Win98-only function to get information on "unidirectional"
1969  * adapters.  Since this is pretty nonsensical in other contexts, it
1970  * never returns anything.
1971  *
1972  * PARAMS
1973  *  pIPIfInfo   [Out] buffer for adapter infos
1974  *  dwOutBufLen [Out] length of the output buffer
1975  *
1976  * RETURNS
1977  *  Success: NO_ERROR
1978  *  Failure: error code from winerror.h
1979  *
1980  * FIXME
1981  *  Stub, returns ERROR_NOT_SUPPORTED.
1982  */
1983 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1984 {
1985   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
1986   /* a unidirectional adapter?? not bloody likely! */
1987   return ERROR_NOT_SUPPORTED;
1988 }
1989
1990
1991 /******************************************************************
1992  *    IpReleaseAddress (IPHLPAPI.@)
1993  *
1994  * Release an IP obtained through DHCP,
1995  *
1996  * PARAMS
1997  *  AdapterInfo [In] adapter to release IP address
1998  *
1999  * RETURNS
2000  *  Success: NO_ERROR
2001  *  Failure: error code from winerror.h
2002  *
2003  * NOTES
2004  *  Since GetAdaptersInfo never returns adapters that have DHCP enabled,
2005  *  this function does nothing.
2006  *
2007  * FIXME
2008  *  Stub, returns ERROR_NOT_SUPPORTED.
2009  */
2010 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2011 {
2012   FIXME("Stub AdapterInfo %p\n", AdapterInfo);
2013   return ERROR_NOT_SUPPORTED;
2014 }
2015
2016
2017 /******************************************************************
2018  *    IpRenewAddress (IPHLPAPI.@)
2019  *
2020  * Renew an IP obtained through DHCP.
2021  *
2022  * PARAMS
2023  *  AdapterInfo [In] adapter to renew IP address
2024  *
2025  * RETURNS
2026  *  Success: NO_ERROR
2027  *  Failure: error code from winerror.h
2028  *
2029  * NOTES
2030  *  Since GetAdaptersInfo never returns adapters that have DHCP enabled,
2031  *  this function does nothing.
2032  *
2033  * FIXME
2034  *  Stub, returns ERROR_NOT_SUPPORTED.
2035  */
2036 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2037 {
2038   FIXME("Stub AdapterInfo %p\n", AdapterInfo);
2039   return ERROR_NOT_SUPPORTED;
2040 }
2041
2042
2043 /******************************************************************
2044  *    NotifyAddrChange (IPHLPAPI.@)
2045  *
2046  * Notify caller whenever the ip-interface map is changed.
2047  *
2048  * PARAMS
2049  *  Handle     [Out] handle usable in asynchronous notification
2050  *  overlapped [In]  overlapped structure that notifies the caller
2051  *
2052  * RETURNS
2053  *  Success: NO_ERROR
2054  *  Failure: error code from winerror.h
2055  *
2056  * FIXME
2057  *  Stub, returns ERROR_NOT_SUPPORTED.
2058  */
2059 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2060 {
2061   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2062   if (Handle) *Handle = INVALID_HANDLE_VALUE;
2063   if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->u.Status = STATUS_PENDING;
2064   return ERROR_IO_PENDING;
2065 }
2066
2067
2068 /******************************************************************
2069  *    NotifyRouteChange (IPHLPAPI.@)
2070  *
2071  * Notify caller whenever the ip routing table is changed.
2072  *
2073  * PARAMS
2074  *  Handle     [Out] handle usable in asynchronous notification
2075  *  overlapped [In]  overlapped structure that notifies the caller
2076  *
2077  * RETURNS
2078  *  Success: NO_ERROR
2079  *  Failure: error code from winerror.h
2080  *
2081  * FIXME
2082  *  Stub, returns ERROR_NOT_SUPPORTED.
2083  */
2084 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2085 {
2086   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2087   return ERROR_NOT_SUPPORTED;
2088 }
2089
2090
2091 /******************************************************************
2092  *    SendARP (IPHLPAPI.@)
2093  *
2094  * Send an ARP request.
2095  *
2096  * PARAMS
2097  *  DestIP     [In]     attempt to obtain this IP
2098  *  SrcIP      [In]     optional sender IP address
2099  *  pMacAddr   [Out]    buffer for the mac address
2100  *  PhyAddrLen [In/Out] length of the output buffer
2101  *
2102  * RETURNS
2103  *  Success: NO_ERROR
2104  *  Failure: error code from winerror.h
2105  *
2106  * FIXME
2107  *  Stub, returns ERROR_NOT_SUPPORTED.
2108  */
2109 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2110 {
2111   FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
2112    DestIP, SrcIP, pMacAddr, PhyAddrLen);
2113   return ERROR_NOT_SUPPORTED;
2114 }
2115
2116
2117 /******************************************************************
2118  *    SetIfEntry (IPHLPAPI.@)
2119  *
2120  * Set the administrative status of an interface.
2121  *
2122  * PARAMS
2123  *  pIfRow [In] dwAdminStatus member specifies the new status.
2124  *
2125  * RETURNS
2126  *  Success: NO_ERROR
2127  *  Failure: error code from winerror.h
2128  *
2129  * FIXME
2130  *  Stub, returns ERROR_NOT_SUPPORTED.
2131  */
2132 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
2133 {
2134   FIXME("(pIfRow %p): stub\n", pIfRow);
2135   /* this is supposed to set an interface administratively up or down.
2136      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2137      this sort of down is indistinguishable from other sorts of down (e.g. no
2138      link). */
2139   return ERROR_NOT_SUPPORTED;
2140 }
2141
2142
2143 /******************************************************************
2144  *    SetIpForwardEntry (IPHLPAPI.@)
2145  *
2146  * Modify an existing route.
2147  *
2148  * PARAMS
2149  *  pRoute [In] route with the new information
2150  *
2151  * RETURNS
2152  *  Success: NO_ERROR
2153  *  Failure: error code from winerror.h
2154  *
2155  * FIXME
2156  *  Stub, returns NO_ERROR.
2157  */
2158 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
2159 {
2160   FIXME("(pRoute %p): stub\n", pRoute);
2161   /* this is to add a route entry, how's it distinguishable from
2162      CreateIpForwardEntry?
2163      could use SIOCADDRT, not sure I want to */
2164   return 0;
2165 }
2166
2167
2168 /******************************************************************
2169  *    SetIpNetEntry (IPHLPAPI.@)
2170  *
2171  * Modify an existing ARP entry.
2172  *
2173  * PARAMS
2174  *  pArpEntry [In] ARP entry with the new information
2175  *
2176  * RETURNS
2177  *  Success: NO_ERROR
2178  *  Failure: error code from winerror.h
2179  *
2180  * FIXME
2181  *  Stub, returns NO_ERROR.
2182  */
2183 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
2184 {
2185   FIXME("(pArpEntry %p): stub\n", pArpEntry);
2186   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
2187   return 0;
2188 }
2189
2190
2191 /******************************************************************
2192  *    SetIpStatistics (IPHLPAPI.@)
2193  *
2194  * Toggle IP forwarding and det the default TTL value.
2195  *
2196  * PARAMS
2197  *  pIpStats [In] IP statistics with the new information
2198  *
2199  * RETURNS
2200  *  Success: NO_ERROR
2201  *  Failure: error code from winerror.h
2202  *
2203  * FIXME
2204  *  Stub, returns NO_ERROR.
2205  */
2206 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
2207 {
2208   FIXME("(pIpStats %p): stub\n", pIpStats);
2209   return 0;
2210 }
2211
2212
2213 /******************************************************************
2214  *    SetIpTTL (IPHLPAPI.@)
2215  *
2216  * Set the default TTL value.
2217  *
2218  * PARAMS
2219  *  nTTL [In] new TTL value
2220  *
2221  * RETURNS
2222  *  Success: NO_ERROR
2223  *  Failure: error code from winerror.h
2224  *
2225  * FIXME
2226  *  Stub, returns NO_ERROR.
2227  */
2228 DWORD WINAPI SetIpTTL(UINT nTTL)
2229 {
2230   FIXME("(nTTL %d): stub\n", nTTL);
2231   /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
2232      want to.  Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
2233   return 0;
2234 }
2235
2236
2237 /******************************************************************
2238  *    SetTcpEntry (IPHLPAPI.@)
2239  *
2240  * Set the state of a TCP connection.
2241  *
2242  * PARAMS
2243  *  pTcpRow [In] specifies connection with new state
2244  *
2245  * RETURNS
2246  *  Success: NO_ERROR
2247  *  Failure: error code from winerror.h
2248  *
2249  * FIXME
2250  *  Stub, returns NO_ERROR.
2251  */
2252 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
2253 {
2254   FIXME("(pTcpRow %p): stub\n", pTcpRow);
2255   return 0;
2256 }
2257
2258
2259 /******************************************************************
2260  *    UnenableRouter (IPHLPAPI.@)
2261  *
2262  * Decrement the IP-forwarding reference count. Turn off IP-forwarding
2263  * if it reaches zero.
2264  *
2265  * PARAMS
2266  *  pOverlapped     [In/Out] should be the same as in EnableRouter()
2267  *  lpdwEnableCount [Out]    optional, receives reference count
2268  *
2269  * RETURNS
2270  *  Success: NO_ERROR
2271  *  Failure: error code from winerror.h
2272  *
2273  * FIXME
2274  *  Stub, returns ERROR_NOT_SUPPORTED.
2275  */
2276 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
2277 {
2278   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
2279    lpdwEnableCount);
2280   /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
2281      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
2282    */
2283   return ERROR_NOT_SUPPORTED;
2284 }
2285
2286 /******************************************************************
2287  *    PfCreateInterface (IPHLPAPI.@)
2288  */
2289 DWORD WINAPI PfCreateInterface(DWORD dwName, PFFORWARD_ACTION inAction, PFFORWARD_ACTION outAction,
2290         BOOL bUseLog, BOOL bMustBeUnique, INTERFACE_HANDLE *ppInterface)
2291 {
2292     FIXME("(%d %d %d %x %x %p) stub\n", dwName, inAction, outAction, bUseLog, bMustBeUnique, ppInterface);
2293     return ERROR_CALL_NOT_IMPLEMENTED;
2294 }
2295
2296 /******************************************************************
2297  *    GetTcpTable2 (IPHLPAPI.@)
2298  */
2299 ULONG WINAPI GetTcpTable2(PMIB_TCPTABLE2 table, PULONG size, BOOL order)
2300 {
2301     FIXME("pTcpTable2 %p, pdwSize %p, bOrder %d: stub\n", table, size, order);
2302     return ERROR_NOT_SUPPORTED;
2303 }
2304
2305 /******************************************************************
2306  *    GetTcp6Table (IPHLPAPI.@)
2307  */
2308 ULONG WINAPI GetTcp6Table(PMIB_TCP6TABLE table, PULONG size, BOOL order)
2309 {
2310     FIXME("pTcp6Table %p, size %p, order %d: stub\n", table, size, order);
2311     return ERROR_NOT_SUPPORTED;
2312 }
2313
2314 /******************************************************************
2315  *    GetTcp6Table2 (IPHLPAPI.@)
2316  */
2317 ULONG WINAPI GetTcp6Table2(PMIB_TCP6TABLE2 table, PULONG size, BOOL order)
2318 {
2319     FIXME("pTcp6Table2 %p, size %p, order %d: stub\n", table, size, order);
2320     return ERROR_NOT_SUPPORTED;
2321 }