Added magic comments to all Wine-specific registry accesses to make
[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: HKLM\Software\Wine\Wine\Config\Network */
623             if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
624              "Software\\Wine\\Wine\\Config\\Network", 0, KEY_READ,
625              &hKey) == ERROR_SUCCESS) {
626               DWORD size = sizeof(primaryWINS.String);
627               unsigned long addr;
628
629               RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
630                primaryWINS.String, &size);
631               addr = inet_addr(primaryWINS.String);
632               if (addr != INADDR_NONE && addr != INADDR_ANY)
633                 winsEnabled = TRUE;
634               size = sizeof(secondaryWINS.String);
635               RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
636                secondaryWINS.String, &size);
637               addr = inet_addr(secondaryWINS.String);
638               if (addr != INADDR_NONE && addr != INADDR_ANY)
639                 winsEnabled = TRUE;
640               RegCloseKey(hKey);
641             }
642             for (ndx = 0; ndx < table->numIndexes; ndx++) {
643               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
644               DWORD addrLen = sizeof(ptr->Address), type;
645
646               /* on Win98 this is left empty, but whatever */
647               lstrcpynA(ptr->AdapterName,
648                getInterfaceNameByIndex(table->indexes[ndx]),
649                MAX_ADAPTER_NAME_LENGTH+1);
650               getInterfacePhysicalByIndex(table->indexes[ndx], &addrLen,
651                ptr->Address, &type);
652               /* MS defines address length and type as UINT in some places and
653                  DWORD in others, **sigh**.  Don't want to assume that PUINT and
654                  PDWORD are equiv (64-bit?) */
655               ptr->AddressLength = addrLen;
656               ptr->Type = type;
657               ptr->Index = table->indexes[ndx];
658               toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
659                ptr->IpAddressList.IpAddress.String);
660               toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
661                ptr->IpAddressList.IpMask.String);
662               if (winsEnabled) {
663                 ptr->HaveWins = TRUE;
664                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
665                  primaryWINS.String, sizeof(primaryWINS.String));
666                 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
667                  secondaryWINS.String, sizeof(secondaryWINS.String));
668               }
669               if (ndx < table->numIndexes - 1)
670                 ptr->Next = &pAdapterInfo[ndx + 1];
671               else
672                 ptr->Next = NULL;
673             }
674             ret = NO_ERROR;
675           }
676           HeapFree(GetProcessHeap(), 0, table);
677         }
678         else
679           ret = ERROR_OUTOFMEMORY;
680       }
681     }
682     else
683       ret = ERROR_NO_DATA;
684   }
685   TRACE("returning %ld\n", ret);
686   return ret;
687 }
688
689
690 /******************************************************************
691  *    GetBestInterface (IPHLPAPI.@)
692  *
693  * PARAMS
694  *
695  *  dwDestAddr [In]
696  *  pdwBestIfIndex [In/Out]
697  *
698  * RETURNS
699  *
700  *  DWORD
701  *
702  */
703 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
704 {
705   DWORD ret;
706
707   TRACE("dwDestAddr 0x%08lx, pdwBestIfIndex %p\n", dwDestAddr, pdwBestIfIndex);
708   if (!pdwBestIfIndex)
709     ret = ERROR_INVALID_PARAMETER;
710   else {
711     MIB_IPFORWARDROW ipRow;
712
713     ret = GetBestRoute(dwDestAddr, 0, &ipRow);
714     if (ret == ERROR_SUCCESS)
715       *pdwBestIfIndex = ipRow.dwForwardIfIndex;
716   }
717   TRACE("returning %ld\n", ret);
718   return ret;
719 }
720
721
722 /******************************************************************
723  *    GetBestRoute (IPHLPAPI.@)
724  *
725  * PARAMS
726  *
727  *  dwDestAddr [In]
728  *  dwSourceAddr [In]
729  *  OUT [In]
730  *
731  * RETURNS
732  *
733  *  DWORD
734  *
735  */
736 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
737 {
738   PMIB_IPFORWARDTABLE table;
739   DWORD ret;
740
741   TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr,
742    dwSourceAddr, pBestRoute);
743   if (!pBestRoute)
744     return ERROR_INVALID_PARAMETER;
745
746   AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
747   if (table) {
748     DWORD ndx, matchedBits, matchedNdx = 0;
749
750     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
751       if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
752        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
753         DWORD numShifts, mask;
754
755         for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
756          mask && !(mask & 1); mask >>= 1, numShifts++)
757           ;
758         if (numShifts > matchedBits) {
759           matchedBits = numShifts;
760           matchedNdx = ndx;
761         }
762       }
763     }
764     memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
765     HeapFree(GetProcessHeap(), 0, table);
766     ret = ERROR_SUCCESS;
767   }
768   else
769     ret = ERROR_OUTOFMEMORY;
770   TRACE("returning %ld\n", ret);
771   return ret;
772 }
773
774
775 /******************************************************************
776  *    GetFriendlyIfIndex (IPHLPAPI.@)
777  *
778  * NOTES
779  * Returns a "friendly" version if IfIndex, which is one that doesn't
780  * have the top byte set.  Doesn't validate whether IfIndex is a valid
781  * adapter index.
782  *
783  * PARAMS
784  *
785  *  IfIndex [In]
786  *
787  * RETURNS
788  * A friendly version of IfIndex.
789  *
790  */
791 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
792 {
793   /* windows doesn't validate these, either, just makes sure the top byte is
794      cleared.  I assume my ifenum module never gives an index with the top
795      byte set. */
796   TRACE("returning %ld\n", IfIndex);
797   return IfIndex;
798 }
799
800
801 /******************************************************************
802  *    GetIcmpStatistics (IPHLPAPI.@)
803  *
804  * PARAMS
805  *
806  *  pStats [In/Out]
807  *
808  * RETURNS
809  *
810  *  DWORD
811  *
812  */
813 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
814 {
815   DWORD ret;
816
817   TRACE("pStats %p\n", pStats);
818   ret = getICMPStats(pStats);
819   TRACE("returning %ld\n", ret);
820   return ret;
821 }
822
823
824 /******************************************************************
825  *    GetIfEntry (IPHLPAPI.@)
826  *
827  * PARAMS
828  *
829  *  pIfRow [In/Out]
830  *
831  * RETURNS
832  *
833  *  DWORD
834  *
835  */
836 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
837 {
838   DWORD ret;
839   const char *name;
840
841   TRACE("pIfRow %p\n", pIfRow);
842   if (!pIfRow)
843     return ERROR_INVALID_PARAMETER;
844
845   name = getInterfaceNameByIndex(pIfRow->dwIndex);
846   if (name) {
847     ret = getInterfaceEntryByName(name, pIfRow);
848     if (ret == NO_ERROR)
849       ret = getInterfaceStatsByName(name, pIfRow);
850   }
851   else
852     ret = ERROR_INVALID_DATA;
853   TRACE("returning %ld\n", ret);
854   return ret;
855 }
856
857
858 static int IfTableSorter(const void *a, const void *b)
859 {
860   int ret;
861
862   if (a && b)
863     ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
864   else
865     ret = 0;
866   return ret;
867 }
868
869
870 /******************************************************************
871  *    GetIfTable (IPHLPAPI.@)
872  *
873  * NOTES
874  * Returns a table of local interfaces, *pdwSize is the size in bytes of
875  * pIfTable.  If this is less than required, the function will return
876  * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
877  * size.
878  * If bOrder is true, the returned table will be sorted by interface index.
879  *
880  * PARAMS
881  *
882  *  pIfTable [In/Out]
883  *  pdwSize [In/Out]
884  *  bOrder [In]
885  *
886  * RETURNS
887  * NO_ERROR on success, something else on failure.
888  *
889  */
890 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
891 {
892   DWORD ret;
893
894   TRACE("pIfTable %p, pdwSize %p, bOrder %ld\n", pdwSize, pdwSize,
895    (DWORD)bOrder);
896   if (!pdwSize)
897     ret = ERROR_INVALID_PARAMETER;
898   else {
899     DWORD numInterfaces = getNumInterfaces();
900     ULONG size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
901
902     if (!pIfTable || *pdwSize < size) {
903       *pdwSize = size;
904       ret = ERROR_INSUFFICIENT_BUFFER;
905     }
906     else {
907       InterfaceIndexTable *table = getInterfaceIndexTable();
908
909       if (table) {
910         size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
911          sizeof(MIB_IFROW);
912         if (*pdwSize < size) {
913           *pdwSize = size;
914           ret = ERROR_INSUFFICIENT_BUFFER;
915         }
916         else {
917           DWORD ndx;
918
919           pIfTable->dwNumEntries = 0;
920           for (ndx = 0; ndx < table->numIndexes; ndx++) {
921             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
922             GetIfEntry(&pIfTable->table[ndx]);
923             pIfTable->dwNumEntries++;
924           }
925           if (bOrder)
926             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
927              IfTableSorter);
928           ret = NO_ERROR;
929         }
930         HeapFree(GetProcessHeap(), 0, table);
931       }
932       else
933         ret = ERROR_OUTOFMEMORY;
934     }
935   }
936   TRACE("returning %ld\n", ret);
937   return ret;
938 }
939
940
941 /******************************************************************
942  *    GetInterfaceInfo (IPHLPAPI.@)
943  *
944  * PARAMS
945  *
946  *  pIfTable [In/Out]
947  *  dwOutBufLen [In/Out]
948  *
949  * RETURNS
950  *
951  *  DWORD
952  *
953  */
954 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
955 {
956   DWORD ret;
957
958   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
959   if (!dwOutBufLen)
960     ret = ERROR_INVALID_PARAMETER;
961   else {
962     DWORD numInterfaces = getNumInterfaces();
963     ULONG size = sizeof(IP_INTERFACE_INFO) + (numInterfaces - 1) *
964      sizeof(IP_ADAPTER_INDEX_MAP);
965
966     if (!pIfTable || *dwOutBufLen < size) {
967       *dwOutBufLen = size;
968       ret = ERROR_INSUFFICIENT_BUFFER;
969     }
970     else {
971       InterfaceIndexTable *table = getInterfaceIndexTable();
972
973       if (table) {
974         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes - 1) *
975          sizeof(IP_ADAPTER_INDEX_MAP);
976         if (*dwOutBufLen < size) {
977           *dwOutBufLen = size;
978           ret = ERROR_INSUFFICIENT_BUFFER;
979         }
980         else {
981           DWORD ndx;
982
983           pIfTable->NumAdapters = 0;
984           for (ndx = 0; ndx < table->numIndexes; ndx++) {
985             const char *walker, *name;
986             WCHAR *assigner;
987
988             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
989             name = getInterfaceNameByIndex(table->indexes[ndx]);
990             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
991              walker && *walker &&
992              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
993              walker++, assigner++)
994               *assigner = *walker;
995             *assigner = 0;
996             pIfTable->NumAdapters++;
997           }
998           ret = NO_ERROR;
999         }
1000         HeapFree(GetProcessHeap(), 0, table);
1001       }
1002       else
1003         ret = ERROR_OUTOFMEMORY;
1004     }
1005   }
1006   TRACE("returning %ld\n", ret);
1007   return ret;
1008 }
1009
1010
1011 static int IpAddrTableSorter(const void *a, const void *b)
1012 {
1013   int ret;
1014
1015   if (a && b)
1016     ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
1017   else
1018     ret = 0;
1019   return ret;
1020 }
1021
1022
1023 /******************************************************************
1024  *    GetIpAddrTable (IPHLPAPI.@)
1025  *
1026  * NOTES
1027  * Returns the route table.  On input, *pdwSize is the size in bytes of
1028  * pIpForwardTable.  If this is less than required, the function will return
1029  * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1030  * size.
1031  * If bOrder is true, the returned table will be sorted by the next hop and
1032  * an assortment of arbitrary parameters.
1033  *
1034  * PARAMS
1035  *
1036  *  pIpAddrTable [In/Out]
1037  *  pdwSize [In/Out]
1038  *  bOrder [In]
1039  *
1040  * RETURNS
1041  * NO_ERROR on success, something else on failure.
1042  *
1043  */
1044 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1045 {
1046   DWORD ret;
1047
1048   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
1049    (DWORD)bOrder);
1050   if (!pdwSize)
1051     ret = ERROR_INVALID_PARAMETER;
1052   else {
1053     DWORD numInterfaces = getNumInterfaces();
1054     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
1055      sizeof(MIB_IPADDRROW);
1056
1057     if (!pIpAddrTable || *pdwSize < size) {
1058       *pdwSize = size;
1059       ret = ERROR_INSUFFICIENT_BUFFER;
1060     }
1061     else {
1062       InterfaceIndexTable *table = getInterfaceIndexTable();
1063
1064       if (table) {
1065         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
1066          sizeof(MIB_IPADDRROW);
1067         if (*pdwSize < size) {
1068           *pdwSize = size;
1069           ret = ERROR_INSUFFICIENT_BUFFER;
1070         }
1071         else {
1072           DWORD ndx, bcast;
1073
1074           pIpAddrTable->dwNumEntries = 0;
1075           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1076             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
1077             pIpAddrTable->table[ndx].dwAddr =
1078              getInterfaceIPAddrByIndex(table->indexes[ndx]);
1079             pIpAddrTable->table[ndx].dwMask =
1080              getInterfaceMaskByIndex(table->indexes[ndx]);
1081             /* the dwBCastAddr member isn't the broadcast address, it indicates
1082              * whether the interface uses the 1's broadcast address (1) or the
1083              * 0's broadcast address (0).
1084              */
1085             bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
1086             pIpAddrTable->table[ndx].dwBCastAddr =
1087              (bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
1088             /* FIXME: hardcoded reasm size, not sure where to get it */
1089             pIpAddrTable->table[ndx].dwReasmSize = 65535;
1090             pIpAddrTable->table[ndx].unused1 = 0;
1091             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
1092             pIpAddrTable->dwNumEntries++;
1093           }
1094           if (bOrder)
1095             qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1096              sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1097           ret = NO_ERROR;
1098         }
1099         HeapFree(GetProcessHeap(), 0, table);
1100       }
1101       else
1102         ret = ERROR_OUTOFMEMORY;
1103     }
1104   }
1105   TRACE("returning %ld\n", ret);
1106   return ret;
1107 }
1108
1109
1110 static int IpForwardTableSorter(const void *a, const void *b)
1111 {
1112   int ret;
1113
1114   if (a && b) {
1115     PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
1116
1117     ret = rowA->dwForwardDest - rowB->dwForwardDest;
1118     if (ret == 0) {
1119       ret = rowA->dwForwardProto - rowB->dwForwardProto;
1120       if (ret == 0) {
1121         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
1122         if (ret == 0)
1123           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1124       }
1125     }
1126   }
1127   else
1128     ret = 0;
1129   return ret;
1130 }
1131
1132
1133 /******************************************************************
1134  *    GetIpForwardTable (IPHLPAPI.@)
1135  *
1136  * NOTES
1137  * Returns the route table.  On input, *pdwSize is the size in bytes of
1138  * pIpForwardTable.  If this is less than required, the function will return
1139  * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1140  * size.
1141  * If bOrder is true, the returned table will be sorted by the next hop and
1142  * an assortment of arbitrary parameters.
1143  *
1144  * PARAMS
1145  *
1146  *  pIpForwardTable [In/Out]
1147  *  pdwSize [In/Out]
1148  *  bOrder [In]
1149  *
1150  * RETURNS
1151  * NO_ERROR on success, something else on failure.
1152  *
1153  */
1154 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1155 {
1156   DWORD ret;
1157
1158   TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
1159    pdwSize, (DWORD)bOrder);
1160   if (!pdwSize)
1161     ret = ERROR_INVALID_PARAMETER;
1162   else {
1163     DWORD numRoutes = getNumRoutes();
1164     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1165      sizeof(MIB_IPFORWARDROW);
1166
1167     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1168       *pdwSize = sizeNeeded;
1169       ret = ERROR_INSUFFICIENT_BUFFER;
1170     }
1171     else {
1172       RouteTable *table = getRouteTable();
1173       if (table) {
1174         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1175          sizeof(MIB_IPFORWARDROW);
1176         if (*pdwSize < sizeNeeded) {
1177           *pdwSize = sizeNeeded;
1178           ret = ERROR_INSUFFICIENT_BUFFER;
1179         }
1180         else {
1181           DWORD ndx;
1182
1183           pIpForwardTable->dwNumEntries = table->numRoutes;
1184           for (ndx = 0; ndx < numRoutes; ndx++) {
1185             pIpForwardTable->table[ndx].dwForwardIfIndex =
1186              table->routes[ndx].ifIndex;
1187             pIpForwardTable->table[ndx].dwForwardDest =
1188              table->routes[ndx].dest;
1189             pIpForwardTable->table[ndx].dwForwardMask =
1190              table->routes[ndx].mask;
1191             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1192             pIpForwardTable->table[ndx].dwForwardNextHop =
1193              table->routes[ndx].gateway;
1194             /* FIXME: this type is appropriate for local interfaces; may not
1195                always be appropriate */
1196             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1197             /* FIXME: other protos might be appropriate, e.g. the default route
1198                is typically set with MIB_IPPROTO_NETMGMT instead */
1199             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1200             /* punt on age and AS */
1201             pIpForwardTable->table[ndx].dwForwardAge = 0;
1202             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1203             pIpForwardTable->table[ndx].dwForwardMetric1 =
1204              table->routes[ndx].metric;
1205             /* rest of the metrics are 0.. */
1206             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1207             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1208             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1209             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1210           }
1211           if (bOrder)
1212             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1213              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1214           ret = NO_ERROR;
1215         }
1216         HeapFree(GetProcessHeap(), 0, table);
1217       }
1218       else
1219         ret = ERROR_OUTOFMEMORY;
1220     }
1221   }
1222   TRACE("returning %ld\n", ret);
1223   return ret;
1224 }
1225
1226
1227 static int IpNetTableSorter(const void *a, const void *b)
1228 {
1229   int ret;
1230
1231   if (a && b)
1232     ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
1233   else
1234     ret = 0;
1235   return ret;
1236 }
1237
1238
1239 /******************************************************************
1240  *    GetIpNetTable (IPHLPAPI.@)
1241  *
1242  * Returns the ARP cache.  On input, *pdwSize is the size in bytes of
1243  * pIpNetTable.  If this is less than required, the function will return
1244  * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1245  * size.
1246  * If bOrder is true, the returned table will be sorted by IP address.
1247  *
1248  * PARAMS
1249  *
1250  *  pIpNetTable [In/Out]
1251  *  pdwSize [In/Out]
1252  *  bOrder [In]
1253  *
1254  * RETURNS
1255  * NO_ERROR on success, something else on failure.
1256  *
1257  */
1258 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1259 {
1260   DWORD ret;
1261
1262   TRACE("pIpNetTable %p, pdwSize %p, bOrder %ld\n", pIpNetTable, pdwSize,
1263    (DWORD)bOrder);
1264   if (!pdwSize)
1265     ret = ERROR_INVALID_PARAMETER;
1266   else {
1267     DWORD numEntries = getNumArpEntries();
1268     ULONG size = sizeof(MIB_IPNETTABLE) + (numEntries - 1) *
1269      sizeof(MIB_IPNETROW);
1270
1271     if (!pIpNetTable || *pdwSize < size) {
1272       *pdwSize = size;
1273       ret = ERROR_INSUFFICIENT_BUFFER;
1274     }
1275     else {
1276       PMIB_IPNETTABLE table = getArpTable();
1277
1278       if (table) {
1279         size = sizeof(MIB_IPNETTABLE) + (table->dwNumEntries - 1) *
1280          sizeof(MIB_IPNETROW);
1281         if (*pdwSize < size) {
1282           *pdwSize = size;
1283           ret = ERROR_INSUFFICIENT_BUFFER;
1284         }
1285         else {
1286           memcpy(pIpNetTable, table, size);
1287           if (bOrder)
1288             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
1289              sizeof(MIB_IPNETROW), IpNetTableSorter);
1290           ret = NO_ERROR;
1291         }
1292         HeapFree(GetProcessHeap(), 0, table);
1293       }
1294       else
1295         ret = ERROR_OUTOFMEMORY;
1296     }
1297   }
1298   TRACE("returning %ld\n", ret);
1299   return ret;
1300 }
1301
1302
1303 /******************************************************************
1304  *    GetIpStatistics (IPHLPAPI.@)
1305  *
1306  * PARAMS
1307  *
1308  *  pStats [In/Out]
1309  *
1310  * RETURNS
1311  *
1312  *  DWORD
1313  *
1314  */
1315 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
1316 {
1317   DWORD ret;
1318
1319   TRACE("pStats %p\n", pStats);
1320   ret = getIPStats(pStats);
1321   TRACE("returning %ld\n", ret);
1322   return ret;
1323 }
1324
1325
1326 /******************************************************************
1327  *    GetNetworkParams (IPHLPAPI.@)
1328  *
1329  * PARAMS
1330  *
1331  *  pFixedInfo [In/Out]
1332  *  pOutBufLen [In/Out]
1333  *
1334  * RETURNS
1335  *
1336  *  DWORD
1337  *
1338  */
1339 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1340 {
1341   DWORD ret, size;
1342   LONG regReturn;
1343   HKEY hKey;
1344
1345   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
1346   if (!pOutBufLen)
1347     return ERROR_INVALID_PARAMETER;
1348
1349   res_init();
1350   size = sizeof(FIXED_INFO) + (_res.nscount > 0 ? (_res.nscount  - 1) *
1351    sizeof(IP_ADDR_STRING) : 0);
1352   if (!pFixedInfo || *pOutBufLen < size) {
1353     *pOutBufLen = size;
1354     return ERROR_BUFFER_OVERFLOW;
1355   }
1356
1357   memset(pFixedInfo, 0, size);
1358   size = sizeof(pFixedInfo->HostName);
1359   GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
1360   size = sizeof(pFixedInfo->DomainName);
1361   GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
1362   if (_res.nscount > 0) {
1363     PIP_ADDR_STRING ptr;
1364     int i;
1365
1366     for (i = 0, ptr = &pFixedInfo->DnsServerList; i < _res.nscount && ptr;
1367      i++, ptr = ptr->Next) {
1368       toIPAddressString(_res.nsaddr_list[i].sin_addr.s_addr,
1369        ptr->IpAddress.String);
1370       if (i == _res.nscount - 1)
1371         ptr->Next = NULL;
1372       else if (i == 0)
1373         ptr->Next = (PIP_ADDR_STRING)((LPBYTE)pFixedInfo + sizeof(FIXED_INFO));
1374       else
1375         ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
1376     }
1377   }
1378   pFixedInfo->NodeType = HYBRID_NODETYPE;
1379   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1380    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
1381   if (regReturn != ERROR_SUCCESS)
1382     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1383      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
1384      &hKey);
1385   if (regReturn == ERROR_SUCCESS)
1386   {
1387     DWORD size = sizeof(pFixedInfo->ScopeId);
1388
1389     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, pFixedInfo->ScopeId, &size);
1390     RegCloseKey(hKey);
1391   }
1392
1393   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1394      I suppose could also check for a listener on port 53 to set EnableDns */
1395   ret = NO_ERROR;
1396   TRACE("returning %ld\n", ret);
1397   return ret;
1398 }
1399
1400
1401 /******************************************************************
1402  *    GetNumberOfInterfaces (IPHLPAPI.@)
1403  *
1404  * NOTES
1405  * Returns the number of interfaces in *pdwNumIf.
1406  *
1407  * PARAMS
1408  *
1409  *  pdwNumIf [In/Out]
1410  *
1411  * RETURNS
1412  * NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
1413  *
1414  */
1415 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1416 {
1417   DWORD ret;
1418
1419   TRACE("pdwNumIf %p\n", pdwNumIf);
1420   if (!pdwNumIf)
1421     ret = ERROR_INVALID_PARAMETER;
1422   else {
1423     *pdwNumIf = getNumInterfaces();
1424     ret = NO_ERROR;
1425   }
1426   TRACE("returning %ld\n", ret);
1427   return ret;
1428 }
1429
1430
1431 /******************************************************************
1432  *    GetPerAdapterInfo (IPHLPAPI.@)
1433  *
1434  * NOTES
1435  * Stub
1436  *
1437  * PARAMS
1438  *
1439  *  IfIndex [In]
1440  *  pPerAdapterInfo [In/Out]
1441  *  pOutBufLen [In/Out]
1442  *
1443  * RETURNS
1444  * ERROR_NOT_SUPPORTED
1445  */
1446 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1447 {
1448   TRACE("(IfIndex %ld, pPerAdapterInfo %p, pOutBufLen %p)\n", IfIndex,
1449    pPerAdapterInfo, pOutBufLen);
1450   /* marking Win2K+ functions not supported */
1451   return ERROR_NOT_SUPPORTED;
1452 }
1453
1454
1455 /******************************************************************
1456  *    GetRTTAndHopCount (IPHLPAPI.@)
1457  *
1458  * NOTES
1459  * Stub
1460  *
1461  * PARAMS
1462  *
1463  *  DestIpAddress [In]
1464  *  HopCount [In/Out]
1465  *  MaxHops [In]
1466  *  RTT [In/Out]
1467  *
1468  * RETURNS
1469  * FALSE
1470  *
1471  */
1472 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
1473 {
1474   FIXME("(DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p): stub\n",
1475    DestIpAddress, HopCount, MaxHops, RTT);
1476   return FALSE;
1477 }
1478
1479
1480 /******************************************************************
1481  *    GetTcpStatistics (IPHLPAPI.@)
1482  *
1483  * PARAMS
1484  *
1485  *  pStats [In/Out]
1486  *
1487  * RETURNS
1488  *
1489  *  DWORD
1490  *
1491  */
1492 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
1493 {
1494   DWORD ret;
1495
1496   TRACE("pStats %p\n", pStats);
1497   ret = getTCPStats(pStats);
1498   TRACE("returning %ld\n", ret);
1499   return ret;
1500 }
1501
1502
1503 static int TcpTableSorter(const void *a, const void *b)
1504 {
1505   int ret;
1506
1507   if (a && b) {
1508     PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)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     PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
1620
1621     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1622     if (ret == 0)
1623       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1624   }
1625   else
1626     ret = 0;
1627   return ret;
1628 }
1629
1630
1631 /******************************************************************
1632  *    GetUdpTable (IPHLPAPI.@)
1633  *
1634  * Returns a table of active UDP connections.  On input, *pdwSize
1635  * is the size in bytes of pUdpTable.  If this is less than required,
1636  * the function will return ERROR_INSUFFICIENT_BUFFER, and *pdwSize
1637  * will be set to the required byte size.
1638  * If bOrder is true, the returned table will be sorted, first by
1639  * local address, then by local port number.
1640  *
1641  * PARAMS
1642  *
1643  *  pUdpTable [In/Out]
1644  *  pdwSize [In/Out]
1645  *  bOrder [In]
1646  *
1647  * RETURNS
1648  * NO_ERROR on success, something else on failure.
1649  *
1650  */
1651 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1652 {
1653   DWORD ret;
1654
1655   TRACE("pUdpTable %p, pdwSize %p, bOrder %ld\n", pUdpTable, pdwSize,
1656    (DWORD)bOrder);
1657   if (!pdwSize)
1658     ret = ERROR_INVALID_PARAMETER;
1659   else {
1660     DWORD numEntries = getNumUdpEntries();
1661     ULONG size = sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW);
1662
1663     if (!pUdpTable || *pdwSize < size) {
1664       *pdwSize = size;
1665       ret = ERROR_INSUFFICIENT_BUFFER;
1666     }
1667     else {
1668       PMIB_UDPTABLE table = getUdpTable();
1669
1670       if (table) {
1671         size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) *
1672          sizeof(MIB_UDPROW);
1673         if (*pdwSize < size) {
1674           *pdwSize = size;
1675           ret = ERROR_INSUFFICIENT_BUFFER;
1676         }
1677         else {
1678           memcpy(pUdpTable, table, size);
1679           if (bOrder)
1680             qsort(pUdpTable->table, pUdpTable->dwNumEntries,
1681              sizeof(MIB_UDPROW), UdpTableSorter);
1682           ret = NO_ERROR;
1683         }
1684         HeapFree(GetProcessHeap(), 0, table);
1685       }
1686       else
1687         ret = ERROR_OUTOFMEMORY;
1688     }
1689   }
1690   TRACE("returning %ld\n", ret);
1691   return ret;
1692 }
1693
1694
1695 /******************************************************************
1696  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1697  *
1698  * This is a Win98-only function to get information on "unidirectional"
1699  * adapters.  Since this is pretty nonsensical in other contexts, it
1700  * never returns anything.
1701  *
1702  * PARAMS
1703  *
1704  *  pIPIfInfo [In/Out]
1705  *  dwOutBufLen [In/Out]
1706  *
1707  * RETURNS
1708  * ERROR_NOT_SUPPORTED
1709  *
1710  */
1711 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1712 {
1713   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
1714   /* a unidirectional adapter?? not bloody likely! */
1715   return ERROR_NOT_SUPPORTED;
1716 }
1717
1718
1719 /******************************************************************
1720  *    IpReleaseAddress (IPHLPAPI.@)
1721  *
1722  * NOTES
1723  * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1724  * this function does nothing.
1725  *
1726  * PARAMS
1727  *
1728  *  AdapterInfo [In/Out]
1729  *
1730  * RETURNS
1731  * ERROR_NOT_SUPPORTED
1732  *
1733  */
1734 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1735 {
1736   TRACE("AdapterInfo %p\n", AdapterInfo);
1737   /* not a stub, never going to support this (and I never mark an adapter as
1738      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1739   return ERROR_NOT_SUPPORTED;
1740 }
1741
1742
1743 /******************************************************************
1744  *    IpRenewAddress (IPHLPAPI.@)
1745  *
1746  * NOTES
1747  * Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1748  * this function does nothing.
1749  *
1750  * PARAMS
1751  *
1752  *  AdapterInfo [In/Out]
1753  *
1754  * RETURNS
1755  * ERROR_NOT_SUPPORTED
1756  *
1757  */
1758 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1759 {
1760   TRACE("AdapterInfo %p\n", AdapterInfo);
1761   /* not a stub, never going to support this (and I never mark an adapter as
1762      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1763   return ERROR_NOT_SUPPORTED;
1764 }
1765
1766
1767 /******************************************************************
1768  *    NotifyAddrChange (IPHLPAPI.@)
1769  *
1770  * NOTES
1771  * Stub
1772  *
1773  * PARAMS
1774  *
1775  *  Handle [In/Out]
1776  *  overlapped [In/Out]
1777  *
1778  * RETURNS
1779  * ERROR_NOT_SUPPORTED
1780  *
1781  */
1782 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1783 {
1784   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
1785   /* marking Win2K+ functions not supported */
1786   return ERROR_NOT_SUPPORTED;
1787 }
1788
1789
1790 /******************************************************************
1791  *    NotifyRouteChange (IPHLPAPI.@)
1792  *
1793  * NOTES
1794  * Stub
1795  *
1796  * PARAMS
1797  *
1798  *  Handle [In/Out]
1799  *  overlapped [In/Out]
1800  *
1801  * RETURNS
1802  * ERROR_NOT_SUPPORTED
1803  *
1804  */
1805 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1806 {
1807   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
1808   /* marking Win2K+ functions not supported */
1809   return ERROR_NOT_SUPPORTED;
1810 }
1811
1812
1813 /******************************************************************
1814  *    SendARP (IPHLPAPI.@)
1815  *
1816  * NOTES
1817  * Stub
1818  *
1819  * PARAMS
1820  *
1821  *  DestIP [In]
1822  *  SrcIP [In]
1823  *  pMacAddr [In/Out]
1824  *  PhyAddrLen [In/Out]
1825  *
1826  * RETURNS
1827  * ERROR_NOT_SUPPORTED
1828  *
1829  */
1830 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
1831 {
1832   FIXME("(DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p): stub\n",
1833    DestIP, SrcIP, pMacAddr, PhyAddrLen);
1834   /* marking Win2K+ functions not supported */
1835   return ERROR_NOT_SUPPORTED;
1836 }
1837
1838
1839 /******************************************************************
1840  *    SetIfEntry (IPHLPAPI.@)
1841  *
1842  * NOTES
1843  * Stub
1844  *
1845  * PARAMS
1846  *
1847  *  pIfRow [In/Out]
1848  *
1849  * RETURNS
1850  * ERROR_NOT_SUPPORTED
1851  *
1852  */
1853 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
1854 {
1855   FIXME("(pIfRow %p): stub\n", pIfRow);
1856   /* this is supposed to set an administratively interface up or down.
1857      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
1858      this sort of down is indistinguishable from other sorts of down (e.g. no
1859      link). */
1860   return ERROR_NOT_SUPPORTED;
1861 }
1862
1863
1864 /******************************************************************
1865  *    SetIpForwardEntry (IPHLPAPI.@)
1866  *
1867  * NOTES
1868  * Stub
1869  *
1870  * PARAMS
1871  *
1872  *  pRoute [In/Out]
1873  *
1874  * RETURNS
1875  * 0
1876  *
1877  */
1878 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
1879 {
1880   FIXME("(pRoute %p): stub\n", pRoute);
1881   /* this is to add a route entry, how's it distinguishable from
1882      CreateIpForwardEntry?
1883      could use SIOCADDRT, not sure I want to */
1884   return (DWORD) 0;
1885 }
1886
1887
1888 /******************************************************************
1889  *    SetIpNetEntry (IPHLPAPI.@)
1890  *
1891  * NOTES
1892  * Stub
1893  *
1894  * PARAMS
1895  *
1896  *  pArpEntry [In/Out]
1897  *
1898  * RETURNS
1899  * 0
1900  *
1901  */
1902 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
1903 {
1904   FIXME("(pArpEntry %p): stub\n", pArpEntry);
1905   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
1906   return (DWORD) 0;
1907 }
1908
1909
1910 /******************************************************************
1911  *    SetIpStatistics (IPHLPAPI.@)
1912  *
1913  * NOTES
1914  * Stub
1915  *
1916  * PARAMS
1917  *
1918  *  pIpStats [In/Out]
1919  *
1920  * RETURNS
1921  * 0
1922  *
1923  */
1924 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
1925 {
1926   FIXME("(pIpStats %p): stub\n", pIpStats);
1927   return (DWORD) 0;
1928 }
1929
1930
1931 /******************************************************************
1932  *    SetIpTTL (IPHLPAPI.@)
1933  *
1934  * NOTES
1935  * Stub
1936  *
1937  * PARAMS
1938  *
1939  *  nTTL [In]
1940  *
1941  * RETURNS
1942  * 0
1943  *
1944  */
1945 DWORD WINAPI SetIpTTL(UINT nTTL)
1946 {
1947   FIXME("(nTTL %d): stub\n", nTTL);
1948   /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
1949      want to.  Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
1950   return (DWORD) 0;
1951 }
1952
1953
1954 /******************************************************************
1955  *    SetTcpEntry (IPHLPAPI.@)
1956  *
1957  * NOTES
1958  * Stub
1959  *
1960  * PARAMS
1961  *
1962  *  pTcpRow [In/Out]
1963  *
1964  * RETURNS
1965  * 0
1966  *
1967  */
1968 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
1969 {
1970   FIXME("(pTcpRow %p): stub\n", pTcpRow);
1971   return (DWORD) 0;
1972 }
1973
1974
1975 /******************************************************************
1976  *    UnenableRouter (IPHLPAPI.@)
1977  *
1978  * NOTES
1979  * Stub
1980  *
1981  * PARAMS
1982  *
1983  *  pOverlapped [In/Out]
1984  *  lpdwEnableCount [In/Out]
1985  *
1986  * RETURNS
1987  * ERROR_NOT_SUPPORTED
1988  *
1989  */
1990 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
1991 {
1992   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
1993    lpdwEnableCount);
1994   /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
1995      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
1996      marking Win2K+ functions not supported */
1997   return ERROR_NOT_SUPPORTED;
1998 }