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