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