wined3d: Set the max mipmap level in the pbo test.
[wine] / dlls / iphlpapi / iphlpapi_main.c
1 /*
2  * iphlpapi dll implementation
3  *
4  * Copyright (C) 2003,2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 #define USE_WS_PREFIX
43 #include "winsock2.h"
44 #include "iphlpapi.h"
45 #include "ifenum.h"
46 #include "ipstats.h"
47
48 #include "wine/debug.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
51
52 #ifndef INADDR_NONE
53 #define INADDR_NONE ~0UL
54 #endif
55
56 static int resolver_initialised;
57
58 /* call res_init() just once because of a bug in Mac OS X 10.4 */
59 static void initialise_resolver(void)
60 {
61     if (!resolver_initialised)
62     {
63         res_init();
64         resolver_initialised = 1;
65     }
66 }
67
68 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
69 {
70   switch (fdwReason) {
71     case DLL_PROCESS_ATTACH:
72       DisableThreadLibraryCalls( hinstDLL );
73       break;
74
75     case DLL_PROCESS_DETACH:
76       break;
77   }
78   return TRUE;
79 }
80
81 /******************************************************************
82  *    AddIPAddress (IPHLPAPI.@)
83  *
84  * Add an IP address to an adapter.
85  *
86  * PARAMS
87  *  Address     [In]  IP address to add to the adapter
88  *  IpMask      [In]  subnet mask for the IP address
89  *  IfIndex     [In]  adapter index to add the address
90  *  NTEContext  [Out] Net Table Entry (NTE) context for the IP address
91  *  NTEInstance [Out] NTE instance for the IP address
92  *
93  * RETURNS
94  *  Success: NO_ERROR
95  *  Failure: error code from winerror.h
96  *
97  * FIXME
98  *  Stub. Currently returns ERROR_NOT_SUPPORTED.
99  */
100 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG NTEContext, PULONG NTEInstance)
101 {
102   FIXME(":stub\n");
103   return ERROR_NOT_SUPPORTED;
104 }
105
106
107 /******************************************************************
108  *    AllocateAndGetIfTableFromStack (IPHLPAPI.@)
109  *
110  * Get table of local interfaces.
111  * Like GetIfTable(), but allocate the returned table from heap.
112  *
113  * PARAMS
114  *  ppIfTable [Out] pointer into which the MIB_IFTABLE is
115  *                  allocated and returned.
116  *  bOrder    [In]  whether to sort the table
117  *  heap      [In]  heap from which the table is allocated
118  *  flags     [In]  flags to HeapAlloc
119  *
120  * RETURNS
121  *  ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
122  *  GetIfTable() returns otherwise.
123  */
124 DWORD WINAPI AllocateAndGetIfTableFromStack(PMIB_IFTABLE *ppIfTable,
125  BOOL bOrder, HANDLE heap, DWORD flags)
126 {
127   DWORD ret;
128
129   TRACE("ppIfTable %p, bOrder %d, heap %p, flags 0x%08x\n", ppIfTable,
130         bOrder, heap, flags);
131   if (!ppIfTable)
132     ret = ERROR_INVALID_PARAMETER;
133   else {
134     DWORD dwSize = 0;
135
136     ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
137     if (ret == ERROR_INSUFFICIENT_BUFFER) {
138       *ppIfTable = HeapAlloc(heap, flags, dwSize);
139       ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
140     }
141   }
142   TRACE("returning %d\n", ret);
143   return ret;
144 }
145
146
147 static int IpAddrTableSorter(const void *a, const void *b)
148 {
149   int ret;
150
151   if (a && b)
152     ret = ((const MIB_IPADDRROW*)a)->dwAddr - ((const MIB_IPADDRROW*)b)->dwAddr;
153   else
154     ret = 0;
155   return ret;
156 }
157
158
159 /******************************************************************
160  *    AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
161  *
162  * Get interface-to-IP address mapping table. 
163  * Like GetIpAddrTable(), but allocate the returned table from heap.
164  *
165  * PARAMS
166  *  ppIpAddrTable [Out] pointer into which the MIB_IPADDRTABLE is
167  *                      allocated and returned.
168  *  bOrder        [In]  whether to sort the table
169  *  heap          [In]  heap from which the table is allocated
170  *  flags         [In]  flags to HeapAlloc
171  *
172  * RETURNS
173  *  ERROR_INVALID_PARAMETER if ppIpAddrTable is NULL, other error codes on
174  *  failure, NO_ERROR on success.
175  */
176 DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
177  BOOL bOrder, HANDLE heap, DWORD flags)
178 {
179   DWORD ret;
180
181   TRACE("ppIpAddrTable %p, bOrder %d, heap %p, flags 0x%08x\n",
182    ppIpAddrTable, bOrder, heap, flags);
183   ret = getIPAddrTable(ppIpAddrTable, heap, flags);
184   if (!ret && bOrder)
185     qsort((*ppIpAddrTable)->table, (*ppIpAddrTable)->dwNumEntries,
186      sizeof(MIB_IPADDRROW), IpAddrTableSorter);
187   TRACE("returning %d\n", ret);
188   return ret;
189 }
190
191
192 /******************************************************************
193  *    CreateIpForwardEntry (IPHLPAPI.@)
194  *
195  * Create a route in the local computer's IP table.
196  *
197  * PARAMS
198  *  pRoute [In] new route information
199  *
200  * RETURNS
201  *  Success: NO_ERROR
202  *  Failure: error code from winerror.h
203  *
204  * FIXME
205  *  Stub, always returns NO_ERROR.
206  */
207 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
208 {
209   FIXME("(pRoute %p): stub\n", pRoute);
210   /* could use SIOCADDRT, not sure I want to */
211   return 0;
212 }
213
214
215 /******************************************************************
216  *    CreateIpNetEntry (IPHLPAPI.@)
217  *
218  * Create entry in the ARP table.
219  *
220  * PARAMS
221  *  pArpEntry [In] new ARP entry
222  *
223  * RETURNS
224  *  Success: NO_ERROR
225  *  Failure: error code from winerror.h
226  *
227  * FIXME
228  *  Stub, always returns NO_ERROR.
229  */
230 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
231 {
232   FIXME("(pArpEntry %p)\n", pArpEntry);
233   /* could use SIOCSARP on systems that support it, not sure I want to */
234   return 0;
235 }
236
237
238 /******************************************************************
239  *    CreateProxyArpEntry (IPHLPAPI.@)
240  *
241  * Create a Proxy ARP (PARP) entry for an IP address.
242  *
243  * PARAMS
244  *  dwAddress [In] IP address for which this computer acts as a proxy. 
245  *  dwMask    [In] subnet mask for dwAddress
246  *  dwIfIndex [In] interface index
247  *
248  * RETURNS
249  *  Success: NO_ERROR
250  *  Failure: error code from winerror.h
251  *
252  * FIXME
253  *  Stub, returns ERROR_NOT_SUPPORTED.
254  */
255 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
256 {
257   FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
258    dwAddress, dwMask, dwIfIndex);
259   return ERROR_NOT_SUPPORTED;
260 }
261
262
263 /******************************************************************
264  *    DeleteIPAddress (IPHLPAPI.@)
265  *
266  * Delete an IP address added with AddIPAddress().
267  *
268  * PARAMS
269  *  NTEContext [In] NTE context from AddIPAddress();
270  *
271  * RETURNS
272  *  Success: NO_ERROR
273  *  Failure: error code from winerror.h
274  *
275  * FIXME
276  *  Stub, returns ERROR_NOT_SUPPORTED.
277  */
278 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
279 {
280   FIXME("(NTEContext %d): stub\n", NTEContext);
281   return ERROR_NOT_SUPPORTED;
282 }
283
284
285 /******************************************************************
286  *    DeleteIpForwardEntry (IPHLPAPI.@)
287  *
288  * Delete a route.
289  *
290  * PARAMS
291  *  pRoute [In] route to delete
292  *
293  * RETURNS
294  *  Success: NO_ERROR
295  *  Failure: error code from winerror.h
296  *
297  * FIXME
298  *  Stub, returns NO_ERROR.
299  */
300 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
301 {
302   FIXME("(pRoute %p): stub\n", pRoute);
303   /* could use SIOCDELRT, not sure I want to */
304   return 0;
305 }
306
307
308 /******************************************************************
309  *    DeleteIpNetEntry (IPHLPAPI.@)
310  *
311  * Delete an ARP entry.
312  *
313  * PARAMS
314  *  pArpEntry [In] ARP entry to delete
315  *
316  * RETURNS
317  *  Success: NO_ERROR
318  *  Failure: error code from winerror.h
319  *
320  * FIXME
321  *  Stub, returns NO_ERROR.
322  */
323 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
324 {
325   FIXME("(pArpEntry %p): stub\n", pArpEntry);
326   /* could use SIOCDARP on systems that support it, not sure I want to */
327   return 0;
328 }
329
330
331 /******************************************************************
332  *    DeleteProxyArpEntry (IPHLPAPI.@)
333  *
334  * Delete a Proxy ARP entry.
335  *
336  * PARAMS
337  *  dwAddress [In] IP address for which this computer acts as a proxy. 
338  *  dwMask    [In] subnet mask for dwAddress
339  *  dwIfIndex [In] interface index
340  *
341  * RETURNS
342  *  Success: NO_ERROR
343  *  Failure: error code from winerror.h
344  *
345  * FIXME
346  *  Stub, returns ERROR_NOT_SUPPORTED.
347  */
348 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
349 {
350   FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
351    dwAddress, dwMask, dwIfIndex);
352   return ERROR_NOT_SUPPORTED;
353 }
354
355
356 /******************************************************************
357  *    EnableRouter (IPHLPAPI.@)
358  *
359  * Turn on ip forwarding.
360  *
361  * PARAMS
362  *  pHandle     [In/Out]
363  *  pOverlapped [In/Out] hEvent member should contain a valid handle.
364  *
365  * RETURNS
366  *  Success: ERROR_IO_PENDING
367  *  Failure: error code from winerror.h
368  *
369  * FIXME
370  *  Stub, returns ERROR_NOT_SUPPORTED.
371  */
372 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
373 {
374   FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle, pOverlapped);
375   /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
376      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
377    */
378   return ERROR_NOT_SUPPORTED;
379 }
380
381
382 /******************************************************************
383  *    FlushIpNetTable (IPHLPAPI.@)
384  *
385  * Delete all ARP entries of an interface
386  *
387  * PARAMS
388  *  dwIfIndex [In] interface index
389  *
390  * RETURNS
391  *  Success: NO_ERROR
392  *  Failure: error code from winerror.h
393  *
394  * FIXME
395  *  Stub, returns ERROR_NOT_SUPPORTED.
396  */
397 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
398 {
399   FIXME("(dwIfIndex 0x%08x): stub\n", dwIfIndex);
400   /* this flushes the arp cache of the given index */
401   return ERROR_NOT_SUPPORTED;
402 }
403
404
405 /******************************************************************
406  *    GetAdapterIndex (IPHLPAPI.@)
407  *
408  * Get interface index from its name.
409  *
410  * PARAMS
411  *  AdapterName [In]  unicode string with the adapter name
412  *  IfIndex     [Out] returns found interface index
413  *
414  * RETURNS
415  *  Success: NO_ERROR
416  *  Failure: error code from winerror.h
417  */
418 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
419 {
420   char adapterName[MAX_ADAPTER_NAME];
421   unsigned int i;
422   DWORD ret;
423
424   TRACE("(AdapterName %p, IfIndex %p)\n", AdapterName, IfIndex);
425   /* The adapter name is guaranteed not to have any unicode characters, so
426    * this translation is never lossy */
427   for (i = 0; i < sizeof(adapterName) - 1 && AdapterName[i]; i++)
428     adapterName[i] = (char)AdapterName[i];
429   adapterName[i] = '\0';
430   ret = getInterfaceIndexByName(adapterName, IfIndex);
431   TRACE("returning %d\n", ret);
432   return ret;
433 }
434
435
436 /******************************************************************
437  *    GetAdaptersInfo (IPHLPAPI.@)
438  *
439  * Get information about adapters.
440  *
441  * PARAMS
442  *  pAdapterInfo [Out] buffer for adapter infos
443  *  pOutBufLen   [In]  length of output buffer
444  *
445  * RETURNS
446  *  Success: NO_ERROR
447  *  Failure: error code from winerror.h
448  */
449 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
450 {
451   DWORD ret;
452
453   TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
454   if (!pOutBufLen)
455     ret = ERROR_INVALID_PARAMETER;
456   else {
457     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
458
459     if (numNonLoopbackInterfaces > 0) {
460       DWORD numIPAddresses = getNumIPAddresses();
461       ULONG size;
462
463       /* This may slightly overestimate the amount of space needed, because
464        * the IP addresses include the loopback address, but it's easier
465        * to make sure there's more than enough space than to make sure there's
466        * precisely enough space.
467        */
468       size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
469       size += numIPAddresses  * sizeof(IP_ADDR_STRING); 
470       if (!pAdapterInfo || *pOutBufLen < size) {
471         *pOutBufLen = size;
472         ret = ERROR_BUFFER_OVERFLOW;
473       }
474       else {
475         InterfaceIndexTable *table = NULL;
476         PMIB_IPADDRTABLE ipAddrTable = NULL;
477         PMIB_IPFORWARDTABLE routeTable = NULL;
478
479         ret = getIPAddrTable(&ipAddrTable, GetProcessHeap(), 0);
480         if (!ret)
481           ret = AllocateAndGetIpForwardTableFromStack(&routeTable, FALSE, GetProcessHeap(), 0);
482         if (!ret)
483           table = getNonLoopbackInterfaceIndexTable();
484         if (table) {
485           size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
486           size += ipAddrTable->dwNumEntries * sizeof(IP_ADDR_STRING); 
487           if (*pOutBufLen < size) {
488             *pOutBufLen = size;
489             ret = ERROR_INSUFFICIENT_BUFFER;
490           }
491           else {
492             DWORD ndx;
493             HKEY hKey;
494             BOOL winsEnabled = FALSE;
495             IP_ADDRESS_STRING primaryWINS, secondaryWINS;
496             PIP_ADDR_STRING nextIPAddr = (PIP_ADDR_STRING)((LPBYTE)pAdapterInfo
497              + numNonLoopbackInterfaces * sizeof(IP_ADAPTER_INFO));
498
499             memset(pAdapterInfo, 0, size);
500             /* @@ Wine registry key: HKCU\Software\Wine\Network */
501             if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Network",
502              &hKey) == ERROR_SUCCESS) {
503               DWORD size = sizeof(primaryWINS.String);
504               unsigned long addr;
505
506               RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
507                (LPBYTE)primaryWINS.String, &size);
508               addr = inet_addr(primaryWINS.String);
509               if (addr != INADDR_NONE && addr != INADDR_ANY)
510                 winsEnabled = TRUE;
511               size = sizeof(secondaryWINS.String);
512               RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
513                (LPBYTE)secondaryWINS.String, &size);
514               addr = inet_addr(secondaryWINS.String);
515               if (addr != INADDR_NONE && addr != INADDR_ANY)
516                 winsEnabled = TRUE;
517               RegCloseKey(hKey);
518             }
519             for (ndx = 0; ndx < table->numIndexes; ndx++) {
520               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
521               DWORD i;
522               PIP_ADDR_STRING currentIPAddr = &ptr->IpAddressList;
523               BOOL firstIPAddr = TRUE;
524
525               /* on Win98 this is left empty, but whatever */
526               getInterfaceNameByIndex(table->indexes[ndx], ptr->AdapterName);
527               getInterfaceNameByIndex(table->indexes[ndx], ptr->Description);
528               ptr->AddressLength = sizeof(ptr->Address);
529               getInterfacePhysicalByIndex(table->indexes[ndx],
530                &ptr->AddressLength, ptr->Address, &ptr->Type);
531               ptr->Index = table->indexes[ndx];
532               for (i = 0; i < ipAddrTable->dwNumEntries; i++) {
533                 if (ipAddrTable->table[i].dwIndex == ptr->Index) {
534                   if (firstIPAddr) {
535                     toIPAddressString(ipAddrTable->table[i].dwAddr,
536                      ptr->IpAddressList.IpAddress.String);
537                     toIPAddressString(ipAddrTable->table[i].dwMask,
538                      ptr->IpAddressList.IpMask.String);
539                     firstIPAddr = FALSE;
540                   }
541                   else {
542                     currentIPAddr->Next = nextIPAddr;
543                     currentIPAddr = nextIPAddr;
544                     toIPAddressString(ipAddrTable->table[i].dwAddr,
545                      currentIPAddr->IpAddress.String);
546                     toIPAddressString(ipAddrTable->table[i].dwMask,
547                      currentIPAddr->IpMask.String);
548                     nextIPAddr++;
549                   }
550                 }
551               }
552               /* Find first router through this interface, which we'll assume
553                * is the default gateway for this adapter */
554               for (i = 0; i < routeTable->dwNumEntries; i++)
555                 if (routeTable->table[i].dwForwardIfIndex == ptr->Index
556                  && routeTable->table[i].dwForwardType ==
557                  MIB_IPROUTE_TYPE_INDIRECT)
558                   toIPAddressString(routeTable->table[i].dwForwardNextHop,
559                    ptr->GatewayList.IpAddress.String);
560               if (winsEnabled) {
561                 ptr->HaveWins = TRUE;
562                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
563                  primaryWINS.String, sizeof(primaryWINS.String));
564                 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
565                  secondaryWINS.String, sizeof(secondaryWINS.String));
566               }
567               if (ndx < table->numIndexes - 1)
568                 ptr->Next = &pAdapterInfo[ndx + 1];
569               else
570                 ptr->Next = NULL;
571             }
572             ret = NO_ERROR;
573           }
574           HeapFree(GetProcessHeap(), 0, table);
575         }
576         else
577           ret = ERROR_OUTOFMEMORY;
578         HeapFree(GetProcessHeap(), 0, routeTable);
579         HeapFree(GetProcessHeap(), 0, ipAddrTable);
580       }
581     }
582     else
583       ret = ERROR_NO_DATA;
584   }
585   TRACE("returning %d\n", ret);
586   return ret;
587 }
588
589
590 /******************************************************************
591  *    GetBestInterface (IPHLPAPI.@)
592  *
593  * Get the interface, with the best route for the given IP address.
594  *
595  * PARAMS
596  *  dwDestAddr     [In]  IP address to search the interface for
597  *  pdwBestIfIndex [Out] found best interface
598  *
599  * RETURNS
600  *  Success: NO_ERROR
601  *  Failure: error code from winerror.h
602  */
603 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
604 {
605     struct WS_sockaddr_in sa_in;
606     memset(&sa_in, 0, sizeof(sa_in));
607     sa_in.sin_family = AF_INET;
608     sa_in.sin_addr.S_un.S_addr = dwDestAddr;
609     return GetBestInterfaceEx((struct WS_sockaddr *)&sa_in, pdwBestIfIndex);
610 }
611
612 /******************************************************************
613  *    GetBestInterfaceEx (IPHLPAPI.@)
614  *
615  * Get the interface, with the best route for the given IP address.
616  *
617  * PARAMS
618  *  dwDestAddr     [In]  IP address to search the interface for
619  *  pdwBestIfIndex [Out] found best interface
620  *
621  * RETURNS
622  *  Success: NO_ERROR
623  *  Failure: error code from winerror.h
624  */
625 DWORD WINAPI GetBestInterfaceEx(struct WS_sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
626 {
627   DWORD ret;
628
629   TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
630   if (!pDestAddr || !pdwBestIfIndex)
631     ret = ERROR_INVALID_PARAMETER;
632   else {
633     MIB_IPFORWARDROW ipRow;
634
635     if (pDestAddr->sa_family == AF_INET) {
636       ret = GetBestRoute(((struct WS_sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
637       if (ret == ERROR_SUCCESS)
638         *pdwBestIfIndex = ipRow.dwForwardIfIndex;
639     } else {
640       FIXME("address family %d not supported\n", pDestAddr->sa_family);
641       ret = ERROR_NOT_SUPPORTED;
642     }
643   }
644   TRACE("returning %d\n", ret);
645   return ret;
646 }
647
648
649 /******************************************************************
650  *    GetBestRoute (IPHLPAPI.@)
651  *
652  * Get the best route for the given IP address.
653  *
654  * PARAMS
655  *  dwDestAddr   [In]  IP address to search the best route for
656  *  dwSourceAddr [In]  optional source IP address
657  *  pBestRoute   [Out] found best route
658  *
659  * RETURNS
660  *  Success: NO_ERROR
661  *  Failure: error code from winerror.h
662  */
663 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
664 {
665   PMIB_IPFORWARDTABLE table;
666   DWORD ret;
667
668   TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr,
669    dwSourceAddr, pBestRoute);
670   if (!pBestRoute)
671     return ERROR_INVALID_PARAMETER;
672
673   ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
674   if (!ret) {
675     DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
676
677     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
678       if (table->table[ndx].dwForwardType != MIB_IPROUTE_TYPE_INVALID &&
679        (dwDestAddr & table->table[ndx].dwForwardMask) ==
680        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
681         DWORD numShifts, mask;
682
683         for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
684          mask && !(mask & 1); mask >>= 1, numShifts++)
685           ;
686         if (numShifts > matchedBits) {
687           matchedBits = numShifts;
688           matchedNdx = ndx;
689         }
690         else if (!matchedBits && table->table[ndx].dwForwardType ==
691          MIB_IPROUTE_TYPE_INDIRECT) {
692           /* default to a default gateway */
693           matchedNdx = ndx;
694         }
695       }
696     }
697     if (matchedNdx < table->dwNumEntries) {
698       memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
699       ret = ERROR_SUCCESS;
700     }
701     else {
702       /* No route matches, which can happen if there's no default route. */
703       ret = ERROR_HOST_UNREACHABLE;
704     }
705     HeapFree(GetProcessHeap(), 0, table);
706   }
707   TRACE("returning %d\n", ret);
708   return ret;
709 }
710
711
712 /******************************************************************
713  *    GetFriendlyIfIndex (IPHLPAPI.@)
714  *
715  * Get a "friendly" version of IfIndex, which is one that doesn't
716  * have the top byte set.  Doesn't validate whether IfIndex is a valid
717  * adapter index.
718  *
719  * PARAMS
720  *  IfIndex [In] interface index to get the friendly one for
721  *
722  * RETURNS
723  *  A friendly version of IfIndex.
724  */
725 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
726 {
727   /* windows doesn't validate these, either, just makes sure the top byte is
728      cleared.  I assume my ifenum module never gives an index with the top
729      byte set. */
730   TRACE("returning %d\n", IfIndex);
731   return IfIndex;
732 }
733
734
735 /******************************************************************
736  *    GetIfEntry (IPHLPAPI.@)
737  *
738  * Get information about an interface.
739  *
740  * PARAMS
741  *  pIfRow [In/Out] In:  dwIndex of MIB_IFROW selects the interface.
742  *                  Out: interface information
743  *
744  * RETURNS
745  *  Success: NO_ERROR
746  *  Failure: error code from winerror.h
747  */
748 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
749 {
750   DWORD ret;
751   char nameBuf[MAX_ADAPTER_NAME];
752   char *name;
753
754   TRACE("pIfRow %p\n", pIfRow);
755   if (!pIfRow)
756     return ERROR_INVALID_PARAMETER;
757
758   name = getInterfaceNameByIndex(pIfRow->dwIndex, nameBuf);
759   if (name) {
760     ret = getInterfaceEntryByName(name, pIfRow);
761     if (ret == NO_ERROR)
762       ret = getInterfaceStatsByName(name, pIfRow);
763   }
764   else
765     ret = ERROR_INVALID_DATA;
766   TRACE("returning %d\n", ret);
767   return ret;
768 }
769
770
771 static int IfTableSorter(const void *a, const void *b)
772 {
773   int ret;
774
775   if (a && b)
776     ret = ((const MIB_IFROW*)a)->dwIndex - ((const MIB_IFROW*)b)->dwIndex;
777   else
778     ret = 0;
779   return ret;
780 }
781
782
783 /******************************************************************
784  *    GetIfTable (IPHLPAPI.@)
785  *
786  * Get a table of local interfaces.
787  *
788  * PARAMS
789  *  pIfTable [Out]    buffer for local interfaces table
790  *  pdwSize  [In/Out] length of output buffer
791  *  bOrder   [In]     whether to sort the table
792  *
793  * RETURNS
794  *  Success: NO_ERROR
795  *  Failure: error code from winerror.h
796  *
797  * NOTES
798  *  If pdwSize is less than required, the function will return
799  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
800  *  size.
801  *  If bOrder is true, the returned table will be sorted by interface index.
802  */
803 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
804 {
805   DWORD ret;
806
807   TRACE("pIfTable %p, pdwSize %p, bOrder %d\n", pdwSize, pdwSize,
808    (DWORD)bOrder);
809   if (!pdwSize)
810     ret = ERROR_INVALID_PARAMETER;
811   else {
812     DWORD numInterfaces = getNumInterfaces();
813     ULONG size = sizeof(MIB_IFTABLE);
814
815     if (numInterfaces > 1)
816       size += (numInterfaces - 1) * sizeof(MIB_IFROW);
817     if (!pIfTable || *pdwSize < size) {
818       *pdwSize = size;
819       ret = ERROR_INSUFFICIENT_BUFFER;
820     }
821     else {
822       InterfaceIndexTable *table = getInterfaceIndexTable();
823
824       if (table) {
825         size = sizeof(MIB_IFTABLE);
826         if (table->numIndexes > 1)
827           size += (table->numIndexes - 1) * sizeof(MIB_IFROW);
828         if (*pdwSize < size) {
829           *pdwSize = size;
830           ret = ERROR_INSUFFICIENT_BUFFER;
831         }
832         else {
833           DWORD ndx;
834
835           *pdwSize = size;
836           pIfTable->dwNumEntries = 0;
837           for (ndx = 0; ndx < table->numIndexes; ndx++) {
838             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
839             GetIfEntry(&pIfTable->table[ndx]);
840             pIfTable->dwNumEntries++;
841           }
842           if (bOrder)
843             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
844              IfTableSorter);
845           ret = NO_ERROR;
846         }
847         HeapFree(GetProcessHeap(), 0, table);
848       }
849       else
850         ret = ERROR_OUTOFMEMORY;
851     }
852   }
853   TRACE("returning %d\n", ret);
854   return ret;
855 }
856
857
858 /******************************************************************
859  *    GetInterfaceInfo (IPHLPAPI.@)
860  *
861  * Get a list of network interface adapters.
862  *
863  * PARAMS
864  *  pIfTable    [Out] buffer for interface adapters
865  *  dwOutBufLen [Out] if buffer is too small, returns required size
866  *
867  * RETURNS
868  *  Success: NO_ERROR
869  *  Failure: error code from winerror.h
870  *
871  * BUGS
872  *  MSDN states this should return non-loopback interfaces only.
873  */
874 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
875 {
876   DWORD ret;
877
878   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
879   if (!dwOutBufLen)
880     ret = ERROR_INVALID_PARAMETER;
881   else {
882     DWORD numInterfaces = getNumInterfaces();
883     ULONG size = sizeof(IP_INTERFACE_INFO);
884
885     if (numInterfaces > 1)
886       size += (numInterfaces - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
887     if (!pIfTable || *dwOutBufLen < size) {
888       *dwOutBufLen = size;
889       ret = ERROR_INSUFFICIENT_BUFFER;
890     }
891     else {
892       InterfaceIndexTable *table = getInterfaceIndexTable();
893
894       if (table) {
895         size = sizeof(IP_INTERFACE_INFO);
896         if (table->numIndexes > 1)
897           size += (table->numIndexes - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
898         if (*dwOutBufLen < size) {
899           *dwOutBufLen = size;
900           ret = ERROR_INSUFFICIENT_BUFFER;
901         }
902         else {
903           DWORD ndx;
904           char nameBuf[MAX_ADAPTER_NAME];
905
906           *dwOutBufLen = size;
907           pIfTable->NumAdapters = 0;
908           for (ndx = 0; ndx < table->numIndexes; ndx++) {
909             const char *walker, *name;
910             WCHAR *assigner;
911
912             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
913             name = getInterfaceNameByIndex(table->indexes[ndx], nameBuf);
914             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
915              walker && *walker &&
916              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
917              walker++, assigner++)
918               *assigner = *walker;
919             *assigner = 0;
920             pIfTable->NumAdapters++;
921           }
922           ret = NO_ERROR;
923         }
924         HeapFree(GetProcessHeap(), 0, table);
925       }
926       else
927         ret = ERROR_OUTOFMEMORY;
928     }
929   }
930   TRACE("returning %d\n", ret);
931   return ret;
932 }
933
934
935 /******************************************************************
936  *    GetIpAddrTable (IPHLPAPI.@)
937  *
938  * Get interface-to-IP address mapping table. 
939  *
940  * PARAMS
941  *  pIpAddrTable [Out]    buffer for mapping table
942  *  pdwSize      [In/Out] length of output buffer
943  *  bOrder       [In]     whether to sort the table
944  *
945  * RETURNS
946  *  Success: NO_ERROR
947  *  Failure: error code from winerror.h
948  *
949  * NOTES
950  *  If pdwSize is less than required, the function will return
951  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
952  *  size.
953  *  If bOrder is true, the returned table will be sorted by the next hop and
954  *  an assortment of arbitrary parameters.
955  */
956 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
957 {
958   DWORD ret;
959
960   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %d\n", pIpAddrTable, pdwSize,
961    (DWORD)bOrder);
962   if (!pdwSize)
963     ret = ERROR_INVALID_PARAMETER;
964   else {
965     PMIB_IPADDRTABLE table;
966
967     ret = getIPAddrTable(&table, GetProcessHeap(), 0);
968     if (ret == NO_ERROR)
969     {
970       ULONG size = sizeof(MIB_IPADDRTABLE);
971
972       if (table->dwNumEntries > 1)
973         size += (table->dwNumEntries - 1) * sizeof(MIB_IPADDRROW);
974       if (!pIpAddrTable || *pdwSize < size) {
975         *pdwSize = size;
976         ret = ERROR_INSUFFICIENT_BUFFER;
977       }
978       else {
979         *pdwSize = size;
980         memcpy(pIpAddrTable, table, size);
981         if (bOrder)
982           qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
983            sizeof(MIB_IPADDRROW), IpAddrTableSorter);
984         ret = NO_ERROR;
985       }
986       HeapFree(GetProcessHeap(), 0, table);
987     }
988   }
989   TRACE("returning %d\n", ret);
990   return ret;
991 }
992
993
994 /******************************************************************
995  *    GetIpForwardTable (IPHLPAPI.@)
996  *
997  * Get the route table.
998  *
999  * PARAMS
1000  *  pIpForwardTable [Out]    buffer for route table
1001  *  pdwSize         [In/Out] length of output buffer
1002  *  bOrder          [In]     whether to sort the table
1003  *
1004  * RETURNS
1005  *  Success: NO_ERROR
1006  *  Failure: error code from winerror.h
1007  *
1008  * NOTES
1009  *  If pdwSize is less than required, the function will return
1010  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1011  *  size.
1012  *  If bOrder is true, the returned table will be sorted by the next hop and
1013  *  an assortment of arbitrary parameters.
1014  */
1015 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1016 {
1017     DWORD ret;
1018     PMIB_IPFORWARDTABLE table;
1019
1020     TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\n", pIpForwardTable, pdwSize, bOrder);
1021
1022     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1023
1024     ret = AllocateAndGetIpForwardTableFromStack(&table, bOrder, GetProcessHeap(), 0);
1025     if (!ret) {
1026         DWORD size = FIELD_OFFSET( MIB_IPFORWARDTABLE, table[table->dwNumEntries] );
1027         if (!pIpForwardTable || *pdwSize < size) {
1028           *pdwSize = size;
1029           ret = ERROR_INSUFFICIENT_BUFFER;
1030         }
1031         else {
1032           *pdwSize = size;
1033           memcpy(pIpForwardTable, table, size);
1034         }
1035         HeapFree(GetProcessHeap(), 0, table);
1036     }
1037     TRACE("returning %d\n", ret);
1038     return ret;
1039 }
1040
1041
1042 /******************************************************************
1043  *    GetIpNetTable (IPHLPAPI.@)
1044  *
1045  * Get the IP-to-physical address mapping table.
1046  *
1047  * PARAMS
1048  *  pIpNetTable [Out]    buffer for mapping table
1049  *  pdwSize     [In/Out] length of output buffer
1050  *  bOrder      [In]     whether to sort the table
1051  *
1052  * RETURNS
1053  *  Success: NO_ERROR
1054  *  Failure: error code from winerror.h
1055  *
1056  * NOTES
1057  *  If pdwSize is less than required, the function will return
1058  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
1059  *  size.
1060  *  If bOrder is true, the returned table will be sorted by IP address.
1061  */
1062 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1063 {
1064     DWORD ret;
1065     PMIB_IPNETTABLE table;
1066
1067     TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize, bOrder);
1068
1069     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1070
1071     ret = AllocateAndGetIpNetTableFromStack( &table, bOrder, GetProcessHeap(), 0 );
1072     if (!ret) {
1073         DWORD size = FIELD_OFFSET( MIB_IPNETTABLE, table[table->dwNumEntries] );
1074         if (!pIpNetTable || *pdwSize < size) {
1075           *pdwSize = size;
1076           ret = ERROR_INSUFFICIENT_BUFFER;
1077         }
1078         else {
1079           *pdwSize = size;
1080           memcpy(pIpNetTable, table, size);
1081         }
1082         HeapFree(GetProcessHeap(), 0, table);
1083     }
1084     TRACE("returning %d\n", ret);
1085     return ret;
1086 }
1087
1088
1089 /******************************************************************
1090  *    GetNetworkParams (IPHLPAPI.@)
1091  *
1092  * Get the network parameters for the local computer.
1093  *
1094  * PARAMS
1095  *  pFixedInfo [Out]    buffer for network parameters
1096  *  pOutBufLen [In/Out] length of output buffer
1097  *
1098  * RETURNS
1099  *  Success: NO_ERROR
1100  *  Failure: error code from winerror.h
1101  *
1102  * NOTES
1103  *  If pOutBufLen is less than required, the function will return
1104  *  ERROR_INSUFFICIENT_BUFFER, and pOutBufLen will be set to the required byte
1105  *  size.
1106  */
1107 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1108 {
1109   DWORD ret, size;
1110   LONG regReturn;
1111   HKEY hKey;
1112
1113   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
1114   if (!pOutBufLen)
1115     return ERROR_INVALID_PARAMETER;
1116
1117   initialise_resolver();
1118   size = sizeof(FIXED_INFO) + (_res.nscount > 0 ? (_res.nscount  - 1) *
1119    sizeof(IP_ADDR_STRING) : 0);
1120   if (!pFixedInfo || *pOutBufLen < size) {
1121     *pOutBufLen = size;
1122     return ERROR_BUFFER_OVERFLOW;
1123   }
1124
1125   memset(pFixedInfo, 0, size);
1126   size = sizeof(pFixedInfo->HostName);
1127   GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
1128   size = sizeof(pFixedInfo->DomainName);
1129   GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
1130   if (_res.nscount > 0) {
1131     PIP_ADDR_STRING ptr;
1132     int i;
1133
1134     for (i = 0, ptr = &pFixedInfo->DnsServerList; i < _res.nscount && ptr;
1135      i++, ptr = ptr->Next) {
1136       toIPAddressString(_res.nsaddr_list[i].sin_addr.s_addr,
1137        ptr->IpAddress.String);
1138       if (i == _res.nscount - 1)
1139         ptr->Next = NULL;
1140       else if (i == 0)
1141         ptr->Next = (PIP_ADDR_STRING)((LPBYTE)pFixedInfo + sizeof(FIXED_INFO));
1142       else
1143         ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
1144     }
1145   }
1146   pFixedInfo->NodeType = HYBRID_NODETYPE;
1147   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1148    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
1149   if (regReturn != ERROR_SUCCESS)
1150     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1151      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
1152      &hKey);
1153   if (regReturn == ERROR_SUCCESS)
1154   {
1155     DWORD size = sizeof(pFixedInfo->ScopeId);
1156
1157     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (LPBYTE)pFixedInfo->ScopeId, &size);
1158     RegCloseKey(hKey);
1159   }
1160
1161   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1162      I suppose could also check for a listener on port 53 to set EnableDns */
1163   ret = NO_ERROR;
1164   TRACE("returning %d\n", ret);
1165   return ret;
1166 }
1167
1168
1169 /******************************************************************
1170  *    GetNumberOfInterfaces (IPHLPAPI.@)
1171  *
1172  * Get the number of interfaces.
1173  *
1174  * PARAMS
1175  *  pdwNumIf [Out] number of interfaces
1176  *
1177  * RETURNS
1178  *  NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
1179  */
1180 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1181 {
1182   DWORD ret;
1183
1184   TRACE("pdwNumIf %p\n", pdwNumIf);
1185   if (!pdwNumIf)
1186     ret = ERROR_INVALID_PARAMETER;
1187   else {
1188     *pdwNumIf = getNumInterfaces();
1189     ret = NO_ERROR;
1190   }
1191   TRACE("returning %d\n", ret);
1192   return ret;
1193 }
1194
1195
1196 /******************************************************************
1197  *    GetPerAdapterInfo (IPHLPAPI.@)
1198  *
1199  * Get information about an adapter corresponding to an interface.
1200  *
1201  * PARAMS
1202  *  IfIndex         [In]     interface info
1203  *  pPerAdapterInfo [Out]    buffer for per adapter info
1204  *  pOutBufLen      [In/Out] length of output buffer
1205  *
1206  * RETURNS
1207  *  Success: NO_ERROR
1208  *  Failure: error code from winerror.h
1209  *
1210  * FIXME
1211  *  Stub, returns empty IP_PER_ADAPTER_INFO in every case.
1212  */
1213 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1214 {
1215   ULONG bytesNeeded = sizeof(IP_PER_ADAPTER_INFO);
1216
1217   TRACE("(IfIndex %d, pPerAdapterInfo %p, pOutBufLen %p)\n", IfIndex, pPerAdapterInfo, pOutBufLen);
1218
1219   if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
1220
1221   if (!pPerAdapterInfo || *pOutBufLen < bytesNeeded)
1222   {
1223     *pOutBufLen = bytesNeeded;
1224     return ERROR_BUFFER_OVERFLOW;
1225   }
1226
1227   memset(pPerAdapterInfo, 0, bytesNeeded);
1228   return NO_ERROR;
1229 }
1230
1231
1232 /******************************************************************
1233  *    GetRTTAndHopCount (IPHLPAPI.@)
1234  *
1235  * Get round-trip time (RTT) and hop count.
1236  *
1237  * PARAMS
1238  *
1239  *  DestIpAddress [In]  destination address to get the info for
1240  *  HopCount      [Out] retrieved hop count
1241  *  MaxHops       [In]  maximum hops to search for the destination
1242  *  RTT           [Out] RTT in milliseconds
1243  *
1244  * RETURNS
1245  *  Success: TRUE
1246  *  Failure: FALSE
1247  *
1248  * FIXME
1249  *  Stub, returns FALSE.
1250  */
1251 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
1252 {
1253   FIXME("(DestIpAddress 0x%08x, HopCount %p, MaxHops %d, RTT %p): stub\n",
1254    DestIpAddress, HopCount, MaxHops, RTT);
1255   return FALSE;
1256 }
1257
1258
1259 /******************************************************************
1260  *    GetTcpTable (IPHLPAPI.@)
1261  *
1262  * Get the table of active TCP connections.
1263  *
1264  * PARAMS
1265  *  pTcpTable [Out]    buffer for TCP connections table
1266  *  pdwSize   [In/Out] length of output buffer
1267  *  bOrder    [In]     whether to order the table
1268  *
1269  * RETURNS
1270  *  Success: NO_ERROR
1271  *  Failure: error code from winerror.h
1272  *
1273  * NOTES
1274  *  If pdwSize is less than required, the function will return 
1275  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to 
1276  *  the required byte size.
1277  *  If bOrder is true, the returned table will be sorted, first by
1278  *  local address and port number, then by remote address and port
1279  *  number.
1280  */
1281 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1282 {
1283     DWORD ret;
1284     PMIB_TCPTABLE table;
1285
1286     TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize, bOrder);
1287
1288     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1289
1290     ret = AllocateAndGetTcpTableFromStack(&table, bOrder, GetProcessHeap(), 0);
1291     if (!ret) {
1292         DWORD size = FIELD_OFFSET( MIB_TCPTABLE, table[table->dwNumEntries] );
1293         if (!pTcpTable || *pdwSize < size) {
1294           *pdwSize = size;
1295           ret = ERROR_INSUFFICIENT_BUFFER;
1296         }
1297         else {
1298           *pdwSize = size;
1299           memcpy(pTcpTable, table, size);
1300         }
1301         HeapFree(GetProcessHeap(), 0, table);
1302     }
1303     TRACE("returning %d\n", ret);
1304     return ret;
1305 }
1306
1307
1308 /******************************************************************
1309  *    GetUdpTable (IPHLPAPI.@)
1310  *
1311  * Get a table of active UDP connections.
1312  *
1313  * PARAMS
1314  *  pUdpTable [Out]    buffer for UDP connections table
1315  *  pdwSize   [In/Out] length of output buffer
1316  *  bOrder    [In]     whether to order the table
1317  *
1318  * RETURNS
1319  *  Success: NO_ERROR
1320  *  Failure: error code from winerror.h
1321  *
1322  * NOTES
1323  *  If pdwSize is less than required, the function will return 
1324  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
1325  *  required byte size.
1326  *  If bOrder is true, the returned table will be sorted, first by
1327  *  local address, then by local port number.
1328  */
1329 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1330 {
1331     DWORD ret;
1332     PMIB_UDPTABLE table;
1333
1334     TRACE("pUdpTable %p, pdwSize %p, bOrder %d\n", pUdpTable, pdwSize, bOrder);
1335
1336     if (!pdwSize) return ERROR_INVALID_PARAMETER;
1337
1338     ret = AllocateAndGetUdpTableFromStack( &table, bOrder, GetProcessHeap(), 0 );
1339     if (!ret) {
1340         DWORD size = FIELD_OFFSET( MIB_UDPTABLE, table[table->dwNumEntries] );
1341         if (!pUdpTable || *pdwSize < size) {
1342           *pdwSize = size;
1343           ret = ERROR_INSUFFICIENT_BUFFER;
1344         }
1345         else {
1346           *pdwSize = size;
1347           memcpy(pUdpTable, table, size);
1348         }
1349         HeapFree(GetProcessHeap(), 0, table);
1350     }
1351     TRACE("returning %d\n", ret);
1352     return ret;
1353 }
1354
1355
1356 /******************************************************************
1357  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1358  *
1359  * This is a Win98-only function to get information on "unidirectional"
1360  * adapters.  Since this is pretty nonsensical in other contexts, it
1361  * never returns anything.
1362  *
1363  * PARAMS
1364  *  pIPIfInfo   [Out] buffer for adapter infos
1365  *  dwOutBufLen [Out] length of the output buffer
1366  *
1367  * RETURNS
1368  *  Success: NO_ERROR
1369  *  Failure: error code from winerror.h
1370  *
1371  * FIXME
1372  *  Stub, returns ERROR_NOT_SUPPORTED.
1373  */
1374 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1375 {
1376   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
1377   /* a unidirectional adapter?? not bloody likely! */
1378   return ERROR_NOT_SUPPORTED;
1379 }
1380
1381
1382 /******************************************************************
1383  *    IpReleaseAddress (IPHLPAPI.@)
1384  *
1385  * Release an IP obtained through DHCP,
1386  *
1387  * PARAMS
1388  *  AdapterInfo [In] adapter to release IP address
1389  *
1390  * RETURNS
1391  *  Success: NO_ERROR
1392  *  Failure: error code from winerror.h
1393  *
1394  * NOTES
1395  *  Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1396  *  this function does nothing.
1397  *
1398  * FIXME
1399  *  Stub, returns ERROR_NOT_SUPPORTED.
1400  */
1401 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1402 {
1403   TRACE("AdapterInfo %p\n", AdapterInfo);
1404   /* not a stub, never going to support this (and I never mark an adapter as
1405      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1406   return ERROR_NOT_SUPPORTED;
1407 }
1408
1409
1410 /******************************************************************
1411  *    IpRenewAddress (IPHLPAPI.@)
1412  *
1413  * Renew an IP obtained through DHCP.
1414  *
1415  * PARAMS
1416  *  AdapterInfo [In] adapter to renew IP address
1417  *
1418  * RETURNS
1419  *  Success: NO_ERROR
1420  *  Failure: error code from winerror.h
1421  *
1422  * NOTES
1423  *  Since GetAdaptersInfo never returns adapters that have DHCP enabled,
1424  *  this function does nothing.
1425  *
1426  * FIXME
1427  *  Stub, returns ERROR_NOT_SUPPORTED.
1428  */
1429 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1430 {
1431   TRACE("AdapterInfo %p\n", AdapterInfo);
1432   /* not a stub, never going to support this (and I never mark an adapter as
1433      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1434   return ERROR_NOT_SUPPORTED;
1435 }
1436
1437
1438 /******************************************************************
1439  *    NotifyAddrChange (IPHLPAPI.@)
1440  *
1441  * Notify caller whenever the ip-interface map is changed.
1442  *
1443  * PARAMS
1444  *  Handle     [Out] handle usable in asynchronous notification
1445  *  overlapped [In]  overlapped structure that notifies the caller
1446  *
1447  * RETURNS
1448  *  Success: NO_ERROR
1449  *  Failure: error code from winerror.h
1450  *
1451  * FIXME
1452  *  Stub, returns ERROR_NOT_SUPPORTED.
1453  */
1454 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1455 {
1456   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
1457   return ERROR_NOT_SUPPORTED;
1458 }
1459
1460
1461 /******************************************************************
1462  *    NotifyRouteChange (IPHLPAPI.@)
1463  *
1464  * Notify caller whenever the ip routing table is changed.
1465  *
1466  * PARAMS
1467  *  Handle     [Out] handle usable in asynchronous notification
1468  *  overlapped [In]  overlapped structure that notifies the caller
1469  *
1470  * RETURNS
1471  *  Success: NO_ERROR
1472  *  Failure: error code from winerror.h
1473  *
1474  * FIXME
1475  *  Stub, returns ERROR_NOT_SUPPORTED.
1476  */
1477 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1478 {
1479   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
1480   return ERROR_NOT_SUPPORTED;
1481 }
1482
1483
1484 /******************************************************************
1485  *    SendARP (IPHLPAPI.@)
1486  *
1487  * Send an ARP request.
1488  *
1489  * PARAMS
1490  *  DestIP     [In]     attempt to obtain this IP
1491  *  SrcIP      [In]     optional sender IP address
1492  *  pMacAddr   [Out]    buffer for the mac address
1493  *  PhyAddrLen [In/Out] length of the output buffer
1494  *
1495  * RETURNS
1496  *  Success: NO_ERROR
1497  *  Failure: error code from winerror.h
1498  *
1499  * FIXME
1500  *  Stub, returns ERROR_NOT_SUPPORTED.
1501  */
1502 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
1503 {
1504   FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
1505    DestIP, SrcIP, pMacAddr, PhyAddrLen);
1506   return ERROR_NOT_SUPPORTED;
1507 }
1508
1509
1510 /******************************************************************
1511  *    SetIfEntry (IPHLPAPI.@)
1512  *
1513  * Set the administrative status of an interface.
1514  *
1515  * PARAMS
1516  *  pIfRow [In] dwAdminStatus member specifies the new status.
1517  *
1518  * RETURNS
1519  *  Success: NO_ERROR
1520  *  Failure: error code from winerror.h
1521  *
1522  * FIXME
1523  *  Stub, returns ERROR_NOT_SUPPORTED.
1524  */
1525 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
1526 {
1527   FIXME("(pIfRow %p): stub\n", pIfRow);
1528   /* this is supposed to set an interface administratively up or down.
1529      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
1530      this sort of down is indistinguishable from other sorts of down (e.g. no
1531      link). */
1532   return ERROR_NOT_SUPPORTED;
1533 }
1534
1535
1536 /******************************************************************
1537  *    SetIpForwardEntry (IPHLPAPI.@)
1538  *
1539  * Modify an existing route.
1540  *
1541  * PARAMS
1542  *  pRoute [In] route with the new information
1543  *
1544  * RETURNS
1545  *  Success: NO_ERROR
1546  *  Failure: error code from winerror.h
1547  *
1548  * FIXME
1549  *  Stub, returns NO_ERROR.
1550  */
1551 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
1552 {
1553   FIXME("(pRoute %p): stub\n", pRoute);
1554   /* this is to add a route entry, how's it distinguishable from
1555      CreateIpForwardEntry?
1556      could use SIOCADDRT, not sure I want to */
1557   return 0;
1558 }
1559
1560
1561 /******************************************************************
1562  *    SetIpNetEntry (IPHLPAPI.@)
1563  *
1564  * Modify an existing ARP entry.
1565  *
1566  * PARAMS
1567  *  pArpEntry [In] ARP entry with the new information
1568  *
1569  * RETURNS
1570  *  Success: NO_ERROR
1571  *  Failure: error code from winerror.h
1572  *
1573  * FIXME
1574  *  Stub, returns NO_ERROR.
1575  */
1576 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
1577 {
1578   FIXME("(pArpEntry %p): stub\n", pArpEntry);
1579   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
1580   return 0;
1581 }
1582
1583
1584 /******************************************************************
1585  *    SetIpStatistics (IPHLPAPI.@)
1586  *
1587  * Toggle IP forwarding and det the default TTL value.
1588  *
1589  * PARAMS
1590  *  pIpStats [In] IP statistics with the new information
1591  *
1592  * RETURNS
1593  *  Success: NO_ERROR
1594  *  Failure: error code from winerror.h
1595  *
1596  * FIXME
1597  *  Stub, returns NO_ERROR.
1598  */
1599 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
1600 {
1601   FIXME("(pIpStats %p): stub\n", pIpStats);
1602   return 0;
1603 }
1604
1605
1606 /******************************************************************
1607  *    SetIpTTL (IPHLPAPI.@)
1608  *
1609  * Set the default TTL value.
1610  *
1611  * PARAMS
1612  *  nTTL [In] new TTL value
1613  *
1614  * RETURNS
1615  *  Success: NO_ERROR
1616  *  Failure: error code from winerror.h
1617  *
1618  * FIXME
1619  *  Stub, returns NO_ERROR.
1620  */
1621 DWORD WINAPI SetIpTTL(UINT nTTL)
1622 {
1623   FIXME("(nTTL %d): stub\n", nTTL);
1624   /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
1625      want to.  Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
1626   return 0;
1627 }
1628
1629
1630 /******************************************************************
1631  *    SetTcpEntry (IPHLPAPI.@)
1632  *
1633  * Set the state of a TCP connection.
1634  *
1635  * PARAMS
1636  *  pTcpRow [In] specifies connection with new state
1637  *
1638  * RETURNS
1639  *  Success: NO_ERROR
1640  *  Failure: error code from winerror.h
1641  *
1642  * FIXME
1643  *  Stub, returns NO_ERROR.
1644  */
1645 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
1646 {
1647   FIXME("(pTcpRow %p): stub\n", pTcpRow);
1648   return 0;
1649 }
1650
1651
1652 /******************************************************************
1653  *    UnenableRouter (IPHLPAPI.@)
1654  *
1655  * Decrement the IP-forwarding reference count. Turn off IP-forwarding
1656  * if it reaches zero.
1657  *
1658  * PARAMS
1659  *  pOverlapped     [In/Out] should be the same as in EnableRouter()
1660  *  lpdwEnableCount [Out]    optional, receives reference count
1661  *
1662  * RETURNS
1663  *  Success: NO_ERROR
1664  *  Failure: error code from winerror.h
1665  *
1666  * FIXME
1667  *  Stub, returns ERROR_NOT_SUPPORTED.
1668  */
1669 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
1670 {
1671   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
1672    lpdwEnableCount);
1673   /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
1674      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
1675    */
1676   return ERROR_NOT_SUPPORTED;
1677 }