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