wined3d: Move shader generation into the shader backend.
[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 (DWORD) 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 (DWORD) 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 (DWORD) 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 (DWORD) 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   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               ptr->AddressLength = sizeof(ptr->Address);
742               getInterfacePhysicalByIndex(table->indexes[ndx],
743                &ptr->AddressLength, ptr->Address, &ptr->Type);
744               ptr->Index = table->indexes[ndx];
745               for (i = 0; i < ipAddrTable->dwNumEntries; i++) {
746                 if (ipAddrTable->table[i].dwIndex == ptr->Index) {
747                   if (firstIPAddr) {
748                     toIPAddressString(ipAddrTable->table[i].dwAddr,
749                      ptr->IpAddressList.IpAddress.String);
750                     toIPAddressString(ipAddrTable->table[i].dwMask,
751                      ptr->IpAddressList.IpMask.String);
752                     firstIPAddr = FALSE;
753                   }
754                   else {
755                     currentIPAddr->Next = nextIPAddr;
756                     currentIPAddr = nextIPAddr;
757                     toIPAddressString(ipAddrTable->table[i].dwAddr,
758                      currentIPAddr->IpAddress.String);
759                     toIPAddressString(ipAddrTable->table[i].dwMask,
760                      currentIPAddr->IpMask.String);
761                     nextIPAddr++;
762                   }
763                 }
764               }
765               /* Find first router through this interface, which we'll assume
766                * is the default gateway for this adapter */
767               for (i = 0; i < routeTable->dwNumEntries; i++)
768                 if (routeTable->table[i].dwForwardIfIndex == ptr->Index
769                  && routeTable->table[i].dwForwardType ==
770                  MIB_IPROUTE_TYPE_INDIRECT)
771                   toIPAddressString(routeTable->table[i].dwForwardNextHop,
772                    ptr->GatewayList.IpAddress.String);
773               if (winsEnabled) {
774                 ptr->HaveWins = TRUE;
775                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
776                  primaryWINS.String, sizeof(primaryWINS.String));
777                 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
778                  secondaryWINS.String, sizeof(secondaryWINS.String));
779               }
780               if (ndx < table->numIndexes - 1)
781                 ptr->Next = &pAdapterInfo[ndx + 1];
782               else
783                 ptr->Next = NULL;
784             }
785             ret = NO_ERROR;
786           }
787           HeapFree(GetProcessHeap(), 0, table);
788         }
789         else
790           ret = ERROR_OUTOFMEMORY;
791         HeapFree(GetProcessHeap(), 0, routeTable);
792         HeapFree(GetProcessHeap(), 0, ipAddrTable);
793       }
794     }
795     else
796       ret = ERROR_NO_DATA;
797   }
798   TRACE("returning %d\n", ret);
799   return ret;
800 }
801
802
803 /******************************************************************
804  *    GetBestInterface (IPHLPAPI.@)
805  *
806  * Get the interface, with the best route for the given IP address.
807  *
808  * PARAMS
809  *  dwDestAddr     [In]  IP address to search the interface for
810  *  pdwBestIfIndex [Out] found best interface
811  *
812  * RETURNS
813  *  Success: NO_ERROR
814  *  Failure: error code from winerror.h
815  */
816 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
817 {
818     struct WS_sockaddr_in sa_in;
819     memset(&sa_in, 0, sizeof(sa_in));
820     sa_in.sin_family = AF_INET;
821     sa_in.sin_addr.S_un.S_addr = dwDestAddr;
822     return GetBestInterfaceEx((struct WS_sockaddr *)&sa_in, pdwBestIfIndex);
823 }
824
825 /******************************************************************
826  *    GetBestInterfaceEx (IPHLPAPI.@)
827  *
828  * Get the interface, with the best route for the given IP address.
829  *
830  * PARAMS
831  *  dwDestAddr     [In]  IP address to search the interface for
832  *  pdwBestIfIndex [Out] found best interface
833  *
834  * RETURNS
835  *  Success: NO_ERROR
836  *  Failure: error code from winerror.h
837  */
838 DWORD WINAPI GetBestInterfaceEx(struct WS_sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
839 {
840   DWORD ret;
841
842   TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
843   if (!pDestAddr || !pdwBestIfIndex)
844     ret = ERROR_INVALID_PARAMETER;
845   else {
846     MIB_IPFORWARDROW ipRow;
847
848     if (pDestAddr->sa_family == AF_INET) {
849       ret = GetBestRoute(((struct WS_sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
850       if (ret == ERROR_SUCCESS)
851         *pdwBestIfIndex = ipRow.dwForwardIfIndex;
852     } else {
853       FIXME("address family %d not supported\n", pDestAddr->sa_family);
854       ret = ERROR_NOT_SUPPORTED;
855     }
856   }
857   TRACE("returning %d\n", ret);
858   return ret;
859 }
860
861
862 /******************************************************************
863  *    GetBestRoute (IPHLPAPI.@)
864  *
865  * Get the best route for the given IP address.
866  *
867  * PARAMS
868  *  dwDestAddr   [In]  IP address to search the best route for
869  *  dwSourceAddr [In]  optional source IP address
870  *  pBestRoute   [Out] found best route
871  *
872  * RETURNS
873  *  Success: NO_ERROR
874  *  Failure: error code from winerror.h
875  */
876 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
877 {
878   PMIB_IPFORWARDTABLE table;
879   DWORD ret;
880
881   TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr,
882    dwSourceAddr, pBestRoute);
883   if (!pBestRoute)
884     return ERROR_INVALID_PARAMETER;
885
886   ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
887   if (!ret) {
888     DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
889
890     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
891       if (table->table[ndx].dwForwardType != MIB_IPROUTE_TYPE_INVALID &&
892        (dwDestAddr & table->table[ndx].dwForwardMask) ==
893        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
894         DWORD numShifts, mask;
895
896         for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
897          mask && !(mask & 1); mask >>= 1, numShifts++)
898           ;
899         if (numShifts > matchedBits) {
900           matchedBits = numShifts;
901           matchedNdx = ndx;
902         }
903         else if (!matchedBits && table->table[ndx].dwForwardType ==
904          MIB_IPROUTE_TYPE_INDIRECT) {
905           /* default to a default gateway */
906           matchedNdx = ndx;
907         }
908       }
909     }
910     if (matchedNdx < table->dwNumEntries) {
911       memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
912       ret = ERROR_SUCCESS;
913     }
914     else {
915       /* No route matches, which can happen if there's no default route. */
916       ret = ERROR_HOST_UNREACHABLE;
917     }
918     HeapFree(GetProcessHeap(), 0, table);
919   }
920   TRACE("returning %d\n", ret);
921   return ret;
922 }
923
924
925 /******************************************************************
926  *    GetFriendlyIfIndex (IPHLPAPI.@)
927  *
928  * Get a "friendly" version of IfIndex, which is one that doesn't
929  * have the top byte set.  Doesn't validate whether IfIndex is a valid
930  * adapter index.
931  *
932  * PARAMS
933  *  IfIndex [In] interface index to get the friendly one for
934  *
935  * RETURNS
936  *  A friendly version of IfIndex.
937  */
938 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
939 {
940   /* windows doesn't validate these, either, just makes sure the top byte is
941      cleared.  I assume my ifenum module never gives an index with the top
942      byte set. */
943   TRACE("returning %d\n", IfIndex);
944   return IfIndex;
945 }
946
947
948 /******************************************************************
949  *    GetIcmpStatistics (IPHLPAPI.@)
950  *
951  * Get the ICMP statistics for the local computer.
952  *
953  * PARAMS
954  *  pStats [Out] buffer for ICMP statistics
955  *
956  * RETURNS
957  *  Success: NO_ERROR
958  *  Failure: error code from winerror.h
959  */
960 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
961 {
962   DWORD ret;
963
964   TRACE("pStats %p\n", pStats);
965   ret = getICMPStats(pStats);
966   TRACE("returning %d\n", ret);
967   return ret;
968 }
969
970
971 /******************************************************************
972  *    GetIfEntry (IPHLPAPI.@)
973  *
974  * Get information about an interface.
975  *
976  * PARAMS
977  *  pIfRow [In/Out] In:  dwIndex of MIB_IFROW selects the interface.
978  *                  Out: interface information
979  *
980  * RETURNS
981  *  Success: NO_ERROR
982  *  Failure: error code from winerror.h
983  */
984 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
985 {
986   DWORD ret;
987   char nameBuf[MAX_ADAPTER_NAME];
988   char *name;
989
990   TRACE("pIfRow %p\n", pIfRow);
991   if (!pIfRow)
992     return ERROR_INVALID_PARAMETER;
993
994   name = getInterfaceNameByIndex(pIfRow->dwIndex, nameBuf);
995   if (name) {
996     ret = getInterfaceEntryByName(name, pIfRow);
997     if (ret == NO_ERROR)
998       ret = getInterfaceStatsByName(name, pIfRow);
999   }
1000   else
1001     ret = ERROR_INVALID_DATA;
1002   TRACE("returning %d\n", ret);
1003   return ret;
1004 }
1005
1006
1007 static int IfTableSorter(const void *a, const void *b)
1008 {
1009   int ret;
1010
1011   if (a && b)
1012     ret = ((const MIB_IFROW*)a)->dwIndex - ((const MIB_IFROW*)b)->dwIndex;
1013   else
1014     ret = 0;
1015   return ret;
1016 }
1017
1018
1019 /******************************************************************
1020  *    GetIfTable (IPHLPAPI.@)
1021  *
1022  * Get a table of local interfaces.
1023  *
1024  * PARAMS
1025  *  pIfTable [Out]    buffer for local interfaces table
1026  *  pdwSize  [In/Out] length of output buffer
1027  *  bOrder   [In]     whether to sort the table
1028  *
1029  * RETURNS
1030  *  Success: NO_ERROR
1031  *  Failure: error code from winerror.h
1032  *
1033  * NOTES
1034  *  If pdwSize is less than required, the function will return
1035  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1036  *  size.
1037  *  If bOrder is true, the returned table will be sorted by interface index.
1038  */
1039 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
1040 {
1041   DWORD ret;
1042
1043   TRACE("pIfTable %p, pdwSize %p, bOrder %d\n", pdwSize, pdwSize,
1044    (DWORD)bOrder);
1045   if (!pdwSize)
1046     ret = ERROR_INVALID_PARAMETER;
1047   else {
1048     DWORD numInterfaces = getNumInterfaces();
1049     ULONG size = sizeof(MIB_IFTABLE);
1050
1051     if (numInterfaces > 1)
1052       size += (numInterfaces - 1) * sizeof(MIB_IFROW);
1053     if (!pIfTable || *pdwSize < size) {
1054       *pdwSize = size;
1055       ret = ERROR_INSUFFICIENT_BUFFER;
1056     }
1057     else {
1058       InterfaceIndexTable *table = getInterfaceIndexTable();
1059
1060       if (table) {
1061         size = sizeof(MIB_IFTABLE);
1062         if (table->numIndexes > 1)
1063           size += (table->numIndexes - 1) * sizeof(MIB_IFROW);
1064         if (*pdwSize < size) {
1065           *pdwSize = size;
1066           ret = ERROR_INSUFFICIENT_BUFFER;
1067         }
1068         else {
1069           DWORD ndx;
1070
1071           *pdwSize = size;
1072           pIfTable->dwNumEntries = 0;
1073           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1074             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
1075             GetIfEntry(&pIfTable->table[ndx]);
1076             pIfTable->dwNumEntries++;
1077           }
1078           if (bOrder)
1079             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
1080              IfTableSorter);
1081           ret = NO_ERROR;
1082         }
1083         HeapFree(GetProcessHeap(), 0, table);
1084       }
1085       else
1086         ret = ERROR_OUTOFMEMORY;
1087     }
1088   }
1089   TRACE("returning %d\n", ret);
1090   return ret;
1091 }
1092
1093
1094 /******************************************************************
1095  *    GetInterfaceInfo (IPHLPAPI.@)
1096  *
1097  * Get a list of network interface adapters.
1098  *
1099  * PARAMS
1100  *  pIfTable    [Out] buffer for interface adapters
1101  *  dwOutBufLen [Out] if buffer is too small, returns required size
1102  *
1103  * RETURNS
1104  *  Success: NO_ERROR
1105  *  Failure: error code from winerror.h
1106  *
1107  * BUGS
1108  *  MSDN states this should return non-loopback interfaces only.
1109  */
1110 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
1111 {
1112   DWORD ret;
1113
1114   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
1115   if (!dwOutBufLen)
1116     ret = ERROR_INVALID_PARAMETER;
1117   else {
1118     DWORD numInterfaces = getNumInterfaces();
1119     ULONG size = sizeof(IP_INTERFACE_INFO);
1120
1121     if (numInterfaces > 1)
1122       size += (numInterfaces - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
1123     if (!pIfTable || *dwOutBufLen < size) {
1124       *dwOutBufLen = size;
1125       ret = ERROR_INSUFFICIENT_BUFFER;
1126     }
1127     else {
1128       InterfaceIndexTable *table = getInterfaceIndexTable();
1129
1130       if (table) {
1131         size = sizeof(IP_INTERFACE_INFO);
1132         if (table->numIndexes > 1)
1133           size += (table->numIndexes - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
1134         if (*dwOutBufLen < size) {
1135           *dwOutBufLen = size;
1136           ret = ERROR_INSUFFICIENT_BUFFER;
1137         }
1138         else {
1139           DWORD ndx;
1140           char nameBuf[MAX_ADAPTER_NAME];
1141
1142           *dwOutBufLen = size;
1143           pIfTable->NumAdapters = 0;
1144           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1145             const char *walker, *name;
1146             WCHAR *assigner;
1147
1148             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
1149             name = getInterfaceNameByIndex(table->indexes[ndx], nameBuf);
1150             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
1151              walker && *walker &&
1152              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
1153              walker++, assigner++)
1154               *assigner = *walker;
1155             *assigner = 0;
1156             pIfTable->NumAdapters++;
1157           }
1158           ret = NO_ERROR;
1159         }
1160         HeapFree(GetProcessHeap(), 0, table);
1161       }
1162       else
1163         ret = ERROR_OUTOFMEMORY;
1164     }
1165   }
1166   TRACE("returning %d\n", ret);
1167   return ret;
1168 }
1169
1170
1171 /******************************************************************
1172  *    GetIpAddrTable (IPHLPAPI.@)
1173  *
1174  * Get interface-to-IP address mapping table. 
1175  *
1176  * PARAMS
1177  *  pIpAddrTable [Out]    buffer for mapping table
1178  *  pdwSize      [In/Out] length of output buffer
1179  *  bOrder       [In]     whether to sort the table
1180  *
1181  * RETURNS
1182  *  Success: NO_ERROR
1183  *  Failure: error code from winerror.h
1184  *
1185  * NOTES
1186  *  If pdwSize is less than required, the function will return
1187  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1188  *  size.
1189  *  If bOrder is true, the returned table will be sorted by the next hop and
1190  *  an assortment of arbitrary parameters.
1191  */
1192 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1193 {
1194   DWORD ret;
1195
1196   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %d\n", pIpAddrTable, pdwSize,
1197    (DWORD)bOrder);
1198   if (!pdwSize)
1199     ret = ERROR_INVALID_PARAMETER;
1200   else {
1201     PMIB_IPADDRTABLE table;
1202
1203     ret = getIPAddrTable(&table, GetProcessHeap(), 0);
1204     if (ret == NO_ERROR)
1205     {
1206       ULONG size = sizeof(MIB_IPADDRTABLE);
1207
1208       if (table->dwNumEntries > 1)
1209         size += (table->dwNumEntries - 1) * sizeof(MIB_IPADDRROW);
1210       if (!pIpAddrTable || *pdwSize < size) {
1211         *pdwSize = size;
1212         ret = ERROR_INSUFFICIENT_BUFFER;
1213       }
1214       else {
1215         *pdwSize = size;
1216         memcpy(pIpAddrTable, table, size);
1217         if (bOrder)
1218           qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1219            sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1220         ret = NO_ERROR;
1221       }
1222       HeapFree(GetProcessHeap(), 0, table);
1223     }
1224   }
1225   TRACE("returning %d\n", ret);
1226   return ret;
1227 }
1228
1229
1230 /******************************************************************
1231  *    GetIpForwardTable (IPHLPAPI.@)
1232  *
1233  * Get the route table.
1234  *
1235  * PARAMS
1236  *  pIpForwardTable [Out]    buffer for route table
1237  *  pdwSize         [In/Out] length of output buffer
1238  *  bOrder          [In]     whether to sort the table
1239  *
1240  * RETURNS
1241  *  Success: NO_ERROR
1242  *  Failure: error code from winerror.h
1243  *
1244  * NOTES
1245  *  If pdwSize is less than required, the function will return
1246  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1247  *  size.
1248  *  If bOrder is true, the returned table will be sorted by the next hop and
1249  *  an assortment of arbitrary parameters.
1250  */
1251 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1252 {
1253   DWORD ret;
1254
1255   TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable,
1256    pdwSize, (DWORD)bOrder);
1257   if (!pdwSize)
1258     ret = ERROR_INVALID_PARAMETER;
1259   else {
1260     DWORD numRoutes = getNumRoutes();
1261     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE);
1262
1263     if (numRoutes > 1)
1264       sizeNeeded += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW);
1265     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1266       *pdwSize = sizeNeeded;
1267       ret = ERROR_INSUFFICIENT_BUFFER;
1268     }
1269     else {
1270       PMIB_IPFORWARDTABLE table;
1271
1272       ret = getRouteTable(&table, GetProcessHeap(), 0);
1273       if (!ret) {
1274         sizeNeeded = sizeof(MIB_IPFORWARDTABLE);
1275         if (table->dwNumEntries > 1)
1276           sizeNeeded += (table->dwNumEntries - 1) * sizeof(MIB_IPFORWARDROW);
1277         if (*pdwSize < sizeNeeded) {
1278           *pdwSize = sizeNeeded;
1279           ret = ERROR_INSUFFICIENT_BUFFER;
1280         }
1281         else {
1282           *pdwSize = sizeNeeded;
1283           memcpy(pIpForwardTable, table, sizeNeeded);
1284           if (bOrder)
1285             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1286              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1287           ret = NO_ERROR;
1288         }
1289         HeapFree(GetProcessHeap(), 0, table);
1290       }
1291     }
1292   }
1293   TRACE("returning %d\n", ret);
1294   return ret;
1295 }
1296
1297
1298 /******************************************************************
1299  *    GetIpNetTable (IPHLPAPI.@)
1300  *
1301  * Get the IP-to-physical address mapping table.
1302  *
1303  * PARAMS
1304  *  pIpNetTable [Out]    buffer for mapping table
1305  *  pdwSize     [In/Out] length of output buffer
1306  *  bOrder      [In]     whether to sort the table
1307  *
1308  * RETURNS
1309  *  Success: NO_ERROR
1310  *  Failure: error code from winerror.h
1311  *
1312  * NOTES
1313  *  If pdwSize is less than required, the function will return
1314  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1315  *  size.
1316  *  If bOrder is true, the returned table will be sorted by IP address.
1317  */
1318 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1319 {
1320   DWORD ret;
1321
1322   TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize,
1323    (DWORD)bOrder);
1324   if (!pdwSize)
1325     ret = ERROR_INVALID_PARAMETER;
1326   else {
1327     DWORD numEntries = getNumArpEntries();
1328     ULONG size = sizeof(MIB_IPNETTABLE);
1329
1330     if (numEntries > 1)
1331       size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1332     if (!pIpNetTable || *pdwSize < size) {
1333       *pdwSize = size;
1334       ret = ERROR_INSUFFICIENT_BUFFER;
1335     }
1336     else {
1337       PMIB_IPNETTABLE table;
1338
1339       ret = getArpTable(&table, GetProcessHeap(), 0);
1340       if (!ret) {
1341         size = sizeof(MIB_IPNETTABLE);
1342         if (table->dwNumEntries > 1)
1343           size += (table->dwNumEntries - 1) * sizeof(MIB_IPNETROW);
1344         if (*pdwSize < size) {
1345           *pdwSize = size;
1346           ret = ERROR_INSUFFICIENT_BUFFER;
1347         }
1348         else {
1349           *pdwSize = size;
1350           memcpy(pIpNetTable, table, size);
1351           if (bOrder)
1352             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
1353              sizeof(MIB_IPNETROW), IpNetTableSorter);
1354           ret = NO_ERROR;
1355         }
1356         HeapFree(GetProcessHeap(), 0, table);
1357       }
1358     }
1359   }
1360   TRACE("returning %d\n", ret);
1361   return ret;
1362 }
1363
1364
1365 /******************************************************************
1366  *    GetIpStatistics (IPHLPAPI.@)
1367  *
1368  * Get the IP statistics for the local computer.
1369  *
1370  * PARAMS
1371  *  pStats [Out] buffer for IP statistics
1372  *
1373  * RETURNS
1374  *  Success: NO_ERROR
1375  *  Failure: error code from winerror.h
1376  */
1377 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
1378 {
1379   DWORD ret;
1380
1381   TRACE("pStats %p\n", pStats);
1382   ret = getIPStats(pStats);
1383   TRACE("returning %d\n", ret);
1384   return ret;
1385 }
1386
1387
1388 /******************************************************************
1389  *    GetNetworkParams (IPHLPAPI.@)
1390  *
1391  * Get the network parameters for the local computer.
1392  *
1393  * PARAMS
1394  *  pFixedInfo [Out]    buffer for network parameters
1395  *  pOutBufLen [In/Out] length of output buffer
1396  *
1397  * RETURNS
1398  *  Success: NO_ERROR
1399  *  Failure: error code from winerror.h
1400  *
1401  * NOTES
1402  *  If pOutBufLen is less than required, the function will return
1403  *  ERROR_INSUFFICIENT_BUFFER, and pOutBufLen will be set to the required byte
1404  *  size.
1405  */
1406 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1407 {
1408   DWORD ret, size;
1409   LONG regReturn;
1410   HKEY hKey;
1411
1412   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
1413   if (!pOutBufLen)
1414     return ERROR_INVALID_PARAMETER;
1415
1416   initialise_resolver();
1417   size = sizeof(FIXED_INFO) + (_res.nscount > 0 ? (_res.nscount  - 1) *
1418    sizeof(IP_ADDR_STRING) : 0);
1419   if (!pFixedInfo || *pOutBufLen < size) {
1420     *pOutBufLen = size;
1421     return ERROR_BUFFER_OVERFLOW;
1422   }
1423
1424   memset(pFixedInfo, 0, size);
1425   size = sizeof(pFixedInfo->HostName);
1426   GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
1427   size = sizeof(pFixedInfo->DomainName);
1428   GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
1429   if (_res.nscount > 0) {
1430     PIP_ADDR_STRING ptr;
1431     int i;
1432
1433     for (i = 0, ptr = &pFixedInfo->DnsServerList; i < _res.nscount && ptr;
1434      i++, ptr = ptr->Next) {
1435       toIPAddressString(_res.nsaddr_list[i].sin_addr.s_addr,
1436        ptr->IpAddress.String);
1437       if (i == _res.nscount - 1)
1438         ptr->Next = NULL;
1439       else if (i == 0)
1440         ptr->Next = (PIP_ADDR_STRING)((LPBYTE)pFixedInfo + sizeof(FIXED_INFO));
1441       else
1442         ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
1443     }
1444   }
1445   pFixedInfo->NodeType = HYBRID_NODETYPE;
1446   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1447    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
1448   if (regReturn != ERROR_SUCCESS)
1449     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1450      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
1451      &hKey);
1452   if (regReturn == ERROR_SUCCESS)
1453   {
1454     DWORD size = sizeof(pFixedInfo->ScopeId);
1455
1456     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (LPBYTE)pFixedInfo->ScopeId, &size);
1457     RegCloseKey(hKey);
1458   }
1459
1460   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1461      I suppose could also check for a listener on port 53 to set EnableDns */
1462   ret = NO_ERROR;
1463   TRACE("returning %d\n", ret);
1464   return ret;
1465 }
1466
1467
1468 /******************************************************************
1469  *    GetNumberOfInterfaces (IPHLPAPI.@)
1470  *
1471  * Get the number of interfaces.
1472  *
1473  * PARAMS
1474  *  pdwNumIf [Out] number of interfaces
1475  *
1476  * RETURNS
1477  *  NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
1478  */
1479 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1480 {
1481   DWORD ret;
1482
1483   TRACE("pdwNumIf %p\n", pdwNumIf);
1484   if (!pdwNumIf)
1485     ret = ERROR_INVALID_PARAMETER;
1486   else {
1487     *pdwNumIf = getNumInterfaces();
1488     ret = NO_ERROR;
1489   }
1490   TRACE("returning %d\n", ret);
1491   return ret;
1492 }
1493
1494
1495 /******************************************************************
1496  *    GetPerAdapterInfo (IPHLPAPI.@)
1497  *
1498  * Get information about an adapter corresponding to an interface.
1499  *
1500  * PARAMS
1501  *  IfIndex         [In]     interface info
1502  *  pPerAdapterInfo [Out]    buffer for per adapter info
1503  *  pOutBufLen      [In/Out] length of output buffer
1504  *
1505  * RETURNS
1506  *  Success: NO_ERROR
1507  *  Failure: error code from winerror.h
1508  *
1509  * FIXME
1510  *  Stub, returns empty IP_PER_ADAPTER_INFO in every case.
1511  */
1512 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1513 {
1514   ULONG bytesNeeded = sizeof(IP_PER_ADAPTER_INFO);
1515   DWORD ret;
1516
1517   TRACE("(IfIndex %d, pPerAdapterInfo %p, pOutBufLen %p)\n", IfIndex,
1518    pPerAdapterInfo, pOutBufLen);
1519   if (!pOutBufLen)
1520     ret = ERROR_INVALID_PARAMETER;
1521   else if (!pPerAdapterInfo)
1522   {
1523     *pOutBufLen = bytesNeeded;
1524     ret = NO_ERROR;
1525   }
1526   else if (*pOutBufLen < bytesNeeded)
1527   {
1528     *pOutBufLen = bytesNeeded;
1529     ret = ERROR_BUFFER_OVERFLOW;
1530   }
1531   else
1532   {
1533     memset(pPerAdapterInfo, 0, bytesNeeded);
1534     ret = NO_ERROR;
1535   }
1536   return ret;
1537 }
1538
1539
1540 /******************************************************************
1541  *    GetRTTAndHopCount (IPHLPAPI.@)
1542  *
1543  * Get round-trip time (RTT) and hop count.
1544  *
1545  * PARAMS
1546  *
1547  *  DestIpAddress [In]  destination address to get the info for
1548  *  HopCount      [Out] retrieved hop count
1549  *  MaxHops       [In]  maximum hops to search for the destination
1550  *  RTT           [Out] RTT in milliseconds
1551  *
1552  * RETURNS
1553  *  Success: TRUE
1554  *  Failure: FALSE
1555  *
1556  * FIXME
1557  *  Stub, returns FALSE.
1558  */
1559 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
1560 {
1561   FIXME("(DestIpAddress 0x%08lx, HopCount %p, MaxHops %d, RTT %p): stub\n",
1562    DestIpAddress, HopCount, MaxHops, RTT);
1563   return FALSE;
1564 }
1565
1566
1567 /******************************************************************
1568  *    GetTcpStatistics (IPHLPAPI.@)
1569  *
1570  * Get the TCP statistics for the local computer.
1571  *
1572  * PARAMS
1573  *  pStats [Out] buffer for TCP statistics
1574  *
1575  * RETURNS
1576  *  Success: NO_ERROR
1577  *  Failure: error code from winerror.h
1578  */
1579 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
1580 {
1581   DWORD ret;
1582
1583   TRACE("pStats %p\n", pStats);
1584   ret = getTCPStats(pStats);
1585   TRACE("returning %d\n", ret);
1586   return ret;
1587 }
1588
1589
1590 /******************************************************************
1591  *    GetTcpTable (IPHLPAPI.@)
1592  *
1593  * Get the table of active TCP connections.
1594  *
1595  * PARAMS
1596  *  pTcpTable [Out]    buffer for TCP connections table
1597  *  pdwSize   [In/Out] length of output buffer
1598  *  bOrder    [In]     whether to order the table
1599  *
1600  * RETURNS
1601  *  Success: NO_ERROR
1602  *  Failure: error code from winerror.h
1603  *
1604  * NOTES
1605  *  If pdwSize is less than required, the function will return 
1606  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to 
1607  *  the required byte size.
1608  *  If bOrder is true, the returned table will be sorted, first by
1609  *  local address and port number, then by remote address and port
1610  *  number.
1611  */
1612 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1613 {
1614   DWORD ret;
1615
1616   TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize,
1617    (DWORD)bOrder);
1618   if (!pdwSize)
1619     ret = ERROR_INVALID_PARAMETER;
1620   else {
1621     DWORD numEntries = getNumTcpEntries();
1622     DWORD size = sizeof(MIB_TCPTABLE);
1623
1624     if (numEntries > 1)
1625       size += (numEntries - 1) * sizeof(MIB_TCPROW);
1626     if (!pTcpTable || *pdwSize < size) {
1627       *pdwSize = size;
1628       ret = ERROR_INSUFFICIENT_BUFFER;
1629     }
1630     else {
1631       ret = getTcpTable(&pTcpTable, numEntries, 0, 0);
1632       if (!ret) {
1633         size = sizeof(MIB_TCPTABLE);
1634         if (pTcpTable->dwNumEntries > 1)
1635           size += (pTcpTable->dwNumEntries - 1) * sizeof(MIB_TCPROW);
1636         *pdwSize = size;
1637
1638         if (bOrder)
1639            qsort(pTcpTable->table, pTcpTable->dwNumEntries,
1640                  sizeof(MIB_TCPROW), TcpTableSorter);
1641         ret = NO_ERROR;
1642       }
1643     }
1644   }
1645   TRACE("returning %d\n", ret);
1646   return ret;
1647 }
1648
1649
1650 /******************************************************************
1651  *    GetUdpStatistics (IPHLPAPI.@)
1652  *
1653  * Get the UDP statistics for the local computer.
1654  *
1655  * PARAMS
1656  *  pStats [Out] buffer for UDP statistics
1657  *
1658  * RETURNS
1659  *  Success: NO_ERROR
1660  *  Failure: error code from winerror.h
1661  */
1662 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
1663 {
1664   DWORD ret;
1665
1666   TRACE("pStats %p\n", pStats);
1667   ret = getUDPStats(pStats);
1668   TRACE("returning %d\n", ret);
1669   return ret;
1670 }
1671
1672
1673 /******************************************************************
1674  *    GetUdpTable (IPHLPAPI.@)
1675  *
1676  * Get a table of active UDP connections.
1677  *
1678  * PARAMS
1679  *  pUdpTable [Out]    buffer for UDP connections table
1680  *  pdwSize   [In/Out] length of output buffer
1681  *  bOrder    [In]     whether to order the table
1682  *
1683  * RETURNS
1684  *  Success: NO_ERROR
1685  *  Failure: error code from winerror.h
1686  *
1687  * NOTES
1688  *  If pdwSize is less than required, the function will return 
1689  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
1690  *  required byte size.
1691  *  If bOrder is true, the returned table will be sorted, first by
1692  *  local address, then by local port number.
1693  */
1694 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1695 {
1696   DWORD ret;
1697
1698   TRACE("pUdpTable %p, pdwSize %p, bOrder %d\n", pUdpTable, pdwSize,
1699    (DWORD)bOrder);
1700   if (!pdwSize)
1701     ret = ERROR_INVALID_PARAMETER;
1702   else {
1703     DWORD numEntries = getNumUdpEntries();
1704     DWORD size = sizeof(MIB_UDPTABLE);
1705
1706     if (numEntries > 1)
1707       size += (numEntries - 1) * sizeof(MIB_UDPROW);
1708     if (!pUdpTable || *pdwSize < size) {
1709       *pdwSize = size;
1710       ret = ERROR_INSUFFICIENT_BUFFER;
1711     }
1712     else {
1713       PMIB_UDPTABLE table;
1714
1715       ret = getUdpTable(&table, GetProcessHeap(), 0);
1716       if (!ret) {
1717         size = sizeof(MIB_UDPTABLE);
1718         if (table->dwNumEntries > 1)
1719           size += (table->dwNumEntries - 1) * sizeof(MIB_UDPROW);
1720         if (*pdwSize < size) {
1721           *pdwSize = size;
1722           ret = ERROR_INSUFFICIENT_BUFFER;
1723         }
1724         else {
1725           *pdwSize = size;
1726           memcpy(pUdpTable, table, size);
1727           if (bOrder)
1728             qsort(pUdpTable->table, pUdpTable->dwNumEntries,
1729              sizeof(MIB_UDPROW), UdpTableSorter);
1730           ret = NO_ERROR;
1731         }
1732         HeapFree(GetProcessHeap(), 0, table);
1733       }
1734       else
1735         ret = ERROR_OUTOFMEMORY;
1736     }
1737   }
1738   TRACE("returning %d\n", ret);
1739   return ret;
1740 }
1741
1742
1743 /******************************************************************
1744  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1745  *
1746  * This is a Win98-only function to get information on "unidirectional"
1747  * adapters.  Since this is pretty nonsensical in other contexts, it
1748  * never returns anything.
1749  *
1750  * PARAMS
1751  *  pIPIfInfo   [Out] buffer for adapter infos
1752  *  dwOutBufLen [Out] length of the output buffer
1753  *
1754  * RETURNS
1755  *  Success: NO_ERROR
1756  *  Failure: error code from winerror.h
1757  *
1758  * FIXME
1759  *  Stub, returns ERROR_NOT_SUPPORTED.
1760  */
1761 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1762 {
1763   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
1764   /* a unidirectional adapter?? not bloody likely! */
1765   return ERROR_NOT_SUPPORTED;
1766 }
1767
1768
1769 /******************************************************************
1770  *    IpReleaseAddress (IPHLPAPI.@)
1771  *
1772  * Release an IP optained through DHCP,
1773  *
1774  * PARAMS
1775  *  AdapterInfo [In] adapter to release IP address
1776  *
1777  * RETURNS
1778  *  Success: NO_ERROR
1779  *  Failure: error code from winerror.h
1780  *
1781  * NOTES
1782  *  Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1783  *  this function does nothing.
1784  *
1785  * FIXME
1786  *  Stub, returns ERROR_NOT_SUPPORTED.
1787  */
1788 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1789 {
1790   TRACE("AdapterInfo %p\n", AdapterInfo);
1791   /* not a stub, never going to support this (and I never mark an adapter as
1792      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1793   return ERROR_NOT_SUPPORTED;
1794 }
1795
1796
1797 /******************************************************************
1798  *    IpRenewAddress (IPHLPAPI.@)
1799  *
1800  * Renew an IP optained through DHCP.
1801  *
1802  * PARAMS
1803  *  AdapterInfo [In] adapter to renew IP address
1804  *
1805  * RETURNS
1806  *  Success: NO_ERROR
1807  *  Failure: error code from winerror.h
1808  *
1809  * NOTES
1810  *  Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1811  *  this function does nothing.
1812  *
1813  * FIXME
1814  *  Stub, returns ERROR_NOT_SUPPORTED.
1815  */
1816 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1817 {
1818   TRACE("AdapterInfo %p\n", AdapterInfo);
1819   /* not a stub, never going to support this (and I never mark an adapter as
1820      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1821   return ERROR_NOT_SUPPORTED;
1822 }
1823
1824
1825 /******************************************************************
1826  *    NotifyAddrChange (IPHLPAPI.@)
1827  *
1828  * Notify caller whenever the ip-interface map is changed.
1829  *
1830  * PARAMS
1831  *  Handle     [Out] handle useable in asynchronus notification
1832  *  overlapped [In]  overlapped structure that notifies the caller
1833  *
1834  * RETURNS
1835  *  Success: NO_ERROR
1836  *  Failure: error code from winerror.h
1837  *
1838  * FIXME
1839  *  Stub, returns ERROR_NOT_SUPPORTED.
1840  */
1841 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1842 {
1843   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
1844   return ERROR_NOT_SUPPORTED;
1845 }
1846
1847
1848 /******************************************************************
1849  *    NotifyRouteChange (IPHLPAPI.@)
1850  *
1851  * Notify caller whenever the ip routing table is changed.
1852  *
1853  * PARAMS
1854  *  Handle     [Out] handle useable in asynchronus notification
1855  *  overlapped [In]  overlapped structure that notifies the caller
1856  *
1857  * RETURNS
1858  *  Success: NO_ERROR
1859  *  Failure: error code from winerror.h
1860  *
1861  * FIXME
1862  *  Stub, returns ERROR_NOT_SUPPORTED.
1863  */
1864 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1865 {
1866   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
1867   return ERROR_NOT_SUPPORTED;
1868 }
1869
1870
1871 /******************************************************************
1872  *    SendARP (IPHLPAPI.@)
1873  *
1874  * Send an ARP request.
1875  *
1876  * PARAMS
1877  *  DestIP     [In]     attempt to obtain this IP
1878  *  SrcIP      [In]     optional sender IP address
1879  *  pMacAddr   [Out]    buffer for the mac address
1880  *  PhyAddrLen [In/Out] length of the output buffer
1881  *
1882  * RETURNS
1883  *  Success: NO_ERROR
1884  *  Failure: error code from winerror.h
1885  *
1886  * FIXME
1887  *  Stub, returns ERROR_NOT_SUPPORTED.
1888  */
1889 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
1890 {
1891   FIXME("(DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p): stub\n",
1892    DestIP, SrcIP, pMacAddr, PhyAddrLen);
1893   return ERROR_NOT_SUPPORTED;
1894 }
1895
1896
1897 /******************************************************************
1898  *    SetIfEntry (IPHLPAPI.@)
1899  *
1900  * Set the administrative status of an interface.
1901  *
1902  * PARAMS
1903  *  pIfRow [In] dwAdminStatus member specifies the new status.
1904  *
1905  * RETURNS
1906  *  Success: NO_ERROR
1907  *  Failure: error code from winerror.h
1908  *
1909  * FIXME
1910  *  Stub, returns ERROR_NOT_SUPPORTED.
1911  */
1912 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
1913 {
1914   FIXME("(pIfRow %p): stub\n", pIfRow);
1915   /* this is supposed to set an interface administratively up or down.
1916      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
1917      this sort of down is indistinguishable from other sorts of down (e.g. no
1918      link). */
1919   return ERROR_NOT_SUPPORTED;
1920 }
1921
1922
1923 /******************************************************************
1924  *    SetIpForwardEntry (IPHLPAPI.@)
1925  *
1926  * Modify an existing route.
1927  *
1928  * PARAMS
1929  *  pRoute [In] route with the new information
1930  *
1931  * RETURNS
1932  *  Success: NO_ERROR
1933  *  Failure: error code from winerror.h
1934  *
1935  * FIXME
1936  *  Stub, returns NO_ERROR.
1937  */
1938 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
1939 {
1940   FIXME("(pRoute %p): stub\n", pRoute);
1941   /* this is to add a route entry, how's it distinguishable from
1942      CreateIpForwardEntry?
1943      could use SIOCADDRT, not sure I want to */
1944   return (DWORD) 0;
1945 }
1946
1947
1948 /******************************************************************
1949  *    SetIpNetEntry (IPHLPAPI.@)
1950  *
1951  * Modify an existing ARP entry.
1952  *
1953  * PARAMS
1954  *  pArpEntry [In] ARP entry with the new information
1955  *
1956  * RETURNS
1957  *  Success: NO_ERROR
1958  *  Failure: error code from winerror.h
1959  *
1960  * FIXME
1961  *  Stub, returns NO_ERROR.
1962  */
1963 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
1964 {
1965   FIXME("(pArpEntry %p): stub\n", pArpEntry);
1966   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
1967   return (DWORD) 0;
1968 }
1969
1970
1971 /******************************************************************
1972  *    SetIpStatistics (IPHLPAPI.@)
1973  *
1974  * Toggle IP forwarding and det the default TTL value.
1975  *
1976  * PARAMS
1977  *  pIpStats [In] IP statistics with the new information
1978  *
1979  * RETURNS
1980  *  Success: NO_ERROR
1981  *  Failure: error code from winerror.h
1982  *
1983  * FIXME
1984  *  Stub, returns NO_ERROR.
1985  */
1986 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
1987 {
1988   FIXME("(pIpStats %p): stub\n", pIpStats);
1989   return (DWORD) 0;
1990 }
1991
1992
1993 /******************************************************************
1994  *    SetIpTTL (IPHLPAPI.@)
1995  *
1996  * Set the default TTL value.
1997  *
1998  * PARAMS
1999  *  nTTL [In] new TTL value
2000  *
2001  * RETURNS
2002  *  Success: NO_ERROR
2003  *  Failure: error code from winerror.h
2004  *
2005  * FIXME
2006  *  Stub, returns NO_ERROR.
2007  */
2008 DWORD WINAPI SetIpTTL(UINT nTTL)
2009 {
2010   FIXME("(nTTL %d): stub\n", nTTL);
2011   /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
2012      want to.  Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
2013   return (DWORD) 0;
2014 }
2015
2016
2017 /******************************************************************
2018  *    SetTcpEntry (IPHLPAPI.@)
2019  *
2020  * Set the state of a TCP connection.
2021  *
2022  * PARAMS
2023  *  pTcpRow [In] specifies connection with new state
2024  *
2025  * RETURNS
2026  *  Success: NO_ERROR
2027  *  Failure: error code from winerror.h
2028  *
2029  * FIXME
2030  *  Stub, returns NO_ERROR.
2031  */
2032 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
2033 {
2034   FIXME("(pTcpRow %p): stub\n", pTcpRow);
2035   return (DWORD) 0;
2036 }
2037
2038
2039 /******************************************************************
2040  *    UnenableRouter (IPHLPAPI.@)
2041  *
2042  * Decrement the IP-forwarding reference count. Turn off IP-forwarding
2043  * if it reaches zero.
2044  *
2045  * PARAMS
2046  *  pOverlapped     [In/Out] should be the same as in EnableRouter()
2047  *  lpdwEnableCount [Out]    optional, receives reference count
2048  *
2049  * RETURNS
2050  *  Success: NO_ERROR
2051  *  Failure: error code from winerror.h
2052  *
2053  * FIXME
2054  *  Stub, returns ERROR_NOT_SUPPORTED.
2055  */
2056 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
2057 {
2058   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
2059    lpdwEnableCount);
2060   /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
2061      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
2062    */
2063   return ERROR_NOT_SUPPORTED;
2064 }