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