Use shell icon cache instead of an own IExtractIcon implementation.
[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             if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
623              "Software\\Wine\\Wine\\Config\\Network", 0, KEY_READ,
624              &hKey) == ERROR_SUCCESS) {
625               DWORD size = sizeof(primaryWINS.String);
626               unsigned long addr;
627
628               RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
629                primaryWINS.String, &size);
630               addr = inet_addr(primaryWINS.String);
631               if (addr != INADDR_NONE && addr != INADDR_ANY)
632                 winsEnabled = TRUE;
633               size = sizeof(secondaryWINS.String);
634               RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
635                secondaryWINS.String, &size);
636               addr = inet_addr(secondaryWINS.String);
637               if (addr != INADDR_NONE && addr != INADDR_ANY)
638                 winsEnabled = TRUE;
639               RegCloseKey(hKey);
640             }
641             for (ndx = 0; ndx < table->numIndexes; ndx++) {
642               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
643               DWORD addrLen = sizeof(ptr->Address), type;
644
645               /* on Win98 this is left empty, but whatever */
646               lstrcpynA(ptr->AdapterName,
647                getInterfaceNameByIndex(table->indexes[ndx]),
648                MAX_ADAPTER_NAME_LENGTH+1);
649               getInterfacePhysicalByIndex(table->indexes[ndx], &addrLen,
650                ptr->Address, &type);
651               /* MS defines address length and type as UINT in some places and
652                  DWORD in others, **sigh**.  Don't want to assume that PUINT and
653                  PDWORD are equiv (64-bit?) */
654               ptr->AddressLength = addrLen;
655               ptr->Type = type;
656               ptr->Index = table->indexes[ndx];
657               toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
658                ptr->IpAddressList.IpAddress.String);
659               toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
660                ptr->IpAddressList.IpMask.String);
661               if (winsEnabled) {
662                 ptr->HaveWins = TRUE;
663                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
664                  primaryWINS.String, sizeof(primaryWINS.String));
665                 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
666                  secondaryWINS.String, sizeof(secondaryWINS.String));
667               }
668               if (ndx < table->numIndexes - 1)
669                 ptr->Next = &pAdapterInfo[ndx + 1];
670               else
671                 ptr->Next = NULL;
672             }
673             ret = NO_ERROR;
674           }
675           HeapFree(GetProcessHeap(), 0, table);
676         }
677         else
678           ret = ERROR_OUTOFMEMORY;
679       }
680     }
681     else
682       ret = ERROR_NO_DATA;
683   }
684   TRACE("returning %ld\n", ret);
685   return ret;
686 }
687
688
689 /******************************************************************
690  *    GetBestInterface (IPHLPAPI.@)
691  *
692  * PARAMS
693  *
694  *  dwDestAddr [In]
695  *  pdwBestIfIndex [In/Out]
696  *
697  * RETURNS
698  *
699  *  DWORD
700  *
701  */
702 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
703 {
704   DWORD ret;
705
706   TRACE("dwDestAddr 0x%08lx, pdwBestIfIndex %p\n", dwDestAddr, pdwBestIfIndex);
707   if (!pdwBestIfIndex)
708     ret = ERROR_INVALID_PARAMETER;
709   else {
710     MIB_IPFORWARDROW ipRow;
711
712     ret = GetBestRoute(dwDestAddr, 0, &ipRow);
713     if (ret == ERROR_SUCCESS)
714       *pdwBestIfIndex = ipRow.dwForwardIfIndex;
715   }
716   TRACE("returning %ld\n", ret);
717   return ret;
718 }
719
720
721 /******************************************************************
722  *    GetBestRoute (IPHLPAPI.@)
723  *
724  * PARAMS
725  *
726  *  dwDestAddr [In]
727  *  dwSourceAddr [In]
728  *  OUT [In]
729  *
730  * RETURNS
731  *
732  *  DWORD
733  *
734  */
735 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
736 {
737   PMIB_IPFORWARDTABLE table;
738   DWORD ret;
739
740   TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr,
741    dwSourceAddr, pBestRoute);
742   if (!pBestRoute)
743     return ERROR_INVALID_PARAMETER;
744
745   AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
746   if (table) {
747     DWORD ndx, matchedBits, matchedNdx = 0;
748
749     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
750       if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
751        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
752         DWORD numShifts, mask;
753
754         for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
755          mask && !(mask & 1); mask >>= 1, numShifts++)
756           ;
757         if (numShifts > matchedBits) {
758           matchedBits = numShifts;
759           matchedNdx = ndx;
760         }
761       }
762     }
763     memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
764     HeapFree(GetProcessHeap(), 0, table);
765     ret = ERROR_SUCCESS;
766   }
767   else
768     ret = ERROR_OUTOFMEMORY;
769   TRACE("returning %ld\n", ret);
770   return ret;
771 }
772
773
774 /******************************************************************
775  *    GetFriendlyIfIndex (IPHLPAPI.@)
776  *
777  * NOTES
778  * Returns a "friendly" version if IfIndex, which is one that doesn't
779  * have the top byte set.  Doesn't validate whether IfIndex is a valid
780  * adapter index.
781  *
782  * PARAMS
783  *
784  *  IfIndex [In]
785  *
786  * RETURNS
787  * A friendly version of IfIndex.
788  *
789  */
790 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
791 {
792   /* windows doesn't validate these, either, just makes sure the top byte is
793      cleared.  I assume my ifenum module never gives an index with the top
794      byte set. */
795   TRACE("returning %ld\n", IfIndex);
796   return IfIndex;
797 }
798
799
800 /******************************************************************
801  *    GetIcmpStatistics (IPHLPAPI.@)
802  *
803  * PARAMS
804  *
805  *  pStats [In/Out]
806  *
807  * RETURNS
808  *
809  *  DWORD
810  *
811  */
812 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
813 {
814   DWORD ret;
815
816   TRACE("pStats %p\n", pStats);
817   ret = getICMPStats(pStats);
818   TRACE("returning %ld\n", ret);
819   return ret;
820 }
821
822
823 /******************************************************************
824  *    GetIfEntry (IPHLPAPI.@)
825  *
826  * PARAMS
827  *
828  *  pIfRow [In/Out]
829  *
830  * RETURNS
831  *
832  *  DWORD
833  *
834  */
835 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
836 {
837   DWORD ret;
838   const char *name;
839
840   TRACE("pIfRow %p\n", pIfRow);
841   if (!pIfRow)
842     return ERROR_INVALID_PARAMETER;
843
844   name = getInterfaceNameByIndex(pIfRow->dwIndex);
845   if (name) {
846     ret = getInterfaceEntryByName(name, pIfRow);
847     if (ret == NO_ERROR)
848       ret = getInterfaceStatsByName(name, pIfRow);
849   }
850   else
851     ret = ERROR_INVALID_DATA;
852   TRACE("returning %ld\n", ret);
853   return ret;
854 }
855
856
857 static int IfTableSorter(const void *a, const void *b)
858 {
859   int ret;
860
861   if (a && b)
862     ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
863   else
864     ret = 0;
865   return ret;
866 }
867
868
869 /******************************************************************
870  *    GetIfTable (IPHLPAPI.@)
871  *
872  * NOTES
873  * Returns a table of local interfaces, *pdwSize is the size in bytes of
874  * pIfTable.  If this is less than required, the function will return
875  * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
876  * size.
877  * If bOrder is true, the returned table will be sorted by interface index.
878  *
879  * PARAMS
880  *
881  *  pIfTable [In/Out]
882  *  pdwSize [In/Out]
883  *  bOrder [In]
884  *
885  * RETURNS
886  * NO_ERROR on success, something else on failure.
887  *
888  */
889 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
890 {
891   DWORD ret;
892
893   TRACE("pIfTable %p, pdwSize %p, bOrder %ld\n", pdwSize, pdwSize,
894    (DWORD)bOrder);
895   if (!pdwSize)
896     ret = ERROR_INVALID_PARAMETER;
897   else {
898     DWORD numInterfaces = getNumInterfaces();
899     ULONG size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
900
901     if (!pIfTable || *pdwSize < size) {
902       *pdwSize = size;
903       ret = ERROR_INSUFFICIENT_BUFFER;
904     }
905     else {
906       InterfaceIndexTable *table = getInterfaceIndexTable();
907
908       if (table) {
909         size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
910          sizeof(MIB_IFROW);
911         if (*pdwSize < size) {
912           *pdwSize = size;
913           ret = ERROR_INSUFFICIENT_BUFFER;
914         }
915         else {
916           DWORD ndx;
917
918           pIfTable->dwNumEntries = 0;
919           for (ndx = 0; ndx < table->numIndexes; ndx++) {
920             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
921             GetIfEntry(&pIfTable->table[ndx]);
922             pIfTable->dwNumEntries++;
923           }
924           if (bOrder)
925             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
926              IfTableSorter);
927           ret = NO_ERROR;
928         }
929         HeapFree(GetProcessHeap(), 0, table);
930       }
931       else
932         ret = ERROR_OUTOFMEMORY;
933     }
934   }
935   TRACE("returning %ld\n", ret);
936   return ret;
937 }
938
939
940 /******************************************************************
941  *    GetInterfaceInfo (IPHLPAPI.@)
942  *
943  * PARAMS
944  *
945  *  pIfTable [In/Out]
946  *  dwOutBufLen [In/Out]
947  *
948  * RETURNS
949  *
950  *  DWORD
951  *
952  */
953 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
954 {
955   DWORD ret;
956
957   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
958   if (!dwOutBufLen)
959     ret = ERROR_INVALID_PARAMETER;
960   else {
961     DWORD numInterfaces = getNumInterfaces();
962     ULONG size = sizeof(IP_INTERFACE_INFO) + (numInterfaces - 1) *
963      sizeof(IP_ADAPTER_INDEX_MAP);
964
965     if (!pIfTable || *dwOutBufLen < size) {
966       *dwOutBufLen = size;
967       ret = ERROR_INSUFFICIENT_BUFFER;
968     }
969     else {
970       InterfaceIndexTable *table = getInterfaceIndexTable();
971
972       if (table) {
973         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes - 1) *
974          sizeof(IP_ADAPTER_INDEX_MAP);
975         if (*dwOutBufLen < size) {
976           *dwOutBufLen = size;
977           ret = ERROR_INSUFFICIENT_BUFFER;
978         }
979         else {
980           DWORD ndx;
981
982           pIfTable->NumAdapters = 0;
983           for (ndx = 0; ndx < table->numIndexes; ndx++) {
984             const char *walker, *name;
985             WCHAR *assigner;
986
987             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
988             name = getInterfaceNameByIndex(table->indexes[ndx]);
989             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
990              walker && *walker &&
991              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
992              walker++, assigner++)
993               *assigner = *walker;
994             *assigner = 0;
995             pIfTable->NumAdapters++;
996           }
997           ret = NO_ERROR;
998         }
999         HeapFree(GetProcessHeap(), 0, table);
1000       }
1001       else
1002         ret = ERROR_OUTOFMEMORY;
1003     }
1004   }
1005   TRACE("returning %ld\n", ret);
1006   return ret;
1007 }
1008
1009
1010 static int IpAddrTableSorter(const void *a, const void *b)
1011 {
1012   int ret;
1013
1014   if (a && b)
1015     ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
1016   else
1017     ret = 0;
1018   return ret;
1019 }
1020
1021
1022 /******************************************************************
1023  *    GetIpAddrTable (IPHLPAPI.@)
1024  *
1025  * NOTES
1026  * Returns the route table.  On input, *pdwSize is the size in bytes of
1027  * pIpForwardTable.  If this is less than required, the function will return
1028  * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1029  * size.
1030  * If bOrder is true, the returned table will be sorted by the next hop and
1031  * an assortment of arbitrary parameters.
1032  *
1033  * PARAMS
1034  *
1035  *  pIpAddrTable [In/Out]
1036  *  pdwSize [In/Out]
1037  *  bOrder [In]
1038  *
1039  * RETURNS
1040  * NO_ERROR on success, something else on failure.
1041  *
1042  */
1043 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1044 {
1045   DWORD ret;
1046
1047   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
1048    (DWORD)bOrder);
1049   if (!pdwSize)
1050     ret = ERROR_INVALID_PARAMETER;
1051   else {
1052     DWORD numInterfaces = getNumInterfaces();
1053     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
1054      sizeof(MIB_IPADDRROW);
1055
1056     if (!pIpAddrTable || *pdwSize < size) {
1057       *pdwSize = size;
1058       ret = ERROR_INSUFFICIENT_BUFFER;
1059     }
1060     else {
1061       InterfaceIndexTable *table = getInterfaceIndexTable();
1062
1063       if (table) {
1064         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
1065          sizeof(MIB_IPADDRROW);
1066         if (*pdwSize < size) {
1067           *pdwSize = size;
1068           ret = ERROR_INSUFFICIENT_BUFFER;
1069         }
1070         else {
1071           DWORD ndx, bcast;
1072
1073           pIpAddrTable->dwNumEntries = 0;
1074           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1075             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
1076             pIpAddrTable->table[ndx].dwAddr =
1077              getInterfaceIPAddrByIndex(table->indexes[ndx]);
1078             pIpAddrTable->table[ndx].dwMask =
1079              getInterfaceMaskByIndex(table->indexes[ndx]);
1080             /* the dwBCastAddr member isn't the broadcast address, it indicates
1081              * whether the interface uses the 1's broadcast address (1) or the
1082              * 0's broadcast address (0).
1083              */
1084             bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
1085             pIpAddrTable->table[ndx].dwBCastAddr =
1086              (bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
1087             /* FIXME: hardcoded reasm size, not sure where to get it */
1088             pIpAddrTable->table[ndx].dwReasmSize = 65535;
1089             pIpAddrTable->table[ndx].unused1 = 0;
1090             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
1091             pIpAddrTable->dwNumEntries++;
1092           }
1093           if (bOrder)
1094             qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1095              sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1096           ret = NO_ERROR;
1097         }
1098         HeapFree(GetProcessHeap(), 0, table);
1099       }
1100       else
1101         ret = ERROR_OUTOFMEMORY;
1102     }
1103   }
1104   TRACE("returning %ld\n", ret);
1105   return ret;
1106 }
1107
1108
1109 static int IpForwardTableSorter(const void *a, const void *b)
1110 {
1111   int ret;
1112
1113   if (a && b) {
1114     PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_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 = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_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, 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     PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
1508
1509     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1510     if (ret == 0) {
1511       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1512       if (ret == 0) {
1513         ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
1514         if (ret == 0)
1515           ret = rowA->dwRemotePort - rowB->dwRemotePort;
1516       }
1517     }
1518   }
1519   else
1520     ret = 0;
1521   return ret;
1522 }
1523
1524
1525 /******************************************************************
1526  *    GetTcpTable (IPHLPAPI.@)
1527  *
1528  * Returns a table of active TCP connections.  On input, *pdwSize
1529  * is the size in bytes of pTcpTable.  If this is less than required,
1530  * the function will return ERROR_INSUFFICIENT_BUFFER, and *pdwSize
1531  * will be set to the required byte size.
1532  * If bOrder is true, the returned table will be sorted, first by
1533  * local address and port number, then by remote address and port
1534  * number.
1535  *
1536  * PARAMS
1537  *
1538  *  pTcpTable [In/Out]
1539  *  pdwSize [In/Out]
1540  *  bOrder [In]
1541  *
1542  * RETURNS
1543  * NO_ERROR on success, something else on failure.
1544  *
1545  */
1546 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1547 {
1548   DWORD ret;
1549
1550   TRACE("pTcpTable %p, pdwSize %p, bOrder %ld\n", pTcpTable, pdwSize,
1551    (DWORD)bOrder);
1552   if (!pdwSize)
1553     ret = ERROR_INVALID_PARAMETER;
1554   else {
1555     DWORD numEntries = getNumTcpEntries();
1556     ULONG size = sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW);
1557
1558     if (!pTcpTable || *pdwSize < size) {
1559       *pdwSize = size;
1560       ret = ERROR_INSUFFICIENT_BUFFER;
1561     }
1562     else {
1563       PMIB_TCPTABLE table = getTcpTable();
1564
1565       if (table) {
1566         size = sizeof(MIB_TCPTABLE) + (table->dwNumEntries - 1) *
1567          sizeof(MIB_TCPROW);
1568         if (*pdwSize < size) {
1569           *pdwSize = size;
1570           ret = ERROR_INSUFFICIENT_BUFFER;
1571         }
1572         else {
1573           memcpy(pTcpTable, table, size);
1574           if (bOrder)
1575             qsort(pTcpTable->table, pTcpTable->dwNumEntries,
1576              sizeof(MIB_TCPROW), TcpTableSorter);
1577           ret = NO_ERROR;
1578         }
1579         HeapFree(GetProcessHeap(), 0, table);
1580       }
1581       else
1582         ret = ERROR_OUTOFMEMORY;
1583     }
1584   }
1585   TRACE("returning %ld\n", ret);
1586   return ret;
1587 }
1588
1589
1590 /******************************************************************
1591  *    GetUdpStatistics (IPHLPAPI.@)
1592  *
1593  * PARAMS
1594  *
1595  *  pStats [In/Out]
1596  *
1597  * RETURNS
1598  *
1599  *  DWORD
1600  *
1601  */
1602 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
1603 {
1604   DWORD ret;
1605
1606   TRACE("pStats %p\n", pStats);
1607   ret = getUDPStats(pStats);
1608   TRACE("returning %ld\n", ret);
1609   return ret;
1610 }
1611
1612
1613 static int UdpTableSorter(const void *a, const void *b)
1614 {
1615   int ret;
1616
1617   if (a && b) {
1618     PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
1619
1620     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1621     if (ret == 0)
1622       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1623   }
1624   else
1625     ret = 0;
1626   return ret;
1627 }
1628
1629
1630 /******************************************************************
1631  *    GetUdpTable (IPHLPAPI.@)
1632  *
1633  * Returns a table of active UDP connections.  On input, *pdwSize
1634  * is the size in bytes of pUdpTable.  If this is less than required,
1635  * the function will return ERROR_INSUFFICIENT_BUFFER, and *pdwSize
1636  * will be set to the required byte size.
1637  * If bOrder is true, the returned table will be sorted, first by
1638  * local address, then by local port number.
1639  *
1640  * PARAMS
1641  *
1642  *  pUdpTable [In/Out]
1643  *  pdwSize [In/Out]
1644  *  bOrder [In]
1645  *
1646  * RETURNS
1647  * NO_ERROR on success, something else on failure.
1648  *
1649  */
1650 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1651 {
1652   DWORD ret;
1653
1654   TRACE("pUdpTable %p, pdwSize %p, bOrder %ld\n", pUdpTable, pdwSize,
1655    (DWORD)bOrder);
1656   if (!pdwSize)
1657     ret = ERROR_INVALID_PARAMETER;
1658   else {
1659     DWORD numEntries = getNumUdpEntries();
1660     ULONG size = sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW);
1661
1662     if (!pUdpTable || *pdwSize < size) {
1663       *pdwSize = size;
1664       ret = ERROR_INSUFFICIENT_BUFFER;
1665     }
1666     else {
1667       PMIB_UDPTABLE table = getUdpTable();
1668
1669       if (table) {
1670         size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) *
1671          sizeof(MIB_UDPROW);
1672         if (*pdwSize < size) {
1673           *pdwSize = size;
1674           ret = ERROR_INSUFFICIENT_BUFFER;
1675         }
1676         else {
1677           memcpy(pUdpTable, table, size);
1678           if (bOrder)
1679             qsort(pUdpTable->table, pUdpTable->dwNumEntries,
1680              sizeof(MIB_UDPROW), UdpTableSorter);
1681           ret = NO_ERROR;
1682         }
1683         HeapFree(GetProcessHeap(), 0, table);
1684       }
1685       else
1686         ret = ERROR_OUTOFMEMORY;
1687     }
1688   }
1689   TRACE("returning %ld\n", ret);
1690   return ret;
1691 }
1692
1693
1694 /******************************************************************
1695  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1696  *
1697  * This is a Win98-only function to get information on "unidirectional"
1698  * adapters.  Since this is pretty nonsensical in other contexts, it
1699  * never returns anything.
1700  *
1701  * PARAMS
1702  *
1703  *  pIPIfInfo [In/Out]
1704  *  dwOutBufLen [In/Out]
1705  *
1706  * RETURNS
1707  * ERROR_NOT_SUPPORTED
1708  *
1709  */
1710 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1711 {
1712   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
1713   /* a unidirectional adapter?? not bloody likely! */
1714   return ERROR_NOT_SUPPORTED;
1715 }
1716
1717
1718 /******************************************************************
1719  *    IpReleaseAddress (IPHLPAPI.@)
1720  *
1721  * NOTES
1722  * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1723  * this function does nothing.
1724  *
1725  * PARAMS
1726  *
1727  *  AdapterInfo [In/Out]
1728  *
1729  * RETURNS
1730  * ERROR_NOT_SUPPORTED
1731  *
1732  */
1733 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1734 {
1735   TRACE("AdapterInfo %p\n", AdapterInfo);
1736   /* not a stub, never going to support this (and I never mark an adapter as
1737      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1738   return ERROR_NOT_SUPPORTED;
1739 }
1740
1741
1742 /******************************************************************
1743  *    IpRenewAddress (IPHLPAPI.@)
1744  *
1745  * NOTES
1746  * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1747  * this function does nothing.
1748  *
1749  * PARAMS
1750  *
1751  *  AdapterInfo [In/Out]
1752  *
1753  * RETURNS
1754  * ERROR_NOT_SUPPORTED
1755  *
1756  */
1757 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1758 {
1759   TRACE("AdapterInfo %p\n", AdapterInfo);
1760   /* not a stub, never going to support this (and I never mark an adapter as
1761      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1762   return ERROR_NOT_SUPPORTED;
1763 }
1764
1765
1766 /******************************************************************
1767  *    NotifyAddrChange (IPHLPAPI.@)
1768  *
1769  * NOTES
1770  * Stub
1771  *
1772  * PARAMS
1773  *
1774  *  Handle [In/Out]
1775  *  overlapped [In/Out]
1776  *
1777  * RETURNS
1778  * ERROR_NOT_SUPPORTED
1779  *
1780  */
1781 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1782 {
1783   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
1784   /* marking Win2K+ functions not supported */
1785   return ERROR_NOT_SUPPORTED;
1786 }
1787
1788
1789 /******************************************************************
1790  *    NotifyRouteChange (IPHLPAPI.@)
1791  *
1792  * NOTES
1793  * Stub
1794  *
1795  * PARAMS
1796  *
1797  *  Handle [In/Out]
1798  *  overlapped [In/Out]
1799  *
1800  * RETURNS
1801  * ERROR_NOT_SUPPORTED
1802  *
1803  */
1804 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1805 {
1806   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
1807   /* marking Win2K+ functions not supported */
1808   return ERROR_NOT_SUPPORTED;
1809 }
1810
1811
1812 /******************************************************************
1813  *    SendARP (IPHLPAPI.@)
1814  *
1815  * NOTES
1816  * Stub
1817  *
1818  * PARAMS
1819  *
1820  *  DestIP [In]
1821  *  SrcIP [In]
1822  *  pMacAddr [In/Out]
1823  *  PhyAddrLen [In/Out]
1824  *
1825  * RETURNS
1826  * ERROR_NOT_SUPPORTED
1827  *
1828  */
1829 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
1830 {
1831   FIXME("(DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p): stub\n",
1832    DestIP, SrcIP, pMacAddr, PhyAddrLen);
1833   /* marking Win2K+ functions not supported */
1834   return ERROR_NOT_SUPPORTED;
1835 }
1836
1837
1838 /******************************************************************
1839  *    SetIfEntry (IPHLPAPI.@)
1840  *
1841  * NOTES
1842  * Stub
1843  *
1844  * PARAMS
1845  *
1846  *  pIfRow [In/Out]
1847  *
1848  * RETURNS
1849  * ERROR_NOT_SUPPORTED
1850  *
1851  */
1852 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
1853 {
1854   FIXME("(pIfRow %p): stub\n", pIfRow);
1855   /* this is supposed to set an administratively interface up or down.
1856      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
1857      this sort of down is indistinguishable from other sorts of down (e.g. no
1858      link). */
1859   return ERROR_NOT_SUPPORTED;
1860 }
1861
1862
1863 /******************************************************************
1864  *    SetIpForwardEntry (IPHLPAPI.@)
1865  *
1866  * NOTES
1867  * Stub
1868  *
1869  * PARAMS
1870  *
1871  *  pRoute [In/Out]
1872  *
1873  * RETURNS
1874  * 0
1875  *
1876  */
1877 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
1878 {
1879   FIXME("(pRoute %p): stub\n", pRoute);
1880   /* this is to add a route entry, how's it distinguishable from
1881      CreateIpForwardEntry?
1882      could use SIOCADDRT, not sure I want to */
1883   return (DWORD) 0;
1884 }
1885
1886
1887 /******************************************************************
1888  *    SetIpNetEntry (IPHLPAPI.@)
1889  *
1890  * NOTES
1891  * Stub
1892  *
1893  * PARAMS
1894  *
1895  *  pArpEntry [In/Out]
1896  *
1897  * RETURNS
1898  * 0
1899  *
1900  */
1901 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
1902 {
1903   FIXME("(pArpEntry %p): stub\n", pArpEntry);
1904   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
1905   return (DWORD) 0;
1906 }
1907
1908
1909 /******************************************************************
1910  *    SetIpStatistics (IPHLPAPI.@)
1911  *
1912  * NOTES
1913  * Stub
1914  *
1915  * PARAMS
1916  *
1917  *  pIpStats [In/Out]
1918  *
1919  * RETURNS
1920  * 0
1921  *
1922  */
1923 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
1924 {
1925   FIXME("(pIpStats %p): stub\n", pIpStats);
1926   return (DWORD) 0;
1927 }
1928
1929
1930 /******************************************************************
1931  *    SetIpTTL (IPHLPAPI.@)
1932  *
1933  * NOTES
1934  * Stub
1935  *
1936  * PARAMS
1937  *
1938  *  nTTL [In]
1939  *
1940  * RETURNS
1941  * 0
1942  *
1943  */
1944 DWORD WINAPI SetIpTTL(UINT nTTL)
1945 {
1946   FIXME("(nTTL %d): stub\n", nTTL);
1947   /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
1948      want to.  Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
1949   return (DWORD) 0;
1950 }
1951
1952
1953 /******************************************************************
1954  *    SetTcpEntry (IPHLPAPI.@)
1955  *
1956  * NOTES
1957  * Stub
1958  *
1959  * PARAMS
1960  *
1961  *  pTcpRow [In/Out]
1962  *
1963  * RETURNS
1964  * 0
1965  *
1966  */
1967 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
1968 {
1969   FIXME("(pTcpRow %p): stub\n", pTcpRow);
1970   return (DWORD) 0;
1971 }
1972
1973
1974 /******************************************************************
1975  *    UnenableRouter (IPHLPAPI.@)
1976  *
1977  * NOTES
1978  * Stub
1979  *
1980  * PARAMS
1981  *
1982  *  pOverlapped [In/Out]
1983  *  lpdwEnableCount [In/Out]
1984  *
1985  * RETURNS
1986  * ERROR_NOT_SUPPORTED
1987  *
1988  */
1989 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
1990 {
1991   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
1992    lpdwEnableCount);
1993   /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
1994      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
1995      marking Win2K+ functions not supported */
1996   return ERROR_NOT_SUPPORTED;
1997 }