xref: /reactos/dll/win32/iphlpapi/iphlpapi_main.c (revision d2aeaba5)
1 /*
2  * iphlpapi dll implementation
3  *
4  * Copyright (C) 2003 Juan Lang
5  *               2018 Pierre Schweitzer
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #define DEBUG
23 
24 #include <config.h>
25 #include "iphlpapi_private.h"
26 #include <strsafe.h>
27 #include <psapi.h>
28 
29 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
30 
31 typedef struct _NAME_SERVER_LIST_CONTEXT {
32     ULONG uSizeAvailable;
33     ULONG uSizeRequired;
34     PIP_PER_ADAPTER_INFO pData;
35     UINT NumServers;
36     IP_ADDR_STRING *pLastAddr;
37 } NAME_SERVER_LIST_CONTEXT, *PNAME_SERVER_LIST_CONTEXT;
38 
39 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
40 {
41   switch (fdwReason) {
42     case DLL_PROCESS_ATTACH:
43       DisableThreadLibraryCalls( hinstDLL );
44       interfaceMapInit();
45       break;
46 
47     case DLL_PROCESS_DETACH:
48       interfaceMapFree();
49       break;
50   }
51   return TRUE;
52 }
53 
54 /******************************************************************
55  *    AddIPAddress (IPHLPAPI.@)
56  *
57  *
58  * PARAMS
59  *
60  *  Address [In]
61  *  IpMask [In]
62  *  IfIndex [In]
63  *  NTEContext [In/Out]
64  *  NTEInstance [In/Out]
65  *
66  * RETURNS
67  *
68  *  DWORD
69  *
70  */
71 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask Netmask, DWORD IfIndex, PULONG NteContext, PULONG NteInstance)
72 {
73     return RtlNtStatusToDosError(addIPAddress(Address, Netmask, IfIndex, NteContext, NteInstance));
74 }
75 
76 DWORD getInterfaceGatewayByIndex(DWORD index)
77 {
78    DWORD ndx, retVal = 0, numRoutes = getNumRoutes();
79    RouteTable *table = getRouteTable();
80    if (!table) return 0;
81 
82     for (ndx = 0; ndx < numRoutes; ndx++)
83     {
84         if ((table->routes[ndx].ifIndex == (index)) && (table->routes[ndx].dest == 0))
85             retVal = table->routes[ndx].gateway;
86     }
87     HeapFree(GetProcessHeap(), 0, table);
88     return retVal;
89 }
90 
91 /******************************************************************
92  *    AllocateAndGetIfTableFromStack (IPHLPAPI.@)
93  *
94  *
95  * PARAMS
96  *
97  *  ppIfTable [Out] -- pointer into which the MIB_IFTABLE is
98  *   allocated and returned.
99  *  bOrder [In] -- passed to GetIfTable to order the table
100  *  heap [In] -- heap from which the table is allocated
101  *  flags [In] -- flags to HeapAlloc
102  *
103  * RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
104  *  GetIfTable returns otherwise
105  *
106  */
107 DWORD WINAPI AllocateAndGetIfTableFromStack(PMIB_IFTABLE *ppIfTable,
108  BOOL bOrder, HANDLE heap, DWORD flags)
109 {
110   DWORD ret;
111 
112   TRACE("ppIfTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n", ppIfTable,
113    (DWORD)bOrder, heap, flags);
114   if (!ppIfTable)
115     ret = ERROR_INVALID_PARAMETER;
116   else {
117     DWORD dwSize = 0;
118 
119     *ppIfTable = NULL;
120     ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
121     if (ret == ERROR_INSUFFICIENT_BUFFER) {
122       *ppIfTable = (PMIB_IFTABLE)HeapAlloc(heap, flags, dwSize);
123       ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
124       if (ret != NO_ERROR) {
125         HeapFree(heap, flags, *ppIfTable);
126         *ppIfTable = NULL;
127       }
128     }
129   }
130   TRACE("returning %ld\n", ret);
131   return ret;
132 }
133 
134 
135 /******************************************************************
136  *    AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
137  *
138  *
139  * PARAMS
140  *
141  *  ppIpAddrTable [Out]
142  *  bOrder [In] -- passed to GetIpAddrTable to order the table
143  *  heap [In] -- heap from which the table is allocated
144  *  flags [In] -- flags to HeapAlloc
145  *
146  * RETURNS
147  *
148  *  DWORD
149  *
150  */
151 DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
152  BOOL bOrder, HANDLE heap, DWORD flags)
153 {
154   DWORD ret;
155 
156   TRACE("ppIpAddrTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n",
157    ppIpAddrTable, (DWORD)bOrder, heap, flags);
158   if (!ppIpAddrTable)
159     ret = ERROR_INVALID_PARAMETER;
160   else {
161     DWORD dwSize = 0;
162 
163     *ppIpAddrTable = NULL;
164     ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
165     if (ret == ERROR_INSUFFICIENT_BUFFER) {
166       *ppIpAddrTable = (PMIB_IPADDRTABLE)HeapAlloc(heap, flags, dwSize);
167       ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
168       if (ret != NO_ERROR) {
169         HeapFree(heap, flags, *ppIpAddrTable);
170         *ppIpAddrTable = NULL;
171       }
172     }
173   }
174   TRACE("returning %ld\n", ret);
175   return ret;
176 }
177 
178 
179 /******************************************************************
180  *    AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
181  *
182  *
183  *  ppIpForwardTable [Out] -- pointer into which the MIB_IPFORWARDTABLE is
184  *   allocated and returned.
185  *  bOrder [In] -- passed to GetIfTable to order the table
186  *  heap [In] -- heap from which the table is allocated
187  *  flags [In] -- flags to HeapAlloc
188  *
189  * RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
190  *  GetIpForwardTable returns otherwise
191  *
192  */
193 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *
194  ppIpForwardTable, BOOL bOrder, HANDLE heap, DWORD flags)
195 {
196   DWORD ret;
197 
198   TRACE("ppIpForwardTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n",
199    ppIpForwardTable, (DWORD)bOrder, heap, flags);
200   if (!ppIpForwardTable)
201     ret = ERROR_INVALID_PARAMETER;
202   else {
203     DWORD dwSize = 0;
204 
205     *ppIpForwardTable = NULL;
206     ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
207     if (ret == ERROR_INSUFFICIENT_BUFFER) {
208       *ppIpForwardTable = (PMIB_IPFORWARDTABLE)HeapAlloc(heap, flags, dwSize);
209       ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
210       if (ret != NO_ERROR) {
211         HeapFree(heap, flags, *ppIpForwardTable);
212         *ppIpForwardTable = NULL;
213       }
214     }
215   }
216   TRACE("returning %ld\n", ret);
217   return ret;
218 }
219 
220 
221 /******************************************************************
222  *    AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
223  *
224  *
225  * PARAMS
226  *
227  *  ppIpNetTable [Out]
228  *  bOrder [In] -- passed to GetIpNetTable to order the table
229  *  heap [In] -- heap from which the table is allocated
230  *  flags [In] -- flags to HeapAlloc
231  *
232  * RETURNS
233  *
234  *  DWORD
235  *
236  */
237 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable,
238  BOOL bOrder, HANDLE heap, DWORD flags)
239 {
240   DWORD ret;
241 
242   TRACE("ppIpNetTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n",
243    ppIpNetTable, (DWORD)bOrder, heap, flags);
244   if (!ppIpNetTable)
245     ret = ERROR_INVALID_PARAMETER;
246   else {
247     DWORD dwSize = 0;
248 
249     *ppIpNetTable = NULL;
250     ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
251     if (ret == ERROR_INSUFFICIENT_BUFFER) {
252       *ppIpNetTable = (PMIB_IPNETTABLE)HeapAlloc(heap, flags, dwSize);
253       ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
254       if (ret != NO_ERROR) {
255         HeapFree(heap, flags, *ppIpNetTable);
256         *ppIpNetTable = NULL;
257       }
258     }
259   }
260   TRACE("returning %ld\n", ret);
261   return ret;
262 }
263 
264 
265 /******************************************************************
266  *    AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
267  *
268  *
269  * PARAMS
270  *
271  *  ppTcpTable [Out]
272  *  bOrder [In] -- passed to GetTcpTable to order the table
273  *  heap [In] -- heap from which the table is allocated
274  *  flags [In] -- flags to HeapAlloc
275  *
276  * RETURNS
277  *
278  *  DWORD
279  *
280  */
281 DWORD WINAPI AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE *ppTcpTable,
282  BOOL bOrder, HANDLE heap, DWORD flags)
283 {
284   DWORD ret;
285 
286   TRACE("ppTcpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n",
287    ppTcpTable, (DWORD)bOrder, heap, flags);
288   if (!ppTcpTable)
289     ret = ERROR_INVALID_PARAMETER;
290   else {
291     DWORD dwSize = 0;
292 
293     *ppTcpTable = NULL;
294     ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
295     if (ret == ERROR_INSUFFICIENT_BUFFER) {
296       *ppTcpTable = (PMIB_TCPTABLE)HeapAlloc(heap, flags, dwSize);
297       ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
298       if (ret != NO_ERROR) {
299         HeapFree(heap, flags, *ppTcpTable);
300         *ppTcpTable = NULL;
301       }
302     }
303   }
304   TRACE("returning %ld\n", ret);
305   return ret;
306 }
307 
308 
309 /******************************************************************
310  *    AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
311  *
312  *
313  * PARAMS
314  *
315  *  ppTcpTable [Out]
316  *  bOrder [In] -- passed to GetExtendedTcpTable to order the table
317  *  heap [In] -- heap from which the table is allocated
318  *  flags [In] -- flags to HeapAlloc
319  *  family [In] -- passed to GetExtendedTcpTable to select INET family
320  *
321  * RETURNS
322  *
323  *  DWORD
324  *
325  */
326 DWORD WINAPI AllocateAndGetTcpExTableFromStack(PVOID *ppTcpTable,
327  BOOL bOrder, HANDLE heap, DWORD flags, DWORD family)
328 {
329   DWORD ret;
330 
331   TRACE("ppTcpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx, family 0x%08lx\n",
332    ppTcpTable, (DWORD)bOrder, heap, flags, family);
333   if (!ppTcpTable)
334     ret = ERROR_INVALID_PARAMETER;
335   else {
336     DWORD dwSize = 0;
337 
338     *ppTcpTable = NULL;
339     ret = GetExtendedTcpTable(*ppTcpTable, &dwSize, bOrder, family, TCP_TABLE_OWNER_PID_ALL, 0);
340     if (ret == ERROR_INSUFFICIENT_BUFFER) {
341       *ppTcpTable = (PMIB_TCPTABLE_OWNER_PID)HeapAlloc(heap, flags, dwSize);
342       ret = GetExtendedTcpTable(*ppTcpTable, &dwSize, bOrder, family, TCP_TABLE_OWNER_PID_ALL, 0);
343       if (ret != NO_ERROR) {
344         HeapFree(heap, flags, *ppTcpTable);
345         *ppTcpTable = NULL;
346       }
347     }
348   }
349   TRACE("returning %ld\n", ret);
350   return ret;
351 }
352 
353 
354 /******************************************************************
355  *    AllocateAndGetTcpExTable2FromStack (IPHLPAPI.@)
356  *
357  *
358  * PARAMS
359  *
360  *  ppTcpTable [Out]
361  *  bOrder [In] -- passed to GetExtendedTcpTable to order the table
362  *  heap [In] -- heap from which the table is allocated
363  *  flags [In] -- flags to HeapAlloc
364  *  family [In] -- passed to GetExtendedTcpTable to select INET family
365  *  class [In] -- passed to GetExtendedTcpTable to select information
366  *
367  * RETURNS
368  *
369  *  DWORD
370  *
371  */
372 DWORD WINAPI AllocateAndGetTcpExTable2FromStack(PVOID *ppTcpTable,
373  BOOL bOrder, HANDLE heap, DWORD flags, DWORD family, TCP_TABLE_CLASS class)
374 {
375   DWORD ret;
376 
377   TRACE("ppTcpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx, family %ld, class %ld\n",
378    ppTcpTable, (DWORD)bOrder, heap, flags, family, class);
379   if (!ppTcpTable)
380     ret = ERROR_INVALID_PARAMETER;
381   else {
382     DWORD dwSize = 0;
383 
384     *ppTcpTable = NULL;
385     ret = GetExtendedTcpTable(*ppTcpTable, &dwSize, bOrder, family, class, 0);
386     if (ret == ERROR_INSUFFICIENT_BUFFER) {
387       *ppTcpTable = HeapAlloc(heap, flags, dwSize);
388       ret = GetExtendedTcpTable(*ppTcpTable, &dwSize, bOrder, family, class, 0);
389       if (ret != NO_ERROR) {
390         HeapFree(heap, flags, *ppTcpTable);
391         *ppTcpTable = NULL;
392       }
393     }
394   }
395   TRACE("returning %ld\n", ret);
396   return ret;
397 }
398 
399 
400 /******************************************************************
401  *    AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
402  *
403  *
404  * PARAMS
405  *
406  *  ppUdpTable [Out]
407  *  bOrder [In] -- passed to GetUdpTable to order the table
408  *  heap [In] -- heap from which the table is allocated
409  *  flags [In] -- flags to HeapAlloc
410  *
411  * RETURNS
412  *
413  *  DWORD
414  *
415  */
416 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable,
417  BOOL bOrder, HANDLE heap, DWORD flags)
418 {
419   DWORD ret;
420 
421   TRACE("ppUdpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n",
422    ppUdpTable, (DWORD)bOrder, heap, flags);
423   if (!ppUdpTable)
424     ret = ERROR_INVALID_PARAMETER;
425   else {
426     DWORD dwSize = 0;
427 
428     *ppUdpTable = NULL;
429     ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
430     if (ret == ERROR_INSUFFICIENT_BUFFER) {
431       *ppUdpTable = (PMIB_UDPTABLE)HeapAlloc(heap, flags, dwSize);
432       ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
433       if (ret != NO_ERROR) {
434         HeapFree(heap, flags, *ppUdpTable);
435         *ppUdpTable = NULL;
436       }
437     }
438   }
439   TRACE("returning %ld\n", ret);
440   return ret;
441 }
442 
443 
444 /******************************************************************
445  *    AllocateAndGetUdpExTableFromStack (IPHLPAPI.@)
446  *
447  *
448  * PARAMS
449  *
450  *  ppUdpTable [Out]
451  *  bOrder [In] -- passed to GetExtendedUdpTable to order the table
452  *  heap [In] -- heap from which the table is allocated
453  *  flags [In] -- flags to HeapAlloc
454  *  family [In] -- passed to GetExtendedUdpTable to select INET family
455  *
456  * RETURNS
457  *
458  *  DWORD
459  *
460  */
461 DWORD WINAPI AllocateAndGetUdpExTableFromStack(PVOID *ppUdpTable,
462  BOOL bOrder, HANDLE heap, DWORD flags, DWORD family)
463 {
464   DWORD ret;
465 
466   TRACE("ppUdpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx, family 0x%08lx\n",
467    ppUdpTable, (DWORD)bOrder, heap, flags, family);
468   if (!ppUdpTable)
469     ret = ERROR_INVALID_PARAMETER;
470   else {
471     DWORD dwSize = 0;
472 
473     *ppUdpTable = NULL;
474     ret = GetExtendedUdpTable(*ppUdpTable, &dwSize, bOrder, family, UDP_TABLE_OWNER_PID, 0);
475     if (ret == ERROR_INSUFFICIENT_BUFFER) {
476       *ppUdpTable = (PMIB_UDPTABLE_OWNER_PID)HeapAlloc(heap, flags, dwSize);
477       ret = GetExtendedUdpTable(*ppUdpTable, &dwSize, bOrder, family, UDP_TABLE_OWNER_PID, 0);
478       if (ret != NO_ERROR) {
479         HeapFree(heap, flags, *ppUdpTable);
480         *ppUdpTable = NULL;
481       }
482     }
483   }
484   TRACE("returning %ld\n", ret);
485   return ret;
486 }
487 
488 
489 /******************************************************************
490  *    AllocateAndGetUdpExTable2FromStack (IPHLPAPI.@)
491  *
492  *
493  * PARAMS
494  *
495  *  ppUdpTable [Out]
496  *  bOrder [In] -- passed to GetExtendedUdpTable to order the table
497  *  heap [In] -- heap from which the table is allocated
498  *  flags [In] -- flags to HeapAlloc
499  *  family [In] -- passed to GetExtendedUdpTable to select INET family
500  *  class [In] -- passed to GetExtendedUdpTable to select information
501  *
502  * RETURNS
503  *
504  *  DWORD
505  *
506  */
507 DWORD WINAPI AllocateAndGetUdpExTable2FromStack(PVOID *ppUdpTable,
508  BOOL bOrder, HANDLE heap, DWORD flags, DWORD family, UDP_TABLE_CLASS class)
509 {
510   DWORD ret;
511 
512   TRACE("ppUdpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx, family %ld, class %ld\n",
513    ppUdpTable, (DWORD)bOrder, heap, flags, family, class);
514   if (!ppUdpTable)
515     ret = ERROR_INVALID_PARAMETER;
516   else {
517     DWORD dwSize = 0;
518 
519     *ppUdpTable = NULL;
520     ret = GetExtendedUdpTable(*ppUdpTable, &dwSize, bOrder, family, class, 0);
521     if (ret == ERROR_INSUFFICIENT_BUFFER) {
522       *ppUdpTable = HeapAlloc(heap, flags, dwSize);
523       ret = GetExtendedUdpTable(*ppUdpTable, &dwSize, bOrder, family, class, 0);
524       if (ret != NO_ERROR) {
525         HeapFree(heap, flags, *ppUdpTable);
526         *ppUdpTable = NULL;
527       }
528     }
529   }
530   TRACE("returning %ld\n", ret);
531   return ret;
532 }
533 
534 
535 /******************************************************************
536  *    CreateIpForwardEntry (IPHLPAPI.@)
537  *
538  *
539  * PARAMS
540  *
541  *  pRoute [In/Out]
542  *
543  * RETURNS
544  *
545  *  DWORD
546  *
547  */
548 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
549 {
550     return createIpForwardEntry( pRoute );
551 }
552 
553 
554 /******************************************************************
555  *    CreateIpNetEntry (IPHLPAPI.@)
556  *
557  *
558  * PARAMS
559  *
560  *  pArpEntry [In/Out]
561  *
562  * RETURNS
563  *
564  *  DWORD
565  *
566  */
567 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
568 {
569   TRACE("pArpEntry %p\n", pArpEntry);
570   /* could use SIOCSARP on systems that support it, not sure I want to */
571   FIXME(":stub\n");
572   return (DWORD) 0;
573 }
574 
575 
576 /******************************************************************
577  *    CreateProxyArpEntry (IPHLPAPI.@)
578  *
579  *
580  * PARAMS
581  *
582  *  dwAddress [In]
583  *  dwMask [In]
584  *  dwIfIndex [In]
585  *
586  * RETURNS
587  *
588  *  DWORD
589  *
590  */
591 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
592 {
593   TRACE("dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx\n", dwAddress,
594    dwMask, dwIfIndex);
595   FIXME(":stub\n");
596   /* marking Win2K+ functions not supported */
597   return ERROR_NOT_SUPPORTED;
598 }
599 
600 
601 /******************************************************************
602  *    DeleteIPAddress (IPHLPAPI.@)
603  *
604  *
605  * PARAMS
606  *
607  *  NTEContext [In]
608  *
609  * RETURNS
610  *
611  *  DWORD
612  *
613  */
614 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
615 {
616   TRACE("NTEContext %ld\n", NTEContext);
617   return RtlNtStatusToDosError(deleteIpAddress(NTEContext));
618 }
619 
620 
621 /******************************************************************
622  *    DeleteIpForwardEntry (IPHLPAPI.@)
623  *
624  *
625  * PARAMS
626  *
627  *  pRoute [In/Out]
628  *
629  * RETURNS
630  *
631  *  DWORD
632  *
633  */
634 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
635 {
636     return deleteIpForwardEntry( pRoute );
637 }
638 
639 
640 /******************************************************************
641  *    DeleteIpNetEntry (IPHLPAPI.@)
642  *
643  *
644  * PARAMS
645  *
646  *  pArpEntry [In/Out]
647  *
648  * RETURNS
649  *
650  *  DWORD
651  *
652  */
653 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
654 {
655   TRACE("pArpEntry %p\n", pArpEntry);
656   /* could use SIOCDARP on systems that support it, not sure I want to */
657   FIXME(":stub\n");
658   return (DWORD) 0;
659 }
660 
661 
662 /******************************************************************
663  *    DeleteProxyArpEntry (IPHLPAPI.@)
664  *
665  *
666  * PARAMS
667  *
668  *  dwAddress [In]
669  *  dwMask [In]
670  *  dwIfIndex [In]
671  *
672  * RETURNS
673  *
674  *  DWORD
675  *
676  */
677 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
678 {
679   TRACE("dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx\n", dwAddress,
680    dwMask, dwIfIndex);
681   FIXME(":stub\n");
682   /* marking Win2K+ functions not supported */
683   return ERROR_NOT_SUPPORTED;
684 }
685 
686 /******************************************************************
687  *    EnableRouter (IPHLPAPI.@)
688  *
689  *
690  * PARAMS
691  *
692  *  pHandle [In/Out]
693  *  pOverlapped [In/Out]
694  *
695  * RETURNS
696  *
697  *  DWORD
698  *
699  */
700 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
701 {
702   TRACE("pHandle %p, pOverlapped %p\n", pHandle, pOverlapped);
703   FIXME(":stub\n");
704   /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
705      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
706      marking Win2K+ functions not supported */
707   return ERROR_NOT_SUPPORTED;
708 }
709 
710 
711 /******************************************************************
712  *    FlushIpNetTable (IPHLPAPI.@)
713  *
714  *
715  * PARAMS
716  *
717  *  dwIfIndex [In]
718  *
719  * RETURNS
720  *
721  *  DWORD
722  *
723  */
724 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
725 {
726   TRACE("dwIfIndex 0x%08lx\n", dwIfIndex);
727   FIXME(":stub\n");
728   /* this flushes the arp cache of the given index
729      marking Win2K+ functions not supported */
730   return ERROR_NOT_SUPPORTED;
731 }
732 
733 
734 /******************************************************************
735  *    GetAdapterIndex (IPHLPAPI.@)
736  *
737  *
738  * PARAMS
739  *
740  *  AdapterName [In/Out]
741  *  IfIndex [In/Out]
742  *
743  * RETURNS
744  *
745  *  DWORD
746  *
747  */
748 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
749 {
750   TRACE("AdapterName %p, IfIndex %p\n", AdapterName, IfIndex);
751   FIXME(":stub\n");
752   /* marking Win2K+ functions not supported */
753   return ERROR_NOT_SUPPORTED;
754 }
755 
756 
757 /******************************************************************
758  *    GetAdaptersInfo (IPHLPAPI.@)
759  *
760  *
761  * PARAMS
762  *
763  *  pAdapterInfo [In/Out]
764  *  pOutBufLen [In/Out]
765  *
766  * RETURNS
767  *
768  *  DWORD
769  *
770  */
771 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
772 {
773   DWORD ret;
774   BOOL dhcpEnabled;
775   DWORD dhcpServer;
776 
777   TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
778   if (!pOutBufLen)
779     ret = ERROR_INVALID_PARAMETER;
780   else {
781     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
782 
783     if (numNonLoopbackInterfaces > 0) {
784       /* this calculation assumes only one address in the IP_ADDR_STRING lists.
785          that's okay, because:
786          - we don't get multiple addresses per adapter anyway
787          - we don't know about per-adapter gateways
788          - DHCP and WINS servers can have max one entry per list */
789       ULONG size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
790 
791       if (!pAdapterInfo || *pOutBufLen < size) {
792         *pOutBufLen = size;
793         ret = ERROR_BUFFER_OVERFLOW;
794       }
795       else {
796         InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
797 
798         if (table) {
799           size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
800           if (*pOutBufLen < size) {
801             *pOutBufLen = size;
802             ret = ERROR_INSUFFICIENT_BUFFER;
803           }
804           else {
805             DWORD ndx;
806             HKEY hKey;
807             BOOL winsEnabled = FALSE;
808             IP_ADDRESS_STRING primaryWINS, secondaryWINS;
809 
810             memset(pAdapterInfo, 0, size);
811             /* @@ Wine registry key: HKCU\Software\Wine\Network */
812             if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Network", &hKey) == ERROR_SUCCESS) {
813               DWORD size = sizeof(primaryWINS.String);
814               unsigned long addr;
815 
816               RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
817                (PBYTE)primaryWINS.String, &size);
818               addr = inet_addr(primaryWINS.String);
819               if (addr != INADDR_NONE && addr != INADDR_ANY)
820                 winsEnabled = TRUE;
821               size = sizeof(secondaryWINS.String);
822               RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
823                (PBYTE)secondaryWINS.String, &size);
824               addr = inet_addr(secondaryWINS.String);
825               if (addr != INADDR_NONE && addr != INADDR_ANY)
826                 winsEnabled = TRUE;
827               RegCloseKey(hKey);
828             }
829 			TRACE("num of index is %lu\n", table->numIndexes);
830             for (ndx = 0; ndx < table->numIndexes; ndx++) {
831               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
832               DWORD addrLen = sizeof(ptr->Address), type;
833               const char *ifname =
834                   getInterfaceNameByIndex(table->indexes[ndx]);
835               if (!ifname) {
836                   ret = ERROR_OUTOFMEMORY;
837                   break;
838               }
839 
840               /* on Win98 this is left empty, but whatever */
841               strncpy(ptr->AdapterName,ifname,sizeof(ptr->AdapterName));
842               consumeInterfaceName(ifname);
843               ptr->AdapterName[MAX_ADAPTER_NAME_LENGTH] = '\0';
844               getInterfacePhysicalByIndex(table->indexes[ndx], &addrLen,
845                ptr->Address, &type);
846               /* MS defines address length and type as UINT in some places and
847                  DWORD in others, **sigh**.  Don't want to assume that PUINT and
848                  PDWORD are equiv (64-bit?) */
849               ptr->AddressLength = addrLen;
850               ptr->Type = type;
851               ptr->Index = table->indexes[ndx];
852               toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
853                ptr->IpAddressList.IpAddress.String);
854               toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
855                ptr->IpAddressList.IpMask.String);
856               ptr->IpAddressList.Context = ptr->Index;
857               toIPAddressString(getInterfaceGatewayByIndex(table->indexes[ndx]),
858                ptr->GatewayList.IpAddress.String);
859               getDhcpInfoForAdapter(table->indexes[ndx], &dhcpEnabled,
860                                     &dhcpServer, &ptr->LeaseObtained,
861                                     &ptr->LeaseExpires);
862               ptr->DhcpEnabled = (DWORD) dhcpEnabled;
863               toIPAddressString(dhcpServer,
864                                 ptr->DhcpServer.IpAddress.String);
865               if (winsEnabled) {
866                 ptr->HaveWins = TRUE;
867                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
868                  primaryWINS.String, sizeof(primaryWINS.String));
869                 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
870                  secondaryWINS.String, sizeof(secondaryWINS.String));
871               }
872               if (ndx < table->numIndexes - 1)
873                 ptr->Next = &pAdapterInfo[ndx + 1];
874               else
875                 ptr->Next = NULL;
876             }
877             ret = NO_ERROR;
878           }
879           free(table);
880         }
881         else
882           ret = ERROR_OUTOFMEMORY;
883       }
884     }
885     else
886       ret = ERROR_NO_DATA;
887   }
888   TRACE("returning %ld\n", ret);
889   return ret;
890 }
891 
892 
893 /******************************************************************
894  *    GetBestInterface (IPHLPAPI.@)
895  *
896  *
897  * PARAMS
898  *
899  *  dwDestAddr [In]
900  *  pdwBestIfIndex [In/Out]
901  *
902  * RETURNS
903  *
904  *  DWORD
905  *
906  */
907 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
908 {
909   DWORD ret;
910 
911   TRACE("dwDestAddr 0x%08lx, pdwBestIfIndex %p\n", dwDestAddr, pdwBestIfIndex);
912   if (!pdwBestIfIndex)
913     ret = ERROR_INVALID_PARAMETER;
914   else {
915     MIB_IPFORWARDROW ipRow;
916 
917     ret = GetBestRoute(dwDestAddr, 0, &ipRow);
918     if (ret == ERROR_SUCCESS)
919       *pdwBestIfIndex = ipRow.dwForwardIfIndex;
920   }
921   TRACE("returning %ld\n", ret);
922   return ret;
923 }
924 
925 
926 /******************************************************************
927  *    GetBestRoute (IPHLPAPI.@)
928  *
929  *
930  * PARAMS
931  *
932  *  dwDestAddr [In]
933  *  dwSourceAddr [In]
934  *  OUT [In]
935  *
936  * RETURNS
937  *
938  *  DWORD
939  *
940  */
941 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
942 {
943   PMIB_IPFORWARDTABLE table;
944   DWORD ret;
945 
946   TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr,
947    dwSourceAddr, pBestRoute);
948   if (!pBestRoute)
949     return ERROR_INVALID_PARAMETER;
950 
951   AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
952   if (table) {
953     DWORD ndx, minMaskSize, matchedNdx = 0;
954 
955     for (ndx = 0, minMaskSize = 255; ndx < table->dwNumEntries; ndx++) {
956       if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
957        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
958         DWORD hostMaskSize;
959 
960         if (!_BitScanForward(&hostMaskSize, ntohl(table->table[ndx].dwForwardMask)))
961         {
962             hostMaskSize = 32;
963         }
964         if (hostMaskSize < minMaskSize) {
965           minMaskSize = hostMaskSize;
966           matchedNdx = ndx;
967         }
968       }
969     }
970     memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
971     HeapFree(GetProcessHeap(), 0, table);
972     ret = ERROR_SUCCESS;
973   }
974   else
975     ret = ERROR_OUTOFMEMORY;
976   TRACE("returning %ld\n", ret);
977   return ret;
978 }
979 
980 static int TcpTableSorter(const void *a, const void *b)
981 {
982   int ret;
983 
984   if (a && b) {
985     PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
986 
987     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
988     if (ret == 0) {
989       ret = rowA->dwLocalPort - rowB->dwLocalPort;
990       if (ret == 0) {
991         ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
992         if (ret == 0)
993           ret = rowA->dwRemotePort - rowB->dwRemotePort;
994       }
995     }
996   }
997   else
998     ret = 0;
999   return ret;
1000 }
1001 
1002 /******************************************************************
1003  *    GetExtendedTcpTable (IPHLPAPI.@)
1004  *
1005  * Get the table of TCP endpoints available to the application.
1006  *
1007  * PARAMS
1008  *  pTcpTable [Out]    table struct with the filtered TCP endpoints available to application
1009  *  pdwSize   [In/Out] estimated size of the structure returned in pTcpTable, in bytes
1010  *  bOrder    [In]     whether to order the table
1011  *  ulAf	[in]	version of IP used by the TCP endpoints
1012  *  TableClass [in]	type of the TCP table structure from TCP_TABLE_CLASS
1013  *  Reserved [in]	reserved - this value must be zero
1014  *
1015  * RETURNS
1016  *  Success: NO_ERROR
1017  *  Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
1018  *
1019  * NOTES
1020  */
1021 
1022 DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
1023 {
1024     DWORD i, count, size;
1025 	DWORD ret = NO_ERROR;
1026 
1027     if (!pdwSize)
1028     {
1029         return ERROR_INVALID_PARAMETER;
1030     }
1031 
1032     if (ulAf != AF_INET)
1033     {
1034         UNIMPLEMENTED;
1035         return ERROR_INVALID_PARAMETER;
1036     }
1037 
1038     switch (TableClass)
1039     {
1040         case TCP_TABLE_BASIC_ALL:
1041         {
1042             PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
1043             PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
1044 
1045             if (pOurTcpTable)
1046             {
1047                 size = FIELD_OFFSET(MIB_TCPTABLE, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW);
1048                 if (size > *pdwSize || !pTheirTcpTable)
1049                 {
1050                     *pdwSize = size;
1051                     ret = ERROR_INSUFFICIENT_BUFFER;
1052                 }
1053                 else
1054                 {
1055                     memcpy(pTheirTcpTable, pOurTcpTable, size);
1056 
1057                     if (bOrder)
1058                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1059                               sizeof(MIB_TCPROW), TcpTableSorter);
1060                 }
1061 
1062                 HeapFree(GetProcessHeap(),0, pOurTcpTable);
1063             }
1064         }
1065         break;
1066 
1067         case TCP_TABLE_BASIC_CONNECTIONS:
1068         {
1069             PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
1070             PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
1071 
1072             if (pOurTcpTable)
1073             {
1074                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1075                 {
1076                     if (pOurTcpTable->table[i].State != MIB_TCP_STATE_LISTEN)
1077                     {
1078                         ++count;
1079                     }
1080                 }
1081 
1082                 size = FIELD_OFFSET(MIB_TCPTABLE, table) + count * sizeof(MIB_TCPROW);
1083                 if (size > *pdwSize || !pTheirTcpTable)
1084                 {
1085                     *pdwSize = size;
1086                     ret = ERROR_INSUFFICIENT_BUFFER;
1087                 }
1088                 else
1089                 {
1090                     pTheirTcpTable->dwNumEntries = count;
1091 
1092                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1093                     {
1094                         if (pOurTcpTable->table[i].State != MIB_TCP_STATE_LISTEN)
1095                         {
1096                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW));
1097                             ++count;
1098                         }
1099                     }
1100                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1101 
1102                     if (bOrder)
1103                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1104                               sizeof(MIB_TCPROW), TcpTableSorter);
1105                 }
1106 
1107                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1108             }
1109         }
1110         break;
1111 
1112         case TCP_TABLE_BASIC_LISTENER:
1113         {
1114             PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
1115             PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
1116 
1117             if (pOurTcpTable)
1118             {
1119                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1120                 {
1121                     if (pOurTcpTable->table[i].State == MIB_TCP_STATE_LISTEN)
1122                     {
1123                         ++count;
1124                     }
1125                 }
1126 
1127                 size = FIELD_OFFSET(MIB_TCPTABLE, table) + count * sizeof(MIB_TCPROW);
1128                 if (size > *pdwSize || !pTheirTcpTable)
1129                 {
1130                     *pdwSize = size;
1131                     ret = ERROR_INSUFFICIENT_BUFFER;
1132                 }
1133                 else
1134                 {
1135                     pTheirTcpTable->dwNumEntries = count;
1136 
1137                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1138                     {
1139                         if (pOurTcpTable->table[i].State == MIB_TCP_STATE_LISTEN)
1140                         {
1141                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW));
1142                             ++count;
1143                         }
1144                     }
1145                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1146 
1147                     if (bOrder)
1148                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1149                               sizeof(MIB_TCPROW), TcpTableSorter);
1150                 }
1151 
1152                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1153             }
1154         }
1155         break;
1156 
1157         case TCP_TABLE_OWNER_PID_ALL:
1158         {
1159             PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
1160             PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1161 
1162             if (pOurTcpTable)
1163             {
1164                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_PID);
1165                 if (size > *pdwSize || !pTheirTcpTable)
1166                 {
1167                     *pdwSize = size;
1168                     ret = ERROR_INSUFFICIENT_BUFFER;
1169                 }
1170                 else
1171                 {
1172                     memcpy(pTheirTcpTable, pOurTcpTable, size);
1173 
1174                     /* Don't sort on PID, so use basic helper */
1175                     if (bOrder)
1176                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1177                               sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1178                 }
1179 
1180                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1181             }
1182         }
1183         break;
1184 
1185         case TCP_TABLE_OWNER_PID_CONNECTIONS:
1186         {
1187             PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
1188             PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1189 
1190             if (pOurTcpTable)
1191             {
1192                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1193                 {
1194                     if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1195                     {
1196                         ++count;
1197                     }
1198                 }
1199 
1200                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + count * sizeof(MIB_TCPROW_OWNER_PID);
1201                 if (size > *pdwSize || !pTheirTcpTable)
1202                 {
1203                     *pdwSize = size;
1204                     ret = ERROR_INSUFFICIENT_BUFFER;
1205                 }
1206                 else
1207                 {
1208                     pTheirTcpTable->dwNumEntries = count;
1209 
1210                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1211                     {
1212                         if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1213                         {
1214                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_PID));
1215                             ++count;
1216                         }
1217                     }
1218                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1219 
1220                     /* Don't sort on PID, so use basic helper */
1221                     if (bOrder)
1222                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1223                               sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1224                 }
1225 
1226                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1227             }
1228         }
1229         break;
1230 
1231         case TCP_TABLE_OWNER_PID_LISTENER:
1232         {
1233             PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
1234             PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1235 
1236             if (pOurTcpTable)
1237             {
1238                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1239                 {
1240                     if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1241                     {
1242                         ++count;
1243                     }
1244                 }
1245 
1246                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + count * sizeof(MIB_TCPROW_OWNER_PID);
1247                 if (size > *pdwSize || !pTheirTcpTable)
1248                 {
1249                     *pdwSize = size;
1250                     ret = ERROR_INSUFFICIENT_BUFFER;
1251                 }
1252                 else
1253                 {
1254                     pTheirTcpTable->dwNumEntries = count;
1255 
1256                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1257                     {
1258                         if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1259                         {
1260                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_PID));
1261                             ++count;
1262                         }
1263                     }
1264                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1265 
1266                     /* Don't sort on PID, so use basic helper */
1267                     if (bOrder)
1268                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1269                               sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1270                 }
1271 
1272                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1273             }
1274         }
1275         break;
1276 
1277         case TCP_TABLE_OWNER_MODULE_ALL:
1278         {
1279             PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getTcpTable(ClassModule);
1280             PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1281 
1282             if (pOurTcpTable)
1283             {
1284                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_MODULE);
1285                 if (size > *pdwSize || !pTheirTcpTable)
1286                 {
1287                     *pdwSize = size;
1288                     ret = ERROR_INSUFFICIENT_BUFFER;
1289                 }
1290                 else
1291                 {
1292                     memcpy(pTheirTcpTable, pOurTcpTable, size);
1293 
1294                     /* Don't sort on PID, so use basic helper */
1295                     if (bOrder)
1296                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1297                               sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1298                 }
1299 
1300                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1301             }
1302         }
1303         break;
1304 
1305         case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
1306         {
1307             PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getTcpTable(ClassModule);
1308             PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1309 
1310             if (pOurTcpTable)
1311             {
1312                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1313                 {
1314                     if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1315                     {
1316                         ++count;
1317                     }
1318                 }
1319 
1320                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table) + count * sizeof(MIB_TCPROW_OWNER_MODULE);
1321                 if (size > *pdwSize || !pTheirTcpTable)
1322                 {
1323                     *pdwSize = size;
1324                     ret = ERROR_INSUFFICIENT_BUFFER;
1325                 }
1326                 else
1327                 {
1328                     pTheirTcpTable->dwNumEntries = count;
1329 
1330                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1331                     {
1332                         if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1333                         {
1334                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_MODULE));
1335                             ++count;
1336                         }
1337                     }
1338                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1339 
1340                     /* Don't sort on PID, so use basic helper */
1341                     if (bOrder)
1342                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1343                               sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1344                 }
1345 
1346                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1347             }
1348         }
1349         break;
1350 
1351         case TCP_TABLE_OWNER_MODULE_LISTENER:
1352         {
1353             PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getTcpTable(ClassModule);
1354             PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1355 
1356             if (pOurTcpTable)
1357             {
1358                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1359                 {
1360                     if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1361                     {
1362                         ++count;
1363                     }
1364                 }
1365 
1366                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table) + count * sizeof(MIB_TCPROW_OWNER_MODULE);
1367                 if (size > *pdwSize || !pTheirTcpTable)
1368                 {
1369                     *pdwSize = size;
1370                     ret = ERROR_INSUFFICIENT_BUFFER;
1371                 }
1372                 else
1373                 {
1374                     pTheirTcpTable->dwNumEntries = count;
1375 
1376                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1377                     {
1378                         if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1379                         {
1380                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_MODULE));
1381                             ++count;
1382                         }
1383                     }
1384                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1385 
1386                     /* Don't sort on PID, so use basic helper */
1387                     if (bOrder)
1388                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1389                               sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1390                 }
1391 
1392                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1393             }
1394         }
1395         break;
1396 
1397         default:
1398             ret = ERROR_INVALID_PARAMETER;
1399             break;
1400     }
1401 
1402     return ret;
1403 }
1404 
1405 
1406 static int UdpTableSorter(const void *a, const void *b)
1407 {
1408   int ret;
1409 
1410   if (a && b) {
1411     PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
1412 
1413     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1414     if (ret == 0)
1415       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1416   }
1417   else
1418     ret = 0;
1419   return ret;
1420 }
1421 
1422 /******************************************************************
1423  *    GetExtendedUdpTable (IPHLPAPI.@)
1424  *
1425  * Get the table of UDP endpoints available to the application.
1426  *
1427  * PARAMS
1428  *  pUdpTable [Out]    table struct with the filtered UDP endpoints available to application
1429  *  pdwSize   [In/Out] estimated size of the structure returned in pUdpTable, in bytes
1430  *  bOrder    [In]     whether to order the table
1431  *  ulAf	[in]	version of IP used by the UDP endpoints
1432  *  TableClass [in]	type of the UDP table structure from UDP_TABLE_CLASS
1433  *  Reserved [in]	reserved - this value must be zero
1434  *
1435  * RETURNS
1436  *  Success: NO_ERROR
1437  *  Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
1438  *
1439  * NOTES
1440  */
1441 
1442 DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved)
1443 {
1444     DWORD size;
1445 	DWORD ret = NO_ERROR;
1446 
1447     if (!pdwSize)
1448     {
1449         return ERROR_INVALID_PARAMETER;
1450     }
1451 
1452     if (ulAf != AF_INET)
1453     {
1454         UNIMPLEMENTED;
1455         return ERROR_INVALID_PARAMETER;
1456     }
1457 
1458     switch (TableClass)
1459     {
1460         case UDP_TABLE_BASIC:
1461         {
1462             PMIB_UDPTABLE pOurUdpTable = getUdpTable(ClassBasic);
1463             PMIB_UDPTABLE pTheirUdpTable = pUdpTable;
1464 
1465             if (pOurUdpTable)
1466             {
1467                 size = FIELD_OFFSET(MIB_UDPTABLE, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW);
1468                 if (size > *pdwSize || !pTheirUdpTable)
1469                 {
1470                     *pdwSize = size;
1471                     ret = ERROR_INSUFFICIENT_BUFFER;
1472                 }
1473                 else
1474                 {
1475                     memcpy(pTheirUdpTable, pOurUdpTable, size);
1476 
1477                     if (bOrder)
1478                         qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1479                               sizeof(MIB_UDPROW), UdpTableSorter);
1480                 }
1481 
1482                 HeapFree(GetProcessHeap(), 0, pOurUdpTable);
1483             }
1484         }
1485         break;
1486 
1487         case UDP_TABLE_OWNER_PID:
1488         {
1489             PMIB_UDPTABLE_OWNER_PID pOurUdpTable = getUdpTable(ClassModulePid);
1490             PMIB_UDPTABLE_OWNER_PID pTheirUdpTable = pUdpTable;
1491 
1492             if (pOurUdpTable)
1493             {
1494                 size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_PID);
1495                 if (size > *pdwSize || !pTheirUdpTable)
1496                 {
1497                     *pdwSize = size;
1498                     ret = ERROR_INSUFFICIENT_BUFFER;
1499                 }
1500                 else
1501                 {
1502                     memcpy(pTheirUdpTable, pOurUdpTable, size);
1503 
1504                     if (bOrder)
1505                         qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1506                               sizeof(MIB_UDPROW_OWNER_PID), UdpTableSorter);
1507                 }
1508 
1509                 HeapFree(GetProcessHeap(), 0, pOurUdpTable);
1510             }
1511         }
1512         break;
1513 
1514         case UDP_TABLE_OWNER_MODULE:
1515         {
1516             PMIB_UDPTABLE_OWNER_MODULE pOurUdpTable = getUdpTable(ClassModule);
1517             PMIB_UDPTABLE_OWNER_MODULE pTheirUdpTable = pUdpTable;
1518 
1519             if (pOurUdpTable)
1520             {
1521                 size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_MODULE);
1522                 if (size > *pdwSize || !pTheirUdpTable)
1523                 {
1524                     *pdwSize = size;
1525                     ret = ERROR_INSUFFICIENT_BUFFER;
1526                 }
1527                 else
1528                 {
1529                     memcpy(pTheirUdpTable, pOurUdpTable, size);
1530 
1531                     if (bOrder)
1532                         qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1533                               sizeof(MIB_UDPROW_OWNER_MODULE), UdpTableSorter);
1534                 }
1535 
1536                 HeapFree(GetProcessHeap(), 0, pOurUdpTable);
1537             }
1538         }
1539         break;
1540 
1541         default:
1542             ret = ERROR_INVALID_PARAMETER;
1543             break;
1544     }
1545 
1546     return ret;
1547 }
1548 
1549 
1550 /******************************************************************
1551  *    GetFriendlyIfIndex (IPHLPAPI.@)
1552  *
1553  *
1554  * PARAMS
1555  *
1556  *  IfIndex [In]
1557  *
1558  * RETURNS
1559  *
1560  *  DWORD
1561  *
1562  */
1563 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1564 {
1565   /* windows doesn't validate these, either, just makes sure the top byte is
1566      cleared.  I assume my ifenum module never gives an index with the top
1567      byte set. */
1568   TRACE("returning %ld\n", IfIndex);
1569   return IfIndex;
1570 }
1571 
1572 
1573 /******************************************************************
1574  *    GetIcmpStatistics (IPHLPAPI.@)
1575  *
1576  *
1577  * PARAMS
1578  *
1579  *  pStats [In/Out]
1580  *
1581  * RETURNS
1582  *
1583  *  DWORD
1584  *
1585  */
1586 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
1587 {
1588   DWORD ret;
1589 
1590   TRACE("pStats %p\n", pStats);
1591   ret = getICMPStats(pStats);
1592   TRACE("returning %ld\n", ret);
1593   return ret;
1594 }
1595 
1596 
1597 /******************************************************************
1598  *    GetIfEntry (IPHLPAPI.@)
1599  *
1600  *
1601  * PARAMS
1602  *
1603  *  pIfRow [In/Out]
1604  *
1605  * RETURNS
1606  *
1607  *  DWORD
1608  *
1609  */
1610 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
1611 {
1612   DWORD ret;
1613   const char *name;
1614 
1615   TRACE("pIfRow %p\n", pIfRow);
1616   if (!pIfRow)
1617     return ERROR_INVALID_PARAMETER;
1618 
1619   name = getInterfaceNameByIndex(pIfRow->dwIndex);
1620   if (name) {
1621     ret = getInterfaceEntryByIndex(pIfRow->dwIndex, pIfRow);
1622     if (ret == NO_ERROR)
1623       ret = getInterfaceStatsByName(name, pIfRow);
1624     consumeInterfaceName(name);
1625   }
1626   else
1627     ret = ERROR_INVALID_DATA;
1628   TRACE("returning %ld\n", ret);
1629   return ret;
1630 }
1631 
1632 
1633 static int IfTableSorter(const void *a, const void *b)
1634 {
1635   int ret;
1636 
1637   if (a && b)
1638     ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
1639   else
1640     ret = 0;
1641   return ret;
1642 }
1643 
1644 
1645 /******************************************************************
1646  *    GetIfTable (IPHLPAPI.@)
1647  *
1648  *
1649  * PARAMS
1650  *
1651  *  pIfTable [In/Out]
1652  *  pdwSize [In/Out]
1653  *  bOrder [In]
1654  *
1655  * RETURNS
1656  *
1657  *  DWORD
1658  *
1659  */
1660 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
1661 {
1662   DWORD ret;
1663 
1664   TRACE("pIfTable %p, pdwSize %p, bOrder %ld\n", pdwSize, pdwSize,
1665    (DWORD)bOrder);
1666   if (!pdwSize)
1667     ret = ERROR_INVALID_PARAMETER;
1668   else {
1669     DWORD numInterfaces = getNumInterfaces();
1670     ULONG size;
1671     TRACE("GetIfTable: numInterfaces = %d\n", (int)numInterfaces);
1672     size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
1673 
1674     if (!pIfTable || *pdwSize < size) {
1675       *pdwSize = size;
1676       ret = ERROR_INSUFFICIENT_BUFFER;
1677     }
1678     else {
1679       InterfaceIndexTable *table = getInterfaceIndexTable();
1680 
1681       if (table) {
1682         size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
1683          sizeof(MIB_IFROW);
1684         if (*pdwSize < size) {
1685           *pdwSize = size;
1686           ret = ERROR_INSUFFICIENT_BUFFER;
1687         }
1688         else {
1689           DWORD ndx;
1690 
1691           pIfTable->dwNumEntries = 0;
1692           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1693             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
1694             GetIfEntry(&pIfTable->table[ndx]);
1695             pIfTable->dwNumEntries++;
1696           }
1697           if (bOrder)
1698             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
1699              IfTableSorter);
1700           ret = NO_ERROR;
1701         }
1702         free(table);
1703       }
1704       else
1705         ret = ERROR_OUTOFMEMORY;
1706     }
1707   }
1708   TRACE("returning %ld\n", ret);
1709   return ret;
1710 }
1711 
1712 
1713 /******************************************************************
1714  *    GetInterfaceInfo (IPHLPAPI.@)
1715  *
1716  *
1717  * PARAMS
1718  *
1719  *  pIfTable [In/Out]
1720  *  dwOutBufLen [In/Out]
1721  *
1722  * RETURNS
1723  *
1724  *  DWORD
1725  *
1726  */
1727 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
1728 {
1729   DWORD ret;
1730 
1731   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
1732   if (!dwOutBufLen)
1733     ret = ERROR_INVALID_PARAMETER;
1734   else {
1735     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
1736     ULONG size;
1737     TRACE("numNonLoopbackInterfaces == 0x%x\n", numNonLoopbackInterfaces);
1738     size = sizeof(IP_INTERFACE_INFO) + (numNonLoopbackInterfaces) *
1739      sizeof(IP_ADAPTER_INDEX_MAP);
1740 
1741     if (!pIfTable || *dwOutBufLen < size) {
1742       *dwOutBufLen = size;
1743       ret = ERROR_INSUFFICIENT_BUFFER;
1744     }
1745     else {
1746       InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
1747 
1748       if (table) {
1749         TRACE("table->numIndexes == 0x%x\n", table->numIndexes);
1750         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes) *
1751          sizeof(IP_ADAPTER_INDEX_MAP);
1752         if (*dwOutBufLen < size) {
1753           *dwOutBufLen = size;
1754           ret = ERROR_INSUFFICIENT_BUFFER;
1755         }
1756         else {
1757           DWORD ndx;
1758 
1759           pIfTable->NumAdapters = 0;
1760           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1761             const char *walker, *name;
1762             WCHAR *assigner;
1763 
1764             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
1765             name = getInterfaceNameByIndex(table->indexes[ndx]);
1766             wcscpy(pIfTable->Adapter[ndx].Name, L"\\DEVICE\\TCPIP_");
1767             for (walker = name, assigner = &pIfTable->Adapter[ndx].Name[14];
1768              walker && *walker &&
1769              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1 - 14;
1770              walker++, assigner++)
1771               *assigner = *walker;
1772             *assigner = 0;
1773             consumeInterfaceName(name);
1774             pIfTable->NumAdapters++;
1775           }
1776           ret = NO_ERROR;
1777         }
1778         free(table);
1779       }
1780       else
1781         ret = ERROR_OUTOFMEMORY;
1782     }
1783   }
1784   TRACE("returning %ld\n", ret);
1785   return ret;
1786 }
1787 
1788 
1789 static int IpAddrTableSorter(const void *a, const void *b)
1790 {
1791   int ret;
1792 
1793   if (a && b)
1794     ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
1795   else
1796     ret = 0;
1797   return ret;
1798 }
1799 
1800 
1801 /******************************************************************
1802  *    GetIpAddrTable (IPHLPAPI.@)
1803  *
1804  *
1805  * PARAMS
1806  *
1807  *  pIpAddrTable [In/Out]
1808  *  pdwSize [In/Out]
1809  *  bOrder [In]
1810  *
1811  * RETURNS
1812  *
1813  *  DWORD
1814  *
1815  */
1816 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1817 {
1818   DWORD ret;
1819 
1820   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
1821    (DWORD)bOrder);
1822   if (!pdwSize)
1823     ret = ERROR_INVALID_PARAMETER;
1824   else {
1825     DWORD numInterfaces = getNumInterfaces();
1826     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
1827      sizeof(MIB_IPADDRROW);
1828 
1829     if (!pIpAddrTable || *pdwSize < size) {
1830       *pdwSize = size;
1831       ret = ERROR_INSUFFICIENT_BUFFER;
1832     }
1833     else {
1834       InterfaceIndexTable *table = getInterfaceIndexTable();
1835 
1836       if (table) {
1837         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
1838          sizeof(MIB_IPADDRROW);
1839         if (*pdwSize < size) {
1840           *pdwSize = size;
1841           ret = ERROR_INSUFFICIENT_BUFFER;
1842         }
1843         else {
1844           DWORD ndx, bcast;
1845 
1846           pIpAddrTable->dwNumEntries = 0;
1847           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1848             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
1849             pIpAddrTable->table[ndx].dwAddr =
1850              getInterfaceIPAddrByIndex(table->indexes[ndx]);
1851             pIpAddrTable->table[ndx].dwMask =
1852              getInterfaceMaskByIndex(table->indexes[ndx]);
1853             /* the dwBCastAddr member isn't the broadcast address, it indicates
1854              * whether the interface uses the 1's broadcast address (1) or the
1855              * 0's broadcast address (0).
1856              */
1857             bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
1858             pIpAddrTable->table[ndx].dwBCastAddr =
1859              (bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
1860             /* FIXME: hardcoded reasm size, not sure where to get it */
1861             pIpAddrTable->table[ndx].dwReasmSize = 65535;
1862             pIpAddrTable->table[ndx].unused1 = 0;
1863             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
1864             pIpAddrTable->dwNumEntries++;
1865           }
1866           if (bOrder)
1867             qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1868              sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1869           ret = NO_ERROR;
1870         }
1871         free(table);
1872       }
1873       else
1874         ret = ERROR_OUTOFMEMORY;
1875     }
1876   }
1877   TRACE("returning %ld\n", ret);
1878   return ret;
1879 }
1880 
1881 
1882 static int IpForwardTableSorter(const void *a, const void *b)
1883 {
1884   int ret;
1885 
1886   if (a && b) {
1887     PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
1888 
1889     ret = rowA->dwForwardDest - rowB->dwForwardDest;
1890     if (ret == 0) {
1891       ret = rowA->dwForwardProto - rowB->dwForwardProto;
1892       if (ret == 0) {
1893         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
1894         if (ret == 0)
1895           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1896       }
1897     }
1898   }
1899   else
1900     ret = 0;
1901   return ret;
1902 }
1903 
1904 
1905 /******************************************************************
1906  *    GetIpForwardTable (IPHLPAPI.@)
1907  *
1908  *
1909  * PARAMS
1910  *
1911  *  pIpForwardTable [In/Out]
1912  *  pdwSize [In/Out]
1913  *  bOrder [In]
1914  *
1915  * RETURNS
1916  *
1917  *  DWORD
1918  *
1919  */
1920 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1921 {
1922   DWORD ret;
1923 
1924   TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
1925         pdwSize, (DWORD)bOrder);
1926   if (!pdwSize)
1927     ret = ERROR_INVALID_PARAMETER;
1928   else {
1929     DWORD numRoutes = getNumRoutes();
1930     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1931      sizeof(MIB_IPFORWARDROW);
1932 
1933     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1934       *pdwSize = sizeNeeded;
1935       ret = ERROR_INSUFFICIENT_BUFFER;
1936     }
1937     else {
1938       RouteTable *table = getRouteTable();
1939       if (table) {
1940         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1941          sizeof(MIB_IPFORWARDROW);
1942         if (*pdwSize < sizeNeeded) {
1943           *pdwSize = sizeNeeded;
1944           ret = ERROR_INSUFFICIENT_BUFFER;
1945         }
1946         else {
1947           DWORD ndx;
1948 
1949           pIpForwardTable->dwNumEntries = table->numRoutes;
1950           for (ndx = 0; ndx < numRoutes; ndx++) {
1951             pIpForwardTable->table[ndx].dwForwardIfIndex =
1952              table->routes[ndx].ifIndex;
1953             pIpForwardTable->table[ndx].dwForwardDest =
1954              table->routes[ndx].dest;
1955             pIpForwardTable->table[ndx].dwForwardMask =
1956              table->routes[ndx].mask;
1957             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1958             pIpForwardTable->table[ndx].dwForwardNextHop =
1959              table->routes[ndx].gateway;
1960             /* FIXME: this type is appropriate for local interfaces; may not
1961                always be appropriate */
1962             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1963             /* FIXME: other protos might be appropriate, e.g. the default route
1964                is typically set with MIB_IPPROTO_NETMGMT instead */
1965             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1966             /* punt on age and AS */
1967             pIpForwardTable->table[ndx].dwForwardAge = 0;
1968             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1969             pIpForwardTable->table[ndx].dwForwardMetric1 =
1970              table->routes[ndx].metric;
1971             /* rest of the metrics are 0.. */
1972             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1973             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1974             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1975             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1976           }
1977           if (bOrder)
1978             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1979              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1980           ret = NO_ERROR;
1981         }
1982         HeapFree(GetProcessHeap(), 0, table);
1983       }
1984       else
1985         ret = ERROR_OUTOFMEMORY;
1986     }
1987   }
1988   TRACE("returning %ld\n", ret);
1989   return ret;
1990 }
1991 
1992 
1993 static int IpNetTableSorter(const void *a, const void *b)
1994 {
1995   int ret;
1996 
1997   if (a && b)
1998     ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
1999   else
2000     ret = 0;
2001   return ret;
2002 }
2003 
2004 
2005 /******************************************************************
2006  *    GetIpNetTable (IPHLPAPI.@)
2007  *
2008  *
2009  * PARAMS
2010  *
2011  *  pIpNetTable [In/Out]
2012  *  pdwSize [In/Out]
2013  *  bOrder [In]
2014  *
2015  * RETURNS
2016  *
2017  *  DWORD
2018  *
2019  */
2020 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
2021 {
2022   DWORD ret = NO_ERROR;
2023 
2024   TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize,
2025    (DWORD)bOrder);
2026   if (!pdwSize)
2027     ret = ERROR_INVALID_PARAMETER;
2028   else {
2029     DWORD numEntries = getNumArpEntries();
2030     ULONG size = sizeof(MIB_IPNETTABLE);
2031 
2032     if (numEntries > 1)
2033       size += (numEntries - 1) * sizeof(MIB_IPNETROW);
2034     if (!pIpNetTable || *pdwSize < size) {
2035       *pdwSize = size;
2036       ret = ERROR_INSUFFICIENT_BUFFER;
2037     }
2038     else {
2039       PMIB_IPNETTABLE table = getArpTable();
2040       if (table) {
2041         size = sizeof(MIB_IPNETTABLE);
2042         if (table->dwNumEntries > 1)
2043           size += (table->dwNumEntries - 1) * sizeof(MIB_IPNETROW);
2044         if (*pdwSize < size) {
2045           *pdwSize = size;
2046           ret = ERROR_INSUFFICIENT_BUFFER;
2047         }
2048         else {
2049           *pdwSize = size;
2050           memcpy(pIpNetTable, table, size);
2051           if (bOrder)
2052             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
2053              sizeof(MIB_IPNETROW), IpNetTableSorter);
2054           ret = NO_ERROR;
2055         }
2056         HeapFree(GetProcessHeap(), 0, table);
2057       }
2058     }
2059   }
2060   TRACE("returning %d\n", ret);
2061   return ret;
2062 }
2063 
2064 
2065 /******************************************************************
2066  *    GetIpStatistics (IPHLPAPI.@)
2067  *
2068  *
2069  * PARAMS
2070  *
2071  *  pStats [In/Out]
2072  *
2073  * RETURNS
2074  *
2075  *  DWORD
2076  *
2077  */
2078 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
2079 {
2080     return GetIpStatisticsEx(pStats, PF_INET);
2081 }
2082 
2083 /******************************************************************
2084  *    GetIpStatisticsEx (IPHLPAPI.@)
2085  *
2086  *
2087  * PARAMS
2088  *
2089  *  pStats [In/Out]
2090  *  dwFamily [In]
2091  *
2092  * RETURNS
2093  *
2094  *  DWORD
2095  *
2096  */
2097 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily)
2098 {
2099   DWORD ret;
2100 
2101   TRACE("pStats %p\n", pStats);
2102   ret = getIPStats(pStats, dwFamily);
2103   TRACE("returning %ld\n", ret);
2104   return ret;
2105 }
2106 
2107 /******************************************************************
2108  *    GetNetworkParams (IPHLPAPI.@)
2109  *
2110  *
2111  * PARAMS
2112  *
2113  *  pFixedInfo [In/Out]
2114  *  pOutBufLen [In/Out]
2115  *
2116  * RETURNS
2117  *
2118  *  DWORD
2119  *
2120  */
2121 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
2122 {
2123   DWORD ret, size, type;
2124   LONG regReturn;
2125   HKEY hKey;
2126   PIPHLP_RES_INFO resInfo;
2127 
2128   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
2129   if (!pOutBufLen)
2130     return ERROR_INVALID_PARAMETER;
2131 
2132   resInfo = getResInfo();
2133   if (!resInfo)
2134     return ERROR_OUTOFMEMORY;
2135 
2136   size = sizeof(FIXED_INFO) + (resInfo->riCount > 1 ? (resInfo->riCount-1) *
2137    sizeof(IP_ADDR_STRING) : 0);
2138   if (!pFixedInfo || *pOutBufLen < size) {
2139     *pOutBufLen = size;
2140     disposeResInfo( resInfo );
2141     return ERROR_BUFFER_OVERFLOW;
2142   }
2143 
2144   memset(pFixedInfo, 0, size);
2145   /* Check for DhcpHostname and DhcpDomain first */
2146   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2147                             "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
2148                             0,
2149                             KEY_READ,
2150                             &hKey);
2151   if (regReturn == ERROR_SUCCESS) {
2152       /* Windows doesn't honor DHCP option 12 even if RFC requires it if it is returned by DHCP server! */
2153 #if 0
2154       type = REG_SZ;
2155       size = sizeof(pFixedInfo->HostName);
2156       regReturn = RegQueryValueExA(hKey,
2157                                       "DhcpHostname",
2158                                       NULL,
2159                                       &type,
2160                                       (LPBYTE)pFixedInfo->HostName,
2161                                       &size);
2162       if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
2163       {
2164 #endif
2165           type = REG_SZ;
2166           size = sizeof(pFixedInfo->HostName);
2167           regReturn = RegQueryValueExA(hKey,
2168                                           "Hostname",
2169                                           NULL,
2170                                           &type,
2171                                           (LPBYTE)pFixedInfo->HostName,
2172                                           &size);
2173 #if 0
2174       }
2175 #endif
2176 
2177       type = REG_SZ;
2178       size = sizeof(pFixedInfo->DomainName);
2179       regReturn = RegQueryValueExA(hKey,
2180                                       "DhcpDomain",
2181                                       NULL,
2182                                       &type,
2183                                       (LPBYTE)pFixedInfo->DomainName,
2184                                       &size);
2185       if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
2186       {
2187           type = REG_SZ;
2188           size = sizeof(pFixedInfo->DomainName);
2189           regReturn = RegQueryValueExA(hKey,
2190                                           "Domain",
2191                                           NULL,
2192                                           &type,
2193                                           (LPBYTE)pFixedInfo->DomainName,
2194                                           &size);
2195       }
2196       RegCloseKey(hKey);
2197   }
2198 
2199   TRACE("GetComputerNameExA: %s\n", pFixedInfo->DomainName);
2200 
2201   if (resInfo->riCount > 0)
2202   {
2203     CopyMemory(&pFixedInfo->DnsServerList, resInfo->DnsList, sizeof(IP_ADDR_STRING));
2204     if (resInfo->riCount > 1)
2205     {
2206       IP_ADDR_STRING *pSrc = resInfo->DnsList->Next;
2207       IP_ADDR_STRING *pTarget = (struct _IP_ADDR_STRING*)((char*)pFixedInfo + sizeof(FIXED_INFO));
2208 
2209       pFixedInfo->DnsServerList.Next = pTarget;
2210 
2211       do
2212       {
2213         CopyMemory(pTarget, pSrc, sizeof(IP_ADDR_STRING));
2214         resInfo->riCount--;
2215         if (resInfo->riCount > 1)
2216         {
2217           pTarget->Next = (IP_ADDR_STRING*)((char*)pTarget + sizeof(IP_ADDR_STRING));
2218           pTarget = pTarget->Next;
2219           pSrc = pSrc->Next;
2220         }
2221         else
2222         {
2223           pTarget->Next = NULL;
2224           break;
2225         }
2226       }
2227       while(TRUE);
2228     }
2229     else
2230     {
2231       pFixedInfo->DnsServerList.Next = NULL;
2232     }
2233   }
2234 
2235   pFixedInfo->NodeType = HYBRID_NODETYPE;
2236   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2237    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
2238   if (regReturn != ERROR_SUCCESS)
2239     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2240      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
2241      &hKey);
2242   if (regReturn == ERROR_SUCCESS)
2243   {
2244     DWORD size = sizeof(pFixedInfo->ScopeId);
2245 
2246     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (PBYTE)pFixedInfo->ScopeId, &size);
2247     RegCloseKey(hKey);
2248   }
2249 
2250   disposeResInfo( resInfo );
2251   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
2252      I suppose could also check for a listener on port 53 to set EnableDns */
2253   ret = NO_ERROR;
2254   TRACE("returning %ld\n", ret);
2255 
2256   return ret;
2257 }
2258 
2259 
2260 /******************************************************************
2261  *    GetNumberOfInterfaces (IPHLPAPI.@)
2262  *
2263  *
2264  * PARAMS
2265  *
2266  *  pdwNumIf [In/Out]
2267  *
2268  * RETURNS
2269  *
2270  *  DWORD
2271  *
2272  */
2273 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
2274 {
2275   DWORD ret;
2276 
2277   TRACE("pdwNumIf %p\n", pdwNumIf);
2278   if (!pdwNumIf)
2279     ret = ERROR_INVALID_PARAMETER;
2280   else {
2281     *pdwNumIf = getNumInterfaces();
2282     ret = NO_ERROR;
2283   }
2284   TRACE("returning %ld\n", ret);
2285   return ret;
2286 }
2287 
2288 
2289 static DWORD GetOwnerModuleFromPidEntry(DWORD OwningPid, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2290 {
2291     HANDLE Process;
2292     DWORD FileLen, PathLen, Error;
2293     WCHAR File[MAX_PATH], Path[MAX_PATH];
2294     PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2295 
2296     if (IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
2297         IsBadWritePtr(Buffer, *pdwSize))
2298     {
2299         return ERROR_INVALID_PARAMETER;
2300     }
2301 
2302     if (OwningPid == 0)
2303     {
2304         return ERROR_NOT_FOUND;
2305     }
2306 
2307     Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, OwningPid);
2308     if (Process == NULL)
2309     {
2310         return GetLastError();
2311     }
2312 
2313     FileLen = GetModuleBaseNameW(Process, NULL, File, MAX_PATH);
2314     if (FileLen != 0)
2315     {
2316         PathLen = GetModuleFileNameExW(Process, NULL, Path, MAX_PATH);
2317         if (PathLen == 0)
2318         {
2319             CloseHandle(Process);
2320             return GetLastError();
2321         }
2322 
2323         /* Add NULL char */
2324         ++FileLen;
2325         ++PathLen;
2326         PathLen *= sizeof(WCHAR);
2327         FileLen *= sizeof(WCHAR);
2328     }
2329     else
2330     {
2331         Error = GetLastError();
2332 
2333         if (Error == ERROR_PARTIAL_COPY)
2334         {
2335             wcscpy(File, L"System");
2336             wcscpy(Path, L"System");
2337 
2338             PathLen = sizeof(L"System");
2339             FileLen = sizeof(L"System");
2340         }
2341         else
2342         {
2343             CloseHandle(Process);
2344             return Error;
2345         }
2346     }
2347 
2348     CloseHandle(Process);
2349 
2350     if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen)
2351     {
2352         *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2353         return ERROR_INSUFFICIENT_BUFFER;
2354     }
2355 
2356     BasicInfo = Buffer;
2357     BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2358     BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + FileLen);
2359     wcscpy(BasicInfo->pModuleName, File);
2360     wcscpy(BasicInfo->pModulePath, Path);
2361     *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2362 
2363     return NO_ERROR;
2364 }
2365 
2366 static DWORD GetOwnerModuleFromTagEntry(DWORD OwningPid, DWORD OwningTag, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2367 {
2368     UINT Size;
2369     HRESULT Res;
2370     HANDLE hAdvapi32;
2371     WCHAR SysDir[MAX_PATH];
2372     PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2373     ULONG (NTAPI *_I_QueryTagInformation)(PVOID, DWORD, PVOID);
2374     struct
2375     {
2376         DWORD ProcessId;
2377         DWORD ServiceTag;
2378         DWORD TagType;
2379         PWSTR Buffer;
2380     } ServiceQuery;
2381 
2382     if (IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
2383         IsBadWritePtr(Buffer, *pdwSize))
2384     {
2385         return ERROR_INVALID_PARAMETER;
2386     }
2387 
2388     /* First, secure (avoid injections) load advapi32.dll */
2389     Size = GetSystemDirectoryW(SysDir, MAX_PATH);
2390     if (Size == 0)
2391     {
2392         return GetLastError();
2393     }
2394 
2395     Res = StringCchCatW(&SysDir[Size], MAX_PATH - Size, L"\\advapi32.dll");
2396     if (FAILED(Res))
2397     {
2398         return Res;
2399     }
2400 
2401     hAdvapi32 = GetModuleHandleW(SysDir);
2402     if (hAdvapi32 == NULL)
2403     {
2404         return GetLastError();
2405     }
2406 
2407     /* Now, we'll query the service associated with the tag */
2408     _I_QueryTagInformation = (PVOID)GetProcAddress(hAdvapi32, "I_QueryTagInformation");
2409     if (_I_QueryTagInformation == NULL)
2410     {
2411         return GetLastError();
2412     }
2413 
2414     /* Set tag and PID for the query */
2415     ServiceQuery.ProcessId = OwningPid;
2416     ServiceQuery.ServiceTag = OwningTag;
2417     ServiceQuery.TagType = 0;
2418     ServiceQuery.Buffer = NULL;
2419 
2420     /* And query */
2421     Res = _I_QueryTagInformation(NULL, 1, &ServiceQuery);
2422     if (Res != ERROR_SUCCESS)
2423     {
2424         return Res;
2425     }
2426 
2427     /* Compute service name length */
2428     Size = wcslen(ServiceQuery.Buffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
2429 
2430     /* We'll copy it twice, so make sure we have enough room */
2431     if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size)
2432     {
2433         *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size;
2434         LocalFree(ServiceQuery.Buffer);
2435         return ERROR_INSUFFICIENT_BUFFER;
2436     }
2437 
2438     /* Copy back data */
2439     BasicInfo = Buffer;
2440     BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2441     BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + Size);
2442     wcscpy(BasicInfo->pModuleName, ServiceQuery.Buffer);
2443     wcscpy(BasicInfo->pModulePath, ServiceQuery.Buffer);
2444     *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size;
2445     LocalFree(ServiceQuery.Buffer);
2446 
2447     return NO_ERROR;
2448 }
2449 
2450 /******************************************************************
2451  *    GetOwnerModuleFromTcpEntry (IPHLPAPI.@)
2452  *
2453  * Get data about the module that issued the context bind for a specific IPv4 TCP endpoint in a MIB table row
2454  *
2455  * PARAMS
2456  *  pTcpEntry [in]    pointer to a MIB_TCPROW_OWNER_MODULE structure
2457  *  Class [in]    	TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2458  *  Buffer [out]     	pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2459  *  pdwSize [in, out]	estimated size of the structure returned in Buffer, in bytes
2460  *
2461  * RETURNS
2462  *  Success: NO_ERROR
2463  *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2464  * 	       ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2465  *
2466  * NOTES
2467  * The type of data returned in Buffer is indicated by the value of the Class parameter.
2468  */
2469 DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2470 {
2471     /* If we have a service tag, that's a service connection */
2472     if (pTcpEntry->OwningModuleInfo[0] != 0)
2473     {
2474         return GetOwnerModuleFromTagEntry(pTcpEntry->dwOwningPid, (DWORD)(pTcpEntry->OwningModuleInfo[0]), Class, Buffer, pdwSize);
2475     }
2476     else
2477     {
2478         return GetOwnerModuleFromPidEntry(pTcpEntry->dwOwningPid, Class, Buffer, pdwSize);
2479     }
2480 }
2481 
2482 /******************************************************************
2483  *    GetOwnerModuleFromUdpEntry (IPHLPAPI.@)
2484  *
2485  * Get data about the module that issued the context bind for a specific IPv4 UDP endpoint in a MIB table row
2486  *
2487  * PARAMS
2488  *  pUdpEntry [in]    pointer to a MIB_UDPROW_OWNER_MODULE structure
2489  *  Class [in]    	TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2490  *  Buffer [out]     	pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2491  *  pdwSize [in, out]	estimated size of the structure returned in Buffer, in bytes
2492  *
2493  * RETURNS
2494  *  Success: NO_ERROR
2495  *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2496  * 	       ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2497  *
2498  * NOTES
2499  * The type of data returned in Buffer is indicated by the value of the Class parameter.
2500  */
2501 DWORD WINAPI GetOwnerModuleFromUdpEntry( PMIB_UDPROW_OWNER_MODULE pUdpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2502 {
2503     /* If we have a service tag, that's a service connection */
2504     if (pUdpEntry->OwningModuleInfo[0] != 0)
2505     {
2506         return GetOwnerModuleFromTagEntry(pUdpEntry->dwOwningPid, (DWORD)(pUdpEntry->OwningModuleInfo[0]), Class, Buffer, pdwSize);
2507     }
2508     else
2509     {
2510         return GetOwnerModuleFromPidEntry(pUdpEntry->dwOwningPid, Class, Buffer, pdwSize);
2511     }
2512 }
2513 
2514 static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
2515 {
2516   IP_ADDR_STRING *pNext;
2517   PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
2518 
2519   if (!Context->NumServers)
2520   {
2521     if (Context->uSizeAvailable >= Context->uSizeRequired)
2522     {
2523       WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
2524       Context->pData->DnsServerList.IpAddress.String[15] = '\0';
2525       Context->pLastAddr = &Context->pData->DnsServerList;
2526     }
2527   }
2528   else
2529   {
2530      Context->uSizeRequired += sizeof(IP_ADDR_STRING);
2531      if (Context->uSizeAvailable >= Context->uSizeRequired)
2532      {
2533          pNext = (IP_ADDR_STRING*)(((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING));
2534          WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
2535          pNext->IpAddress.String[15] = '\0';
2536          Context->pLastAddr->Next = pNext;
2537          Context->pLastAddr = pNext;
2538          pNext->Next = NULL;
2539      }
2540   }
2541   Context->NumServers++;
2542 }
2543 
2544 /******************************************************************
2545  *    GetPerAdapterInfo (IPHLPAPI.@)
2546  *
2547  *
2548  * PARAMS
2549  *
2550  *  IfIndex [In]
2551  *  pPerAdapterInfo [In/Out]
2552  *  pOutBufLen [In/Out]
2553  *
2554  * RETURNS
2555  *
2556  *  DWORD
2557  *
2558  */
2559 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
2560 {
2561   HKEY hkey;
2562   DWORD dwSize = 0;
2563   const char *ifName;
2564   NAME_SERVER_LIST_CONTEXT Context;
2565   WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
2566 
2567   if (!pOutBufLen)
2568     return ERROR_INVALID_PARAMETER;
2569 
2570   if (!pPerAdapterInfo || *pOutBufLen < sizeof(IP_PER_ADAPTER_INFO))
2571   {
2572     *pOutBufLen = sizeof(IP_PER_ADAPTER_INFO);
2573     return ERROR_BUFFER_OVERFLOW;
2574   }
2575 
2576   ifName = getInterfaceNameByIndex(IfIndex);
2577   if (!ifName)
2578     return ERROR_INVALID_PARAMETER;
2579 
2580   MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
2581   HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
2582 
2583   if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
2584   {
2585     return ERROR_NOT_SUPPORTED;
2586   }
2587   Context.NumServers = 0;
2588   Context.uSizeAvailable = *pOutBufLen;
2589   Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
2590   Context.pData = pPerAdapterInfo;
2591 
2592   if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
2593     ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
2594 
2595   EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
2596 
2597   if (Context.uSizeRequired > Context.uSizeAvailable)
2598   {
2599     *pOutBufLen = Context.uSizeRequired;
2600     RegCloseKey(hkey);
2601     return ERROR_BUFFER_OVERFLOW;
2602   }
2603 
2604   if(RegQueryValueExW(hkey, L"NameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
2605   {
2606     pPerAdapterInfo->AutoconfigActive = FALSE;
2607   }
2608   else
2609   {
2610     pPerAdapterInfo->AutoconfigActive = TRUE;
2611   }
2612 
2613   RegCloseKey(hkey);
2614   return NOERROR;
2615 }
2616 
2617 
2618 /******************************************************************
2619  *    GetRTTAndHopCount (IPHLPAPI.@)
2620  *
2621  *
2622  * PARAMS
2623  *
2624  *  DestIpAddress [In]
2625  *  HopCount [In/Out]
2626  *  MaxHops [In]
2627  *  RTT [In/Out]
2628  *
2629  * RETURNS
2630  *
2631  *  BOOL
2632  *
2633  */
2634 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2635 {
2636   TRACE("DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p\n",
2637    DestIpAddress, HopCount, MaxHops, RTT);
2638   FIXME(":stub\n");
2639   return (BOOL) 0;
2640 }
2641 
2642 
2643 /******************************************************************
2644  *    GetTcpStatisticsEx (IPHLPAPI.@)
2645  *
2646  *
2647  * PARAMS
2648  *
2649  *  pStats [In/Out]
2650  *  dwFamily [In]
2651  *
2652  * RETURNS
2653  *
2654  *  DWORD
2655  *
2656  */
2657 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily)
2658 {
2659   DWORD ret;
2660 
2661   TRACE("pStats %p\n", pStats);
2662   ret = getTCPStats(pStats, dwFamily);
2663   TRACE("returning %ld\n", ret);
2664   return ret;
2665 }
2666 
2667 /******************************************************************
2668  *    GetTcpStatistics (IPHLPAPI.@)
2669  *
2670  *
2671  * PARAMS
2672  *
2673  *  pStats [In/Out]
2674  *
2675  * RETURNS
2676  *
2677  *  DWORD
2678  *
2679  */
2680 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
2681 {
2682     return GetTcpStatisticsEx(pStats, PF_INET);
2683 }
2684 
2685 
2686 /******************************************************************
2687  *    GetTcpTable (IPHLPAPI.@)
2688  *
2689  * Get the table of active TCP connections.
2690  *
2691  * PARAMS
2692  *  pTcpTable [Out]    buffer for TCP connections table
2693  *  pdwSize   [In/Out] length of output buffer
2694  *  bOrder    [In]     whether to order the table
2695  *
2696  * RETURNS
2697  *  Success: NO_ERROR
2698  *  Failure: error code from winerror.h
2699  *
2700  * NOTES
2701  *  If pdwSize is less than required, the function will return
2702  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
2703  *  the required byte size.
2704  *  If bOrder is true, the returned table will be sorted, first by
2705  *  local address and port number, then by remote address and port
2706  *  number.
2707  */
2708 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
2709 {
2710   return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, AF_INET, TCP_TABLE_BASIC_ALL, 0);
2711 }
2712 
2713 
2714 /******************************************************************
2715  *    GetUdpStatisticsEx (IPHLPAPI.@)
2716  *
2717  *
2718  * PARAMS
2719  *
2720  *  pStats [In/Out]
2721  *  dwFamily [In]
2722  *
2723  * RETURNS
2724  *
2725  *  DWORD
2726  *
2727  */
2728 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS pStats, DWORD dwFamily)
2729 {
2730   DWORD ret;
2731 
2732   TRACE("pStats %p\n", pStats);
2733   ret = getUDPStats(pStats, dwFamily);
2734   TRACE("returning %ld\n", ret);
2735   return ret;
2736 }
2737 
2738 /******************************************************************
2739  *    GetUdpStatistics (IPHLPAPI.@)
2740  *
2741  *
2742  * PARAMS
2743  *
2744  *  pStats [In/Out]
2745  *
2746  * RETURNS
2747  *
2748  *  DWORD
2749  *
2750  */
2751 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
2752 {
2753     return GetUdpStatisticsEx(pStats, PF_INET);
2754 }
2755 
2756 
2757 /******************************************************************
2758  *    GetUdpTable (IPHLPAPI.@)
2759  *
2760  *
2761  * PARAMS
2762  *
2763  *  pUdpTable [In/Out]
2764  *  pdwSize [In/Out]
2765  *  bOrder [In]
2766  *
2767  * RETURNS
2768  *
2769  *  DWORD
2770  *
2771  */
2772 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2773 {
2774   return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, AF_INET, UDP_TABLE_BASIC, 0);
2775 }
2776 
2777 
2778 /******************************************************************
2779  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
2780  *
2781  * This is a Win98-only function to get information on "unidirectional"
2782  * adapters.  Since this is pretty nonsensical in other contexts, it
2783  * never returns anything.
2784  *
2785  * PARAMS
2786  *  pIPIfInfo   [Out] buffer for adapter infos
2787  *  dwOutBufLen [Out] length of the output buffer
2788  *
2789  * RETURNS
2790  *  Success: NO_ERROR
2791  *  Failure: error code from winerror.h
2792  *
2793  * FIXME
2794  *  Stub, returns ERROR_NOT_SUPPORTED.
2795  */
2796 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
2797 {
2798   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
2799   /* a unidirectional adapter?? not bloody likely! */
2800   return ERROR_NOT_SUPPORTED;
2801 }
2802 
2803 
2804 /******************************************************************
2805  *    IpReleaseAddress (IPHLPAPI.@)
2806  *
2807  * Release an IP obtained through DHCP,
2808  *
2809  * PARAMS
2810  *  AdapterInfo [In] adapter to release IP address
2811  *
2812  * RETURNS
2813  *  Success: NO_ERROR
2814  *  Failure: error code from winerror.h
2815  *
2816  */
2817 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2818 {
2819   DWORD Status, Version = 0;
2820 
2821   if (!AdapterInfo)
2822       return ERROR_INVALID_PARAMETER;
2823 
2824   /* Maybe we should do this in DllMain */
2825   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2826       return ERROR_PROC_NOT_FOUND;
2827 
2828   if (DhcpReleaseIpAddressLease(AdapterInfo->Index))
2829       Status = ERROR_SUCCESS;
2830   else
2831       Status = ERROR_PROC_NOT_FOUND;
2832 
2833   DhcpCApiCleanup();
2834 
2835   return Status;
2836 }
2837 
2838 
2839 /******************************************************************
2840  *    IpRenewAddress (IPHLPAPI.@)
2841  *
2842  * Renew an IP obtained through DHCP.
2843  *
2844  * PARAMS
2845  *  AdapterInfo [In] adapter to renew IP address
2846  *
2847  * RETURNS
2848  *  Success: NO_ERROR
2849  *  Failure: error code from winerror.h
2850  */
2851 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2852 {
2853   DWORD Status, Version = 0;
2854 
2855   if (!AdapterInfo)
2856       return ERROR_INVALID_PARAMETER;
2857 
2858   /* Maybe we should do this in DllMain */
2859   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2860       return ERROR_PROC_NOT_FOUND;
2861 
2862   if (DhcpRenewIpAddressLease(AdapterInfo->Index))
2863       Status = ERROR_SUCCESS;
2864   else
2865       Status = ERROR_PROC_NOT_FOUND;
2866 
2867   DhcpCApiCleanup();
2868 
2869   return Status;
2870 }
2871 
2872 
2873 /******************************************************************
2874  *    NotifyAddrChange (IPHLPAPI.@)
2875  *
2876  * Notify caller whenever the ip-interface map is changed.
2877  *
2878  * PARAMS
2879  *  Handle     [Out] handle usable in asynchronous notification
2880  *  overlapped [In]  overlapped structure that notifies the caller
2881  *
2882  * RETURNS
2883  *  Success: NO_ERROR
2884  *  Failure: error code from winerror.h
2885  *
2886  * FIXME
2887  *  Stub, returns ERROR_NOT_SUPPORTED.
2888  */
2889 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2890 {
2891   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2892   if (Handle) *Handle = INVALID_HANDLE_VALUE;
2893   if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING;
2894   return ERROR_IO_PENDING;
2895 }
2896 
2897 
2898 /******************************************************************
2899  *    NotifyRouteChange (IPHLPAPI.@)
2900  *
2901  * Notify caller whenever the ip routing table is changed.
2902  *
2903  * PARAMS
2904  *  Handle     [Out] handle usable in asynchronous notification
2905  *  overlapped [In]  overlapped structure that notifies the caller
2906  *
2907  * RETURNS
2908  *  Success: NO_ERROR
2909  *  Failure: error code from winerror.h
2910  *
2911  * FIXME
2912  *  Stub, returns ERROR_NOT_SUPPORTED.
2913  */
2914 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2915 {
2916   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2917   return ERROR_NOT_SUPPORTED;
2918 }
2919 
2920 /******************************************************************
2921  *    SendARP (IPHLPAPI.@)
2922  *
2923  * Send an ARP request.
2924  *
2925  * PARAMS
2926  *  DestIP     [In]     attempt to obtain this IP
2927  *  SrcIP      [In]     optional sender IP address
2928  *  pMacAddr   [Out]    buffer for the mac address
2929  *  PhyAddrLen [In/Out] length of the output buffer
2930  *
2931  * RETURNS
2932  *  Success: NO_ERROR
2933  *  Failure: error code from winerror.h
2934  */
2935 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2936 {
2937   IPAddr IPs[2];
2938   ULONG Size;
2939 
2940   if (IsBadWritePtr(pMacAddr, sizeof(ULONG)) || IsBadWritePtr(PhyAddrLen, sizeof(ULONG)))
2941     return ERROR_INVALID_PARAMETER;
2942 
2943   IPs[0] = DestIP;
2944   IPs[1] = SrcIP;
2945   Size = sizeof(IPs);
2946   return TCPSendIoctl(INVALID_HANDLE_VALUE, IOCTL_QUERY_IP_HW_ADDRESS, IPs, &Size, pMacAddr, PhyAddrLen);
2947 }
2948 
2949 
2950 /******************************************************************
2951  *    SetIfEntry (IPHLPAPI.@)
2952  *
2953  * Set the administrative status of an interface.
2954  *
2955  * PARAMS
2956  *  pIfRow [In] dwAdminStatus member specifies the new status.
2957  *
2958  * RETURNS
2959  *  Success: NO_ERROR
2960  *  Failure: error code from winerror.h
2961  *
2962  * FIXME
2963  *  Stub, returns ERROR_NOT_SUPPORTED.
2964  */
2965 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
2966 {
2967   FIXME("(pIfRow %p): stub\n", pIfRow);
2968   /* this is supposed to set an interface administratively up or down.
2969      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2970      this sort of down is indistinguishable from other sorts of down (e.g. no
2971      link). */
2972   return ERROR_NOT_SUPPORTED;
2973 }
2974 
2975 
2976 /******************************************************************
2977  *    SetIpForwardEntry (IPHLPAPI.@)
2978  *
2979  * Modify an existing route.
2980  *
2981  * PARAMS
2982  *  pRoute [In] route with the new information
2983  *
2984  * RETURNS
2985  *  Success: NO_ERROR
2986  *  Failure: error code from winerror.h
2987  *
2988  */
2989 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
2990 {
2991     return setIpForwardEntry( pRoute );
2992 }
2993 
2994 
2995 /******************************************************************
2996  *    SetIpNetEntry (IPHLPAPI.@)
2997  *
2998  * Modify an existing ARP entry.
2999  *
3000  * PARAMS
3001  *  pArpEntry [In] ARP entry with the new information
3002  *
3003  * RETURNS
3004  *  Success: NO_ERROR
3005  *  Failure: error code from winerror.h
3006  */
3007 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
3008 {
3009   HANDLE tcpFile;
3010   NTSTATUS status;
3011   TCP_REQUEST_SET_INFORMATION_EX_ARP_ENTRY req =
3012       TCP_REQUEST_SET_INFORMATION_INIT;
3013   TDIEntityID id;
3014   DWORD returnSize;
3015   PMIB_IPNETROW arpBuff;
3016 
3017   if (!pArpEntry)
3018       return ERROR_INVALID_PARAMETER;
3019 
3020   if (!NT_SUCCESS(openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA )))
3021       return ERROR_NOT_SUPPORTED;
3022 
3023   if (!NT_SUCCESS(getNthIpEntity( tcpFile, pArpEntry->dwIndex, &id )))
3024   {
3025       closeTcpFile(tcpFile);
3026       return ERROR_INVALID_PARAMETER;
3027   }
3028 
3029   req.Req.ID.toi_class = INFO_CLASS_PROTOCOL;
3030   req.Req.ID.toi_type = INFO_TYPE_PROVIDER;
3031   req.Req.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
3032   req.Req.ID.toi_entity.tei_instance = id.tei_instance;
3033   req.Req.ID.toi_entity.tei_entity = AT_ENTITY;
3034   req.Req.BufferSize = sizeof(MIB_IPNETROW);
3035   arpBuff = (PMIB_IPNETROW)&req.Req.Buffer[0];
3036 
3037   RtlCopyMemory(arpBuff, pArpEntry, sizeof(MIB_IPNETROW));
3038 
3039   status = DeviceIoControl( tcpFile,
3040                             IOCTL_TCP_SET_INFORMATION_EX,
3041                             &req,
3042                             sizeof(req),
3043                             NULL,
3044                             0,
3045                             &returnSize,
3046                             NULL );
3047 
3048   closeTcpFile(tcpFile);
3049 
3050   if (status)
3051      return NO_ERROR;
3052   else
3053      return ERROR_INVALID_PARAMETER;
3054 }
3055 
3056 
3057 /******************************************************************
3058  *    SetIpStatistics (IPHLPAPI.@)
3059  *
3060  * Toggle IP forwarding and det the default TTL value.
3061  *
3062  * PARAMS
3063  *  pIpStats [In] IP statistics with the new information
3064  *
3065  * RETURNS
3066  *  Success: NO_ERROR
3067  *  Failure: error code from winerror.h
3068  *
3069  * FIXME
3070  *  Stub, returns NO_ERROR.
3071  */
3072 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
3073 {
3074   FIXME("(pIpStats %p): stub\n", pIpStats);
3075   return 0;
3076 }
3077 
3078 
3079 /******************************************************************
3080  *    SetIpTTL (IPHLPAPI.@)
3081  *
3082  * Set the default TTL value.
3083  *
3084  * PARAMS
3085  *  nTTL [In] new TTL value
3086  *
3087  * RETURNS
3088  *  Success: NO_ERROR
3089  *  Failure: error code from winerror.h
3090  *
3091  * FIXME
3092  *  Stub, returns NO_ERROR.
3093  */
3094 DWORD WINAPI SetIpTTL(UINT nTTL)
3095 {
3096   FIXME("(nTTL %d): stub\n", nTTL);
3097   return 0;
3098 }
3099 
3100 
3101 /******************************************************************
3102  *    SetTcpEntry (IPHLPAPI.@)
3103  *
3104  * Set the state of a TCP connection.
3105  *
3106  * PARAMS
3107  *  pTcpRow [In] specifies connection with new state
3108  *
3109  * RETURNS
3110  *  Success: NO_ERROR
3111  *  Failure: error code from winerror.h
3112  *
3113  * FIXME
3114  *  Stub, returns NO_ERROR.
3115  */
3116 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
3117 {
3118   FIXME("(pTcpRow %p): stub\n", pTcpRow);
3119   return 0;
3120 }
3121 
3122 
3123 /******************************************************************
3124  *    UnenableRouter (IPHLPAPI.@)
3125  *
3126  * Decrement the IP-forwarding reference count. Turn off IP-forwarding
3127  * if it reaches zero.
3128  *
3129  * PARAMS
3130  *  pOverlapped     [In/Out] should be the same as in EnableRouter()
3131  *  lpdwEnableCount [Out]    optional, receives reference count
3132  *
3133  * RETURNS
3134  *  Success: NO_ERROR
3135  *  Failure: error code from winerror.h
3136  *
3137  * FIXME
3138  *  Stub, returns ERROR_NOT_SUPPORTED.
3139  */
3140 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
3141 {
3142   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
3143    lpdwEnableCount);
3144   return ERROR_NOT_SUPPORTED;
3145 }
3146 
3147 /*
3148  * @unimplemented
3149  */
3150 DWORD WINAPI GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)
3151 {
3152     FIXME(":stub\n");
3153     return 0L;
3154 }
3155 
3156 
3157 /*
3158  * @unimplemented
3159  */
3160 PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
3161 {
3162     FIXME(":stub\n");
3163     return 0L;
3164 }
3165 
3166 /*
3167  * @implemented
3168  */
3169 #ifdef GetAdaptersAddressesV1
3170 DWORD WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
3171 {
3172     InterfaceIndexTable *indexTable;
3173     IFInfo ifInfo;
3174     int i;
3175     ULONG ret, requiredSize = 0;
3176     PIP_ADAPTER_ADDRESSES currentAddress;
3177     PUCHAR currentLocation;
3178     HANDLE tcpFile;
3179 
3180     if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
3181     if (Reserved) return ERROR_INVALID_PARAMETER;
3182 
3183     indexTable = getInterfaceIndexTable();
3184     if (!indexTable)
3185         return ERROR_NOT_ENOUGH_MEMORY;
3186 
3187     ret = openTcpFile(&tcpFile, FILE_READ_DATA);
3188     if (!NT_SUCCESS(ret))
3189     {
3190         free(indexTable);
3191         return ERROR_NO_DATA;
3192     }
3193 
3194     for (i = indexTable->numIndexes; i >= 0; i--)
3195     {
3196         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3197                                            NULL,
3198                                            indexTable->indexes[i],
3199                                            &ifInfo)))
3200         {
3201             /* The whole struct */
3202             requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
3203 
3204             /* Friendly name */
3205             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3206                 requiredSize += ifInfo.if_info.ent.if_descrlen + 1; //FIXME
3207 
3208             /* Adapter name */
3209             requiredSize += ifInfo.if_info.ent.if_descrlen + 1;
3210 
3211             /* Unicast address */
3212             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3213                 requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3214 
3215             /* FIXME: Implement multicast, anycast, and dns server stuff */
3216 
3217             /* FIXME: Implement dns suffix and description */
3218             requiredSize += 2 * sizeof(WCHAR);
3219 
3220             /* We're only going to implement what's required for XP SP0 */
3221         }
3222     }
3223     TRACE("size: %d, requiredSize: %d\n", *pOutBufLen, requiredSize);
3224     if (!pAdapterAddresses || *pOutBufLen < requiredSize)
3225     {
3226         *pOutBufLen = requiredSize;
3227         closeTcpFile(tcpFile);
3228         free(indexTable);
3229         return ERROR_BUFFER_OVERFLOW;
3230     }
3231 
3232     RtlZeroMemory(pAdapterAddresses, requiredSize);
3233 
3234     /* Let's set up the pointers */
3235     currentAddress = pAdapterAddresses;
3236     for (i = indexTable->numIndexes; i >= 0; i--)
3237     {
3238         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3239                                            NULL,
3240                                            indexTable->indexes[i],
3241                                            &ifInfo)))
3242         {
3243             currentLocation = (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
3244 
3245             /* FIXME: Friendly name */
3246             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3247             {
3248                 currentAddress->FriendlyName = (PVOID)currentLocation;
3249                 currentLocation += sizeof(WCHAR);
3250             }
3251 
3252             /* Adapter name */
3253             currentAddress->AdapterName = (PVOID)currentLocation;
3254             currentLocation += ifInfo.if_info.ent.if_descrlen + 1;
3255 
3256             /* Unicast address */
3257             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3258             {
3259                 currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
3260                 currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3261                 currentAddress->FirstUnicastAddress->Address.lpSockaddr = (PVOID)currentLocation;
3262                 currentLocation += sizeof(struct sockaddr);
3263             }
3264 
3265             /* FIXME: Implement multicast, anycast, and dns server stuff */
3266 
3267             /* FIXME: Implement dns suffix and description */
3268             currentAddress->DnsSuffix = (PVOID)currentLocation;
3269             currentLocation += sizeof(WCHAR);
3270 
3271             currentAddress->Description = (PVOID)currentLocation;
3272             currentLocation += sizeof(WCHAR);
3273 
3274             currentAddress->Next = (PVOID)currentLocation;
3275             /* Terminate the last address correctly */
3276             if(i==0)
3277                 currentAddress->Next = NULL;
3278 
3279             /* We're only going to implement what's required for XP SP0 */
3280 
3281             currentAddress = currentAddress->Next;
3282         }
3283     }
3284 
3285     /* Now again, for real this time */
3286 
3287     currentAddress = pAdapterAddresses;
3288     for (i = indexTable->numIndexes; i >= 0; i--)
3289     {
3290         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3291                                            NULL,
3292                                            indexTable->indexes[i],
3293                                            &ifInfo)))
3294         {
3295             /* Make sure we're not looping more than we hoped for */
3296             ASSERT(currentAddress);
3297 
3298             /* Alignment information */
3299             currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
3300             currentAddress->IfIndex = indexTable->indexes[i];
3301 
3302             /* Adapter name */
3303             memcpy(currentAddress->AdapterName, ifInfo.if_info.ent.if_descr, ifInfo.if_info.ent.if_descrlen);
3304             currentAddress->AdapterName[ifInfo.if_info.ent.if_descrlen] = '\0';
3305 
3306             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3307             {
3308                 currentAddress->FirstUnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3309                 currentAddress->FirstUnicastAddress->Flags = 0; //FIXME
3310                 currentAddress->FirstUnicastAddress->Next = NULL; //FIXME: Support more than one address per adapter
3311                 currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
3312                 memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
3313                        &ifInfo.ip_addr.iae_addr,
3314                        sizeof(ifInfo.ip_addr.iae_addr));
3315                 currentAddress->FirstUnicastAddress->Address.iSockaddrLength = sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
3316                 currentAddress->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; //FIXME
3317                 currentAddress->FirstUnicastAddress->SuffixOrigin = IpPrefixOriginOther; //FIXME
3318                 currentAddress->FirstUnicastAddress->DadState = IpDadStatePreferred; //FIXME
3319                 currentAddress->FirstUnicastAddress->ValidLifetime = 0xFFFFFFFF; //FIXME
3320                 currentAddress->FirstUnicastAddress->PreferredLifetime = 0xFFFFFFFF; //FIXME
3321                 currentAddress->FirstUnicastAddress->LeaseLifetime = 0xFFFFFFFF; //FIXME
3322             }
3323 
3324             /* FIXME: Implement multicast, anycast, and dns server stuff */
3325             currentAddress->FirstAnycastAddress = NULL;
3326             currentAddress->FirstMulticastAddress = NULL;
3327             currentAddress->FirstDnsServerAddress = NULL;
3328 
3329             /* FIXME: Implement dns suffix, description, and friendly name */
3330             currentAddress->DnsSuffix[0] = UNICODE_NULL;
3331             currentAddress->Description[0] = UNICODE_NULL;
3332             currentAddress->FriendlyName[0] = UNICODE_NULL;
3333 
3334             /* Physical Address */
3335             memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, ifInfo.if_info.ent.if_physaddrlen);
3336             currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
3337 
3338             /* Flags */
3339             currentAddress->Flags = 0; //FIXME
3340 
3341             /* MTU */
3342             currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
3343 
3344             /* Interface type */
3345             currentAddress->IfType = ifInfo.if_info.ent.if_type;
3346 
3347             /* Operational status */
3348             if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
3349                 currentAddress->OperStatus = IfOperStatusUp;
3350             else
3351                 currentAddress->OperStatus = IfOperStatusDown;
3352 
3353             /* We're only going to implement what's required for XP SP0 */
3354 
3355             /* Move to the next address */
3356             currentAddress = currentAddress->Next;
3357         }
3358     }
3359 
3360     closeTcpFile(tcpFile);
3361     free(indexTable);
3362 
3363     return NO_ERROR;
3364 }
3365 #endif
3366 
3367 /*
3368  * @unimplemented
3369  */
3370 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)
3371 {
3372     FIXME(":stub\n");
3373     return 0L;
3374 }
3375 
3376 /*
3377  * @unimplemented
3378  */
3379 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex)
3380 {
3381     FIXME(":stub\n");
3382     return 0L;
3383 }
3384 
3385 /*
3386  * @unimplemented
3387  */
3388 DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)
3389 {
3390     FIXME(":stub\n");
3391     return 0L;
3392 }
3393 
3394 /*
3395  * @unimplemented
3396  */
3397 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
3398 {
3399     FIXME(":stub\n");
3400 
3401     if (!pStats)
3402         return ERROR_INVALID_PARAMETER;
3403 
3404     if (dwFamily != AF_INET && dwFamily != AF_INET6)
3405         return ERROR_INVALID_PARAMETER;
3406 
3407     return 0L;
3408 }
3409 
3410 DWORD WINAPI
3411 SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)
3412 {
3413     FIXME("SetIpForwardEntryToStack() stub\n");
3414     return 0L;
3415 }
3416 
3417 DWORD GetInterfaceNameInternal(_In_ const GUID * pInterfaceGUID,
3418                                _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3419                                _Inout_ PULONG pOutBufLen)
3420 {
3421     UNICODE_STRING GuidString;
3422     DWORD result, type;
3423     WCHAR szKeyName[2*MAX_PATH];
3424     HRESULT hr;
3425     HKEY hKey;
3426 
3427     if (pInterfaceGUID == NULL || pOutBufLen == NULL)
3428         return ERROR_INVALID_PARAMETER;
3429 
3430     result = RtlStringFromGUID(pInterfaceGUID, &GuidString);
3431 
3432     if (!NT_SUCCESS(result))
3433     {
3434         // failed to convert guid to string
3435         return RtlNtStatusToDosError(result);
3436     }
3437 
3438     hr = StringCbPrintfW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", GuidString.Buffer);
3439     RtlFreeUnicodeString(&GuidString);
3440 
3441     if (FAILED(hr))
3442     {
3443         // key name is too long
3444         return ERROR_BUFFER_OVERFLOW;
3445     }
3446 
3447     result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKey);
3448 
3449     if (result != ERROR_SUCCESS)
3450     {
3451         // failed to find adapter entry
3452         return ERROR_NOT_FOUND;
3453     }
3454 
3455     result = RegQueryValueExW(hKey, L"Name", NULL, &type, (PVOID)pInterfaceName, pOutBufLen);
3456 
3457     RegCloseKey(hKey);
3458 
3459     if (result == ERROR_MORE_DATA)
3460     {
3461         *pOutBufLen = MAX_INTERFACE_NAME_LEN * 2;
3462         return ERROR_INSUFFICIENT_BUFFER;
3463     }
3464 
3465     if (result != ERROR_SUCCESS || type != REG_SZ)
3466     {
3467         // failed to read adapter name
3468         return ERROR_NO_DATA;
3469     }
3470     return ERROR_SUCCESS;
3471 }
3472 
3473 /*
3474  * @implemented
3475  */
3476 DWORD WINAPI
3477 NhGetInterfaceNameFromDeviceGuid(_In_ const GUID * pInterfaceGUID,
3478                                  _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3479                                  _Inout_ PULONG pOutBufLen,
3480                                  DWORD dwUnknown4,
3481                                  DWORD dwUnknown5)
3482 {
3483     SetLastError(ERROR_SUCCESS);
3484 
3485     if (pInterfaceName == NULL)
3486         return ERROR_INVALID_PARAMETER;
3487 
3488     return GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3489 }
3490 
3491 /*
3492  * @implemented
3493  */
3494 DWORD WINAPI
3495 NhGetInterfaceNameFromGuid(_In_ const GUID * pInterfaceGUID,
3496                            _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3497                            _Inout_ PULONG pOutBufLen,
3498                            DWORD dwUnknown4,
3499                            DWORD dwUnknown5)
3500 {
3501     DWORD result;
3502 
3503     result = GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3504 
3505     if (result == ERROR_NOT_FOUND)
3506         SetLastError(ERROR_PATH_NOT_FOUND);
3507 
3508     return result;
3509 }
3510