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