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