xref: /reactos/dll/win32/iphlpapi/iphlpapi_main.c (revision 6ef7b676)
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             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
1767              walker && *walker &&
1768              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
1769              walker++, assigner++)
1770               *assigner = *walker;
1771             *assigner = 0;
1772             consumeInterfaceName(name);
1773             pIfTable->NumAdapters++;
1774           }
1775           ret = NO_ERROR;
1776         }
1777         free(table);
1778       }
1779       else
1780         ret = ERROR_OUTOFMEMORY;
1781     }
1782   }
1783   TRACE("returning %ld\n", ret);
1784   return ret;
1785 }
1786 
1787 
1788 static int IpAddrTableSorter(const void *a, const void *b)
1789 {
1790   int ret;
1791 
1792   if (a && b)
1793     ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
1794   else
1795     ret = 0;
1796   return ret;
1797 }
1798 
1799 
1800 /******************************************************************
1801  *    GetIpAddrTable (IPHLPAPI.@)
1802  *
1803  *
1804  * PARAMS
1805  *
1806  *  pIpAddrTable [In/Out]
1807  *  pdwSize [In/Out]
1808  *  bOrder [In]
1809  *
1810  * RETURNS
1811  *
1812  *  DWORD
1813  *
1814  */
1815 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1816 {
1817   DWORD ret;
1818 
1819   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
1820    (DWORD)bOrder);
1821   if (!pdwSize)
1822     ret = ERROR_INVALID_PARAMETER;
1823   else {
1824     DWORD numInterfaces = getNumInterfaces();
1825     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
1826      sizeof(MIB_IPADDRROW);
1827 
1828     if (!pIpAddrTable || *pdwSize < size) {
1829       *pdwSize = size;
1830       ret = ERROR_INSUFFICIENT_BUFFER;
1831     }
1832     else {
1833       InterfaceIndexTable *table = getInterfaceIndexTable();
1834 
1835       if (table) {
1836         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
1837          sizeof(MIB_IPADDRROW);
1838         if (*pdwSize < size) {
1839           *pdwSize = size;
1840           ret = ERROR_INSUFFICIENT_BUFFER;
1841         }
1842         else {
1843           DWORD ndx, bcast;
1844 
1845           pIpAddrTable->dwNumEntries = 0;
1846           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1847             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
1848             pIpAddrTable->table[ndx].dwAddr =
1849              getInterfaceIPAddrByIndex(table->indexes[ndx]);
1850             pIpAddrTable->table[ndx].dwMask =
1851              getInterfaceMaskByIndex(table->indexes[ndx]);
1852             /* the dwBCastAddr member isn't the broadcast address, it indicates
1853              * whether the interface uses the 1's broadcast address (1) or the
1854              * 0's broadcast address (0).
1855              */
1856             bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
1857             pIpAddrTable->table[ndx].dwBCastAddr =
1858              (bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
1859             /* FIXME: hardcoded reasm size, not sure where to get it */
1860             pIpAddrTable->table[ndx].dwReasmSize = 65535;
1861             pIpAddrTable->table[ndx].unused1 = 0;
1862             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
1863             pIpAddrTable->dwNumEntries++;
1864           }
1865           if (bOrder)
1866             qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1867              sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1868           ret = NO_ERROR;
1869         }
1870         free(table);
1871       }
1872       else
1873         ret = ERROR_OUTOFMEMORY;
1874     }
1875   }
1876   TRACE("returning %ld\n", ret);
1877   return ret;
1878 }
1879 
1880 
1881 static int IpForwardTableSorter(const void *a, const void *b)
1882 {
1883   int ret;
1884 
1885   if (a && b) {
1886     PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
1887 
1888     ret = rowA->dwForwardDest - rowB->dwForwardDest;
1889     if (ret == 0) {
1890       ret = rowA->dwForwardProto - rowB->dwForwardProto;
1891       if (ret == 0) {
1892         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
1893         if (ret == 0)
1894           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1895       }
1896     }
1897   }
1898   else
1899     ret = 0;
1900   return ret;
1901 }
1902 
1903 
1904 /******************************************************************
1905  *    GetIpForwardTable (IPHLPAPI.@)
1906  *
1907  *
1908  * PARAMS
1909  *
1910  *  pIpForwardTable [In/Out]
1911  *  pdwSize [In/Out]
1912  *  bOrder [In]
1913  *
1914  * RETURNS
1915  *
1916  *  DWORD
1917  *
1918  */
1919 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1920 {
1921   DWORD ret;
1922 
1923   TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
1924         pdwSize, (DWORD)bOrder);
1925   if (!pdwSize)
1926     ret = ERROR_INVALID_PARAMETER;
1927   else {
1928     DWORD numRoutes = getNumRoutes();
1929     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1930      sizeof(MIB_IPFORWARDROW);
1931 
1932     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1933       *pdwSize = sizeNeeded;
1934       ret = ERROR_INSUFFICIENT_BUFFER;
1935     }
1936     else {
1937       RouteTable *table = getRouteTable();
1938       if (table) {
1939         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1940          sizeof(MIB_IPFORWARDROW);
1941         if (*pdwSize < sizeNeeded) {
1942           *pdwSize = sizeNeeded;
1943           ret = ERROR_INSUFFICIENT_BUFFER;
1944         }
1945         else {
1946           DWORD ndx;
1947 
1948           pIpForwardTable->dwNumEntries = table->numRoutes;
1949           for (ndx = 0; ndx < numRoutes; ndx++) {
1950             pIpForwardTable->table[ndx].dwForwardIfIndex =
1951              table->routes[ndx].ifIndex;
1952             pIpForwardTable->table[ndx].dwForwardDest =
1953              table->routes[ndx].dest;
1954             pIpForwardTable->table[ndx].dwForwardMask =
1955              table->routes[ndx].mask;
1956             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1957             pIpForwardTable->table[ndx].dwForwardNextHop =
1958              table->routes[ndx].gateway;
1959             /* FIXME: this type is appropriate for local interfaces; may not
1960                always be appropriate */
1961             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1962             /* FIXME: other protos might be appropriate, e.g. the default route
1963                is typically set with MIB_IPPROTO_NETMGMT instead */
1964             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1965             /* punt on age and AS */
1966             pIpForwardTable->table[ndx].dwForwardAge = 0;
1967             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1968             pIpForwardTable->table[ndx].dwForwardMetric1 =
1969              table->routes[ndx].metric;
1970             /* rest of the metrics are 0.. */
1971             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1972             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1973             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1974             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1975           }
1976           if (bOrder)
1977             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1978              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1979           ret = NO_ERROR;
1980         }
1981         HeapFree(GetProcessHeap(), 0, table);
1982       }
1983       else
1984         ret = ERROR_OUTOFMEMORY;
1985     }
1986   }
1987   TRACE("returning %ld\n", ret);
1988   return ret;
1989 }
1990 
1991 
1992 static int IpNetTableSorter(const void *a, const void *b)
1993 {
1994   int ret;
1995 
1996   if (a && b)
1997     ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
1998   else
1999     ret = 0;
2000   return ret;
2001 }
2002 
2003 
2004 /******************************************************************
2005  *    GetIpNetTable (IPHLPAPI.@)
2006  *
2007  *
2008  * PARAMS
2009  *
2010  *  pIpNetTable [In/Out]
2011  *  pdwSize [In/Out]
2012  *  bOrder [In]
2013  *
2014  * RETURNS
2015  *
2016  *  DWORD
2017  *
2018  */
2019 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
2020 {
2021   DWORD ret = NO_ERROR;
2022 
2023   TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize,
2024    (DWORD)bOrder);
2025   if (!pdwSize)
2026     ret = ERROR_INVALID_PARAMETER;
2027   else {
2028     DWORD numEntries = getNumArpEntries();
2029     ULONG size = sizeof(MIB_IPNETTABLE);
2030 
2031     if (numEntries > 1)
2032       size += (numEntries - 1) * sizeof(MIB_IPNETROW);
2033     if (!pIpNetTable || *pdwSize < size) {
2034       *pdwSize = size;
2035       ret = ERROR_INSUFFICIENT_BUFFER;
2036     }
2037     else {
2038       PMIB_IPNETTABLE table = getArpTable();
2039       if (table) {
2040         size = sizeof(MIB_IPNETTABLE);
2041         if (table->dwNumEntries > 1)
2042           size += (table->dwNumEntries - 1) * sizeof(MIB_IPNETROW);
2043         if (*pdwSize < size) {
2044           *pdwSize = size;
2045           ret = ERROR_INSUFFICIENT_BUFFER;
2046         }
2047         else {
2048           *pdwSize = size;
2049           memcpy(pIpNetTable, table, size);
2050           if (bOrder)
2051             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
2052              sizeof(MIB_IPNETROW), IpNetTableSorter);
2053           ret = NO_ERROR;
2054         }
2055         HeapFree(GetProcessHeap(), 0, table);
2056       }
2057     }
2058   }
2059   TRACE("returning %d\n", ret);
2060   return ret;
2061 }
2062 
2063 
2064 /******************************************************************
2065  *    GetIpStatistics (IPHLPAPI.@)
2066  *
2067  *
2068  * PARAMS
2069  *
2070  *  pStats [In/Out]
2071  *
2072  * RETURNS
2073  *
2074  *  DWORD
2075  *
2076  */
2077 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
2078 {
2079     return GetIpStatisticsEx(pStats, PF_INET);
2080 }
2081 
2082 /******************************************************************
2083  *    GetIpStatisticsEx (IPHLPAPI.@)
2084  *
2085  *
2086  * PARAMS
2087  *
2088  *  pStats [In/Out]
2089  *  dwFamily [In]
2090  *
2091  * RETURNS
2092  *
2093  *  DWORD
2094  *
2095  */
2096 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily)
2097 {
2098   DWORD ret;
2099 
2100   TRACE("pStats %p\n", pStats);
2101   ret = getIPStats(pStats, dwFamily);
2102   TRACE("returning %ld\n", ret);
2103   return ret;
2104 }
2105 
2106 /******************************************************************
2107  *    GetNetworkParams (IPHLPAPI.@)
2108  *
2109  *
2110  * PARAMS
2111  *
2112  *  pFixedInfo [In/Out]
2113  *  pOutBufLen [In/Out]
2114  *
2115  * RETURNS
2116  *
2117  *  DWORD
2118  *
2119  */
2120 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
2121 {
2122   DWORD ret, size, type;
2123   LONG regReturn;
2124   HKEY hKey;
2125   PIPHLP_RES_INFO resInfo;
2126 
2127   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
2128   if (!pOutBufLen)
2129     return ERROR_INVALID_PARAMETER;
2130 
2131   resInfo = getResInfo();
2132   if (!resInfo)
2133     return ERROR_OUTOFMEMORY;
2134 
2135   size = sizeof(FIXED_INFO) + (resInfo->riCount > 1 ? (resInfo->riCount-1) *
2136    sizeof(IP_ADDR_STRING) : 0);
2137   if (!pFixedInfo || *pOutBufLen < size) {
2138     *pOutBufLen = size;
2139     disposeResInfo( resInfo );
2140     return ERROR_BUFFER_OVERFLOW;
2141   }
2142 
2143   memset(pFixedInfo, 0, size);
2144   /* Check for DhcpHostname and DhcpDomain first */
2145   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2146                             "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
2147                             0,
2148                             KEY_READ,
2149                             &hKey);
2150   if (regReturn == ERROR_SUCCESS) {
2151       /* Windows doesn't honor DHCP option 12 even if RFC requires it if it is returned by DHCP server! */
2152 #if 0
2153       type = REG_SZ;
2154       size = sizeof(pFixedInfo->HostName);
2155       regReturn = RegQueryValueExA(hKey,
2156                                       "DhcpHostname",
2157                                       NULL,
2158                                       &type,
2159                                       (LPBYTE)pFixedInfo->HostName,
2160                                       &size);
2161       if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
2162       {
2163 #endif
2164           type = REG_SZ;
2165           size = sizeof(pFixedInfo->HostName);
2166           regReturn = RegQueryValueExA(hKey,
2167                                           "Hostname",
2168                                           NULL,
2169                                           &type,
2170                                           (LPBYTE)pFixedInfo->HostName,
2171                                           &size);
2172 #if 0
2173       }
2174 #endif
2175 
2176       type = REG_SZ;
2177       size = sizeof(pFixedInfo->DomainName);
2178       regReturn = RegQueryValueExA(hKey,
2179                                       "DhcpDomain",
2180                                       NULL,
2181                                       &type,
2182                                       (LPBYTE)pFixedInfo->DomainName,
2183                                       &size);
2184       if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
2185       {
2186           type = REG_SZ;
2187           size = sizeof(pFixedInfo->DomainName);
2188           regReturn = RegQueryValueExA(hKey,
2189                                           "Domain",
2190                                           NULL,
2191                                           &type,
2192                                           (LPBYTE)pFixedInfo->DomainName,
2193                                           &size);
2194       }
2195       RegCloseKey(hKey);
2196   }
2197 
2198   TRACE("GetComputerNameExA: %s\n", pFixedInfo->DomainName);
2199 
2200   if (resInfo->riCount > 0)
2201   {
2202     CopyMemory(&pFixedInfo->DnsServerList, resInfo->DnsList, sizeof(IP_ADDR_STRING));
2203     if (resInfo->riCount > 1)
2204     {
2205       IP_ADDR_STRING *pSrc = resInfo->DnsList->Next;
2206       IP_ADDR_STRING *pTarget = (struct _IP_ADDR_STRING*)((char*)pFixedInfo + sizeof(FIXED_INFO));
2207 
2208       pFixedInfo->DnsServerList.Next = pTarget;
2209 
2210       do
2211       {
2212         CopyMemory(pTarget, pSrc, sizeof(IP_ADDR_STRING));
2213         resInfo->riCount--;
2214         if (resInfo->riCount > 1)
2215         {
2216           pTarget->Next = (IP_ADDR_STRING*)((char*)pTarget + sizeof(IP_ADDR_STRING));
2217           pTarget = pTarget->Next;
2218           pSrc = pSrc->Next;
2219         }
2220         else
2221         {
2222           pTarget->Next = NULL;
2223           break;
2224         }
2225       }
2226       while(TRUE);
2227     }
2228     else
2229     {
2230       pFixedInfo->DnsServerList.Next = NULL;
2231     }
2232   }
2233 
2234   pFixedInfo->NodeType = HYBRID_NODETYPE;
2235   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2236    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
2237   if (regReturn != ERROR_SUCCESS)
2238     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2239      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
2240      &hKey);
2241   if (regReturn == ERROR_SUCCESS)
2242   {
2243     DWORD size = sizeof(pFixedInfo->ScopeId);
2244 
2245     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (PBYTE)pFixedInfo->ScopeId, &size);
2246     RegCloseKey(hKey);
2247   }
2248 
2249   disposeResInfo( resInfo );
2250   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
2251      I suppose could also check for a listener on port 53 to set EnableDns */
2252   ret = NO_ERROR;
2253   TRACE("returning %ld\n", ret);
2254 
2255   return ret;
2256 }
2257 
2258 
2259 /******************************************************************
2260  *    GetNumberOfInterfaces (IPHLPAPI.@)
2261  *
2262  *
2263  * PARAMS
2264  *
2265  *  pdwNumIf [In/Out]
2266  *
2267  * RETURNS
2268  *
2269  *  DWORD
2270  *
2271  */
2272 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
2273 {
2274   DWORD ret;
2275 
2276   TRACE("pdwNumIf %p\n", pdwNumIf);
2277   if (!pdwNumIf)
2278     ret = ERROR_INVALID_PARAMETER;
2279   else {
2280     *pdwNumIf = getNumInterfaces();
2281     ret = NO_ERROR;
2282   }
2283   TRACE("returning %ld\n", ret);
2284   return ret;
2285 }
2286 
2287 
2288 static DWORD GetOwnerModuleFromPidEntry(DWORD OwningPid, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2289 {
2290     HANDLE Process;
2291     DWORD FileLen, PathLen, Error;
2292     WCHAR File[MAX_PATH], Path[MAX_PATH];
2293     PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2294 
2295     if (IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
2296         IsBadWritePtr(Buffer, *pdwSize))
2297     {
2298         return ERROR_INVALID_PARAMETER;
2299     }
2300 
2301     if (OwningPid == 0)
2302     {
2303         return ERROR_NOT_FOUND;
2304     }
2305 
2306     Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, OwningPid);
2307     if (Process == NULL)
2308     {
2309         return GetLastError();
2310     }
2311 
2312     FileLen = GetModuleBaseNameW(Process, NULL, File, MAX_PATH);
2313     if (FileLen != 0)
2314     {
2315         PathLen = GetModuleFileNameExW(Process, NULL, Path, MAX_PATH);
2316         if (PathLen == 0)
2317         {
2318             CloseHandle(Process);
2319             return GetLastError();
2320         }
2321 
2322         /* Add NULL char */
2323         ++FileLen;
2324         ++PathLen;
2325         PathLen *= sizeof(WCHAR);
2326         FileLen *= sizeof(WCHAR);
2327     }
2328     else
2329     {
2330         Error = GetLastError();
2331 
2332         if (Error == ERROR_PARTIAL_COPY)
2333         {
2334             wcscpy(File, L"System");
2335             wcscpy(Path, L"System");
2336 
2337             PathLen = sizeof(L"System");
2338             FileLen = sizeof(L"System");
2339         }
2340         else
2341         {
2342             CloseHandle(Process);
2343             return Error;
2344         }
2345     }
2346 
2347     CloseHandle(Process);
2348 
2349     if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen)
2350     {
2351         *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2352         return ERROR_INSUFFICIENT_BUFFER;
2353     }
2354 
2355     BasicInfo = Buffer;
2356     BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2357     BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + FileLen);
2358     wcscpy(BasicInfo->pModuleName, File);
2359     wcscpy(BasicInfo->pModulePath, Path);
2360     *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2361 
2362     return NO_ERROR;
2363 }
2364 
2365 static DWORD GetOwnerModuleFromTagEntry(DWORD OwningPid, DWORD OwningTag, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2366 {
2367     UINT Size;
2368     HRESULT Res;
2369     HANDLE hAdvapi32;
2370     WCHAR SysDir[MAX_PATH];
2371     PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2372     ULONG (NTAPI *_I_QueryTagInformation)(PVOID, DWORD, PVOID);
2373     struct
2374     {
2375         DWORD ProcessId;
2376         DWORD ServiceTag;
2377         DWORD TagType;
2378         PWSTR Buffer;
2379     } ServiceQuery;
2380 
2381     if (IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
2382         IsBadWritePtr(Buffer, *pdwSize))
2383     {
2384         return ERROR_INVALID_PARAMETER;
2385     }
2386 
2387     /* First, secure (avoid injections) load advapi32.dll */
2388     Size = GetSystemDirectoryW(SysDir, MAX_PATH);
2389     if (Size == 0)
2390     {
2391         return GetLastError();
2392     }
2393 
2394     Res = StringCchCatW(&SysDir[Size], MAX_PATH - Size, L"\\advapi32.dll");
2395     if (FAILED(Res))
2396     {
2397         return Res;
2398     }
2399 
2400     hAdvapi32 = GetModuleHandleW(SysDir);
2401     if (hAdvapi32 == NULL)
2402     {
2403         return GetLastError();
2404     }
2405 
2406     /* Now, we'll query the service associated with the tag */
2407     _I_QueryTagInformation = (PVOID)GetProcAddress(hAdvapi32, "I_QueryTagInformation");
2408     if (_I_QueryTagInformation == NULL)
2409     {
2410         return GetLastError();
2411     }
2412 
2413     /* Set tag and PID for the query */
2414     ServiceQuery.ProcessId = OwningPid;
2415     ServiceQuery.ServiceTag = OwningTag;
2416     ServiceQuery.TagType = 0;
2417     ServiceQuery.Buffer = NULL;
2418 
2419     /* And query */
2420     Res = _I_QueryTagInformation(NULL, 1, &ServiceQuery);
2421     if (Res != ERROR_SUCCESS)
2422     {
2423         return Res;
2424     }
2425 
2426     /* Compute service name length */
2427     Size = wcslen(ServiceQuery.Buffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
2428 
2429     /* We'll copy it twice, so make sure we have enough room */
2430     if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size)
2431     {
2432         *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size;
2433         LocalFree(ServiceQuery.Buffer);
2434         return ERROR_INSUFFICIENT_BUFFER;
2435     }
2436 
2437     /* Copy back data */
2438     BasicInfo = Buffer;
2439     BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2440     BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + Size);
2441     wcscpy(BasicInfo->pModuleName, ServiceQuery.Buffer);
2442     wcscpy(BasicInfo->pModulePath, ServiceQuery.Buffer);
2443     *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size;
2444     LocalFree(ServiceQuery.Buffer);
2445 
2446     return NO_ERROR;
2447 }
2448 
2449 /******************************************************************
2450  *    GetOwnerModuleFromTcpEntry (IPHLPAPI.@)
2451  *
2452  * Get data about the module that issued the context bind for a specific IPv4 TCP endpoint in a MIB table row
2453  *
2454  * PARAMS
2455  *  pTcpEntry [in]    pointer to a MIB_TCPROW_OWNER_MODULE structure
2456  *  Class [in]    	TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2457  *  Buffer [out]     	pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2458  *  pdwSize [in, out]	estimated size of the structure returned in Buffer, in bytes
2459  *
2460  * RETURNS
2461  *  Success: NO_ERROR
2462  *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2463  * 	       ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2464  *
2465  * NOTES
2466  * The type of data returned in Buffer is indicated by the value of the Class parameter.
2467  */
2468 DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2469 {
2470     /* If we have a service tag, that's a service connection */
2471     if (pTcpEntry->OwningModuleInfo[0] != 0)
2472     {
2473         return GetOwnerModuleFromTagEntry(pTcpEntry->dwOwningPid, (DWORD)(pTcpEntry->OwningModuleInfo[0]), Class, Buffer, pdwSize);
2474     }
2475     else
2476     {
2477         return GetOwnerModuleFromPidEntry(pTcpEntry->dwOwningPid, Class, Buffer, pdwSize);
2478     }
2479 }
2480 
2481 /******************************************************************
2482  *    GetOwnerModuleFromUdpEntry (IPHLPAPI.@)
2483  *
2484  * Get data about the module that issued the context bind for a specific IPv4 UDP endpoint in a MIB table row
2485  *
2486  * PARAMS
2487  *  pUdpEntry [in]    pointer to a MIB_UDPROW_OWNER_MODULE structure
2488  *  Class [in]    	TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2489  *  Buffer [out]     	pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2490  *  pdwSize [in, out]	estimated size of the structure returned in Buffer, in bytes
2491  *
2492  * RETURNS
2493  *  Success: NO_ERROR
2494  *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2495  * 	       ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2496  *
2497  * NOTES
2498  * The type of data returned in Buffer is indicated by the value of the Class parameter.
2499  */
2500 DWORD WINAPI GetOwnerModuleFromUdpEntry( PMIB_UDPROW_OWNER_MODULE pUdpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2501 {
2502     /* If we have a service tag, that's a service connection */
2503     if (pUdpEntry->OwningModuleInfo[0] != 0)
2504     {
2505         return GetOwnerModuleFromTagEntry(pUdpEntry->dwOwningPid, (DWORD)(pUdpEntry->OwningModuleInfo[0]), Class, Buffer, pdwSize);
2506     }
2507     else
2508     {
2509         return GetOwnerModuleFromPidEntry(pUdpEntry->dwOwningPid, Class, Buffer, pdwSize);
2510     }
2511 }
2512 
2513 static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
2514 {
2515   IP_ADDR_STRING *pNext;
2516   PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
2517 
2518   if (!Context->NumServers)
2519   {
2520     if (Context->uSizeAvailable >= Context->uSizeRequired)
2521     {
2522       WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
2523       Context->pData->DnsServerList.IpAddress.String[15] = '\0';
2524       Context->pLastAddr = &Context->pData->DnsServerList;
2525     }
2526   }
2527   else
2528   {
2529      Context->uSizeRequired += sizeof(IP_ADDR_STRING);
2530      if (Context->uSizeAvailable >= Context->uSizeRequired)
2531      {
2532          pNext = (IP_ADDR_STRING*)(((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING));
2533          WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
2534          pNext->IpAddress.String[15] = '\0';
2535          Context->pLastAddr->Next = pNext;
2536          Context->pLastAddr = pNext;
2537          pNext->Next = NULL;
2538      }
2539   }
2540   Context->NumServers++;
2541 }
2542 
2543 /******************************************************************
2544  *    GetPerAdapterInfo (IPHLPAPI.@)
2545  *
2546  *
2547  * PARAMS
2548  *
2549  *  IfIndex [In]
2550  *  pPerAdapterInfo [In/Out]
2551  *  pOutBufLen [In/Out]
2552  *
2553  * RETURNS
2554  *
2555  *  DWORD
2556  *
2557  */
2558 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
2559 {
2560   HKEY hkey;
2561   DWORD dwSize = 0;
2562   const char *ifName;
2563   NAME_SERVER_LIST_CONTEXT Context;
2564   WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
2565 
2566   if (!pOutBufLen)
2567     return ERROR_INVALID_PARAMETER;
2568 
2569   if (!pPerAdapterInfo || *pOutBufLen < sizeof(IP_PER_ADAPTER_INFO))
2570   {
2571     *pOutBufLen = sizeof(IP_PER_ADAPTER_INFO);
2572     return ERROR_BUFFER_OVERFLOW;
2573   }
2574 
2575   ifName = getInterfaceNameByIndex(IfIndex);
2576   if (!ifName)
2577     return ERROR_INVALID_PARAMETER;
2578 
2579   MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
2580   HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
2581 
2582   if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
2583   {
2584     return ERROR_NOT_SUPPORTED;
2585   }
2586   Context.NumServers = 0;
2587   Context.uSizeAvailable = *pOutBufLen;
2588   Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
2589   Context.pData = pPerAdapterInfo;
2590 
2591   if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
2592     ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
2593 
2594   EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
2595 
2596   if (Context.uSizeRequired > Context.uSizeAvailable)
2597   {
2598     *pOutBufLen = Context.uSizeRequired;
2599     RegCloseKey(hkey);
2600     return ERROR_BUFFER_OVERFLOW;
2601   }
2602 
2603   if(RegQueryValueExW(hkey, L"NameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
2604   {
2605     pPerAdapterInfo->AutoconfigActive = FALSE;
2606   }
2607   else
2608   {
2609     pPerAdapterInfo->AutoconfigActive = TRUE;
2610   }
2611 
2612   RegCloseKey(hkey);
2613   return NOERROR;
2614 }
2615 
2616 
2617 /******************************************************************
2618  *    GetRTTAndHopCount (IPHLPAPI.@)
2619  *
2620  *
2621  * PARAMS
2622  *
2623  *  DestIpAddress [In]
2624  *  HopCount [In/Out]
2625  *  MaxHops [In]
2626  *  RTT [In/Out]
2627  *
2628  * RETURNS
2629  *
2630  *  BOOL
2631  *
2632  */
2633 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2634 {
2635   TRACE("DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p\n",
2636    DestIpAddress, HopCount, MaxHops, RTT);
2637   FIXME(":stub\n");
2638   return (BOOL) 0;
2639 }
2640 
2641 
2642 /******************************************************************
2643  *    GetTcpStatisticsEx (IPHLPAPI.@)
2644  *
2645  *
2646  * PARAMS
2647  *
2648  *  pStats [In/Out]
2649  *  dwFamily [In]
2650  *
2651  * RETURNS
2652  *
2653  *  DWORD
2654  *
2655  */
2656 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily)
2657 {
2658   DWORD ret;
2659 
2660   TRACE("pStats %p\n", pStats);
2661   ret = getTCPStats(pStats, dwFamily);
2662   TRACE("returning %ld\n", ret);
2663   return ret;
2664 }
2665 
2666 /******************************************************************
2667  *    GetTcpStatistics (IPHLPAPI.@)
2668  *
2669  *
2670  * PARAMS
2671  *
2672  *  pStats [In/Out]
2673  *
2674  * RETURNS
2675  *
2676  *  DWORD
2677  *
2678  */
2679 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
2680 {
2681     return GetTcpStatisticsEx(pStats, PF_INET);
2682 }
2683 
2684 
2685 /******************************************************************
2686  *    GetTcpTable (IPHLPAPI.@)
2687  *
2688  * Get the table of active TCP connections.
2689  *
2690  * PARAMS
2691  *  pTcpTable [Out]    buffer for TCP connections table
2692  *  pdwSize   [In/Out] length of output buffer
2693  *  bOrder    [In]     whether to order the table
2694  *
2695  * RETURNS
2696  *  Success: NO_ERROR
2697  *  Failure: error code from winerror.h
2698  *
2699  * NOTES
2700  *  If pdwSize is less than required, the function will return
2701  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
2702  *  the required byte size.
2703  *  If bOrder is true, the returned table will be sorted, first by
2704  *  local address and port number, then by remote address and port
2705  *  number.
2706  */
2707 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
2708 {
2709   return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, AF_INET, TCP_TABLE_BASIC_ALL, 0);
2710 }
2711 
2712 
2713 /******************************************************************
2714  *    GetUdpStatisticsEx (IPHLPAPI.@)
2715  *
2716  *
2717  * PARAMS
2718  *
2719  *  pStats [In/Out]
2720  *  dwFamily [In]
2721  *
2722  * RETURNS
2723  *
2724  *  DWORD
2725  *
2726  */
2727 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS pStats, DWORD dwFamily)
2728 {
2729   DWORD ret;
2730 
2731   TRACE("pStats %p\n", pStats);
2732   ret = getUDPStats(pStats, dwFamily);
2733   TRACE("returning %ld\n", ret);
2734   return ret;
2735 }
2736 
2737 /******************************************************************
2738  *    GetUdpStatistics (IPHLPAPI.@)
2739  *
2740  *
2741  * PARAMS
2742  *
2743  *  pStats [In/Out]
2744  *
2745  * RETURNS
2746  *
2747  *  DWORD
2748  *
2749  */
2750 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
2751 {
2752     return GetUdpStatisticsEx(pStats, PF_INET);
2753 }
2754 
2755 
2756 /******************************************************************
2757  *    GetUdpTable (IPHLPAPI.@)
2758  *
2759  *
2760  * PARAMS
2761  *
2762  *  pUdpTable [In/Out]
2763  *  pdwSize [In/Out]
2764  *  bOrder [In]
2765  *
2766  * RETURNS
2767  *
2768  *  DWORD
2769  *
2770  */
2771 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2772 {
2773   return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, AF_INET, UDP_TABLE_BASIC, 0);
2774 }
2775 
2776 
2777 /******************************************************************
2778  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
2779  *
2780  * This is a Win98-only function to get information on "unidirectional"
2781  * adapters.  Since this is pretty nonsensical in other contexts, it
2782  * never returns anything.
2783  *
2784  * PARAMS
2785  *  pIPIfInfo   [Out] buffer for adapter infos
2786  *  dwOutBufLen [Out] length of the output buffer
2787  *
2788  * RETURNS
2789  *  Success: NO_ERROR
2790  *  Failure: error code from winerror.h
2791  *
2792  * FIXME
2793  *  Stub, returns ERROR_NOT_SUPPORTED.
2794  */
2795 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
2796 {
2797   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
2798   /* a unidirectional adapter?? not bloody likely! */
2799   return ERROR_NOT_SUPPORTED;
2800 }
2801 
2802 
2803 /******************************************************************
2804  *    IpReleaseAddress (IPHLPAPI.@)
2805  *
2806  * Release an IP obtained through DHCP,
2807  *
2808  * PARAMS
2809  *  AdapterInfo [In] adapter to release IP address
2810  *
2811  * RETURNS
2812  *  Success: NO_ERROR
2813  *  Failure: error code from winerror.h
2814  *
2815  */
2816 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2817 {
2818   DWORD Status, Version = 0;
2819 
2820   if (!AdapterInfo)
2821       return ERROR_INVALID_PARAMETER;
2822 
2823   /* Maybe we should do this in DllMain */
2824   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2825       return ERROR_PROC_NOT_FOUND;
2826 
2827   if (DhcpReleaseIpAddressLease(AdapterInfo->Index))
2828       Status = ERROR_SUCCESS;
2829   else
2830       Status = ERROR_PROC_NOT_FOUND;
2831 
2832   DhcpCApiCleanup();
2833 
2834   return Status;
2835 }
2836 
2837 
2838 /******************************************************************
2839  *    IpRenewAddress (IPHLPAPI.@)
2840  *
2841  * Renew an IP obtained through DHCP.
2842  *
2843  * PARAMS
2844  *  AdapterInfo [In] adapter to renew IP address
2845  *
2846  * RETURNS
2847  *  Success: NO_ERROR
2848  *  Failure: error code from winerror.h
2849  */
2850 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2851 {
2852   DWORD Status, Version = 0;
2853 
2854   if (!AdapterInfo)
2855       return ERROR_INVALID_PARAMETER;
2856 
2857   /* Maybe we should do this in DllMain */
2858   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2859       return ERROR_PROC_NOT_FOUND;
2860 
2861   if (DhcpRenewIpAddressLease(AdapterInfo->Index))
2862       Status = ERROR_SUCCESS;
2863   else
2864       Status = ERROR_PROC_NOT_FOUND;
2865 
2866   DhcpCApiCleanup();
2867 
2868   return Status;
2869 }
2870 
2871 
2872 /******************************************************************
2873  *    NotifyAddrChange (IPHLPAPI.@)
2874  *
2875  * Notify caller whenever the ip-interface map is changed.
2876  *
2877  * PARAMS
2878  *  Handle     [Out] handle usable in asynchronous notification
2879  *  overlapped [In]  overlapped structure that notifies the caller
2880  *
2881  * RETURNS
2882  *  Success: NO_ERROR
2883  *  Failure: error code from winerror.h
2884  *
2885  * FIXME
2886  *  Stub, returns ERROR_NOT_SUPPORTED.
2887  */
2888 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2889 {
2890   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2891   if (Handle) *Handle = INVALID_HANDLE_VALUE;
2892   if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING;
2893   return ERROR_IO_PENDING;
2894 }
2895 
2896 
2897 /******************************************************************
2898  *    NotifyRouteChange (IPHLPAPI.@)
2899  *
2900  * Notify caller whenever the ip routing table is changed.
2901  *
2902  * PARAMS
2903  *  Handle     [Out] handle usable in asynchronous notification
2904  *  overlapped [In]  overlapped structure that notifies the caller
2905  *
2906  * RETURNS
2907  *  Success: NO_ERROR
2908  *  Failure: error code from winerror.h
2909  *
2910  * FIXME
2911  *  Stub, returns ERROR_NOT_SUPPORTED.
2912  */
2913 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2914 {
2915   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2916   return ERROR_NOT_SUPPORTED;
2917 }
2918 
2919 /******************************************************************
2920  *    SendARP (IPHLPAPI.@)
2921  *
2922  * Send an ARP request.
2923  *
2924  * PARAMS
2925  *  DestIP     [In]     attempt to obtain this IP
2926  *  SrcIP      [In]     optional sender IP address
2927  *  pMacAddr   [Out]    buffer for the mac address
2928  *  PhyAddrLen [In/Out] length of the output buffer
2929  *
2930  * RETURNS
2931  *  Success: NO_ERROR
2932  *  Failure: error code from winerror.h
2933  */
2934 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2935 {
2936   IPAddr IPs[2];
2937   ULONG Size;
2938 
2939   if (IsBadWritePtr(pMacAddr, sizeof(ULONG)) || IsBadWritePtr(PhyAddrLen, sizeof(ULONG)))
2940     return ERROR_INVALID_PARAMETER;
2941 
2942   IPs[0] = DestIP;
2943   IPs[1] = SrcIP;
2944   Size = sizeof(IPs);
2945   return TCPSendIoctl(INVALID_HANDLE_VALUE, IOCTL_QUERY_IP_HW_ADDRESS, IPs, &Size, pMacAddr, PhyAddrLen);
2946 }
2947 
2948 
2949 /******************************************************************
2950  *    SetIfEntry (IPHLPAPI.@)
2951  *
2952  * Set the administrative status of an interface.
2953  *
2954  * PARAMS
2955  *  pIfRow [In] dwAdminStatus member specifies the new status.
2956  *
2957  * RETURNS
2958  *  Success: NO_ERROR
2959  *  Failure: error code from winerror.h
2960  *
2961  * FIXME
2962  *  Stub, returns ERROR_NOT_SUPPORTED.
2963  */
2964 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
2965 {
2966   FIXME("(pIfRow %p): stub\n", pIfRow);
2967   /* this is supposed to set an interface administratively up or down.
2968      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2969      this sort of down is indistinguishable from other sorts of down (e.g. no
2970      link). */
2971   return ERROR_NOT_SUPPORTED;
2972 }
2973 
2974 
2975 /******************************************************************
2976  *    SetIpForwardEntry (IPHLPAPI.@)
2977  *
2978  * Modify an existing route.
2979  *
2980  * PARAMS
2981  *  pRoute [In] route with the new information
2982  *
2983  * RETURNS
2984  *  Success: NO_ERROR
2985  *  Failure: error code from winerror.h
2986  *
2987  */
2988 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
2989 {
2990     return setIpForwardEntry( pRoute );
2991 }
2992 
2993 
2994 /******************************************************************
2995  *    SetIpNetEntry (IPHLPAPI.@)
2996  *
2997  * Modify an existing ARP entry.
2998  *
2999  * PARAMS
3000  *  pArpEntry [In] ARP entry with the new information
3001  *
3002  * RETURNS
3003  *  Success: NO_ERROR
3004  *  Failure: error code from winerror.h
3005  */
3006 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
3007 {
3008   HANDLE tcpFile;
3009   NTSTATUS status;
3010   TCP_REQUEST_SET_INFORMATION_EX_ARP_ENTRY req =
3011       TCP_REQUEST_SET_INFORMATION_INIT;
3012   TDIEntityID id;
3013   DWORD returnSize;
3014   PMIB_IPNETROW arpBuff;
3015 
3016   if (!pArpEntry)
3017       return ERROR_INVALID_PARAMETER;
3018 
3019   if (!NT_SUCCESS(openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA )))
3020       return ERROR_NOT_SUPPORTED;
3021 
3022   if (!NT_SUCCESS(getNthIpEntity( tcpFile, pArpEntry->dwIndex, &id )))
3023   {
3024       closeTcpFile(tcpFile);
3025       return ERROR_INVALID_PARAMETER;
3026   }
3027 
3028   req.Req.ID.toi_class = INFO_CLASS_PROTOCOL;
3029   req.Req.ID.toi_type = INFO_TYPE_PROVIDER;
3030   req.Req.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
3031   req.Req.ID.toi_entity.tei_instance = id.tei_instance;
3032   req.Req.ID.toi_entity.tei_entity = AT_ENTITY;
3033   req.Req.BufferSize = sizeof(MIB_IPNETROW);
3034   arpBuff = (PMIB_IPNETROW)&req.Req.Buffer[0];
3035 
3036   RtlCopyMemory(arpBuff, pArpEntry, sizeof(MIB_IPNETROW));
3037 
3038   status = DeviceIoControl( tcpFile,
3039                             IOCTL_TCP_SET_INFORMATION_EX,
3040                             &req,
3041                             sizeof(req),
3042                             NULL,
3043                             0,
3044                             &returnSize,
3045                             NULL );
3046 
3047   closeTcpFile(tcpFile);
3048 
3049   if (status)
3050      return NO_ERROR;
3051   else
3052      return ERROR_INVALID_PARAMETER;
3053 }
3054 
3055 
3056 /******************************************************************
3057  *    SetIpStatistics (IPHLPAPI.@)
3058  *
3059  * Toggle IP forwarding and det the default TTL value.
3060  *
3061  * PARAMS
3062  *  pIpStats [In] IP statistics with the new information
3063  *
3064  * RETURNS
3065  *  Success: NO_ERROR
3066  *  Failure: error code from winerror.h
3067  *
3068  * FIXME
3069  *  Stub, returns NO_ERROR.
3070  */
3071 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
3072 {
3073   FIXME("(pIpStats %p): stub\n", pIpStats);
3074   return 0;
3075 }
3076 
3077 
3078 /******************************************************************
3079  *    SetIpTTL (IPHLPAPI.@)
3080  *
3081  * Set the default TTL value.
3082  *
3083  * PARAMS
3084  *  nTTL [In] new TTL value
3085  *
3086  * RETURNS
3087  *  Success: NO_ERROR
3088  *  Failure: error code from winerror.h
3089  *
3090  * FIXME
3091  *  Stub, returns NO_ERROR.
3092  */
3093 DWORD WINAPI SetIpTTL(UINT nTTL)
3094 {
3095   FIXME("(nTTL %d): stub\n", nTTL);
3096   return 0;
3097 }
3098 
3099 
3100 /******************************************************************
3101  *    SetTcpEntry (IPHLPAPI.@)
3102  *
3103  * Set the state of a TCP connection.
3104  *
3105  * PARAMS
3106  *  pTcpRow [In] specifies connection with new state
3107  *
3108  * RETURNS
3109  *  Success: NO_ERROR
3110  *  Failure: error code from winerror.h
3111  *
3112  * FIXME
3113  *  Stub, returns NO_ERROR.
3114  */
3115 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
3116 {
3117   FIXME("(pTcpRow %p): stub\n", pTcpRow);
3118   return 0;
3119 }
3120 
3121 
3122 /******************************************************************
3123  *    UnenableRouter (IPHLPAPI.@)
3124  *
3125  * Decrement the IP-forwarding reference count. Turn off IP-forwarding
3126  * if it reaches zero.
3127  *
3128  * PARAMS
3129  *  pOverlapped     [In/Out] should be the same as in EnableRouter()
3130  *  lpdwEnableCount [Out]    optional, receives reference count
3131  *
3132  * RETURNS
3133  *  Success: NO_ERROR
3134  *  Failure: error code from winerror.h
3135  *
3136  * FIXME
3137  *  Stub, returns ERROR_NOT_SUPPORTED.
3138  */
3139 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
3140 {
3141   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
3142    lpdwEnableCount);
3143   return ERROR_NOT_SUPPORTED;
3144 }
3145 
3146 /*
3147  * @unimplemented
3148  */
3149 DWORD WINAPI GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)
3150 {
3151     FIXME(":stub\n");
3152     return 0L;
3153 }
3154 
3155 
3156 /*
3157  * @unimplemented
3158  */
3159 PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
3160 {
3161     FIXME(":stub\n");
3162     return 0L;
3163 }
3164 
3165 /*
3166  * @implemented
3167  */
3168 #ifdef GetAdaptersAddressesV1
3169 DWORD WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
3170 {
3171     InterfaceIndexTable *indexTable;
3172     IFInfo ifInfo;
3173     int i;
3174     ULONG ret, requiredSize = 0;
3175     PIP_ADAPTER_ADDRESSES currentAddress;
3176     PUCHAR currentLocation;
3177     HANDLE tcpFile;
3178 
3179     if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
3180     if (Reserved) return ERROR_INVALID_PARAMETER;
3181 
3182     indexTable = getInterfaceIndexTable();
3183     if (!indexTable)
3184         return ERROR_NOT_ENOUGH_MEMORY;
3185 
3186     ret = openTcpFile(&tcpFile, FILE_READ_DATA);
3187     if (!NT_SUCCESS(ret))
3188     {
3189         free(indexTable);
3190         return ERROR_NO_DATA;
3191     }
3192 
3193     for (i = indexTable->numIndexes; i >= 0; i--)
3194     {
3195         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3196                                            NULL,
3197                                            indexTable->indexes[i],
3198                                            &ifInfo)))
3199         {
3200             /* The whole struct */
3201             requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
3202 
3203             /* Friendly name */
3204             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3205                 requiredSize += ifInfo.if_info.ent.if_descrlen + 1; //FIXME
3206 
3207             /* Adapter name */
3208             requiredSize += ifInfo.if_info.ent.if_descrlen + 1;
3209 
3210             /* Unicast address */
3211             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3212                 requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3213 
3214             /* FIXME: Implement multicast, anycast, and dns server stuff */
3215 
3216             /* FIXME: Implement dns suffix and description */
3217             requiredSize += 2 * sizeof(WCHAR);
3218 
3219             /* We're only going to implement what's required for XP SP0 */
3220         }
3221     }
3222     TRACE("size: %d, requiredSize: %d\n", *pOutBufLen, requiredSize);
3223     if (!pAdapterAddresses || *pOutBufLen < requiredSize)
3224     {
3225         *pOutBufLen = requiredSize;
3226         closeTcpFile(tcpFile);
3227         free(indexTable);
3228         return ERROR_BUFFER_OVERFLOW;
3229     }
3230 
3231     RtlZeroMemory(pAdapterAddresses, requiredSize);
3232 
3233     /* Let's set up the pointers */
3234     currentAddress = pAdapterAddresses;
3235     for (i = indexTable->numIndexes; i >= 0; i--)
3236     {
3237         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3238                                            NULL,
3239                                            indexTable->indexes[i],
3240                                            &ifInfo)))
3241         {
3242             currentLocation = (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
3243 
3244             /* FIXME: Friendly name */
3245             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3246             {
3247                 currentAddress->FriendlyName = (PVOID)currentLocation;
3248                 currentLocation += sizeof(WCHAR);
3249             }
3250 
3251             /* Adapter name */
3252             currentAddress->AdapterName = (PVOID)currentLocation;
3253             currentLocation += ifInfo.if_info.ent.if_descrlen + 1;
3254 
3255             /* Unicast address */
3256             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3257             {
3258                 currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
3259                 currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3260                 currentAddress->FirstUnicastAddress->Address.lpSockaddr = (PVOID)currentLocation;
3261                 currentLocation += sizeof(struct sockaddr);
3262             }
3263 
3264             /* FIXME: Implement multicast, anycast, and dns server stuff */
3265 
3266             /* FIXME: Implement dns suffix and description */
3267             currentAddress->DnsSuffix = (PVOID)currentLocation;
3268             currentLocation += sizeof(WCHAR);
3269 
3270             currentAddress->Description = (PVOID)currentLocation;
3271             currentLocation += sizeof(WCHAR);
3272 
3273             currentAddress->Next = (PVOID)currentLocation;
3274             /* Terminate the last address correctly */
3275             if(i==0)
3276                 currentAddress->Next = NULL;
3277 
3278             /* We're only going to implement what's required for XP SP0 */
3279 
3280             currentAddress = currentAddress->Next;
3281         }
3282     }
3283 
3284     /* Now again, for real this time */
3285 
3286     currentAddress = pAdapterAddresses;
3287     for (i = indexTable->numIndexes; i >= 0; i--)
3288     {
3289         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3290                                            NULL,
3291                                            indexTable->indexes[i],
3292                                            &ifInfo)))
3293         {
3294             /* Make sure we're not looping more than we hoped for */
3295             ASSERT(currentAddress);
3296 
3297             /* Alignment information */
3298             currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
3299             currentAddress->IfIndex = indexTable->indexes[i];
3300 
3301             /* Adapter name */
3302             memcpy(currentAddress->AdapterName, ifInfo.if_info.ent.if_descr, ifInfo.if_info.ent.if_descrlen);
3303             currentAddress->AdapterName[ifInfo.if_info.ent.if_descrlen] = '\0';
3304 
3305             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3306             {
3307                 currentAddress->FirstUnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3308                 currentAddress->FirstUnicastAddress->Flags = 0; //FIXME
3309                 currentAddress->FirstUnicastAddress->Next = NULL; //FIXME: Support more than one address per adapter
3310                 currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
3311                 memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
3312                        &ifInfo.ip_addr.iae_addr,
3313                        sizeof(ifInfo.ip_addr.iae_addr));
3314                 currentAddress->FirstUnicastAddress->Address.iSockaddrLength = sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
3315                 currentAddress->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; //FIXME
3316                 currentAddress->FirstUnicastAddress->SuffixOrigin = IpPrefixOriginOther; //FIXME
3317                 currentAddress->FirstUnicastAddress->DadState = IpDadStatePreferred; //FIXME
3318                 currentAddress->FirstUnicastAddress->ValidLifetime = 0xFFFFFFFF; //FIXME
3319                 currentAddress->FirstUnicastAddress->PreferredLifetime = 0xFFFFFFFF; //FIXME
3320                 currentAddress->FirstUnicastAddress->LeaseLifetime = 0xFFFFFFFF; //FIXME
3321             }
3322 
3323             /* FIXME: Implement multicast, anycast, and dns server stuff */
3324             currentAddress->FirstAnycastAddress = NULL;
3325             currentAddress->FirstMulticastAddress = NULL;
3326             currentAddress->FirstDnsServerAddress = NULL;
3327 
3328             /* FIXME: Implement dns suffix, description, and friendly name */
3329             currentAddress->DnsSuffix[0] = UNICODE_NULL;
3330             currentAddress->Description[0] = UNICODE_NULL;
3331             currentAddress->FriendlyName[0] = UNICODE_NULL;
3332 
3333             /* Physical Address */
3334             memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, ifInfo.if_info.ent.if_physaddrlen);
3335             currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
3336 
3337             /* Flags */
3338             currentAddress->Flags = 0; //FIXME
3339 
3340             /* MTU */
3341             currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
3342 
3343             /* Interface type */
3344             currentAddress->IfType = ifInfo.if_info.ent.if_type;
3345 
3346             /* Operational status */
3347             if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
3348                 currentAddress->OperStatus = IfOperStatusUp;
3349             else
3350                 currentAddress->OperStatus = IfOperStatusDown;
3351 
3352             /* We're only going to implement what's required for XP SP0 */
3353 
3354             /* Move to the next address */
3355             currentAddress = currentAddress->Next;
3356         }
3357     }
3358 
3359     closeTcpFile(tcpFile);
3360     free(indexTable);
3361 
3362     return NO_ERROR;
3363 }
3364 #endif
3365 
3366 /*
3367  * @unimplemented
3368  */
3369 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)
3370 {
3371     FIXME(":stub\n");
3372     return 0L;
3373 }
3374 
3375 /*
3376  * @unimplemented
3377  */
3378 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex)
3379 {
3380     FIXME(":stub\n");
3381     return 0L;
3382 }
3383 
3384 /*
3385  * @unimplemented
3386  */
3387 DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)
3388 {
3389     FIXME(":stub\n");
3390     return 0L;
3391 }
3392 
3393 /*
3394  * @unimplemented
3395  */
3396 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
3397 {
3398     FIXME(":stub\n");
3399 
3400     if (!pStats)
3401         return ERROR_INVALID_PARAMETER;
3402 
3403     if (dwFamily != AF_INET && dwFamily != AF_INET6)
3404         return ERROR_INVALID_PARAMETER;
3405 
3406     return 0L;
3407 }
3408 
3409 DWORD WINAPI
3410 SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)
3411 {
3412     FIXME("SetIpForwardEntryToStack() stub\n");
3413     return 0L;
3414 }
3415 
3416 DWORD GetInterfaceNameInternal(_In_ const GUID * pInterfaceGUID,
3417                                _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3418                                _Inout_ PULONG pOutBufLen)
3419 {
3420     UNICODE_STRING GuidString;
3421     DWORD result, type;
3422     WCHAR szKeyName[2*MAX_PATH];
3423     HRESULT hr;
3424     HKEY hKey;
3425 
3426     if (pInterfaceGUID == NULL || pOutBufLen == NULL)
3427         return ERROR_INVALID_PARAMETER;
3428 
3429     result = RtlStringFromGUID(pInterfaceGUID, &GuidString);
3430 
3431     if (!NT_SUCCESS(result))
3432     {
3433         // failed to convert guid to string
3434         return RtlNtStatusToDosError(result);
3435     }
3436 
3437     hr = StringCbPrintfW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", GuidString.Buffer);
3438     RtlFreeUnicodeString(&GuidString);
3439 
3440     if (FAILED(hr))
3441     {
3442         // key name is too long
3443         return ERROR_BUFFER_OVERFLOW;
3444     }
3445 
3446     result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKey);
3447 
3448     if (result != ERROR_SUCCESS)
3449     {
3450         // failed to find adapter entry
3451         return ERROR_NOT_FOUND;
3452     }
3453 
3454     result = RegQueryValueExW(hKey, L"Name", NULL, &type, (PVOID)pInterfaceName, pOutBufLen);
3455 
3456     RegCloseKey(hKey);
3457 
3458     if (result == ERROR_MORE_DATA)
3459     {
3460         *pOutBufLen = MAX_INTERFACE_NAME_LEN * 2;
3461         return ERROR_INSUFFICIENT_BUFFER;
3462     }
3463 
3464     if (result != ERROR_SUCCESS || type != REG_SZ)
3465     {
3466         // failed to read adapter name
3467         return ERROR_NO_DATA;
3468     }
3469     return ERROR_SUCCESS;
3470 }
3471 
3472 /*
3473  * @implemented
3474  */
3475 DWORD WINAPI
3476 NhGetInterfaceNameFromDeviceGuid(_In_ const GUID * pInterfaceGUID,
3477                                  _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3478                                  _Inout_ PULONG pOutBufLen,
3479                                  DWORD dwUnknown4,
3480                                  DWORD dwUnknown5)
3481 {
3482     SetLastError(ERROR_SUCCESS);
3483 
3484     if (pInterfaceName == NULL)
3485         return ERROR_INVALID_PARAMETER;
3486 
3487     return GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3488 }
3489 
3490 /*
3491  * @implemented
3492  */
3493 DWORD WINAPI
3494 NhGetInterfaceNameFromGuid(_In_ const GUID * pInterfaceGUID,
3495                            _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3496                            _Inout_ PULONG pOutBufLen,
3497                            DWORD dwUnknown4,
3498                            DWORD dwUnknown5)
3499 {
3500     DWORD result;
3501 
3502     result = GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3503 
3504     if (result == ERROR_NOT_FOUND)
3505         SetLastError(ERROR_PATH_NOT_FOUND);
3506 
3507     return result;
3508 }
3509