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