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