Use LPSTORAGE to better match the PSDK.
[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                (LPBYTE)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                (LPBYTE)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 = ((const MIB_IFROW*)a)->dwIndex - ((const MIB_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 = ((const MIB_IPADDRROW*)a)->dwAddr - ((const MIB_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    const MIB_IPFORWARDROW* rowA = (const MIB_IPFORWARDROW*)a;
1114    const MIB_IPFORWARDROW* rowB = (const MIB_IPFORWARDROW*)b;
1115
1116     ret = rowA->dwForwardDest - rowB->dwForwardDest;
1117     if (ret == 0) {
1118       ret = rowA->dwForwardProto - rowB->dwForwardProto;
1119       if (ret == 0) {
1120         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
1121         if (ret == 0)
1122           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1123       }
1124     }
1125   }
1126   else
1127     ret = 0;
1128   return ret;
1129 }
1130
1131
1132 /******************************************************************
1133  *    GetIpForwardTable (IPHLPAPI.@)
1134  *
1135  * NOTES
1136  * Returns the route table.  On input, *pdwSize is the size in bytes of
1137  * pIpForwardTable.  If this is less than required, the function will return
1138  * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1139  * size.
1140  * If bOrder is true, the returned table will be sorted by the next hop and
1141  * an assortment of arbitrary parameters.
1142  *
1143  * PARAMS
1144  *
1145  *  pIpForwardTable [In/Out]
1146  *  pdwSize [In/Out]
1147  *  bOrder [In]
1148  *
1149  * RETURNS
1150  * NO_ERROR on success, something else on failure.
1151  *
1152  */
1153 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1154 {
1155   DWORD ret;
1156
1157   TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
1158    pdwSize, (DWORD)bOrder);
1159   if (!pdwSize)
1160     ret = ERROR_INVALID_PARAMETER;
1161   else {
1162     DWORD numRoutes = getNumRoutes();
1163     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1164      sizeof(MIB_IPFORWARDROW);
1165
1166     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1167       *pdwSize = sizeNeeded;
1168       ret = ERROR_INSUFFICIENT_BUFFER;
1169     }
1170     else {
1171       RouteTable *table = getRouteTable();
1172       if (table) {
1173         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1174          sizeof(MIB_IPFORWARDROW);
1175         if (*pdwSize < sizeNeeded) {
1176           *pdwSize = sizeNeeded;
1177           ret = ERROR_INSUFFICIENT_BUFFER;
1178         }
1179         else {
1180           DWORD ndx;
1181
1182           pIpForwardTable->dwNumEntries = table->numRoutes;
1183           for (ndx = 0; ndx < numRoutes; ndx++) {
1184             pIpForwardTable->table[ndx].dwForwardIfIndex =
1185              table->routes[ndx].ifIndex;
1186             pIpForwardTable->table[ndx].dwForwardDest =
1187              table->routes[ndx].dest;
1188             pIpForwardTable->table[ndx].dwForwardMask =
1189              table->routes[ndx].mask;
1190             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1191             pIpForwardTable->table[ndx].dwForwardNextHop =
1192              table->routes[ndx].gateway;
1193             /* FIXME: this type is appropriate for local interfaces; may not
1194                always be appropriate */
1195             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1196             /* FIXME: other protos might be appropriate, e.g. the default route
1197                is typically set with MIB_IPPROTO_NETMGMT instead */
1198             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1199             /* punt on age and AS */
1200             pIpForwardTable->table[ndx].dwForwardAge = 0;
1201             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1202             pIpForwardTable->table[ndx].dwForwardMetric1 =
1203              table->routes[ndx].metric;
1204             /* rest of the metrics are 0.. */
1205             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1206             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1207             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1208             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1209           }
1210           if (bOrder)
1211             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1212              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1213           ret = NO_ERROR;
1214         }
1215         HeapFree(GetProcessHeap(), 0, table);
1216       }
1217       else
1218         ret = ERROR_OUTOFMEMORY;
1219     }
1220   }
1221   TRACE("returning %ld\n", ret);
1222   return ret;
1223 }
1224
1225
1226 static int IpNetTableSorter(const void *a, const void *b)
1227 {
1228   int ret;
1229
1230   if (a && b)
1231     ret = ((const MIB_IPNETROW*)a)->dwAddr - ((const MIB_IPNETROW*)b)->dwAddr;
1232   else
1233     ret = 0;
1234   return ret;
1235 }
1236
1237
1238 /******************************************************************
1239  *    GetIpNetTable (IPHLPAPI.@)
1240  *
1241  * Returns the ARP cache.  On input, *pdwSize is the size in bytes of
1242  * pIpNetTable.  If this is less than required, the function will return
1243  * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1244  * size.
1245  * If bOrder is true, the returned table will be sorted by IP address.
1246  *
1247  * PARAMS
1248  *
1249  *  pIpNetTable [In/Out]
1250  *  pdwSize [In/Out]
1251  *  bOrder [In]
1252  *
1253  * RETURNS
1254  * NO_ERROR on success, something else on failure.
1255  *
1256  */
1257 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1258 {
1259   DWORD ret;
1260
1261   TRACE("pIpNetTable %p, pdwSize %p, bOrder %ld\n", pIpNetTable, pdwSize,
1262    (DWORD)bOrder);
1263   if (!pdwSize)
1264     ret = ERROR_INVALID_PARAMETER;
1265   else {
1266     DWORD numEntries = getNumArpEntries();
1267     ULONG size = sizeof(MIB_IPNETTABLE) + (numEntries - 1) *
1268      sizeof(MIB_IPNETROW);
1269
1270     if (!pIpNetTable || *pdwSize < size) {
1271       *pdwSize = size;
1272       ret = ERROR_INSUFFICIENT_BUFFER;
1273     }
1274     else {
1275       PMIB_IPNETTABLE table = getArpTable();
1276
1277       if (table) {
1278         size = sizeof(MIB_IPNETTABLE) + (table->dwNumEntries - 1) *
1279          sizeof(MIB_IPNETROW);
1280         if (*pdwSize < size) {
1281           *pdwSize = size;
1282           ret = ERROR_INSUFFICIENT_BUFFER;
1283         }
1284         else {
1285           memcpy(pIpNetTable, table, size);
1286           if (bOrder)
1287             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
1288              sizeof(MIB_IPNETROW), IpNetTableSorter);
1289           ret = NO_ERROR;
1290         }
1291         HeapFree(GetProcessHeap(), 0, table);
1292       }
1293       else
1294         ret = ERROR_OUTOFMEMORY;
1295     }
1296   }
1297   TRACE("returning %ld\n", ret);
1298   return ret;
1299 }
1300
1301
1302 /******************************************************************
1303  *    GetIpStatistics (IPHLPAPI.@)
1304  *
1305  * PARAMS
1306  *
1307  *  pStats [In/Out]
1308  *
1309  * RETURNS
1310  *
1311  *  DWORD
1312  *
1313  */
1314 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
1315 {
1316   DWORD ret;
1317
1318   TRACE("pStats %p\n", pStats);
1319   ret = getIPStats(pStats);
1320   TRACE("returning %ld\n", ret);
1321   return ret;
1322 }
1323
1324
1325 /******************************************************************
1326  *    GetNetworkParams (IPHLPAPI.@)
1327  *
1328  * PARAMS
1329  *
1330  *  pFixedInfo [In/Out]
1331  *  pOutBufLen [In/Out]
1332  *
1333  * RETURNS
1334  *
1335  *  DWORD
1336  *
1337  */
1338 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1339 {
1340   DWORD ret, size;
1341   LONG regReturn;
1342   HKEY hKey;
1343
1344   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
1345   if (!pOutBufLen)
1346     return ERROR_INVALID_PARAMETER;
1347
1348   res_init();
1349   size = sizeof(FIXED_INFO) + (_res.nscount > 0 ? (_res.nscount  - 1) *
1350    sizeof(IP_ADDR_STRING) : 0);
1351   if (!pFixedInfo || *pOutBufLen < size) {
1352     *pOutBufLen = size;
1353     return ERROR_BUFFER_OVERFLOW;
1354   }
1355
1356   memset(pFixedInfo, 0, size);
1357   size = sizeof(pFixedInfo->HostName);
1358   GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
1359   size = sizeof(pFixedInfo->DomainName);
1360   GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
1361   if (_res.nscount > 0) {
1362     PIP_ADDR_STRING ptr;
1363     int i;
1364
1365     for (i = 0, ptr = &pFixedInfo->DnsServerList; i < _res.nscount && ptr;
1366      i++, ptr = ptr->Next) {
1367       toIPAddressString(_res.nsaddr_list[i].sin_addr.s_addr,
1368        ptr->IpAddress.String);
1369       if (i == _res.nscount - 1)
1370         ptr->Next = NULL;
1371       else if (i == 0)
1372         ptr->Next = (PIP_ADDR_STRING)((LPBYTE)pFixedInfo + sizeof(FIXED_INFO));
1373       else
1374         ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
1375     }
1376   }
1377   pFixedInfo->NodeType = HYBRID_NODETYPE;
1378   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1379    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
1380   if (regReturn != ERROR_SUCCESS)
1381     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1382      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
1383      &hKey);
1384   if (regReturn == ERROR_SUCCESS)
1385   {
1386     DWORD size = sizeof(pFixedInfo->ScopeId);
1387
1388     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (LPBYTE)pFixedInfo->ScopeId, &size);
1389     RegCloseKey(hKey);
1390   }
1391
1392   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1393      I suppose could also check for a listener on port 53 to set EnableDns */
1394   ret = NO_ERROR;
1395   TRACE("returning %ld\n", ret);
1396   return ret;
1397 }
1398
1399
1400 /******************************************************************
1401  *    GetNumberOfInterfaces (IPHLPAPI.@)
1402  *
1403  * NOTES
1404  * Returns the number of interfaces in *pdwNumIf.
1405  *
1406  * PARAMS
1407  *
1408  *  pdwNumIf [In/Out]
1409  *
1410  * RETURNS
1411  * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
1412  *
1413  */
1414 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1415 {
1416   DWORD ret;
1417
1418   TRACE("pdwNumIf %p\n", pdwNumIf);
1419   if (!pdwNumIf)
1420     ret = ERROR_INVALID_PARAMETER;
1421   else {
1422     *pdwNumIf = getNumInterfaces();
1423     ret = NO_ERROR;
1424   }
1425   TRACE("returning %ld\n", ret);
1426   return ret;
1427 }
1428
1429
1430 /******************************************************************
1431  *    GetPerAdapterInfo (IPHLPAPI.@)
1432  *
1433  * NOTES
1434  * Stub
1435  *
1436  * PARAMS
1437  *
1438  *  IfIndex [In]
1439  *  pPerAdapterInfo [In/Out]
1440  *  pOutBufLen [In/Out]
1441  *
1442  * RETURNS
1443  * ERROR_NOT_SUPPORTED
1444  */
1445 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1446 {
1447   TRACE("(IfIndex %ld, pPerAdapterInfo %p, pOutBufLen %p)\n", IfIndex,
1448    pPerAdapterInfo, pOutBufLen);
1449   /* marking Win2K+ functions not supported */
1450   return ERROR_NOT_SUPPORTED;
1451 }
1452
1453
1454 /******************************************************************
1455  *    GetRTTAndHopCount (IPHLPAPI.@)
1456  *
1457  * NOTES
1458  * Stub
1459  *
1460  * PARAMS
1461  *
1462  *  DestIpAddress [In]
1463  *  HopCount [In/Out]
1464  *  MaxHops [In]
1465  *  RTT [In/Out]
1466  *
1467  * RETURNS
1468  * FALSE
1469  *
1470  */
1471 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
1472 {
1473   FIXME("(DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p): stub\n",
1474    DestIpAddress, HopCount, MaxHops, RTT);
1475   return FALSE;
1476 }
1477
1478
1479 /******************************************************************
1480  *    GetTcpStatistics (IPHLPAPI.@)
1481  *
1482  * PARAMS
1483  *
1484  *  pStats [In/Out]
1485  *
1486  * RETURNS
1487  *
1488  *  DWORD
1489  *
1490  */
1491 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
1492 {
1493   DWORD ret;
1494
1495   TRACE("pStats %p\n", pStats);
1496   ret = getTCPStats(pStats);
1497   TRACE("returning %ld\n", ret);
1498   return ret;
1499 }
1500
1501
1502 static int TcpTableSorter(const void *a, const void *b)
1503 {
1504   int ret;
1505
1506   if (a && b) {
1507     const MIB_TCPROW* rowA = a;
1508     const MIB_TCPROW* rowB = b;
1509
1510     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1511     if (ret == 0) {
1512       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1513       if (ret == 0) {
1514         ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
1515         if (ret == 0)
1516           ret = rowA->dwRemotePort - rowB->dwRemotePort;
1517       }
1518     }
1519   }
1520   else
1521     ret = 0;
1522   return ret;
1523 }
1524
1525
1526 /******************************************************************
1527  *    GetTcpTable (IPHLPAPI.@)
1528  *
1529  * Returns a table of active TCP connections.  On input, *pdwSize
1530  * is the size in bytes of pTcpTable.  If this is less than required,
1531  * the function will return ERROR_INSUFFICIENT_BUFFER, and *pdwSize
1532  * will be set to the required byte size.
1533  * If bOrder is true, the returned table will be sorted, first by
1534  * local address and port number, then by remote address and port
1535  * number.
1536  *
1537  * PARAMS
1538  *
1539  *  pTcpTable [In/Out]
1540  *  pdwSize [In/Out]
1541  *  bOrder [In]
1542  *
1543  * RETURNS
1544  * NO_ERROR on success, something else on failure.
1545  *
1546  */
1547 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1548 {
1549   DWORD ret;
1550
1551   TRACE("pTcpTable %p, pdwSize %p, bOrder %ld\n", pTcpTable, pdwSize,
1552    (DWORD)bOrder);
1553   if (!pdwSize)
1554     ret = ERROR_INVALID_PARAMETER;
1555   else {
1556     DWORD numEntries = getNumTcpEntries();
1557     ULONG size = sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW);
1558
1559     if (!pTcpTable || *pdwSize < size) {
1560       *pdwSize = size;
1561       ret = ERROR_INSUFFICIENT_BUFFER;
1562     }
1563     else {
1564       PMIB_TCPTABLE table = getTcpTable();
1565
1566       if (table) {
1567         size = sizeof(MIB_TCPTABLE) + (table->dwNumEntries - 1) *
1568          sizeof(MIB_TCPROW);
1569         if (*pdwSize < size) {
1570           *pdwSize = size;
1571           ret = ERROR_INSUFFICIENT_BUFFER;
1572         }
1573         else {
1574           memcpy(pTcpTable, table, size);
1575           if (bOrder)
1576             qsort(pTcpTable->table, pTcpTable->dwNumEntries,
1577              sizeof(MIB_TCPROW), TcpTableSorter);
1578           ret = NO_ERROR;
1579         }
1580         HeapFree(GetProcessHeap(), 0, table);
1581       }
1582       else
1583         ret = ERROR_OUTOFMEMORY;
1584     }
1585   }
1586   TRACE("returning %ld\n", ret);
1587   return ret;
1588 }
1589
1590
1591 /******************************************************************
1592  *    GetUdpStatistics (IPHLPAPI.@)
1593  *
1594  * PARAMS
1595  *
1596  *  pStats [In/Out]
1597  *
1598  * RETURNS
1599  *
1600  *  DWORD
1601  *
1602  */
1603 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
1604 {
1605   DWORD ret;
1606
1607   TRACE("pStats %p\n", pStats);
1608   ret = getUDPStats(pStats);
1609   TRACE("returning %ld\n", ret);
1610   return ret;
1611 }
1612
1613
1614 static int UdpTableSorter(const void *a, const void *b)
1615 {
1616   int ret;
1617
1618   if (a && b) {
1619     const MIB_UDPROW* rowA = (const MIB_UDPROW*)a;
1620     const MIB_UDPROW* rowB = (const MIB_UDPROW*)b;
1621
1622     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1623     if (ret == 0)
1624       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1625   }
1626   else
1627     ret = 0;
1628   return ret;
1629 }
1630
1631
1632 /******************************************************************
1633  *    GetUdpTable (IPHLPAPI.@)
1634  *
1635  * Returns a table of active UDP connections.  On input, *pdwSize
1636  * is the size in bytes of pUdpTable.  If this is less than required,
1637  * the function will return ERROR_INSUFFICIENT_BUFFER, and *pdwSize
1638  * will be set to the required byte size.
1639  * If bOrder is true, the returned table will be sorted, first by
1640  * local address, then by local port number.
1641  *
1642  * PARAMS
1643  *
1644  *  pUdpTable [In/Out]
1645  *  pdwSize [In/Out]
1646  *  bOrder [In]
1647  *
1648  * RETURNS
1649  * NO_ERROR on success, something else on failure.
1650  *
1651  */
1652 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1653 {
1654   DWORD ret;
1655
1656   TRACE("pUdpTable %p, pdwSize %p, bOrder %ld\n", pUdpTable, pdwSize,
1657    (DWORD)bOrder);
1658   if (!pdwSize)
1659     ret = ERROR_INVALID_PARAMETER;
1660   else {
1661     DWORD numEntries = getNumUdpEntries();
1662     ULONG size = sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW);
1663
1664     if (!pUdpTable || *pdwSize < size) {
1665       *pdwSize = size;
1666       ret = ERROR_INSUFFICIENT_BUFFER;
1667     }
1668     else {
1669       PMIB_UDPTABLE table = getUdpTable();
1670
1671       if (table) {
1672         size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) *
1673          sizeof(MIB_UDPROW);
1674         if (*pdwSize < size) {
1675           *pdwSize = size;
1676           ret = ERROR_INSUFFICIENT_BUFFER;
1677         }
1678         else {
1679           memcpy(pUdpTable, table, size);
1680           if (bOrder)
1681             qsort(pUdpTable->table, pUdpTable->dwNumEntries,
1682              sizeof(MIB_UDPROW), UdpTableSorter);
1683           ret = NO_ERROR;
1684         }
1685         HeapFree(GetProcessHeap(), 0, table);
1686       }
1687       else
1688         ret = ERROR_OUTOFMEMORY;
1689     }
1690   }
1691   TRACE("returning %ld\n", ret);
1692   return ret;
1693 }
1694
1695
1696 /******************************************************************
1697  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1698  *
1699  * This is a Win98-only function to get information on "unidirectional"
1700  * adapters.  Since this is pretty nonsensical in other contexts, it
1701  * never returns anything.
1702  *
1703  * PARAMS
1704  *
1705  *  pIPIfInfo [In/Out]
1706  *  dwOutBufLen [In/Out]
1707  *
1708  * RETURNS
1709  * ERROR_NOT_SUPPORTED
1710  *
1711  */
1712 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1713 {
1714   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
1715   /* a unidirectional adapter?? not bloody likely! */
1716   return ERROR_NOT_SUPPORTED;
1717 }
1718
1719
1720 /******************************************************************
1721  *    IpReleaseAddress (IPHLPAPI.@)
1722  *
1723  * NOTES
1724  * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1725  * this function does nothing.
1726  *
1727  * PARAMS
1728  *
1729  *  AdapterInfo [In/Out]
1730  *
1731  * RETURNS
1732  * ERROR_NOT_SUPPORTED
1733  *
1734  */
1735 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1736 {
1737   TRACE("AdapterInfo %p\n", AdapterInfo);
1738   /* not a stub, never going to support this (and I never mark an adapter as
1739      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1740   return ERROR_NOT_SUPPORTED;
1741 }
1742
1743
1744 /******************************************************************
1745  *    IpRenewAddress (IPHLPAPI.@)
1746  *
1747  * NOTES
1748  * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1749  * this function does nothing.
1750  *
1751  * PARAMS
1752  *
1753  *  AdapterInfo [In/Out]
1754  *
1755  * RETURNS
1756  * ERROR_NOT_SUPPORTED
1757  *
1758  */
1759 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1760 {
1761   TRACE("AdapterInfo %p\n", AdapterInfo);
1762   /* not a stub, never going to support this (and I never mark an adapter as
1763      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1764   return ERROR_NOT_SUPPORTED;
1765 }
1766
1767
1768 /******************************************************************
1769  *    NotifyAddrChange (IPHLPAPI.@)
1770  *
1771  * NOTES
1772  * Stub
1773  *
1774  * PARAMS
1775  *
1776  *  Handle [In/Out]
1777  *  overlapped [In/Out]
1778  *
1779  * RETURNS
1780  * ERROR_NOT_SUPPORTED
1781  *
1782  */
1783 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1784 {
1785   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
1786   /* marking Win2K+ functions not supported */
1787   return ERROR_NOT_SUPPORTED;
1788 }
1789
1790
1791 /******************************************************************
1792  *    NotifyRouteChange (IPHLPAPI.@)
1793  *
1794  * NOTES
1795  * Stub
1796  *
1797  * PARAMS
1798  *
1799  *  Handle [In/Out]
1800  *  overlapped [In/Out]
1801  *
1802  * RETURNS
1803  * ERROR_NOT_SUPPORTED
1804  *
1805  */
1806 DWORD WINAPI NotifyRouteChange(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  *    SendARP (IPHLPAPI.@)
1816  *
1817  * NOTES
1818  * Stub
1819  *
1820  * PARAMS
1821  *
1822  *  DestIP [In]
1823  *  SrcIP [In]
1824  *  pMacAddr [In/Out]
1825  *  PhyAddrLen [In/Out]
1826  *
1827  * RETURNS
1828  * ERROR_NOT_SUPPORTED
1829  *
1830  */
1831 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
1832 {
1833   FIXME("(DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p): stub\n",
1834    DestIP, SrcIP, pMacAddr, PhyAddrLen);
1835   /* marking Win2K+ functions not supported */
1836   return ERROR_NOT_SUPPORTED;
1837 }
1838
1839
1840 /******************************************************************
1841  *    SetIfEntry (IPHLPAPI.@)
1842  *
1843  * NOTES
1844  * Stub
1845  *
1846  * PARAMS
1847  *
1848  *  pIfRow [In/Out]
1849  *
1850  * RETURNS
1851  * ERROR_NOT_SUPPORTED
1852  *
1853  */
1854 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
1855 {
1856   FIXME("(pIfRow %p): stub\n", pIfRow);
1857   /* this is supposed to set an administratively interface up or down.
1858      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
1859      this sort of down is indistinguishable from other sorts of down (e.g. no
1860      link). */
1861   return ERROR_NOT_SUPPORTED;
1862 }
1863
1864
1865 /******************************************************************
1866  *    SetIpForwardEntry (IPHLPAPI.@)
1867  *
1868  * NOTES
1869  * Stub
1870  *
1871  * PARAMS
1872  *
1873  *  pRoute [In/Out]
1874  *
1875  * RETURNS
1876  * 0
1877  *
1878  */
1879 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
1880 {
1881   FIXME("(pRoute %p): stub\n", pRoute);
1882   /* this is to add a route entry, how's it distinguishable from
1883      CreateIpForwardEntry?
1884      could use SIOCADDRT, not sure I want to */
1885   return (DWORD) 0;
1886 }
1887
1888
1889 /******************************************************************
1890  *    SetIpNetEntry (IPHLPAPI.@)
1891  *
1892  * NOTES
1893  * Stub
1894  *
1895  * PARAMS
1896  *
1897  *  pArpEntry [In/Out]
1898  *
1899  * RETURNS
1900  * 0
1901  *
1902  */
1903 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
1904 {
1905   FIXME("(pArpEntry %p): stub\n", pArpEntry);
1906   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
1907   return (DWORD) 0;
1908 }
1909
1910
1911 /******************************************************************
1912  *    SetIpStatistics (IPHLPAPI.@)
1913  *
1914  * NOTES
1915  * Stub
1916  *
1917  * PARAMS
1918  *
1919  *  pIpStats [In/Out]
1920  *
1921  * RETURNS
1922  * 0
1923  *
1924  */
1925 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
1926 {
1927   FIXME("(pIpStats %p): stub\n", pIpStats);
1928   return (DWORD) 0;
1929 }
1930
1931
1932 /******************************************************************
1933  *    SetIpTTL (IPHLPAPI.@)
1934  *
1935  * NOTES
1936  * Stub
1937  *
1938  * PARAMS
1939  *
1940  *  nTTL [In]
1941  *
1942  * RETURNS
1943  * 0
1944  *
1945  */
1946 DWORD WINAPI SetIpTTL(UINT nTTL)
1947 {
1948   FIXME("(nTTL %d): stub\n", nTTL);
1949   /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
1950      want to.  Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
1951   return (DWORD) 0;
1952 }
1953
1954
1955 /******************************************************************
1956  *    SetTcpEntry (IPHLPAPI.@)
1957  *
1958  * NOTES
1959  * Stub
1960  *
1961  * PARAMS
1962  *
1963  *  pTcpRow [In/Out]
1964  *
1965  * RETURNS
1966  * 0
1967  *
1968  */
1969 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
1970 {
1971   FIXME("(pTcpRow %p): stub\n", pTcpRow);
1972   return (DWORD) 0;
1973 }
1974
1975
1976 /******************************************************************
1977  *    UnenableRouter (IPHLPAPI.@)
1978  *
1979  * NOTES
1980  * Stub
1981  *
1982  * PARAMS
1983  *
1984  *  pOverlapped [In/Out]
1985  *  lpdwEnableCount [In/Out]
1986  *
1987  * RETURNS
1988  * ERROR_NOT_SUPPORTED
1989  *
1990  */
1991 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
1992 {
1993   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
1994    lpdwEnableCount);
1995   /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
1996      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
1997      marking Win2K+ functions not supported */
1998   return ERROR_NOT_SUPPORTED;
1999 }