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