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