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