iphlpapi: Add GetTcp6Table/GetTcp6Table2 stubs.
[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             ret = NO_ERROR;
603           }
604           HeapFree(GetProcessHeap(), 0, table);
605         }
606         else
607           ret = ERROR_OUTOFMEMORY;
608         HeapFree(GetProcessHeap(), 0, routeTable);
609         HeapFree(GetProcessHeap(), 0, ipAddrTable);
610       }
611     }
612     else
613       ret = ERROR_NO_DATA;
614   }
615   TRACE("returning %d\n", ret);
616   return ret;
617 }
618
619 static DWORD typeFromMibType(DWORD mib_type)
620 {
621     switch (mib_type)
622     {
623     case MIB_IF_TYPE_ETHERNET:  return IF_TYPE_ETHERNET_CSMACD;
624     case MIB_IF_TYPE_TOKENRING: return IF_TYPE_ISO88025_TOKENRING;
625     case MIB_IF_TYPE_PPP:       return IF_TYPE_PPP;
626     case MIB_IF_TYPE_LOOPBACK:  return IF_TYPE_SOFTWARE_LOOPBACK;
627     default:                    return IF_TYPE_OTHER;
628     }
629 }
630
631 static NET_IF_CONNECTION_TYPE connectionTypeFromMibType(DWORD mib_type)
632 {
633     switch (mib_type)
634     {
635     case MIB_IF_TYPE_PPP:       return NET_IF_CONNECTION_DEMAND;
636     case MIB_IF_TYPE_SLIP:      return NET_IF_CONNECTION_DEMAND;
637     default:                    return NET_IF_CONNECTION_DEDICATED;
638     }
639 }
640
641 static ULONG v4addressesFromIndex(IF_INDEX index, DWORD **addrs, ULONG *num_addrs)
642 {
643     ULONG ret, i, j;
644     MIB_IPADDRTABLE *at;
645
646     *num_addrs = 0;
647     if ((ret = getIPAddrTable(&at, GetProcessHeap(), 0))) return ret;
648     for (i = 0; i < at->dwNumEntries; i++)
649     {
650         if (at->table[i].dwIndex == index) (*num_addrs)++;
651     }
652     if (!(*addrs = HeapAlloc(GetProcessHeap(), 0, *num_addrs * sizeof(DWORD))))
653     {
654         HeapFree(GetProcessHeap(), 0, at);
655         return ERROR_OUTOFMEMORY;
656     }
657     for (i = 0, j = 0; i < at->dwNumEntries; i++)
658     {
659         if (at->table[i].dwIndex == index) (*addrs)[j++] = at->table[i].dwAddr;
660     }
661     HeapFree(GetProcessHeap(), 0, at);
662     return ERROR_SUCCESS;
663 }
664
665 static char *debugstr_ipv4(const in_addr_t *in_addr, char *buf)
666 {
667     const BYTE *addrp;
668     char *p = buf;
669
670     for (addrp = (const BYTE *)in_addr;
671      addrp - (const BYTE *)in_addr < sizeof(*in_addr);
672      addrp++)
673     {
674         if (addrp == (const BYTE *)in_addr + sizeof(*in_addr) - 1)
675             sprintf(p, "%d", *addrp);
676         else
677             p += sprintf(p, "%d.", *addrp);
678     }
679     return buf;
680 }
681
682 static char *debugstr_ipv6(const struct WS_sockaddr_in6 *sin, char *buf)
683 {
684     const IN6_ADDR *addr = &sin->sin6_addr;
685     char *p = buf;
686     int i;
687     BOOL in_zero = FALSE;
688
689     for (i = 0; i < 7; i++)
690     {
691         if (!addr->u.Word[i])
692         {
693             if (i == 0)
694                 *p++ = ':';
695             if (!in_zero)
696             {
697                 *p++ = ':';
698                 in_zero = TRUE;
699             }
700         }
701         else
702         {
703             p += sprintf(p, "%x:", ntohs(addr->u.Word[i]));
704             in_zero = FALSE;
705         }
706     }
707     sprintf(p, "%x", ntohs(addr->u.Word[7]));
708     return buf;
709 }
710
711 static ULONG count_v4_gateways(DWORD index, PMIB_IPFORWARDTABLE routeTable)
712 {
713     DWORD i, num_gateways = 0;
714
715     for (i = 0; i < routeTable->dwNumEntries; i++)
716     {
717         if (routeTable->table[i].dwForwardIfIndex == index &&
718             routeTable->table[i].u1.ForwardType == MIB_IPROUTE_TYPE_INDIRECT)
719             num_gateways++;
720     }
721     return num_gateways;
722 }
723
724 static PMIB_IPFORWARDROW findIPv4Gateway(DWORD index,
725                                          PMIB_IPFORWARDTABLE routeTable)
726 {
727     DWORD i;
728     PMIB_IPFORWARDROW row = NULL;
729
730     for (i = 0; !row && i < routeTable->dwNumEntries; i++)
731     {
732         if (routeTable->table[i].dwForwardIfIndex == index &&
733             routeTable->table[i].u1.ForwardType == MIB_IPROUTE_TYPE_INDIRECT)
734             row = &routeTable->table[i];
735     }
736     return row;
737 }
738
739 static ULONG adapterAddressesFromIndex(ULONG family, ULONG flags, IF_INDEX index,
740                                        IP_ADAPTER_ADDRESSES *aa, ULONG *size)
741 {
742     ULONG ret = ERROR_SUCCESS, i, num_v4addrs = 0, num_v4_gateways = 0, num_v6addrs = 0, total_size;
743     DWORD *v4addrs = NULL;
744     SOCKET_ADDRESS *v6addrs = NULL;
745     PMIB_IPFORWARDTABLE routeTable = NULL;
746
747     if (family == WS_AF_INET)
748     {
749         if (!(flags & GAA_FLAG_SKIP_UNICAST))
750             ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs);
751         if (!ret && flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
752         {
753             ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE,
754                                                         GetProcessHeap(), 0);
755             if (!ret)
756                 num_v4_gateways = count_v4_gateways(index, routeTable);
757         }
758     }
759     else if (family == WS_AF_INET6)
760     {
761         if (!(flags & GAA_FLAG_SKIP_UNICAST))
762             ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs);
763     }
764     else if (family == WS_AF_UNSPEC)
765     {
766         if (!(flags & GAA_FLAG_SKIP_UNICAST))
767             ret = v4addressesFromIndex(index, &v4addrs, &num_v4addrs);
768         if (!ret && flags & GAA_FLAG_INCLUDE_ALL_GATEWAYS)
769         {
770             ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE,
771                                                         GetProcessHeap(), 0);
772             if (!ret)
773                 num_v4_gateways = count_v4_gateways(index, routeTable);
774         }
775         if (!ret && !(flags & GAA_FLAG_SKIP_UNICAST))
776             ret = v6addressesFromIndex(index, &v6addrs, &num_v6addrs);
777     }
778     else
779     {
780         FIXME("address family %u unsupported\n", family);
781         ret = ERROR_NO_DATA;
782     }
783     if (ret)
784     {
785         HeapFree(GetProcessHeap(), 0, routeTable);
786         return ret;
787     }
788
789     total_size = sizeof(IP_ADAPTER_ADDRESSES);
790     total_size += IF_NAMESIZE;
791     total_size += IF_NAMESIZE * sizeof(WCHAR);
792     if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
793         total_size += IF_NAMESIZE * sizeof(WCHAR);
794     total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v4addrs;
795     total_size += sizeof(struct sockaddr_in) * num_v4addrs;
796     total_size += (sizeof(IP_ADAPTER_GATEWAY_ADDRESS) + sizeof(SOCKADDR_IN)) * num_v4_gateways;
797     total_size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) * num_v6addrs;
798     total_size += sizeof(SOCKET_ADDRESS) * num_v6addrs;
799     for (i = 0; i < num_v6addrs; i++)
800         total_size += v6addrs[i].iSockaddrLength;
801
802     if (aa && *size >= total_size)
803     {
804         char name[IF_NAMESIZE], *ptr = (char *)aa + sizeof(IP_ADAPTER_ADDRESSES), *src;
805         WCHAR *dst;
806         DWORD buflen, type;
807         INTERNAL_IF_OPER_STATUS status;
808
809         memset(aa, 0, sizeof(IP_ADAPTER_ADDRESSES));
810         aa->u.s.Length  = sizeof(IP_ADAPTER_ADDRESSES);
811         aa->u.s.IfIndex = index;
812
813         getInterfaceNameByIndex(index, name);
814         memcpy(ptr, name, IF_NAMESIZE);
815         aa->AdapterName = ptr;
816         ptr += IF_NAMESIZE;
817         if (!(flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
818         {
819             aa->FriendlyName = (WCHAR *)ptr;
820             for (src = name, dst = (WCHAR *)ptr; *src; src++, dst++)
821                 *dst = *src;
822             *dst++ = 0;
823             ptr = (char *)dst;
824         }
825         aa->Description = (WCHAR *)ptr;
826         for (src = name, dst = (WCHAR *)ptr; *src; src++, dst++)
827             *dst = *src;
828         *dst++ = 0;
829         ptr = (char *)dst;
830
831         TRACE("%s: %d IPv4 addresses, %d IPv6 addresses:\n", name, num_v4addrs,
832               num_v6addrs);
833         if (num_v4_gateways)
834         {
835             PMIB_IPFORWARDROW adapterRow;
836
837             if ((adapterRow = findIPv4Gateway(index, routeTable)))
838             {
839                 PIP_ADAPTER_GATEWAY_ADDRESS gw;
840                 PSOCKADDR_IN sin;
841
842                 gw = (PIP_ADAPTER_GATEWAY_ADDRESS)ptr;
843                 aa->FirstGatewayAddress = gw;
844
845                 gw->u.s.Length = sizeof(IP_ADAPTER_GATEWAY_ADDRESS);
846                 ptr += sizeof(IP_ADAPTER_GATEWAY_ADDRESS);
847                 sin = (PSOCKADDR_IN)ptr;
848                 sin->sin_family = AF_INET;
849                 sin->sin_port = 0;
850                 memcpy(&sin->sin_addr, &adapterRow->dwForwardNextHop,
851                        sizeof(DWORD));
852                 gw->Address.lpSockaddr = (LPSOCKADDR)sin;
853                 gw->Address.iSockaddrLength = sizeof(SOCKADDR_IN);
854                 gw->Next = NULL;
855                 ptr += sizeof(SOCKADDR_IN);
856             }
857         }
858         if (num_v4addrs)
859         {
860             IP_ADAPTER_UNICAST_ADDRESS *ua;
861             struct sockaddr_in *sa;
862             aa->Flags |= IP_ADAPTER_IPV4_ENABLED;
863             ua = aa->FirstUnicastAddress = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
864             for (i = 0; i < num_v4addrs; i++)
865             {
866                 char addr_buf[16];
867
868                 memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
869                 ua->u.s.Length              = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
870                 ua->Address.iSockaddrLength = sizeof(struct sockaddr_in);
871                 ua->Address.lpSockaddr      = (SOCKADDR *)((char *)ua + ua->u.s.Length);
872
873                 sa = (struct sockaddr_in *)ua->Address.lpSockaddr;
874                 sa->sin_family      = AF_INET;
875                 sa->sin_addr.s_addr = v4addrs[i];
876                 sa->sin_port        = 0;
877                 TRACE("IPv4 %d/%d: %s\n", i + 1, num_v4addrs,
878                       debugstr_ipv4(&sa->sin_addr.s_addr, addr_buf));
879
880                 ptr += ua->u.s.Length + ua->Address.iSockaddrLength;
881                 if (i < num_v4addrs - 1)
882                 {
883                     ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
884                     ua = ua->Next;
885                 }
886             }
887         }
888         if (num_v6addrs)
889         {
890             IP_ADAPTER_UNICAST_ADDRESS *ua;
891             struct WS_sockaddr_in6 *sa;
892
893             aa->Flags |= IP_ADAPTER_IPV6_ENABLED;
894             if (aa->FirstUnicastAddress)
895             {
896                 for (ua = aa->FirstUnicastAddress; ua->Next; ua = ua->Next)
897                     ;
898                 ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
899                 ua = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
900             }
901             else
902                 ua = aa->FirstUnicastAddress = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
903             for (i = 0; i < num_v6addrs; i++)
904             {
905                 char addr_buf[46];
906
907                 memset(ua, 0, sizeof(IP_ADAPTER_UNICAST_ADDRESS));
908                 ua->u.s.Length              = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
909                 ua->Address.iSockaddrLength = v6addrs[i].iSockaddrLength;
910                 ua->Address.lpSockaddr      = (SOCKADDR *)((char *)ua + ua->u.s.Length);
911
912                 sa = (struct WS_sockaddr_in6 *)ua->Address.lpSockaddr;
913                 memcpy(sa, v6addrs[i].lpSockaddr, sizeof(*sa));
914                 TRACE("IPv6 %d/%d: %s\n", i + 1, num_v6addrs,
915                       debugstr_ipv6(sa, addr_buf));
916
917                 ptr += ua->u.s.Length + ua->Address.iSockaddrLength;
918                 if (i < num_v6addrs - 1)
919                 {
920                     ua->Next = (IP_ADAPTER_UNICAST_ADDRESS *)ptr;
921                     ua = ua->Next;
922                 }
923             }
924         }
925
926         buflen = MAX_INTERFACE_PHYSADDR;
927         getInterfacePhysicalByIndex(index, &buflen, aa->PhysicalAddress, &type);
928         aa->PhysicalAddressLength = buflen;
929         aa->IfType = typeFromMibType(type);
930         aa->ConnectionType = connectionTypeFromMibType(type);
931
932         getInterfaceMtuByName(name, &aa->Mtu);
933
934         getInterfaceStatusByName(name, &status);
935         if (status == MIB_IF_OPER_STATUS_OPERATIONAL) aa->OperStatus = IfOperStatusUp;
936         else if (status == MIB_IF_OPER_STATUS_NON_OPERATIONAL) aa->OperStatus = IfOperStatusDown;
937         else aa->OperStatus = IfOperStatusUnknown;
938     }
939     *size = total_size;
940     HeapFree(GetProcessHeap(), 0, routeTable);
941     HeapFree(GetProcessHeap(), 0, v6addrs);
942     HeapFree(GetProcessHeap(), 0, v4addrs);
943     return ERROR_SUCCESS;
944 }
945
946 static ULONG get_dns_server_addresses(PIP_ADAPTER_DNS_SERVER_ADDRESS address, ULONG *len)
947 {
948     DWORD size;
949
950     initialise_resolver();
951     /* FIXME: no support for IPv6 DNS server addresses.  Doing so requires
952      * sizeof SOCKADDR_STORAGE instead, and using _res._u._ext.nsaddrs when
953      * available.
954      */
955     size = _res.nscount * (sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + sizeof(SOCKADDR));
956     if (!address || *len < size)
957     {
958         *len = size;
959         return ERROR_BUFFER_OVERFLOW;
960     }
961     *len = size;
962     if (_res.nscount > 0)
963     {
964         PIP_ADAPTER_DNS_SERVER_ADDRESS addr;
965         int i;
966
967         for (i = 0, addr = address; i < _res.nscount && addr;
968              i++, addr = addr->Next)
969         {
970             SOCKADDR_IN *sin;
971
972             addr->Address.iSockaddrLength = sizeof(SOCKADDR);
973             addr->Address.lpSockaddr =
974              (LPSOCKADDR)((PBYTE)addr + sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS));
975             sin = (SOCKADDR_IN *)addr->Address.lpSockaddr;
976             sin->sin_family = WS_AF_INET;
977             sin->sin_port = _res.nsaddr_list[i].sin_port;
978             memcpy(&sin->sin_addr, &_res.nsaddr_list[i].sin_addr, sizeof(sin->sin_addr));
979             if (i == _res.nscount - 1)
980                 addr->Next = NULL;
981             else
982                 addr->Next =
983                  (PIP_ADAPTER_DNS_SERVER_ADDRESS)((PBYTE)addr +
984                  sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + sizeof(SOCKADDR));
985         }
986     }
987     return ERROR_SUCCESS;
988 }
989
990 static BOOL is_ip_address_string(const char *str)
991 {
992     struct in_addr in;
993     int ret;
994
995     ret = inet_aton(str, &in);
996     return ret != 0;
997 }
998
999 static ULONG get_dns_suffix(WCHAR *suffix, ULONG *len)
1000 {
1001     ULONG size, i;
1002     char *found_suffix = NULL;
1003
1004     initialise_resolver();
1005     /* Always return a NULL-terminated string, even if it's empty. */
1006     size = sizeof(WCHAR);
1007     for (i = 0, found_suffix = NULL;
1008          !found_suffix && i < MAXDNSRCH + 1 && _res.dnsrch[i]; i++)
1009     {
1010         /* This uses a heuristic to select a DNS suffix:
1011          * the first, non-IP address string is selected.
1012          */
1013         if (!is_ip_address_string(_res.dnsrch[i]))
1014             found_suffix = _res.dnsrch[i];
1015     }
1016     if (found_suffix)
1017         size += strlen(found_suffix) * sizeof(WCHAR);
1018     if (!suffix || *len < size)
1019     {
1020         *len = size;
1021         return ERROR_BUFFER_OVERFLOW;
1022     }
1023     *len = size;
1024     if (found_suffix)
1025     {
1026         char *p;
1027
1028         for (p = found_suffix; *p; p++)
1029             *suffix++ = *p;
1030     }
1031     *suffix = 0;
1032     return ERROR_SUCCESS;
1033 }
1034
1035 ULONG WINAPI GetAdaptersAddresses(ULONG family, ULONG flags, PVOID reserved,
1036                                   PIP_ADAPTER_ADDRESSES aa, PULONG buflen)
1037 {
1038     InterfaceIndexTable *table;
1039     ULONG i, size, dns_server_size, dns_suffix_size, total_size, ret = ERROR_NO_DATA;
1040
1041     TRACE("(%d, %08x, %p, %p, %p)\n", family, flags, reserved, aa, buflen);
1042
1043     if (!buflen) return ERROR_INVALID_PARAMETER;
1044
1045     table = getInterfaceIndexTable();
1046     if (!table || !table->numIndexes)
1047     {
1048         HeapFree(GetProcessHeap(), 0, table);
1049         return ERROR_NO_DATA;
1050     }
1051     total_size = 0;
1052     for (i = 0; i < table->numIndexes; i++)
1053     {
1054         size = 0;
1055         if ((ret = adapterAddressesFromIndex(family, flags, table->indexes[i], NULL, &size)))
1056         {
1057             HeapFree(GetProcessHeap(), 0, table);
1058             return ret;
1059         }
1060         total_size += size;
1061     }
1062     if (!(flags & GAA_FLAG_SKIP_DNS_SERVER))
1063     {
1064         /* Since DNS servers aren't really per adapter, get enough space for a
1065          * single copy of them.
1066          */
1067         get_dns_server_addresses(NULL, &dns_server_size);
1068         total_size += dns_server_size;
1069     }
1070     /* Since DNS suffix also isn't really per adapter, get enough space for a
1071      * single copy of it.
1072      */
1073     get_dns_suffix(NULL, &dns_suffix_size);
1074     total_size += dns_suffix_size;
1075     if (aa && *buflen >= total_size)
1076     {
1077         ULONG bytes_left = size = total_size;
1078         PIP_ADAPTER_ADDRESSES first_aa = aa;
1079         PIP_ADAPTER_DNS_SERVER_ADDRESS firstDns;
1080         WCHAR *dnsSuffix;
1081
1082         for (i = 0; i < table->numIndexes; i++)
1083         {
1084             if ((ret = adapterAddressesFromIndex(family, flags, table->indexes[i], aa, &size)))
1085             {
1086                 HeapFree(GetProcessHeap(), 0, table);
1087                 return ret;
1088             }
1089             if (i < table->numIndexes - 1)
1090             {
1091                 aa->Next = (IP_ADAPTER_ADDRESSES *)((char *)aa + size);
1092                 aa = aa->Next;
1093                 size = bytes_left -= size;
1094             }
1095         }
1096         if (!(flags & GAA_FLAG_SKIP_DNS_SERVER))
1097         {
1098             firstDns = (PIP_ADAPTER_DNS_SERVER_ADDRESS)((BYTE *)first_aa + total_size - dns_server_size - dns_suffix_size);
1099             get_dns_server_addresses(firstDns, &dns_server_size);
1100             for (aa = first_aa; aa; aa = aa->Next)
1101             {
1102                 if (aa->IfType != IF_TYPE_SOFTWARE_LOOPBACK && aa->OperStatus == IfOperStatusUp)
1103                     aa->FirstDnsServerAddress = firstDns;
1104             }
1105         }
1106         aa = first_aa;
1107         dnsSuffix = (WCHAR *)((BYTE *)aa + total_size - dns_suffix_size);
1108         get_dns_suffix(dnsSuffix, &dns_suffix_size);
1109         for (; aa; aa = aa->Next)
1110         {
1111             if (aa->IfType != IF_TYPE_SOFTWARE_LOOPBACK && aa->OperStatus == IfOperStatusUp)
1112                 aa->DnsSuffix = dnsSuffix;
1113             else
1114                 aa->DnsSuffix = (WCHAR *)((BYTE*)dnsSuffix + dns_suffix_size - 2);
1115         }
1116         ret = ERROR_SUCCESS;
1117     }
1118     else
1119         ret = ERROR_BUFFER_OVERFLOW;
1120     *buflen = total_size;
1121
1122     TRACE("num adapters %u\n", table->numIndexes);
1123     HeapFree(GetProcessHeap(), 0, table);
1124     return ret;
1125 }
1126
1127 /******************************************************************
1128  *    GetBestInterface (IPHLPAPI.@)
1129  *
1130  * Get the interface, with the best route for the given IP address.
1131  *
1132  * PARAMS
1133  *  dwDestAddr     [In]  IP address to search the interface for
1134  *  pdwBestIfIndex [Out] found best interface
1135  *
1136  * RETURNS
1137  *  Success: NO_ERROR
1138  *  Failure: error code from winerror.h
1139  */
1140 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
1141 {
1142     struct WS_sockaddr_in sa_in;
1143     memset(&sa_in, 0, sizeof(sa_in));
1144     sa_in.sin_family = AF_INET;
1145     sa_in.sin_addr.S_un.S_addr = dwDestAddr;
1146     return GetBestInterfaceEx((struct WS_sockaddr *)&sa_in, pdwBestIfIndex);
1147 }
1148
1149 /******************************************************************
1150  *    GetBestInterfaceEx (IPHLPAPI.@)
1151  *
1152  * Get the interface, with the best route for the given IP address.
1153  *
1154  * PARAMS
1155  *  dwDestAddr     [In]  IP address to search the interface for
1156  *  pdwBestIfIndex [Out] found best interface
1157  *
1158  * RETURNS
1159  *  Success: NO_ERROR
1160  *  Failure: error code from winerror.h
1161  */
1162 DWORD WINAPI GetBestInterfaceEx(struct WS_sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
1163 {
1164   DWORD ret;
1165
1166   TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
1167   if (!pDestAddr || !pdwBestIfIndex)
1168     ret = ERROR_INVALID_PARAMETER;
1169   else {
1170     MIB_IPFORWARDROW ipRow;
1171
1172     if (pDestAddr->sa_family == AF_INET) {
1173       ret = GetBestRoute(((struct WS_sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
1174       if (ret == ERROR_SUCCESS)
1175         *pdwBestIfIndex = ipRow.dwForwardIfIndex;
1176     } else {
1177       FIXME("address family %d not supported\n", pDestAddr->sa_family);
1178       ret = ERROR_NOT_SUPPORTED;
1179     }
1180   }
1181   TRACE("returning %d\n", ret);
1182   return ret;
1183 }
1184
1185
1186 /******************************************************************
1187  *    GetBestRoute (IPHLPAPI.@)
1188  *
1189  * Get the best route for the given IP address.
1190  *
1191  * PARAMS
1192  *  dwDestAddr   [In]  IP address to search the best route for
1193  *  dwSourceAddr [In]  optional source IP address
1194  *  pBestRoute   [Out] found best route
1195  *
1196  * RETURNS
1197  *  Success: NO_ERROR
1198  *  Failure: error code from winerror.h
1199  */
1200 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
1201 {
1202   PMIB_IPFORWARDTABLE table;
1203   DWORD ret;
1204
1205   TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr,
1206    dwSourceAddr, pBestRoute);
1207   if (!pBestRoute)
1208     return ERROR_INVALID_PARAMETER;
1209
1210   ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
1211   if (!ret) {
1212     DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
1213
1214     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
1215       if (table->table[ndx].u1.ForwardType != MIB_IPROUTE_TYPE_INVALID &&
1216        (dwDestAddr & table->table[ndx].dwForwardMask) ==
1217        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
1218         DWORD numShifts, mask;
1219
1220         for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
1221          mask && mask & 1; mask >>= 1, numShifts++)
1222           ;
1223         if (numShifts > matchedBits) {
1224           matchedBits = numShifts;
1225           matchedNdx = ndx;
1226         }
1227         else if (!matchedBits) {
1228           matchedNdx = ndx;
1229         }
1230       }
1231     }
1232     if (matchedNdx < table->dwNumEntries) {
1233       memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
1234       ret = ERROR_SUCCESS;
1235     }
1236     else {
1237       /* No route matches, which can happen if there's no default route. */
1238       ret = ERROR_HOST_UNREACHABLE;
1239     }
1240     HeapFree(GetProcessHeap(), 0, table);
1241   }
1242   TRACE("returning %d\n", ret);
1243   return ret;
1244 }
1245
1246
1247 /******************************************************************
1248  *    GetFriendlyIfIndex (IPHLPAPI.@)
1249  *
1250  * Get a "friendly" version of IfIndex, which is one that doesn't
1251  * have the top byte set.  Doesn't validate whether IfIndex is a valid
1252  * adapter index.
1253  *
1254  * PARAMS
1255  *  IfIndex [In] interface index to get the friendly one for
1256  *
1257  * RETURNS
1258  *  A friendly version of IfIndex.
1259  */
1260 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1261 {
1262   /* windows doesn't validate these, either, just makes sure the top byte is
1263      cleared.  I assume my ifenum module never gives an index with the top
1264      byte set. */
1265   TRACE("returning %d\n", IfIndex);
1266   return IfIndex;
1267 }
1268
1269
1270 /******************************************************************
1271  *    GetIfEntry (IPHLPAPI.@)
1272  *
1273  * Get information about an interface.
1274  *
1275  * PARAMS
1276  *  pIfRow [In/Out] In:  dwIndex of MIB_IFROW selects the interface.
1277  *                  Out: interface information
1278  *
1279  * RETURNS
1280  *  Success: NO_ERROR
1281  *  Failure: error code from winerror.h
1282  */
1283 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
1284 {
1285   DWORD ret;
1286   char nameBuf[MAX_ADAPTER_NAME];
1287   char *name;
1288
1289   TRACE("pIfRow %p\n", pIfRow);
1290   if (!pIfRow)
1291     return ERROR_INVALID_PARAMETER;
1292
1293   name = getInterfaceNameByIndex(pIfRow->dwIndex, nameBuf);
1294   if (name) {
1295     ret = getInterfaceEntryByName(name, pIfRow);
1296     if (ret == NO_ERROR)
1297       ret = getInterfaceStatsByName(name, pIfRow);
1298   }
1299   else
1300     ret = ERROR_INVALID_DATA;
1301   TRACE("returning %d\n", ret);
1302   return ret;
1303 }
1304
1305
1306 static int IfTableSorter(const void *a, const void *b)
1307 {
1308   int ret;
1309
1310   if (a && b)
1311     ret = ((const MIB_IFROW*)a)->dwIndex - ((const MIB_IFROW*)b)->dwIndex;
1312   else
1313     ret = 0;
1314   return ret;
1315 }
1316
1317
1318 /******************************************************************
1319  *    GetIfTable (IPHLPAPI.@)
1320  *
1321  * Get a table of local interfaces.
1322  *
1323  * PARAMS
1324  *  pIfTable [Out]    buffer for local interfaces table
1325  *  pdwSize  [In/Out] length of output buffer
1326  *  bOrder   [In]     whether to sort the table
1327  *
1328  * RETURNS
1329  *  Success: NO_ERROR
1330  *  Failure: error code from winerror.h
1331  *
1332  * NOTES
1333  *  If pdwSize is less than required, the function will return
1334  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1335  *  size.
1336  *  If bOrder is true, the returned table will be sorted by interface index.
1337  */
1338 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
1339 {
1340   DWORD ret;
1341
1342   TRACE("pIfTable %p, pdwSize %p, bOrder %d\n", pdwSize, pdwSize,
1343    (DWORD)bOrder);
1344   if (!pdwSize)
1345     ret = ERROR_INVALID_PARAMETER;
1346   else {
1347     DWORD numInterfaces = getNumInterfaces();
1348     ULONG size = sizeof(MIB_IFTABLE);
1349
1350     if (numInterfaces > 1)
1351       size += (numInterfaces - 1) * sizeof(MIB_IFROW);
1352     if (!pIfTable || *pdwSize < size) {
1353       *pdwSize = size;
1354       ret = ERROR_INSUFFICIENT_BUFFER;
1355     }
1356     else {
1357       InterfaceIndexTable *table = getInterfaceIndexTable();
1358
1359       if (table) {
1360         size = sizeof(MIB_IFTABLE);
1361         if (table->numIndexes > 1)
1362           size += (table->numIndexes - 1) * sizeof(MIB_IFROW);
1363         if (*pdwSize < size) {
1364           *pdwSize = size;
1365           ret = ERROR_INSUFFICIENT_BUFFER;
1366         }
1367         else {
1368           DWORD ndx;
1369
1370           *pdwSize = size;
1371           pIfTable->dwNumEntries = 0;
1372           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1373             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
1374             GetIfEntry(&pIfTable->table[ndx]);
1375             pIfTable->dwNumEntries++;
1376           }
1377           if (bOrder)
1378             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
1379              IfTableSorter);
1380           ret = NO_ERROR;
1381         }
1382         HeapFree(GetProcessHeap(), 0, table);
1383       }
1384       else
1385         ret = ERROR_OUTOFMEMORY;
1386     }
1387   }
1388   TRACE("returning %d\n", ret);
1389   return ret;
1390 }
1391
1392
1393 /******************************************************************
1394  *    GetInterfaceInfo (IPHLPAPI.@)
1395  *
1396  * Get a list of network interface adapters.
1397  *
1398  * PARAMS
1399  *  pIfTable    [Out] buffer for interface adapters
1400  *  dwOutBufLen [Out] if buffer is too small, returns required size
1401  *
1402  * RETURNS
1403  *  Success: NO_ERROR
1404  *  Failure: error code from winerror.h
1405  *
1406  * BUGS
1407  *  MSDN states this should return non-loopback interfaces only.
1408  */
1409 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
1410 {
1411   DWORD ret;
1412
1413   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
1414   if (!dwOutBufLen)
1415     ret = ERROR_INVALID_PARAMETER;
1416   else {
1417     DWORD numInterfaces = getNumInterfaces();
1418     ULONG size = sizeof(IP_INTERFACE_INFO);
1419
1420     if (numInterfaces > 1)
1421       size += (numInterfaces - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
1422     if (!pIfTable || *dwOutBufLen < size) {
1423       *dwOutBufLen = size;
1424       ret = ERROR_INSUFFICIENT_BUFFER;
1425     }
1426     else {
1427       InterfaceIndexTable *table = getInterfaceIndexTable();
1428
1429       if (table) {
1430         size = sizeof(IP_INTERFACE_INFO);
1431         if (table->numIndexes > 1)
1432           size += (table->numIndexes - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
1433         if (*dwOutBufLen < size) {
1434           *dwOutBufLen = size;
1435           ret = ERROR_INSUFFICIENT_BUFFER;
1436         }
1437         else {
1438           DWORD ndx;
1439           char nameBuf[MAX_ADAPTER_NAME];
1440
1441           *dwOutBufLen = size;
1442           pIfTable->NumAdapters = 0;
1443           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1444             const char *walker, *name;
1445             WCHAR *assigner;
1446
1447             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
1448             name = getInterfaceNameByIndex(table->indexes[ndx], nameBuf);
1449             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
1450              walker && *walker &&
1451              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
1452              walker++, assigner++)
1453               *assigner = *walker;
1454             *assigner = 0;
1455             pIfTable->NumAdapters++;
1456           }
1457           ret = NO_ERROR;
1458         }
1459         HeapFree(GetProcessHeap(), 0, table);
1460       }
1461       else
1462         ret = ERROR_OUTOFMEMORY;
1463     }
1464   }
1465   TRACE("returning %d\n", ret);
1466   return ret;
1467 }
1468
1469
1470 /******************************************************************
1471  *    GetIpAddrTable (IPHLPAPI.@)
1472  *
1473  * Get interface-to-IP address mapping table. 
1474  *
1475  * PARAMS
1476  *  pIpAddrTable [Out]    buffer for mapping table
1477  *  pdwSize      [In/Out] length of output buffer
1478  *  bOrder       [In]     whether to sort the table
1479  *
1480  * RETURNS
1481  *  Success: NO_ERROR
1482  *  Failure: error code from winerror.h
1483  *
1484  * NOTES
1485  *  If pdwSize is less than required, the function will return
1486  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1487  *  size.
1488  *  If bOrder is true, the returned table will be sorted by the next hop and
1489  *  an assortment of arbitrary parameters.
1490  */
1491 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1492 {
1493   DWORD ret;
1494
1495   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %d\n", pIpAddrTable, pdwSize,
1496    (DWORD)bOrder);
1497   if (!pdwSize)
1498     ret = ERROR_INVALID_PARAMETER;
1499   else {
1500     PMIB_IPADDRTABLE table;
1501
1502     ret = getIPAddrTable(&table, GetProcessHeap(), 0);
1503     if (ret == NO_ERROR)
1504     {
1505       ULONG size = sizeof(MIB_IPADDRTABLE);
1506
1507       if (table->dwNumEntries > 1)
1508         size += (table->dwNumEntries - 1) * sizeof(MIB_IPADDRROW);
1509       if (!pIpAddrTable || *pdwSize < size) {
1510         *pdwSize = size;
1511         ret = ERROR_INSUFFICIENT_BUFFER;
1512       }
1513       else {
1514         *pdwSize = size;
1515         memcpy(pIpAddrTable, table, size);
1516         if (bOrder)
1517           qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1518            sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1519         ret = NO_ERROR;
1520       }
1521       HeapFree(GetProcessHeap(), 0, table);
1522     }
1523   }
1524   TRACE("returning %d\n", ret);
1525   return ret;
1526 }
1527
1528
1529 /******************************************************************
1530  *    GetIpForwardTable (IPHLPAPI.@)
1531  *
1532  * Get the route table.
1533  *
1534  * PARAMS
1535  *  pIpForwardTable [Out]    buffer for route table
1536  *  pdwSize         [In/Out] length of output buffer
1537  *  bOrder          [In]     whether to sort the table
1538  *
1539  * RETURNS
1540  *  Success: NO_ERROR
1541  *  Failure: error code from winerror.h
1542  *
1543  * NOTES
1544  *  If pdwSize is less than required, the function will return
1545  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1546  *  size.
1547  *  If bOrder is true, the returned table will be sorted by the next hop and
1548  *  an assortment of arbitrary parameters.
1549  */
1550 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1551 {
1552     DWORD ret;
1553     PMIB_IPFORWARDTABLE table;
1554
1555     TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable, pdwSize, bOrder);
1556
1557     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1558
1559     ret = AllocateAndGetIpForwardTableFromStack(&table, bOrder, GetProcessHeap(), 0);
1560     if (!ret) {
1561         DWORD size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[table->dwNumEntries] );
1562         if (!pIpForwardTable || *pdwSize < size) {
1563           *pdwSize = size;
1564           ret = ERROR_INSUFFICIENT_BUFFER;
1565         }
1566         else {
1567           *pdwSize = size;
1568           memcpy(pIpForwardTable, table, size);
1569         }
1570         HeapFree(GetProcessHeap(), 0, table);
1571     }
1572     TRACE("returning %d\n", ret);
1573     return ret;
1574 }
1575
1576
1577 /******************************************************************
1578  *    GetIpNetTable (IPHLPAPI.@)
1579  *
1580  * Get the IP-to-physical address mapping table.
1581  *
1582  * PARAMS
1583  *  pIpNetTable [Out]    buffer for mapping table
1584  *  pdwSize     [In/Out] length of output buffer
1585  *  bOrder      [In]     whether to sort the table
1586  *
1587  * RETURNS
1588  *  Success: NO_ERROR
1589  *  Failure: error code from winerror.h
1590  *
1591  * NOTES
1592  *  If pdwSize is less than required, the function will return
1593  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1594  *  size.
1595  *  If bOrder is true, the returned table will be sorted by IP address.
1596  */
1597 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1598 {
1599     DWORD ret;
1600     PMIB_IPNETTABLE table;
1601
1602     TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize, bOrder);
1603
1604     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1605
1606     ret = AllocateAndGetIpNetTableFromStack( &table, bOrder, GetProcessHeap(), 0 );
1607     if (!ret) {
1608         DWORD size = FIELD_OFFSET( MIB_IPNETTABLE, table[table->dwNumEntries] );
1609         if (!pIpNetTable || *pdwSize < size) {
1610           *pdwSize = size;
1611           ret = ERROR_INSUFFICIENT_BUFFER;
1612         }
1613         else {
1614           *pdwSize = size;
1615           memcpy(pIpNetTable, table, size);
1616         }
1617         HeapFree(GetProcessHeap(), 0, table);
1618     }
1619     TRACE("returning %d\n", ret);
1620     return ret;
1621 }
1622
1623 /* Gets the DNS server list into the list beginning at list.  Assumes that
1624  * a single server address may be placed at list if *len is at least
1625  * sizeof(IP_ADDR_STRING) long.  Otherwise, list->Next is set to firstDynamic,
1626  * and assumes that all remaining DNS servers are contiguously located
1627  * beginning at firstDynamic.  On input, *len is assumed to be the total number
1628  * of bytes available for all DNS servers, and is ignored if list is NULL.
1629  * On return, *len is set to the total number of bytes required for all DNS
1630  * servers.
1631  * Returns ERROR_BUFFER_OVERFLOW if *len is insufficient,
1632  * ERROR_SUCCESS otherwise.
1633  */
1634 static DWORD get_dns_server_list(PIP_ADDR_STRING list,
1635  PIP_ADDR_STRING firstDynamic, DWORD *len)
1636 {
1637   DWORD size;
1638
1639   initialise_resolver();
1640   size = _res.nscount * sizeof(IP_ADDR_STRING);
1641   if (!list || *len < size) {
1642     *len = size;
1643     return ERROR_BUFFER_OVERFLOW;
1644   }
1645   *len = size;
1646   if (_res.nscount > 0) {
1647     PIP_ADDR_STRING ptr;
1648     int i;
1649
1650     for (i = 0, ptr = list; i < _res.nscount && ptr; i++, ptr = ptr->Next) {
1651       toIPAddressString(_res.nsaddr_list[i].sin_addr.s_addr,
1652        ptr->IpAddress.String);
1653       if (i == _res.nscount - 1)
1654         ptr->Next = NULL;
1655       else if (i == 0)
1656         ptr->Next = firstDynamic;
1657       else
1658         ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
1659     }
1660   }
1661   return ERROR_SUCCESS;
1662 }
1663
1664 /******************************************************************
1665  *    GetNetworkParams (IPHLPAPI.@)
1666  *
1667  * Get the network parameters for the local computer.
1668  *
1669  * PARAMS
1670  *  pFixedInfo [Out]    buffer for network parameters
1671  *  pOutBufLen [In/Out] length of output buffer
1672  *
1673  * RETURNS
1674  *  Success: NO_ERROR
1675  *  Failure: error code from winerror.h
1676  *
1677  * NOTES
1678  *  If pOutBufLen is less than required, the function will return
1679  *  ERROR_INSUFFICIENT_BUFFER, and pOutBufLen will be set to the required byte
1680  *  size.
1681  */
1682 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1683 {
1684   DWORD ret, size, serverListSize;
1685   LONG regReturn;
1686   HKEY hKey;
1687
1688   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
1689   if (!pOutBufLen)
1690     return ERROR_INVALID_PARAMETER;
1691
1692   get_dns_server_list(NULL, NULL, &serverListSize);
1693   size = sizeof(FIXED_INFO) + serverListSize - sizeof(IP_ADDR_STRING);
1694   if (!pFixedInfo || *pOutBufLen < size) {
1695     *pOutBufLen = size;
1696     return ERROR_BUFFER_OVERFLOW;
1697   }
1698
1699   memset(pFixedInfo, 0, size);
1700   size = sizeof(pFixedInfo->HostName);
1701   GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
1702   size = sizeof(pFixedInfo->DomainName);
1703   GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
1704   get_dns_server_list(&pFixedInfo->DnsServerList,
1705    (PIP_ADDR_STRING)((BYTE *)pFixedInfo + sizeof(FIXED_INFO)),
1706    &serverListSize);
1707   /* Assume the first DNS server in the list is the "current" DNS server: */
1708   pFixedInfo->CurrentDnsServer = &pFixedInfo->DnsServerList;
1709   pFixedInfo->NodeType = HYBRID_NODETYPE;
1710   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1711    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
1712   if (regReturn != ERROR_SUCCESS)
1713     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1714      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
1715      &hKey);
1716   if (regReturn == ERROR_SUCCESS)
1717   {
1718     DWORD size = sizeof(pFixedInfo->ScopeId);
1719
1720     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (LPBYTE)pFixedInfo->ScopeId, &size);
1721     RegCloseKey(hKey);
1722   }
1723
1724   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1725      I suppose could also check for a listener on port 53 to set EnableDns */
1726   ret = NO_ERROR;
1727   TRACE("returning %d\n", ret);
1728   return ret;
1729 }
1730
1731
1732 /******************************************************************
1733  *    GetNumberOfInterfaces (IPHLPAPI.@)
1734  *
1735  * Get the number of interfaces.
1736  *
1737  * PARAMS
1738  *  pdwNumIf [Out] number of interfaces
1739  *
1740  * RETURNS
1741  *  NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
1742  */
1743 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1744 {
1745   DWORD ret;
1746
1747   TRACE("pdwNumIf %p\n", pdwNumIf);
1748   if (!pdwNumIf)
1749     ret = ERROR_INVALID_PARAMETER;
1750   else {
1751     *pdwNumIf = getNumInterfaces();
1752     ret = NO_ERROR;
1753   }
1754   TRACE("returning %d\n", ret);
1755   return ret;
1756 }
1757
1758
1759 /******************************************************************
1760  *    GetPerAdapterInfo (IPHLPAPI.@)
1761  *
1762  * Get information about an adapter corresponding to an interface.
1763  *
1764  * PARAMS
1765  *  IfIndex         [In]     interface info
1766  *  pPerAdapterInfo [Out]    buffer for per adapter info
1767  *  pOutBufLen      [In/Out] length of output buffer
1768  *
1769  * RETURNS
1770  *  Success: NO_ERROR
1771  *  Failure: error code from winerror.h
1772  */
1773 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1774 {
1775   ULONG bytesNeeded = sizeof(IP_PER_ADAPTER_INFO), serverListSize = 0;
1776   DWORD ret = NO_ERROR;
1777
1778   TRACE("(IfIndex %d, pPerAdapterInfo %p, pOutBufLen %p)\n", IfIndex, pPerAdapterInfo, pOutBufLen);
1779
1780   if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
1781
1782   if (!isIfIndexLoopback(IfIndex)) {
1783     get_dns_server_list(NULL, NULL, &serverListSize);
1784     if (serverListSize > sizeof(IP_ADDR_STRING))
1785       bytesNeeded += serverListSize - sizeof(IP_ADDR_STRING);
1786   }
1787   if (!pPerAdapterInfo || *pOutBufLen < bytesNeeded)
1788   {
1789     *pOutBufLen = bytesNeeded;
1790     return ERROR_BUFFER_OVERFLOW;
1791   }
1792
1793   memset(pPerAdapterInfo, 0, bytesNeeded);
1794   if (!isIfIndexLoopback(IfIndex)) {
1795     ret = get_dns_server_list(&pPerAdapterInfo->DnsServerList,
1796      (PIP_ADDR_STRING)((PBYTE)pPerAdapterInfo + sizeof(IP_PER_ADAPTER_INFO)),
1797      &serverListSize);
1798     /* Assume the first DNS server in the list is the "current" DNS server: */
1799     pPerAdapterInfo->CurrentDnsServer = &pPerAdapterInfo->DnsServerList;
1800   }
1801   return ret;
1802 }
1803
1804
1805 /******************************************************************
1806  *    GetRTTAndHopCount (IPHLPAPI.@)
1807  *
1808  * Get round-trip time (RTT) and hop count.
1809  *
1810  * PARAMS
1811  *
1812  *  DestIpAddress [In]  destination address to get the info for
1813  *  HopCount      [Out] retrieved hop count
1814  *  MaxHops       [In]  maximum hops to search for the destination
1815  *  RTT           [Out] RTT in milliseconds
1816  *
1817  * RETURNS
1818  *  Success: TRUE
1819  *  Failure: FALSE
1820  *
1821  * FIXME
1822  *  Stub, returns FALSE.
1823  */
1824 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
1825 {
1826   FIXME("(DestIpAddress 0x%08x, HopCount %p, MaxHops %d, RTT %p): stub\n",
1827    DestIpAddress, HopCount, MaxHops, RTT);
1828   return FALSE;
1829 }
1830
1831
1832 /******************************************************************
1833  *    GetTcpTable (IPHLPAPI.@)
1834  *
1835  * Get the table of active TCP connections.
1836  *
1837  * PARAMS
1838  *  pTcpTable [Out]    buffer for TCP connections table
1839  *  pdwSize   [In/Out] length of output buffer
1840  *  bOrder    [In]     whether to order the table
1841  *
1842  * RETURNS
1843  *  Success: NO_ERROR
1844  *  Failure: error code from winerror.h
1845  *
1846  * NOTES
1847  *  If pdwSize is less than required, the function will return 
1848  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to 
1849  *  the required byte size.
1850  *  If bOrder is true, the returned table will be sorted, first by
1851  *  local address and port number, then by remote address and port
1852  *  number.
1853  */
1854 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1855 {
1856     DWORD ret;
1857     PMIB_TCPTABLE table;
1858
1859     TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize, bOrder);
1860
1861     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1862
1863     ret = AllocateAndGetTcpTableFromStack(&table, bOrder, GetProcessHeap(), 0);
1864     if (!ret) {
1865         DWORD size = FIELD_OFFSET( MIB_TCPTABLE, table[table->dwNumEntries] );
1866         if (!pTcpTable || *pdwSize < size) {
1867           *pdwSize = size;
1868           ret = ERROR_INSUFFICIENT_BUFFER;
1869         }
1870         else {
1871           *pdwSize = size;
1872           memcpy(pTcpTable, table, size);
1873         }
1874         HeapFree(GetProcessHeap(), 0, table);
1875     }
1876     TRACE("returning %d\n", ret);
1877     return ret;
1878 }
1879
1880 /******************************************************************
1881  *    GetExtendedTcpTable (IPHLPAPI.@)
1882  */
1883 DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder,
1884                                  ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
1885 {
1886     TRACE("pTcpTable %p, pdwSize %p, bOrder %d, ulAf %u, TableClass %u, Reserved %u\n",
1887            pTcpTable, pdwSize, bOrder, ulAf, TableClass, Reserved);
1888
1889     if (ulAf == AF_INET6 || TableClass != TCP_TABLE_BASIC_ALL)
1890     {
1891         FIXME("ulAf = %u, TableClass = %u not supportted\n", ulAf, TableClass);
1892         return ERROR_NOT_SUPPORTED;
1893     }
1894     return GetTcpTable(pTcpTable, pdwSize, bOrder);
1895 }
1896
1897 /******************************************************************
1898  *    GetUdpTable (IPHLPAPI.@)
1899  *
1900  * Get a table of active UDP connections.
1901  *
1902  * PARAMS
1903  *  pUdpTable [Out]    buffer for UDP connections table
1904  *  pdwSize   [In/Out] length of output buffer
1905  *  bOrder    [In]     whether to order the table
1906  *
1907  * RETURNS
1908  *  Success: NO_ERROR
1909  *  Failure: error code from winerror.h
1910  *
1911  * NOTES
1912  *  If pdwSize is less than required, the function will return 
1913  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
1914  *  required byte size.
1915  *  If bOrder is true, the returned table will be sorted, first by
1916  *  local address, then by local port number.
1917  */
1918 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1919 {
1920     DWORD ret;
1921     PMIB_UDPTABLE table;
1922
1923     TRACE("pUdpTable %p, pdwSize %p, bOrder %d\n", pUdpTable, pdwSize, bOrder);
1924
1925     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1926
1927     ret = AllocateAndGetUdpTableFromStack( &table, bOrder, GetProcessHeap(), 0 );
1928     if (!ret) {
1929         DWORD size = FIELD_OFFSET( MIB_UDPTABLE, table[table->dwNumEntries] );
1930         if (!pUdpTable || *pdwSize < size) {
1931           *pdwSize = size;
1932           ret = ERROR_INSUFFICIENT_BUFFER;
1933         }
1934         else {
1935           *pdwSize = size;
1936           memcpy(pUdpTable, table, size);
1937         }
1938         HeapFree(GetProcessHeap(), 0, table);
1939     }
1940     TRACE("returning %d\n", ret);
1941     return ret;
1942 }
1943
1944
1945 /******************************************************************
1946  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1947  *
1948  * This is a Win98-only function to get information on "unidirectional"
1949  * adapters.  Since this is pretty nonsensical in other contexts, it
1950  * never returns anything.
1951  *
1952  * PARAMS
1953  *  pIPIfInfo   [Out] buffer for adapter infos
1954  *  dwOutBufLen [Out] length of the output buffer
1955  *
1956  * RETURNS
1957  *  Success: NO_ERROR
1958  *  Failure: error code from winerror.h
1959  *
1960  * FIXME
1961  *  Stub, returns ERROR_NOT_SUPPORTED.
1962  */
1963 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1964 {
1965   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
1966   /* a unidirectional adapter?? not bloody likely! */
1967   return ERROR_NOT_SUPPORTED;
1968 }
1969
1970
1971 /******************************************************************
1972  *    IpReleaseAddress (IPHLPAPI.@)
1973  *
1974  * Release an IP obtained through DHCP,
1975  *
1976  * PARAMS
1977  *  AdapterInfo [In] adapter to release IP address
1978  *
1979  * RETURNS
1980  *  Success: NO_ERROR
1981  *  Failure: error code from winerror.h
1982  *
1983  * NOTES
1984  *  Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1985  *  this function does nothing.
1986  *
1987  * FIXME
1988  *  Stub, returns ERROR_NOT_SUPPORTED.
1989  */
1990 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1991 {
1992   TRACE("AdapterInfo %p\n", AdapterInfo);
1993   /* not a stub, never going to support this (and I never mark an adapter as
1994      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1995   return ERROR_NOT_SUPPORTED;
1996 }
1997
1998
1999 /******************************************************************
2000  *    IpRenewAddress (IPHLPAPI.@)
2001  *
2002  * Renew an IP obtained through DHCP.
2003  *
2004  * PARAMS
2005  *  AdapterInfo [In] adapter to renew IP address
2006  *
2007  * RETURNS
2008  *  Success: NO_ERROR
2009  *  Failure: error code from winerror.h
2010  *
2011  * NOTES
2012  *  Since GetAdaptersInfo never returns adapters that have DHCP enabled,
2013  *  this function does nothing.
2014  *
2015  * FIXME
2016  *  Stub, returns ERROR_NOT_SUPPORTED.
2017  */
2018 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2019 {
2020   TRACE("AdapterInfo %p\n", AdapterInfo);
2021   /* not a stub, never going to support this (and I never mark an adapter as
2022      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
2023   return ERROR_NOT_SUPPORTED;
2024 }
2025
2026
2027 /******************************************************************
2028  *    NotifyAddrChange (IPHLPAPI.@)
2029  *
2030  * Notify caller whenever the ip-interface map is changed.
2031  *
2032  * PARAMS
2033  *  Handle     [Out] handle usable in asynchronous notification
2034  *  overlapped [In]  overlapped structure that notifies the caller
2035  *
2036  * RETURNS
2037  *  Success: NO_ERROR
2038  *  Failure: error code from winerror.h
2039  *
2040  * FIXME
2041  *  Stub, returns ERROR_NOT_SUPPORTED.
2042  */
2043 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2044 {
2045   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2046   if (Handle) *Handle = INVALID_HANDLE_VALUE;
2047   if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->u.Status = STATUS_PENDING;
2048   return ERROR_IO_PENDING;
2049 }
2050
2051
2052 /******************************************************************
2053  *    NotifyRouteChange (IPHLPAPI.@)
2054  *
2055  * Notify caller whenever the ip routing table is changed.
2056  *
2057  * PARAMS
2058  *  Handle     [Out] handle usable in asynchronous notification
2059  *  overlapped [In]  overlapped structure that notifies the caller
2060  *
2061  * RETURNS
2062  *  Success: NO_ERROR
2063  *  Failure: error code from winerror.h
2064  *
2065  * FIXME
2066  *  Stub, returns ERROR_NOT_SUPPORTED.
2067  */
2068 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2069 {
2070   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2071   return ERROR_NOT_SUPPORTED;
2072 }
2073
2074
2075 /******************************************************************
2076  *    SendARP (IPHLPAPI.@)
2077  *
2078  * Send an ARP request.
2079  *
2080  * PARAMS
2081  *  DestIP     [In]     attempt to obtain this IP
2082  *  SrcIP      [In]     optional sender IP address
2083  *  pMacAddr   [Out]    buffer for the mac address
2084  *  PhyAddrLen [In/Out] length of the output buffer
2085  *
2086  * RETURNS
2087  *  Success: NO_ERROR
2088  *  Failure: error code from winerror.h
2089  *
2090  * FIXME
2091  *  Stub, returns ERROR_NOT_SUPPORTED.
2092  */
2093 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2094 {
2095   FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
2096    DestIP, SrcIP, pMacAddr, PhyAddrLen);
2097   return ERROR_NOT_SUPPORTED;
2098 }
2099
2100
2101 /******************************************************************
2102  *    SetIfEntry (IPHLPAPI.@)
2103  *
2104  * Set the administrative status of an interface.
2105  *
2106  * PARAMS
2107  *  pIfRow [In] dwAdminStatus member specifies the new status.
2108  *
2109  * RETURNS
2110  *  Success: NO_ERROR
2111  *  Failure: error code from winerror.h
2112  *
2113  * FIXME
2114  *  Stub, returns ERROR_NOT_SUPPORTED.
2115  */
2116 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
2117 {
2118   FIXME("(pIfRow %p): stub\n", pIfRow);
2119   /* this is supposed to set an interface administratively up or down.
2120      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2121      this sort of down is indistinguishable from other sorts of down (e.g. no
2122      link). */
2123   return ERROR_NOT_SUPPORTED;
2124 }
2125
2126
2127 /******************************************************************
2128  *    SetIpForwardEntry (IPHLPAPI.@)
2129  *
2130  * Modify an existing route.
2131  *
2132  * PARAMS
2133  *  pRoute [In] route with the new information
2134  *
2135  * RETURNS
2136  *  Success: NO_ERROR
2137  *  Failure: error code from winerror.h
2138  *
2139  * FIXME
2140  *  Stub, returns NO_ERROR.
2141  */
2142 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
2143 {
2144   FIXME("(pRoute %p): stub\n", pRoute);
2145   /* this is to add a route entry, how's it distinguishable from
2146      CreateIpForwardEntry?
2147      could use SIOCADDRT, not sure I want to */
2148   return 0;
2149 }
2150
2151
2152 /******************************************************************
2153  *    SetIpNetEntry (IPHLPAPI.@)
2154  *
2155  * Modify an existing ARP entry.
2156  *
2157  * PARAMS
2158  *  pArpEntry [In] ARP entry with the new information
2159  *
2160  * RETURNS
2161  *  Success: NO_ERROR
2162  *  Failure: error code from winerror.h
2163  *
2164  * FIXME
2165  *  Stub, returns NO_ERROR.
2166  */
2167 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
2168 {
2169   FIXME("(pArpEntry %p): stub\n", pArpEntry);
2170   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
2171   return 0;
2172 }
2173
2174
2175 /******************************************************************
2176  *    SetIpStatistics (IPHLPAPI.@)
2177  *
2178  * Toggle IP forwarding and det the default TTL value.
2179  *
2180  * PARAMS
2181  *  pIpStats [In] IP statistics with the new information
2182  *
2183  * RETURNS
2184  *  Success: NO_ERROR
2185  *  Failure: error code from winerror.h
2186  *
2187  * FIXME
2188  *  Stub, returns NO_ERROR.
2189  */
2190 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
2191 {
2192   FIXME("(pIpStats %p): stub\n", pIpStats);
2193   return 0;
2194 }
2195
2196
2197 /******************************************************************
2198  *    SetIpTTL (IPHLPAPI.@)
2199  *
2200  * Set the default TTL value.
2201  *
2202  * PARAMS
2203  *  nTTL [In] new TTL value
2204  *
2205  * RETURNS
2206  *  Success: NO_ERROR
2207  *  Failure: error code from winerror.h
2208  *
2209  * FIXME
2210  *  Stub, returns NO_ERROR.
2211  */
2212 DWORD WINAPI SetIpTTL(UINT nTTL)
2213 {
2214   FIXME("(nTTL %d): stub\n", nTTL);
2215   /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
2216      want to.  Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
2217   return 0;
2218 }
2219
2220
2221 /******************************************************************
2222  *    SetTcpEntry (IPHLPAPI.@)
2223  *
2224  * Set the state of a TCP connection.
2225  *
2226  * PARAMS
2227  *  pTcpRow [In] specifies connection with new state
2228  *
2229  * RETURNS
2230  *  Success: NO_ERROR
2231  *  Failure: error code from winerror.h
2232  *
2233  * FIXME
2234  *  Stub, returns NO_ERROR.
2235  */
2236 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
2237 {
2238   FIXME("(pTcpRow %p): stub\n", pTcpRow);
2239   return 0;
2240 }
2241
2242
2243 /******************************************************************
2244  *    UnenableRouter (IPHLPAPI.@)
2245  *
2246  * Decrement the IP-forwarding reference count. Turn off IP-forwarding
2247  * if it reaches zero.
2248  *
2249  * PARAMS
2250  *  pOverlapped     [In/Out] should be the same as in EnableRouter()
2251  *  lpdwEnableCount [Out]    optional, receives reference count
2252  *
2253  * RETURNS
2254  *  Success: NO_ERROR
2255  *  Failure: error code from winerror.h
2256  *
2257  * FIXME
2258  *  Stub, returns ERROR_NOT_SUPPORTED.
2259  */
2260 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
2261 {
2262   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
2263    lpdwEnableCount);
2264   /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
2265      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
2266    */
2267   return ERROR_NOT_SUPPORTED;
2268 }
2269
2270 /******************************************************************
2271  *    PfCreateInterface (IPHLPAPI.@)
2272  */
2273 DWORD WINAPI PfCreateInterface(DWORD dwName, PFFORWARD_ACTION inAction, PFFORWARD_ACTION outAction,
2274         BOOL bUseLog, BOOL bMustBeUnique, INTERFACE_HANDLE *ppInterface)
2275 {
2276     FIXME("(%d %d %d %x %x %p) stub\n", dwName, inAction, outAction, bUseLog, bMustBeUnique, ppInterface);
2277     return ERROR_CALL_NOT_IMPLEMENTED;
2278 }
2279
2280 /******************************************************************
2281  *    GetTcpTable2 (IPHLPAPI.@)
2282  */
2283 ULONG WINAPI GetTcpTable2(PMIB_TCPTABLE2 table, PULONG size, BOOL order)
2284 {
2285     FIXME("pTcpTable2 %p, pdwSize %p, bOrder %d: stub\n", table, size, order);
2286     return ERROR_NOT_SUPPORTED;
2287 }
2288
2289 /******************************************************************
2290  *    GetTcp6Table (IPHLPAPI.@)
2291  */
2292 ULONG WINAPI GetTcp6Table(PMIB_TCP6TABLE table, PULONG size, BOOL order)
2293 {
2294     FIXME("pTcp6Table %p, size %p, order %d: stub\n", table, size, order);
2295     return ERROR_NOT_SUPPORTED;
2296 }
2297
2298 /******************************************************************
2299  *    GetTcp6Table2 (IPHLPAPI.@)
2300  */
2301 ULONG WINAPI GetTcp6Table2(PMIB_TCP6TABLE2 table, PULONG size, BOOL order)
2302 {
2303     FIXME("pTcp6Table2 %p, size %p, order %d: stub\n", table, size, order);
2304     return ERROR_NOT_SUPPORTED;
2305 }