~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/iphlpapi/iphlpapi_main.c

Version: ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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 static int IpForwardTableSorter(const void *a, const void *b)
193 {
194   int ret;
195 
196   if (a && b) {
197    const MIB_IPFORWARDROW* rowA = (const MIB_IPFORWARDROW*)a;
198    const MIB_IPFORWARDROW* rowB = (const MIB_IPFORWARDROW*)b;
199 
200     ret = rowA->dwForwardDest - rowB->dwForwardDest;
201     if (ret == 0) {
202       ret = rowA->dwForwardProto - rowB->dwForwardProto;
203       if (ret == 0) {
204         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
205         if (ret == 0)
206           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
207       }
208     }
209   }
210   else
211     ret = 0;
212   return ret;
213 }
214 
215 
216 /******************************************************************
217  *    AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
218  *
219  * Get the route table.
220  * Like GetIpForwardTable(), but allocate the returned table from heap.
221  *
222  * PARAMS
223  *  ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
224  *                         allocated and returned.
225  *  bOrder           [In]  whether to sort the table
226  *  heap             [In]  heap from which the table is allocated
227  *  flags            [In]  flags to HeapAlloc
228  *
229  * RETURNS
230  *  ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
231  *  on failure, NO_ERROR on success.
232  */
233 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *
234  ppIpForwardTable, BOOL bOrder, HANDLE heap, DWORD flags)
235 {
236   DWORD ret;
237 
238   TRACE("ppIpForwardTable %p, bOrder %d, heap %p, flags 0x%08x\n",
239    ppIpForwardTable, bOrder, heap, flags);
240   ret = getRouteTable(ppIpForwardTable, heap, flags);
241   if (!ret && bOrder)
242     qsort((*ppIpForwardTable)->table, (*ppIpForwardTable)->dwNumEntries,
243      sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
244   TRACE("returning %d\n", ret);
245   return ret;
246 }
247 
248 
249 static int IpNetTableSorter(const void *a, const void *b)
250 {
251   int ret;
252 
253   if (a && b)
254     ret = ((const MIB_IPNETROW*)a)->dwAddr - ((const MIB_IPNETROW*)b)->dwAddr;
255   else
256     ret = 0;
257   return ret;
258 }
259 
260 
261 /******************************************************************
262  *    AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
263  *
264  * Get the IP-to-physical address mapping table.
265  * Like GetIpNetTable(), but allocate the returned table from heap.
266  *
267  * PARAMS
268  *  ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
269  *                     allocated and returned.
270  *  bOrder       [In]  whether to sort the table
271  *  heap         [In]  heap from which the table is allocated
272  *  flags        [In]  flags to HeapAlloc
273  *
274  * RETURNS
275  *  ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
276  *  on failure, NO_ERROR on success.
277  */
278 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable,
279  BOOL bOrder, HANDLE heap, DWORD flags)
280 {
281   DWORD ret;
282 
283   TRACE("ppIpNetTable %p, bOrder %d, heap %p, flags 0x%08x\n",
284    ppIpNetTable, bOrder, heap, flags);
285   ret = getArpTable(ppIpNetTable, heap, flags);
286   if (!ret && bOrder)
287     qsort((*ppIpNetTable)->table, (*ppIpNetTable)->dwNumEntries,
288      sizeof(MIB_IPADDRROW), IpNetTableSorter);
289   TRACE("returning %d\n", ret);
290   return ret;
291 }
292 
293 
294 static int TcpTableSorter(const void *a, const void *b)
295 {
296   int ret;
297 
298   if (a && b) {
299     const MIB_TCPROW* rowA = a;
300     const MIB_TCPROW* rowB = b;
301 
302     ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr);
303     if (ret == 0) {
304        ret = ntohs ((unsigned short)rowA->dwLocalPort) -
305           ntohs ((unsigned short)rowB->dwLocalPort);
306       if (ret == 0) {
307          ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr);
308         if (ret == 0)
309            ret = ntohs ((unsigned short)rowA->dwRemotePort) -
310               ntohs ((unsigned short)rowB->dwRemotePort);
311       }
312     }
313   }
314   else
315     ret = 0;
316   return ret;
317 }
318 
319 
320 /******************************************************************
321  *    AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
322  *
323  * Get the TCP connection table.
324  * Like GetTcpTable(), but allocate the returned table from heap.
325  *
326  * PARAMS
327  *  ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
328  *                   allocated and returned.
329  *  bOrder     [In]  whether to sort the table
330  *  heap       [In]  heap from which the table is allocated
331  *  flags      [In]  flags to HeapAlloc
332  *
333  * RETURNS
334  *  ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
335  *  returns otherwise.
336  */
337 DWORD WINAPI AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE *ppTcpTable,
338  BOOL bOrder, HANDLE heap, DWORD flags)
339 {
340   DWORD ret;
341 
342   TRACE("ppTcpTable %p, bOrder %d, heap %p, flags 0x%08x\n",
343    ppTcpTable, bOrder, heap, flags);
344 
345   *ppTcpTable = NULL;
346   ret = getTcpTable(ppTcpTable, 0, heap, flags);
347   if (!ret && bOrder)
348     qsort((*ppTcpTable)->table, (*ppTcpTable)->dwNumEntries,
349      sizeof(MIB_TCPROW), TcpTableSorter);
350   TRACE("returning %d\n", ret);
351   return ret;
352 }
353 
354 
355 static int UdpTableSorter(const void *a, const void *b)
356 {
357   int ret;
358 
359   if (a && b) {
360     const MIB_UDPROW* rowA = (const MIB_UDPROW*)a;
361     const MIB_UDPROW* rowB = (const MIB_UDPROW*)b;
362 
363     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
364     if (ret == 0)
365       ret = rowA->dwLocalPort - rowB->dwLocalPort;
366   }
367   else
368     ret = 0;
369   return ret;
370 }
371 
372 
373 /******************************************************************
374  *    AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
375  *
376  * Get the UDP listener table.
377  * Like GetUdpTable(), but allocate the returned table from heap.
378  *
379  * PARAMS
380  *  ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
381  *                   allocated and returned.
382  *  bOrder     [In]  whether to sort the table
383  *  heap       [In]  heap from which the table is allocated
384  *  flags      [In]  flags to HeapAlloc
385  *
386  * RETURNS
387  *  ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
388  *  returns otherwise.
389  */
390 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable,
391  BOOL bOrder, HANDLE heap, DWORD flags)
392 {
393   DWORD ret;
394 
395   TRACE("ppUdpTable %p, bOrder %d, heap %p, flags 0x%08x\n",
396    ppUdpTable, bOrder, heap, flags);
397   ret = getUdpTable(ppUdpTable, heap, flags);
398   if (!ret && bOrder)
399     qsort((*ppUdpTable)->table, (*ppUdpTable)->dwNumEntries,
400      sizeof(MIB_UDPROW), UdpTableSorter);
401   TRACE("returning %d\n", ret);
402   return ret;
403 }
404 
405 
406 /******************************************************************
407  *    CreateIpForwardEntry (IPHLPAPI.@)
408  *
409  * Create a route in the local computer's IP table.
410  *
411  * PARAMS
412  *  pRoute [In] new route information
413  *
414  * RETURNS
415  *  Success: NO_ERROR
416  *  Failure: error code from winerror.h
417  *
418  * FIXME
419  *  Stub, always returns NO_ERROR.
420  */
421 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
422 {
423   FIXME("(pRoute %p): stub\n", pRoute);
424   /* could use SIOCADDRT, not sure I want to */
425   return 0;
426 }
427 
428 
429 /******************************************************************
430  *    CreateIpNetEntry (IPHLPAPI.@)
431  *
432  * Create entry in the ARP table.
433  *
434  * PARAMS
435  *  pArpEntry [In] new ARP entry
436  *
437  * RETURNS
438  *  Success: NO_ERROR
439  *  Failure: error code from winerror.h
440  *
441  * FIXME
442  *  Stub, always returns NO_ERROR.
443  */
444 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
445 {
446   FIXME("(pArpEntry %p)\n", pArpEntry);
447   /* could use SIOCSARP on systems that support it, not sure I want to */
448   return 0;
449 }
450 
451 
452 /******************************************************************
453  *    CreateProxyArpEntry (IPHLPAPI.@)
454  *
455  * Create a Proxy ARP (PARP) entry for an IP address.
456  *
457  * PARAMS
458  *  dwAddress [In] IP address for which this computer acts as a proxy. 
459  *  dwMask    [In] subnet mask for dwAddress
460  *  dwIfIndex [In] interface index
461  *
462  * RETURNS
463  *  Success: NO_ERROR
464  *  Failure: error code from winerror.h
465  *
466  * FIXME
467  *  Stub, returns ERROR_NOT_SUPPORTED.
468  */
469 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
470 {
471   FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
472    dwAddress, dwMask, dwIfIndex);
473   return ERROR_NOT_SUPPORTED;
474 }
475 
476 
477 /******************************************************************
478  *    DeleteIPAddress (IPHLPAPI.@)
479  *
480  * Delete an IP address added with AddIPAddress().
481  *
482  * PARAMS
483  *  NTEContext [In] NTE context from AddIPAddress();
484  *
485  * RETURNS
486  *  Success: NO_ERROR
487  *  Failure: error code from winerror.h
488  *
489  * FIXME
490  *  Stub, returns ERROR_NOT_SUPPORTED.
491  */
492 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
493 {
494   FIXME("(NTEContext %d): stub\n", NTEContext);
495   return ERROR_NOT_SUPPORTED;
496 }
497 
498 
499 /******************************************************************
500  *    DeleteIpForwardEntry (IPHLPAPI.@)
501  *
502  * Delete a route.
503  *
504  * PARAMS
505  *  pRoute [In] route to delete
506  *
507  * RETURNS
508  *  Success: NO_ERROR
509  *  Failure: error code from winerror.h
510  *
511  * FIXME
512  *  Stub, returns NO_ERROR.
513  */
514 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
515 {
516   FIXME("(pRoute %p): stub\n", pRoute);
517   /* could use SIOCDELRT, not sure I want to */
518   return 0;
519 }
520 
521 
522 /******************************************************************
523  *    DeleteIpNetEntry (IPHLPAPI.@)
524  *
525  * Delete an ARP entry.
526  *
527  * PARAMS
528  *  pArpEntry [In] ARP entry to delete
529  *
530  * RETURNS
531  *  Success: NO_ERROR
532  *  Failure: error code from winerror.h
533  *
534  * FIXME
535  *  Stub, returns NO_ERROR.
536  */
537 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
538 {
539   FIXME("(pArpEntry %p): stub\n", pArpEntry);
540   /* could use SIOCDARP on systems that support it, not sure I want to */
541   return 0;
542 }
543 
544 
545 /******************************************************************
546  *    DeleteProxyArpEntry (IPHLPAPI.@)
547  *
548  * Delete a Proxy ARP entry.
549  *
550  * PARAMS
551  *  dwAddress [In] IP address for which this computer acts as a proxy. 
552  *  dwMask    [In] subnet mask for dwAddress
553  *  dwIfIndex [In] interface index
554  *
555  * RETURNS
556  *  Success: NO_ERROR
557  *  Failure: error code from winerror.h
558  *
559  * FIXME
560  *  Stub, returns ERROR_NOT_SUPPORTED.
561  */
562 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
563 {
564   FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
565    dwAddress, dwMask, dwIfIndex);
566   return ERROR_NOT_SUPPORTED;
567 }
568 
569 
570 /******************************************************************
571  *    EnableRouter (IPHLPAPI.@)
572  *
573  * Turn on ip forwarding.
574  *
575  * PARAMS
576  *  pHandle     [In/Out]
577  *  pOverlapped [In/Out] hEvent member should contain a valid handle.
578  *
579  * RETURNS
580  *  Success: ERROR_IO_PENDING
581  *  Failure: error code from winerror.h
582  *
583  * FIXME
584  *  Stub, returns ERROR_NOT_SUPPORTED.
585  */
586 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
587 {
588   FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle, pOverlapped);
589   /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
590      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
591    */
592   return ERROR_NOT_SUPPORTED;
593 }
594 
595 
596 /******************************************************************
597  *    FlushIpNetTable (IPHLPAPI.@)
598  *
599  * Delete all ARP entries of an interface
600  *
601  * PARAMS
602  *  dwIfIndex [In] interface index
603  *
604  * RETURNS
605  *  Success: NO_ERROR
606  *  Failure: error code from winerror.h
607  *
608  * FIXME
609  *  Stub, returns ERROR_NOT_SUPPORTED.
610  */
611 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
612 {
613   FIXME("(dwIfIndex 0x%08x): stub\n", dwIfIndex);
614   /* this flushes the arp cache of the given index */
615   return ERROR_NOT_SUPPORTED;
616 }
617 
618 
619 /******************************************************************
620  *    GetAdapterIndex (IPHLPAPI.@)
621  *
622  * Get interface index from its name.
623  *
624  * PARAMS
625  *  AdapterName [In]  unicode string with the adapter name
626  *  IfIndex     [Out] returns found interface index
627  *
628  * RETURNS
629  *  Success: NO_ERROR
630  *  Failure: error code from winerror.h
631  */
632 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
633 {
634   char adapterName[MAX_ADAPTER_NAME];
635   unsigned int i;
636   DWORD ret;
637 
638   TRACE("(AdapterName %p, IfIndex %p)\n", AdapterName, IfIndex);
639   /* The adapter name is guaranteed not to have any unicode characters, so
640    * this translation is never lossy */
641   for (i = 0; i < sizeof(adapterName) - 1 && AdapterName[i]; i++)
642     adapterName[i] = (char)AdapterName[i];
643   adapterName[i] = '\0';
644   ret = getInterfaceIndexByName(adapterName, IfIndex);
645   TRACE("returning %d\n", ret);
646   return ret;
647 }
648 
649 
650 /******************************************************************
651  *    GetAdaptersInfo (IPHLPAPI.@)
652  *
653  * Get information about adapters.
654  *
655  * PARAMS
656  *  pAdapterInfo [Out] buffer for adapter infos
657  *  pOutBufLen   [In]  length of output buffer
658  *
659  * RETURNS
660  *  Success: NO_ERROR
661  *  Failure: error code from winerror.h
662  */
663 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
664 {
665   DWORD ret;
666 
667   TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
668   if (!pOutBufLen)
669     ret = ERROR_INVALID_PARAMETER;
670   else {
671     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
672 
673     if (numNonLoopbackInterfaces > 0) {
674       DWORD numIPAddresses = getNumIPAddresses();
675       ULONG size;
676 
677       /* This may slightly overestimate the amount of space needed, because
678        * the IP addresses include the loopback address, but it's easier
679        * to make sure there's more than enough space than to make sure there's
680        * precisely enough space.
681        */
682       size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
683       size += numIPAddresses  * sizeof(IP_ADDR_STRING); 
684       if (!pAdapterInfo || *pOutBufLen < size) {
685         *pOutBufLen = size;
686         ret = ERROR_BUFFER_OVERFLOW;
687       }
688       else {
689         InterfaceIndexTable *table = NULL;
690         PMIB_IPADDRTABLE ipAddrTable = NULL;
691         PMIB_IPFORWARDTABLE routeTable = NULL;
692 
693         ret = getIPAddrTable(&ipAddrTable, GetProcessHeap(), 0);
694         if (!ret)
695           ret = getRouteTable(&routeTable, GetProcessHeap(), 0);
696         if (!ret)
697           table = getNonLoopbackInterfaceIndexTable();
698         if (table) {
699           size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
700           size += ipAddrTable->dwNumEntries * sizeof(IP_ADDR_STRING); 
701           if (*pOutBufLen < size) {
702             *pOutBufLen = size;
703             ret = ERROR_INSUFFICIENT_BUFFER;
704           }
705           else {
706             DWORD ndx;
707             HKEY hKey;
708             BOOL winsEnabled = FALSE;
709             IP_ADDRESS_STRING primaryWINS, secondaryWINS;
710             PIP_ADDR_STRING nextIPAddr = (PIP_ADDR_STRING)((LPBYTE)pAdapterInfo
711              + numNonLoopbackInterfaces * sizeof(IP_ADAPTER_INFO));
712 
713             memset(pAdapterInfo, 0, size);
714             /* @@ Wine registry key: HKCU\Software\Wine\Network */
715             if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Network",
716              &hKey) == ERROR_SUCCESS) {
717               DWORD size = sizeof(primaryWINS.String);
718               unsigned long addr;
719 
720               RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
721                (LPBYTE)primaryWINS.String, &size);
722               addr = inet_addr(primaryWINS.String);
723               if (addr != INADDR_NONE && addr != INADDR_ANY)
724                 winsEnabled = TRUE;
725               size = sizeof(secondaryWINS.String);
726               RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
727                (LPBYTE)secondaryWINS.String, &size);
728               addr = inet_addr(secondaryWINS.String);
729               if (addr != INADDR_NONE && addr != INADDR_ANY)
730                 winsEnabled = TRUE;
731               RegCloseKey(hKey);
732             }
733             for (ndx = 0; ndx < table->numIndexes; ndx++) {
734               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
735               DWORD i;
736               PIP_ADDR_STRING currentIPAddr = &ptr->IpAddressList;
737               BOOL firstIPAddr = TRUE;
738 
739               /* on Win98 this is left empty, but whatever */
740               getInterfaceNameByIndex(table->indexes[ndx], ptr->AdapterName);
741               getInterfaceNameByIndex(table->indexes[ndx], ptr->Description);
742               ptr->AddressLength = sizeof(ptr->Address);
743               getInterfacePhysicalByIndex(table->indexes[ndx],
744                &ptr->AddressLength, ptr->Address, &ptr->Type);
745               ptr->Index = table->indexes[ndx];
746               for (i = 0; i < ipAddrTable->dwNumEntries; i++) {
747                 if (ipAddrTable->table[i].dwIndex == ptr->Index) {
748                   if (firstIPAddr) {
749                     toIPAddressString(ipAddrTable->table[i].dwAddr,
750                      ptr->IpAddressList.IpAddress.String);
751                     toIPAddressString(ipAddrTable->table[i].dwMask,
752                      ptr->IpAddressList.IpMask.String);
753                     firstIPAddr = FALSE;
754                   }
755                   else {
756                     currentIPAddr->Next = nextIPAddr;
757                     currentIPAddr = nextIPAddr;
758                     toIPAddressString(ipAddrTable->table[i].dwAddr,
759                      currentIPAddr->IpAddress.String);
760                     toIPAddressString(ipAddrTable->table[i].dwMask,
761                      currentIPAddr->IpMask.String);
762                     nextIPAddr++;
763                   }
764                 }
765               }
766               /* Find first router through this interface, which we'll assume
767                * is the default gateway for this adapter */
768               for (i = 0; i < routeTable->dwNumEntries; i++)
769                 if (routeTable->table[i].dwForwardIfIndex == ptr->Index
770                  && routeTable->table[i].dwForwardType ==
771                  MIB_IPROUTE_TYPE_INDIRECT)
772                   toIPAddressString(routeTable->table[i].dwForwardNextHop,
773                    ptr->GatewayList.IpAddress.String);
774               if (winsEnabled) {
775                 ptr->HaveWins = TRUE;
776                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
777                  primaryWINS.String, sizeof(primaryWINS.String));
778                 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
779                  secondaryWINS.String, sizeof(secondaryWINS.String));
780               }
781               if (ndx < table->numIndexes - 1)
782                 ptr->Next = &pAdapterInfo[ndx + 1];
783               else
784                 ptr->Next = NULL;
785             }
786             ret = NO_ERROR;
787           }
788           HeapFree(GetProcessHeap(), 0, table);
789         }
790         else
791           ret = ERROR_OUTOFMEMORY;
792         HeapFree(GetProcessHeap(), 0, routeTable);
793         HeapFree(GetProcessHeap(), 0, ipAddrTable);
794       }
795     }
796     else
797       ret = ERROR_NO_DATA;
798   }
799   TRACE("returning %d\n", ret);
800   return ret;
801 }
802 
803 
804 /******************************************************************
805  *    GetBestInterface (IPHLPAPI.@)
806  *
807  * Get the interface, with the best route for the given IP address.
808  *
809  * PARAMS
810  *  dwDestAddr     [In]  IP address to search the interface for
811  *  pdwBestIfIndex [Out] found best interface
812  *
813  * RETURNS
814  *  Success: NO_ERROR
815  *  Failure: error code from winerror.h
816  */
817 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
818 {
819     struct WS_sockaddr_in sa_in;
820     memset(&sa_in, 0, sizeof(sa_in));
821     sa_in.sin_family = AF_INET;
822     sa_in.sin_addr.S_un.S_addr = dwDestAddr;
823     return GetBestInterfaceEx((struct WS_sockaddr *)&sa_in, pdwBestIfIndex);
824 }
825 
826 /******************************************************************
827  *    GetBestInterfaceEx (IPHLPAPI.@)
828  *
829  * Get the interface, with the best route for the given IP address.
830  *
831  * PARAMS
832  *  dwDestAddr     [In]  IP address to search the interface for
833  *  pdwBestIfIndex [Out] found best interface
834  *
835  * RETURNS
836  *  Success: NO_ERROR
837  *  Failure: error code from winerror.h
838  */
839 DWORD WINAPI GetBestInterfaceEx(struct WS_sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
840 {
841   DWORD ret;
842 
843   TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
844   if (!pDestAddr || !pdwBestIfIndex)
845     ret = ERROR_INVALID_PARAMETER;
846   else {
847     MIB_IPFORWARDROW ipRow;
848 
849     if (pDestAddr->sa_family == AF_INET) {
850       ret = GetBestRoute(((struct WS_sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
851       if (ret == ERROR_SUCCESS)
852         *pdwBestIfIndex = ipRow.dwForwardIfIndex;
853     } else {
854       FIXME("address family %d not supported\n", pDestAddr->sa_family);
855       ret = ERROR_NOT_SUPPORTED;
856     }
857   }
858   TRACE("returning %d\n", ret);
859   return ret;
860 }
861 
862 
863 /******************************************************************
864  *    GetBestRoute (IPHLPAPI.@)
865  *
866  * Get the best route for the given IP address.
867  *
868  * PARAMS
869  *  dwDestAddr   [In]  IP address to search the best route for
870  *  dwSourceAddr [In]  optional source IP address
871  *  pBestRoute   [Out] found best route
872  *
873  * RETURNS
874  *  Success: NO_ERROR
875  *  Failure: error code from winerror.h
876  */
877 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
878 {
879   PMIB_IPFORWARDTABLE table;
880   DWORD ret;
881 
882   TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr,
883    dwSourceAddr, pBestRoute);
884   if (!pBestRoute)
885     return ERROR_INVALID_PARAMETER;
886 
887   ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
888   if (!ret) {
889     DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
890 
891     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
892       if (table->table[ndx].dwForwardType != MIB_IPROUTE_TYPE_INVALID &&
893        (dwDestAddr & table->table[ndx].dwForwardMask) ==
894        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
895         DWORD numShifts, mask;
896 
897         for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
898          mask && !(mask & 1); mask >>= 1, numShifts++)
899           ;
900         if (numShifts > matchedBits) {
901           matchedBits = numShifts;
902           matchedNdx = ndx;
903         }
904         else if (!matchedBits && table->table[ndx].dwForwardType ==
905          MIB_IPROUTE_TYPE_INDIRECT) {
906           /* default to a default gateway */
907           matchedNdx = ndx;
908         }
909       }
910     }
911     if (matchedNdx < table->dwNumEntries) {