xref: /reactos/dll/win32/iphlpapi/iphlpapi_main.c (revision 7eead935)
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             if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
812              "Software\\Wine\\Wine\\Config\\Network", 0, KEY_READ,
813              &hKey) == ERROR_SUCCESS) {
814               DWORD size = sizeof(primaryWINS.String);
815               unsigned long addr;
816 
817               RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
818                (PBYTE)primaryWINS.String, &size);
819               addr = inet_addr(primaryWINS.String);
820               if (addr != INADDR_NONE && addr != INADDR_ANY)
821                 winsEnabled = TRUE;
822               size = sizeof(secondaryWINS.String);
823               RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
824                (PBYTE)secondaryWINS.String, &size);
825               addr = inet_addr(secondaryWINS.String);
826               if (addr != INADDR_NONE && addr != INADDR_ANY)
827                 winsEnabled = TRUE;
828               RegCloseKey(hKey);
829             }
830 			TRACE("num of index is %lu\n", table->numIndexes);
831             for (ndx = 0; ndx < table->numIndexes; ndx++) {
832               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
833               DWORD addrLen = sizeof(ptr->Address), type;
834               const char *ifname =
835                   getInterfaceNameByIndex(table->indexes[ndx]);
836               if (!ifname) {
837                   ret = ERROR_OUTOFMEMORY;
838                   break;
839               }
840 
841               /* on Win98 this is left empty, but whatever */
842               strncpy(ptr->AdapterName,ifname,sizeof(ptr->AdapterName));
843               consumeInterfaceName(ifname);
844               ptr->AdapterName[MAX_ADAPTER_NAME_LENGTH] = '\0';
845               getInterfacePhysicalByIndex(table->indexes[ndx], &addrLen,
846                ptr->Address, &type);
847               /* MS defines address length and type as UINT in some places and
848                  DWORD in others, **sigh**.  Don't want to assume that PUINT and
849                  PDWORD are equiv (64-bit?) */
850               ptr->AddressLength = addrLen;
851               ptr->Type = type;
852               ptr->Index = table->indexes[ndx];
853               toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
854                ptr->IpAddressList.IpAddress.String);
855               toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
856                ptr->IpAddressList.IpMask.String);
857               ptr->IpAddressList.Context = ptr->Index;
858               toIPAddressString(getInterfaceGatewayByIndex(table->indexes[ndx]),
859                ptr->GatewayList.IpAddress.String);
860               getDhcpInfoForAdapter(table->indexes[ndx], &dhcpEnabled,
861                                     &dhcpServer, &ptr->LeaseObtained,
862                                     &ptr->LeaseExpires);
863               ptr->DhcpEnabled = (DWORD) dhcpEnabled;
864               toIPAddressString(dhcpServer,
865                                 ptr->DhcpServer.IpAddress.String);
866               if (winsEnabled) {
867                 ptr->HaveWins = TRUE;
868                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
869                  primaryWINS.String, sizeof(primaryWINS.String));
870                 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
871                  secondaryWINS.String, sizeof(secondaryWINS.String));
872               }
873               if (ndx < table->numIndexes - 1)
874                 ptr->Next = &pAdapterInfo[ndx + 1];
875               else
876                 ptr->Next = NULL;
877             }
878             ret = NO_ERROR;
879           }
880           free(table);
881         }
882         else
883           ret = ERROR_OUTOFMEMORY;
884       }
885     }
886     else
887       ret = ERROR_NO_DATA;
888   }
889   TRACE("returning %ld\n", ret);
890   return ret;
891 }
892 
893 
894 /******************************************************************
895  *    GetBestInterface (IPHLPAPI.@)
896  *
897  *
898  * PARAMS
899  *
900  *  dwDestAddr [In]
901  *  pdwBestIfIndex [In/Out]
902  *
903  * RETURNS
904  *
905  *  DWORD
906  *
907  */
908 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
909 {
910   DWORD ret;
911 
912   TRACE("dwDestAddr 0x%08lx, pdwBestIfIndex %p\n", dwDestAddr, pdwBestIfIndex);
913   if (!pdwBestIfIndex)
914     ret = ERROR_INVALID_PARAMETER;
915   else {
916     MIB_IPFORWARDROW ipRow;
917 
918     ret = GetBestRoute(dwDestAddr, 0, &ipRow);
919     if (ret == ERROR_SUCCESS)
920       *pdwBestIfIndex = ipRow.dwForwardIfIndex;
921   }
922   TRACE("returning %ld\n", ret);
923   return ret;
924 }
925 
926 
927 /******************************************************************
928  *    GetBestRoute (IPHLPAPI.@)
929  *
930  *
931  * PARAMS
932  *
933  *  dwDestAddr [In]
934  *  dwSourceAddr [In]
935  *  OUT [In]
936  *
937  * RETURNS
938  *
939  *  DWORD
940  *
941  */
942 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
943 {
944   PMIB_IPFORWARDTABLE table;
945   DWORD ret;
946 
947   TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr,
948    dwSourceAddr, pBestRoute);
949   if (!pBestRoute)
950     return ERROR_INVALID_PARAMETER;
951 
952   AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
953   if (table) {
954     DWORD ndx, minMaskSize, matchedNdx = 0;
955 
956     for (ndx = 0, minMaskSize = 255; ndx < table->dwNumEntries; ndx++) {
957       if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
958        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
959         DWORD hostMaskSize;
960 
961         if (!_BitScanForward(&hostMaskSize, ntohl(table->table[ndx].dwForwardMask)))
962         {
963             hostMaskSize = 32;
964         }
965         if (hostMaskSize < minMaskSize) {
966           minMaskSize = hostMaskSize;
967           matchedNdx = ndx;
968         }
969       }
970     }
971     memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
972     HeapFree(GetProcessHeap(), 0, table);
973     ret = ERROR_SUCCESS;
974   }
975   else
976     ret = ERROR_OUTOFMEMORY;
977   TRACE("returning %ld\n", ret);
978   return ret;
979 }
980 
981 static int TcpTableSorter(const void *a, const void *b)
982 {
983   int ret;
984 
985   if (a && b) {
986     PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
987 
988     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
989     if (ret == 0) {
990       ret = rowA->dwLocalPort - rowB->dwLocalPort;
991       if (ret == 0) {
992         ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
993         if (ret == 0)
994           ret = rowA->dwRemotePort - rowB->dwRemotePort;
995       }
996     }
997   }
998   else
999     ret = 0;
1000   return ret;
1001 }
1002 
1003 /******************************************************************
1004  *    GetExtendedTcpTable (IPHLPAPI.@)
1005  *
1006  * Get the table of TCP endpoints available to the application.
1007  *
1008  * PARAMS
1009  *  pTcpTable [Out]    table struct with the filtered TCP endpoints available to application
1010  *  pdwSize   [In/Out] estimated size of the structure returned in pTcpTable, in bytes
1011  *  bOrder    [In]     whether to order the table
1012  *  ulAf	[in]	version of IP used by the TCP endpoints
1013  *  TableClass [in]	type of the TCP table structure from TCP_TABLE_CLASS
1014  *  Reserved [in]	reserved - this value must be zero
1015  *
1016  * RETURNS
1017  *  Success: NO_ERROR
1018  *  Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
1019  *
1020  * NOTES
1021  */
1022 
1023 DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
1024 {
1025     DWORD i, count, size;
1026 	DWORD ret = NO_ERROR;
1027 
1028     if (!pdwSize)
1029     {
1030         return ERROR_INVALID_PARAMETER;
1031     }
1032 
1033     if (ulAf != AF_INET)
1034     {
1035         UNIMPLEMENTED;
1036         return ERROR_INVALID_PARAMETER;
1037     }
1038 
1039     switch (TableClass)
1040     {
1041         case TCP_TABLE_BASIC_ALL:
1042         {
1043             PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
1044             PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
1045 
1046             if (pOurTcpTable)
1047             {
1048                 size = FIELD_OFFSET(MIB_TCPTABLE, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW);
1049                 if (size > *pdwSize || !pTheirTcpTable)
1050                 {
1051                     *pdwSize = size;
1052                     ret = ERROR_INSUFFICIENT_BUFFER;
1053                 }
1054                 else
1055                 {
1056                     memcpy(pTheirTcpTable, pOurTcpTable, size);
1057 
1058                     if (bOrder)
1059                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1060                               sizeof(MIB_TCPROW), TcpTableSorter);
1061                 }
1062 
1063                 free(pOurTcpTable);
1064             }
1065         }
1066         break;
1067 
1068         case TCP_TABLE_BASIC_CONNECTIONS:
1069         {
1070             PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
1071             PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
1072 
1073             if (pOurTcpTable)
1074             {
1075                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1076                 {
1077                     if (pOurTcpTable->table[i].State != MIB_TCP_STATE_LISTEN)
1078                     {
1079                         ++count;
1080                     }
1081                 }
1082 
1083                 size = FIELD_OFFSET(MIB_TCPTABLE, table) + count * sizeof(MIB_TCPROW);
1084                 if (size > *pdwSize || !pTheirTcpTable)
1085                 {
1086                     *pdwSize = size;
1087                     ret = ERROR_INSUFFICIENT_BUFFER;
1088                 }
1089                 else
1090                 {
1091                     pTheirTcpTable->dwNumEntries = count;
1092 
1093                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1094                     {
1095                         if (pOurTcpTable->table[i].State != MIB_TCP_STATE_LISTEN)
1096                         {
1097                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW));
1098                             ++count;
1099                         }
1100                     }
1101                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1102 
1103                     if (bOrder)
1104                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1105                               sizeof(MIB_TCPROW), TcpTableSorter);
1106                 }
1107 
1108                 free(pOurTcpTable);
1109             }
1110         }
1111         break;
1112 
1113         case TCP_TABLE_BASIC_LISTENER:
1114         {
1115             PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
1116             PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
1117 
1118             if (pOurTcpTable)
1119             {
1120                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1121                 {
1122                     if (pOurTcpTable->table[i].State == MIB_TCP_STATE_LISTEN)
1123                     {
1124                         ++count;
1125                     }
1126                 }
1127 
1128                 size = FIELD_OFFSET(MIB_TCPTABLE, table) + count * sizeof(MIB_TCPROW);
1129                 if (size > *pdwSize || !pTheirTcpTable)
1130                 {
1131                     *pdwSize = size;
1132                     ret = ERROR_INSUFFICIENT_BUFFER;
1133                 }
1134                 else
1135                 {
1136                     pTheirTcpTable->dwNumEntries = count;
1137 
1138                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1139                     {
1140                         if (pOurTcpTable->table[i].State == MIB_TCP_STATE_LISTEN)
1141                         {
1142                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW));
1143                             ++count;
1144                         }
1145                     }
1146                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1147 
1148                     if (bOrder)
1149                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1150                               sizeof(MIB_TCPROW), TcpTableSorter);
1151                 }
1152 
1153                 free(pOurTcpTable);
1154             }
1155         }
1156         break;
1157 
1158         case TCP_TABLE_OWNER_PID_ALL:
1159         {
1160             PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
1161             PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1162 
1163             if (pOurTcpTable)
1164             {
1165                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_PID);
1166                 if (size > *pdwSize || !pTheirTcpTable)
1167                 {
1168                     *pdwSize = size;
1169                     ret = ERROR_INSUFFICIENT_BUFFER;
1170                 }
1171                 else
1172                 {
1173                     memcpy(pTheirTcpTable, pOurTcpTable, size);
1174 
1175                     /* Don't sort on PID, so use basic helper */
1176                     if (bOrder)
1177                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1178                               sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1179                 }
1180 
1181                 free(pOurTcpTable);
1182             }
1183         }
1184         break;
1185 
1186         case TCP_TABLE_OWNER_PID_CONNECTIONS:
1187         {
1188             PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
1189             PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1190 
1191             if (pOurTcpTable)
1192             {
1193                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1194                 {
1195                     if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1196                     {
1197                         ++count;
1198                     }
1199                 }
1200 
1201                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + count * sizeof(MIB_TCPROW_OWNER_PID);
1202                 if (size > *pdwSize || !pTheirTcpTable)
1203                 {
1204                     *pdwSize = size;
1205                     ret = ERROR_INSUFFICIENT_BUFFER;
1206                 }
1207                 else
1208                 {
1209                     pTheirTcpTable->dwNumEntries = count;
1210 
1211                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1212                     {
1213                         if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1214                         {
1215                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_PID));
1216                             ++count;
1217                         }
1218                     }
1219                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1220 
1221                     /* Don't sort on PID, so use basic helper */
1222                     if (bOrder)
1223                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1224                               sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1225                 }
1226 
1227                 free(pOurTcpTable);
1228             }
1229         }
1230         break;
1231 
1232         case TCP_TABLE_OWNER_PID_LISTENER:
1233         {
1234             PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
1235             PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1236 
1237             if (pOurTcpTable)
1238             {
1239                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1240                 {
1241                     if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1242                     {
1243                         ++count;
1244                     }
1245                 }
1246 
1247                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + count * sizeof(MIB_TCPROW_OWNER_PID);
1248                 if (size > *pdwSize || !pTheirTcpTable)
1249                 {
1250                     *pdwSize = size;
1251                     ret = ERROR_INSUFFICIENT_BUFFER;
1252                 }
1253                 else
1254                 {
1255                     pTheirTcpTable->dwNumEntries = count;
1256 
1257                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1258                     {
1259                         if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1260                         {
1261                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_PID));
1262                             ++count;
1263                         }
1264                     }
1265                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1266 
1267                     /* Don't sort on PID, so use basic helper */
1268                     if (bOrder)
1269                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1270                               sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1271                 }
1272 
1273                 free(pOurTcpTable);
1274             }
1275         }
1276         break;
1277 
1278         case TCP_TABLE_OWNER_MODULE_ALL:
1279         {
1280             PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getTcpTable(ClassModule);
1281             PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1282 
1283             if (pOurTcpTable)
1284             {
1285                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_MODULE);
1286                 if (size > *pdwSize || !pTheirTcpTable)
1287                 {
1288                     *pdwSize = size;
1289                     ret = ERROR_INSUFFICIENT_BUFFER;
1290                 }
1291                 else
1292                 {
1293                     memcpy(pTheirTcpTable, pOurTcpTable, size);
1294 
1295                     /* Don't sort on PID, so use basic helper */
1296                     if (bOrder)
1297                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1298                               sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1299                 }
1300 
1301                 free(pOurTcpTable);
1302             }
1303         }
1304         break;
1305 
1306         case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
1307         {
1308             PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getTcpTable(ClassModule);
1309             PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1310 
1311             if (pOurTcpTable)
1312             {
1313                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1314                 {
1315                     if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1316                     {
1317                         ++count;
1318                     }
1319                 }
1320 
1321                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table) + count * sizeof(MIB_TCPROW_OWNER_MODULE);
1322                 if (size > *pdwSize || !pTheirTcpTable)
1323                 {
1324                     *pdwSize = size;
1325                     ret = ERROR_INSUFFICIENT_BUFFER;
1326                 }
1327                 else
1328                 {
1329                     pTheirTcpTable->dwNumEntries = count;
1330 
1331                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1332                     {
1333                         if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1334                         {
1335                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_MODULE));
1336                             ++count;
1337                         }
1338                     }
1339                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1340 
1341                     /* Don't sort on PID, so use basic helper */
1342                     if (bOrder)
1343                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1344                               sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1345                 }
1346 
1347                 free(pOurTcpTable);
1348             }
1349         }
1350         break;
1351 
1352         case TCP_TABLE_OWNER_MODULE_LISTENER:
1353         {
1354             PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getTcpTable(ClassModule);
1355             PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1356 
1357             if (pOurTcpTable)
1358             {
1359                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1360                 {
1361                     if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1362                     {
1363                         ++count;
1364                     }
1365                 }
1366 
1367                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table) + count * sizeof(MIB_TCPROW_OWNER_MODULE);
1368                 if (size > *pdwSize || !pTheirTcpTable)
1369                 {
1370                     *pdwSize = size;
1371                     ret = ERROR_INSUFFICIENT_BUFFER;
1372                 }
1373                 else
1374                 {
1375                     pTheirTcpTable->dwNumEntries = count;
1376 
1377                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1378                     {
1379                         if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1380                         {
1381                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_MODULE));
1382                             ++count;
1383                         }
1384                     }
1385                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1386 
1387                     /* Don't sort on PID, so use basic helper */
1388                     if (bOrder)
1389                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1390                               sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1391                 }
1392 
1393                 free(pOurTcpTable);
1394             }
1395         }
1396         break;
1397 
1398         default:
1399             ret = ERROR_INVALID_PARAMETER;
1400             break;
1401     }
1402 
1403     return ret;
1404 }
1405 
1406 
1407 static int UdpTableSorter(const void *a, const void *b)
1408 {
1409   int ret;
1410 
1411   if (a && b) {
1412     PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
1413 
1414     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1415     if (ret == 0)
1416       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1417   }
1418   else
1419     ret = 0;
1420   return ret;
1421 }
1422 
1423 /******************************************************************
1424  *    GetExtendedUdpTable (IPHLPAPI.@)
1425  *
1426  * Get the table of UDP endpoints available to the application.
1427  *
1428  * PARAMS
1429  *  pUdpTable [Out]    table struct with the filtered UDP endpoints available to application
1430  *  pdwSize   [In/Out] estimated size of the structure returned in pUdpTable, in bytes
1431  *  bOrder    [In]     whether to order the table
1432  *  ulAf	[in]	version of IP used by the UDP endpoints
1433  *  TableClass [in]	type of the UDP table structure from UDP_TABLE_CLASS
1434  *  Reserved [in]	reserved - this value must be zero
1435  *
1436  * RETURNS
1437  *  Success: NO_ERROR
1438  *  Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
1439  *
1440  * NOTES
1441  */
1442 
1443 DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved)
1444 {
1445     DWORD size;
1446 	DWORD ret = NO_ERROR;
1447 
1448     if (!pdwSize)
1449     {
1450         return ERROR_INVALID_PARAMETER;
1451     }
1452 
1453     if (ulAf != AF_INET)
1454     {
1455         UNIMPLEMENTED;
1456         return ERROR_INVALID_PARAMETER;
1457     }
1458 
1459     switch (TableClass)
1460     {
1461         case UDP_TABLE_BASIC:
1462         {
1463             PMIB_UDPTABLE pOurUdpTable = getUdpTable(ClassBasic);
1464             PMIB_UDPTABLE pTheirUdpTable = pUdpTable;
1465 
1466             if (pOurUdpTable)
1467             {
1468                 size = FIELD_OFFSET(MIB_UDPTABLE, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW);
1469                 if (size > *pdwSize || !pTheirUdpTable)
1470                 {
1471                     *pdwSize = size;
1472                     ret = ERROR_INSUFFICIENT_BUFFER;
1473                 }
1474                 else
1475                 {
1476                     memcpy(pTheirUdpTable, pOurUdpTable, size);
1477 
1478                     if (bOrder)
1479                         qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1480                               sizeof(MIB_UDPROW), UdpTableSorter);
1481                 }
1482 
1483                 free(pOurUdpTable);
1484             }
1485         }
1486         break;
1487 
1488         case UDP_TABLE_OWNER_PID:
1489         {
1490             PMIB_UDPTABLE_OWNER_PID pOurUdpTable = getUdpTable(ClassModulePid);
1491             PMIB_UDPTABLE_OWNER_PID pTheirUdpTable = pUdpTable;
1492 
1493             if (pOurUdpTable)
1494             {
1495                 size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_PID);
1496                 if (size > *pdwSize || !pTheirUdpTable)
1497                 {
1498                     *pdwSize = size;
1499                     ret = ERROR_INSUFFICIENT_BUFFER;
1500                 }
1501                 else
1502                 {
1503                     memcpy(pTheirUdpTable, pOurUdpTable, size);
1504 
1505                     if (bOrder)
1506                         qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1507                               sizeof(MIB_UDPROW_OWNER_PID), UdpTableSorter);
1508                 }
1509 
1510                 free(pOurUdpTable);
1511             }
1512         }
1513         break;
1514 
1515         case UDP_TABLE_OWNER_MODULE:
1516         {
1517             PMIB_UDPTABLE_OWNER_MODULE pOurUdpTable = getUdpTable(ClassModule);
1518             PMIB_UDPTABLE_OWNER_MODULE pTheirUdpTable = pUdpTable;
1519 
1520             if (pOurUdpTable)
1521             {
1522                 size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_MODULE);
1523                 if (size > *pdwSize || !pTheirUdpTable)
1524                 {
1525                     *pdwSize = size;
1526                     ret = ERROR_INSUFFICIENT_BUFFER;
1527                 }
1528                 else
1529                 {
1530                     memcpy(pTheirUdpTable, pOurUdpTable, size);
1531 
1532                     if (bOrder)
1533                         qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1534                               sizeof(MIB_UDPROW_OWNER_MODULE), UdpTableSorter);
1535                 }
1536 
1537                 free(pOurUdpTable);
1538             }
1539         }
1540         break;
1541 
1542         default:
1543             ret = ERROR_INVALID_PARAMETER;
1544             break;
1545     }
1546 
1547     return ret;
1548 }
1549 
1550 
1551 /******************************************************************
1552  *    GetFriendlyIfIndex (IPHLPAPI.@)
1553  *
1554  *
1555  * PARAMS
1556  *
1557  *  IfIndex [In]
1558  *
1559  * RETURNS
1560  *
1561  *  DWORD
1562  *
1563  */
1564 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1565 {
1566   /* windows doesn't validate these, either, just makes sure the top byte is
1567      cleared.  I assume my ifenum module never gives an index with the top
1568      byte set. */
1569   TRACE("returning %ld\n", IfIndex);
1570   return IfIndex;
1571 }
1572 
1573 
1574 /******************************************************************
1575  *    GetIcmpStatistics (IPHLPAPI.@)
1576  *
1577  *
1578  * PARAMS
1579  *
1580  *  pStats [In/Out]
1581  *
1582  * RETURNS
1583  *
1584  *  DWORD
1585  *
1586  */
1587 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
1588 {
1589   DWORD ret;
1590 
1591   TRACE("pStats %p\n", pStats);
1592   ret = getICMPStats(pStats);
1593   TRACE("returning %ld\n", ret);
1594   return ret;
1595 }
1596 
1597 
1598 /******************************************************************
1599  *    GetIfEntry (IPHLPAPI.@)
1600  *
1601  *
1602  * PARAMS
1603  *
1604  *  pIfRow [In/Out]
1605  *
1606  * RETURNS
1607  *
1608  *  DWORD
1609  *
1610  */
1611 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
1612 {
1613   DWORD ret;
1614   const char *name;
1615 
1616   TRACE("pIfRow %p\n", pIfRow);
1617   if (!pIfRow)
1618     return ERROR_INVALID_PARAMETER;
1619 
1620   name = getInterfaceNameByIndex(pIfRow->dwIndex);
1621   if (name) {
1622     ret = getInterfaceEntryByIndex(pIfRow->dwIndex, pIfRow);
1623     if (ret == NO_ERROR)
1624       ret = getInterfaceStatsByName(name, pIfRow);
1625     consumeInterfaceName(name);
1626   }
1627   else
1628     ret = ERROR_INVALID_DATA;
1629   TRACE("returning %ld\n", ret);
1630   return ret;
1631 }
1632 
1633 
1634 static int IfTableSorter(const void *a, const void *b)
1635 {
1636   int ret;
1637 
1638   if (a && b)
1639     ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
1640   else
1641     ret = 0;
1642   return ret;
1643 }
1644 
1645 
1646 /******************************************************************
1647  *    GetIfTable (IPHLPAPI.@)
1648  *
1649  *
1650  * PARAMS
1651  *
1652  *  pIfTable [In/Out]
1653  *  pdwSize [In/Out]
1654  *  bOrder [In]
1655  *
1656  * RETURNS
1657  *
1658  *  DWORD
1659  *
1660  */
1661 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
1662 {
1663   DWORD ret;
1664 
1665   TRACE("pIfTable %p, pdwSize %p, bOrder %ld\n", pdwSize, pdwSize,
1666    (DWORD)bOrder);
1667   if (!pdwSize)
1668     ret = ERROR_INVALID_PARAMETER;
1669   else {
1670     DWORD numInterfaces = getNumInterfaces();
1671     ULONG size;
1672     TRACE("GetIfTable: numInterfaces = %d\n", (int)numInterfaces);
1673     size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
1674 
1675     if (!pIfTable || *pdwSize < size) {
1676       *pdwSize = size;
1677       ret = ERROR_INSUFFICIENT_BUFFER;
1678     }
1679     else {
1680       InterfaceIndexTable *table = getInterfaceIndexTable();
1681 
1682       if (table) {
1683         size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
1684          sizeof(MIB_IFROW);
1685         if (*pdwSize < size) {
1686           *pdwSize = size;
1687           ret = ERROR_INSUFFICIENT_BUFFER;
1688         }
1689         else {
1690           DWORD ndx;
1691 
1692           pIfTable->dwNumEntries = 0;
1693           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1694             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
1695             GetIfEntry(&pIfTable->table[ndx]);
1696             pIfTable->dwNumEntries++;
1697           }
1698           if (bOrder)
1699             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
1700              IfTableSorter);
1701           ret = NO_ERROR;
1702         }
1703         free(table);
1704       }
1705       else
1706         ret = ERROR_OUTOFMEMORY;
1707     }
1708   }
1709   TRACE("returning %ld\n", ret);
1710   return ret;
1711 }
1712 
1713 
1714 /******************************************************************
1715  *    GetInterfaceInfo (IPHLPAPI.@)
1716  *
1717  *
1718  * PARAMS
1719  *
1720  *  pIfTable [In/Out]
1721  *  dwOutBufLen [In/Out]
1722  *
1723  * RETURNS
1724  *
1725  *  DWORD
1726  *
1727  */
1728 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
1729 {
1730   DWORD ret;
1731 
1732   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
1733   if (!dwOutBufLen)
1734     ret = ERROR_INVALID_PARAMETER;
1735   else {
1736     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
1737     ULONG size;
1738     TRACE("numNonLoopbackInterfaces == 0x%x\n", numNonLoopbackInterfaces);
1739     size = sizeof(IP_INTERFACE_INFO) + (numNonLoopbackInterfaces) *
1740      sizeof(IP_ADAPTER_INDEX_MAP);
1741 
1742     if (!pIfTable || *dwOutBufLen < size) {
1743       *dwOutBufLen = size;
1744       ret = ERROR_INSUFFICIENT_BUFFER;
1745     }
1746     else {
1747       InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
1748 
1749       if (table) {
1750         TRACE("table->numIndexes == 0x%x\n", table->numIndexes);
1751         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes) *
1752          sizeof(IP_ADAPTER_INDEX_MAP);
1753         if (*dwOutBufLen < size) {
1754           *dwOutBufLen = size;
1755           ret = ERROR_INSUFFICIENT_BUFFER;
1756         }
1757         else {
1758           DWORD ndx;
1759 
1760           pIfTable->NumAdapters = 0;
1761           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1762             const char *walker, *name;
1763             WCHAR *assigner;
1764 
1765             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
1766             name = getInterfaceNameByIndex(table->indexes[ndx]);
1767             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
1768              walker && *walker &&
1769              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
1770              walker++, assigner++)
1771               *assigner = *walker;
1772             *assigner = 0;
1773             consumeInterfaceName(name);
1774             pIfTable->NumAdapters++;
1775           }
1776           ret = NO_ERROR;
1777         }
1778         free(table);
1779       }
1780       else
1781         ret = ERROR_OUTOFMEMORY;
1782     }
1783   }
1784   TRACE("returning %ld\n", ret);
1785   return ret;
1786 }
1787 
1788 
1789 static int IpAddrTableSorter(const void *a, const void *b)
1790 {
1791   int ret;
1792 
1793   if (a && b)
1794     ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
1795   else
1796     ret = 0;
1797   return ret;
1798 }
1799 
1800 
1801 /******************************************************************
1802  *    GetIpAddrTable (IPHLPAPI.@)
1803  *
1804  *
1805  * PARAMS
1806  *
1807  *  pIpAddrTable [In/Out]
1808  *  pdwSize [In/Out]
1809  *  bOrder [In]
1810  *
1811  * RETURNS
1812  *
1813  *  DWORD
1814  *
1815  */
1816 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1817 {
1818   DWORD ret;
1819 
1820   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
1821    (DWORD)bOrder);
1822   if (!pdwSize)
1823     ret = ERROR_INVALID_PARAMETER;
1824   else {
1825     DWORD numInterfaces = getNumInterfaces();
1826     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
1827      sizeof(MIB_IPADDRROW);
1828 
1829     if (!pIpAddrTable || *pdwSize < size) {
1830       *pdwSize = size;
1831       ret = ERROR_INSUFFICIENT_BUFFER;
1832     }
1833     else {
1834       InterfaceIndexTable *table = getInterfaceIndexTable();
1835 
1836       if (table) {
1837         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
1838          sizeof(MIB_IPADDRROW);
1839         if (*pdwSize < size) {
1840           *pdwSize = size;
1841           ret = ERROR_INSUFFICIENT_BUFFER;
1842         }
1843         else {
1844           DWORD ndx, bcast;
1845 
1846           pIpAddrTable->dwNumEntries = 0;
1847           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1848             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
1849             pIpAddrTable->table[ndx].dwAddr =
1850              getInterfaceIPAddrByIndex(table->indexes[ndx]);
1851             pIpAddrTable->table[ndx].dwMask =
1852              getInterfaceMaskByIndex(table->indexes[ndx]);
1853             /* the dwBCastAddr member isn't the broadcast address, it indicates
1854              * whether the interface uses the 1's broadcast address (1) or the
1855              * 0's broadcast address (0).
1856              */
1857             bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
1858             pIpAddrTable->table[ndx].dwBCastAddr =
1859              (bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
1860             /* FIXME: hardcoded reasm size, not sure where to get it */
1861             pIpAddrTable->table[ndx].dwReasmSize = 65535;
1862             pIpAddrTable->table[ndx].unused1 = 0;
1863             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
1864             pIpAddrTable->dwNumEntries++;
1865           }
1866           if (bOrder)
1867             qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1868              sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1869           ret = NO_ERROR;
1870         }
1871         free(table);
1872       }
1873       else
1874         ret = ERROR_OUTOFMEMORY;
1875     }
1876   }
1877   TRACE("returning %ld\n", ret);
1878   return ret;
1879 }
1880 
1881 
1882 static int IpForwardTableSorter(const void *a, const void *b)
1883 {
1884   int ret;
1885 
1886   if (a && b) {
1887     PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
1888 
1889     ret = rowA->dwForwardDest - rowB->dwForwardDest;
1890     if (ret == 0) {
1891       ret = rowA->dwForwardProto - rowB->dwForwardProto;
1892       if (ret == 0) {
1893         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
1894         if (ret == 0)
1895           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1896       }
1897     }
1898   }
1899   else
1900     ret = 0;
1901   return ret;
1902 }
1903 
1904 
1905 /******************************************************************
1906  *    GetIpForwardTable (IPHLPAPI.@)
1907  *
1908  *
1909  * PARAMS
1910  *
1911  *  pIpForwardTable [In/Out]
1912  *  pdwSize [In/Out]
1913  *  bOrder [In]
1914  *
1915  * RETURNS
1916  *
1917  *  DWORD
1918  *
1919  */
1920 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1921 {
1922   DWORD ret;
1923 
1924   TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
1925         pdwSize, (DWORD)bOrder);
1926   if (!pdwSize)
1927     ret = ERROR_INVALID_PARAMETER;
1928   else {
1929     DWORD numRoutes = getNumRoutes();
1930     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1931      sizeof(MIB_IPFORWARDROW);
1932 
1933     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1934       *pdwSize = sizeNeeded;
1935       ret = ERROR_INSUFFICIENT_BUFFER;
1936     }
1937     else {
1938       RouteTable *table = getRouteTable();
1939       if (table) {
1940         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1941          sizeof(MIB_IPFORWARDROW);
1942         if (*pdwSize < sizeNeeded) {
1943           *pdwSize = sizeNeeded;
1944           ret = ERROR_INSUFFICIENT_BUFFER;
1945         }
1946         else {
1947           DWORD ndx;
1948 
1949           pIpForwardTable->dwNumEntries = table->numRoutes;
1950           for (ndx = 0; ndx < numRoutes; ndx++) {
1951             pIpForwardTable->table[ndx].dwForwardIfIndex =
1952              table->routes[ndx].ifIndex;
1953             pIpForwardTable->table[ndx].dwForwardDest =
1954              table->routes[ndx].dest;
1955             pIpForwardTable->table[ndx].dwForwardMask =
1956              table->routes[ndx].mask;
1957             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1958             pIpForwardTable->table[ndx].dwForwardNextHop =
1959              table->routes[ndx].gateway;
1960             /* FIXME: this type is appropriate for local interfaces; may not
1961                always be appropriate */
1962             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1963             /* FIXME: other protos might be appropriate, e.g. the default route
1964                is typically set with MIB_IPPROTO_NETMGMT instead */
1965             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1966             /* punt on age and AS */
1967             pIpForwardTable->table[ndx].dwForwardAge = 0;
1968             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1969             pIpForwardTable->table[ndx].dwForwardMetric1 =
1970              table->routes[ndx].metric;
1971             /* rest of the metrics are 0.. */
1972             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1973             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1974             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1975             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1976           }
1977           if (bOrder)
1978             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1979              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1980           ret = NO_ERROR;
1981         }
1982         HeapFree(GetProcessHeap(), 0, table);
1983       }
1984       else
1985         ret = ERROR_OUTOFMEMORY;
1986     }
1987   }
1988   TRACE("returning %ld\n", ret);
1989   return ret;
1990 }
1991 
1992 
1993 static int IpNetTableSorter(const void *a, const void *b)
1994 {
1995   int ret;
1996 
1997   if (a && b)
1998     ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
1999   else
2000     ret = 0;
2001   return ret;
2002 }
2003 
2004 
2005 /******************************************************************
2006  *    GetIpNetTable (IPHLPAPI.@)
2007  *
2008  *
2009  * PARAMS
2010  *
2011  *  pIpNetTable [In/Out]
2012  *  pdwSize [In/Out]
2013  *  bOrder [In]
2014  *
2015  * RETURNS
2016  *
2017  *  DWORD
2018  *
2019  */
2020 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
2021 {
2022   DWORD ret = NO_ERROR;
2023 
2024   TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize,
2025    (DWORD)bOrder);
2026   if (!pdwSize)
2027     ret = ERROR_INVALID_PARAMETER;
2028   else {
2029     DWORD numEntries = getNumArpEntries();
2030     ULONG size = sizeof(MIB_IPNETTABLE);
2031 
2032     if (numEntries > 1)
2033       size += (numEntries - 1) * sizeof(MIB_IPNETROW);
2034     if (!pIpNetTable || *pdwSize < size) {
2035       *pdwSize = size;
2036       ret = ERROR_INSUFFICIENT_BUFFER;
2037     }
2038     else {
2039       PMIB_IPNETTABLE table = getArpTable();
2040       if (table) {
2041         size = sizeof(MIB_IPNETTABLE);
2042         if (table->dwNumEntries > 1)
2043           size += (table->dwNumEntries - 1) * sizeof(MIB_IPNETROW);
2044         if (*pdwSize < size) {
2045           *pdwSize = size;
2046           ret = ERROR_INSUFFICIENT_BUFFER;
2047         }
2048         else {
2049           *pdwSize = size;
2050           memcpy(pIpNetTable, table, size);
2051           if (bOrder)
2052             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
2053              sizeof(MIB_IPNETROW), IpNetTableSorter);
2054           ret = NO_ERROR;
2055         }
2056         HeapFree(GetProcessHeap(), 0, table);
2057       }
2058     }
2059   }
2060   TRACE("returning %d\n", ret);
2061   return ret;
2062 }
2063 
2064 
2065 /******************************************************************
2066  *    GetIpStatistics (IPHLPAPI.@)
2067  *
2068  *
2069  * PARAMS
2070  *
2071  *  pStats [In/Out]
2072  *
2073  * RETURNS
2074  *
2075  *  DWORD
2076  *
2077  */
2078 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
2079 {
2080     return GetIpStatisticsEx(pStats, PF_INET);
2081 }
2082 
2083 /******************************************************************
2084  *    GetIpStatisticsEx (IPHLPAPI.@)
2085  *
2086  *
2087  * PARAMS
2088  *
2089  *  pStats [In/Out]
2090  *  dwFamily [In]
2091  *
2092  * RETURNS
2093  *
2094  *  DWORD
2095  *
2096  */
2097 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily)
2098 {
2099   DWORD ret;
2100 
2101   TRACE("pStats %p\n", pStats);
2102   ret = getIPStats(pStats, dwFamily);
2103   TRACE("returning %ld\n", ret);
2104   return ret;
2105 }
2106 
2107 /******************************************************************
2108  *    GetNetworkParams (IPHLPAPI.@)
2109  *
2110  *
2111  * PARAMS
2112  *
2113  *  pFixedInfo [In/Out]
2114  *  pOutBufLen [In/Out]
2115  *
2116  * RETURNS
2117  *
2118  *  DWORD
2119  *
2120  */
2121 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
2122 {
2123   DWORD ret, size, type;
2124   LONG regReturn;
2125   HKEY hKey;
2126   PIPHLP_RES_INFO resInfo;
2127 
2128   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
2129   if (!pOutBufLen)
2130     return ERROR_INVALID_PARAMETER;
2131 
2132   resInfo = getResInfo();
2133   if (!resInfo)
2134     return ERROR_OUTOFMEMORY;
2135 
2136   size = sizeof(FIXED_INFO) + (resInfo->riCount > 1 ? (resInfo->riCount-1) *
2137    sizeof(IP_ADDR_STRING) : 0);
2138   if (!pFixedInfo || *pOutBufLen < size) {
2139     *pOutBufLen = size;
2140     disposeResInfo( resInfo );
2141     return ERROR_BUFFER_OVERFLOW;
2142   }
2143 
2144   memset(pFixedInfo, 0, size);
2145   /* Check for DhcpHostname and DhcpDomain first */
2146   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2147                             "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
2148                             0,
2149                             KEY_READ,
2150                             &hKey);
2151   if (regReturn == ERROR_SUCCESS) {
2152       /* Windows doesn't honor DHCP option 12 even if RFC requires it if it is returned by DHCP server! */
2153 #if 0
2154       type = REG_SZ;
2155       size = sizeof(pFixedInfo->HostName);
2156       regReturn = RegQueryValueExA(hKey,
2157                                       "DhcpHostname",
2158                                       NULL,
2159                                       &type,
2160                                       (LPBYTE)pFixedInfo->HostName,
2161                                       &size);
2162       if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
2163       {
2164 #endif
2165           type = REG_SZ;
2166           size = sizeof(pFixedInfo->HostName);
2167           regReturn = RegQueryValueExA(hKey,
2168                                           "Hostname",
2169                                           NULL,
2170                                           &type,
2171                                           (LPBYTE)pFixedInfo->HostName,
2172                                           &size);
2173 #if 0
2174       }
2175 #endif
2176 
2177       type = REG_SZ;
2178       size = sizeof(pFixedInfo->DomainName);
2179       regReturn = RegQueryValueExA(hKey,
2180                                       "DhcpDomain",
2181                                       NULL,
2182                                       &type,
2183                                       (LPBYTE)pFixedInfo->DomainName,
2184                                       &size);
2185       if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
2186       {
2187           type = REG_SZ;
2188           size = sizeof(pFixedInfo->DomainName);
2189           regReturn = RegQueryValueExA(hKey,
2190                                           "Domain",
2191                                           NULL,
2192                                           &type,
2193                                           (LPBYTE)pFixedInfo->DomainName,
2194                                           &size);
2195       }
2196       RegCloseKey(hKey);
2197   }
2198 
2199   TRACE("GetComputerNameExA: %s\n", pFixedInfo->DomainName);
2200 
2201   if (resInfo->riCount > 0)
2202   {
2203     CopyMemory(&pFixedInfo->DnsServerList, resInfo->DnsList, sizeof(IP_ADDR_STRING));
2204     if (resInfo->riCount > 1)
2205     {
2206       IP_ADDR_STRING *pSrc = resInfo->DnsList->Next;
2207       IP_ADDR_STRING *pTarget = (struct _IP_ADDR_STRING*)((char*)pFixedInfo + sizeof(FIXED_INFO));
2208 
2209       pFixedInfo->DnsServerList.Next = pTarget;
2210 
2211       do
2212       {
2213         CopyMemory(pTarget, pSrc, sizeof(IP_ADDR_STRING));
2214         resInfo->riCount--;
2215         if (resInfo->riCount > 1)
2216         {
2217           pTarget->Next = (IP_ADDR_STRING*)((char*)pTarget + sizeof(IP_ADDR_STRING));
2218           pTarget = pTarget->Next;
2219           pSrc = pSrc->Next;
2220         }
2221         else
2222         {
2223           pTarget->Next = NULL;
2224           break;
2225         }
2226       }
2227       while(TRUE);
2228     }
2229     else
2230     {
2231       pFixedInfo->DnsServerList.Next = NULL;
2232     }
2233   }
2234 
2235   pFixedInfo->NodeType = HYBRID_NODETYPE;
2236   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2237    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
2238   if (regReturn != ERROR_SUCCESS)
2239     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2240      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
2241      &hKey);
2242   if (regReturn == ERROR_SUCCESS)
2243   {
2244     DWORD size = sizeof(pFixedInfo->ScopeId);
2245 
2246     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (PBYTE)pFixedInfo->ScopeId, &size);
2247     RegCloseKey(hKey);
2248   }
2249 
2250   disposeResInfo( resInfo );
2251   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
2252      I suppose could also check for a listener on port 53 to set EnableDns */
2253   ret = NO_ERROR;
2254   TRACE("returning %ld\n", ret);
2255 
2256   return ret;
2257 }
2258 
2259 
2260 /******************************************************************
2261  *    GetNumberOfInterfaces (IPHLPAPI.@)
2262  *
2263  *
2264  * PARAMS
2265  *
2266  *  pdwNumIf [In/Out]
2267  *
2268  * RETURNS
2269  *
2270  *  DWORD
2271  *
2272  */
2273 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
2274 {
2275   DWORD ret;
2276 
2277   TRACE("pdwNumIf %p\n", pdwNumIf);
2278   if (!pdwNumIf)
2279     ret = ERROR_INVALID_PARAMETER;
2280   else {
2281     *pdwNumIf = getNumInterfaces();
2282     ret = NO_ERROR;
2283   }
2284   TRACE("returning %ld\n", ret);
2285   return ret;
2286 }
2287 
2288 
2289 static DWORD GetOwnerModuleFromPidEntry(DWORD OwningPid, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2290 {
2291     HANDLE Process;
2292     DWORD FileLen, PathLen, Error;
2293     WCHAR File[MAX_PATH], Path[MAX_PATH];
2294     PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2295 
2296     if (IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
2297         IsBadWritePtr(Buffer, *pdwSize))
2298     {
2299         return ERROR_INVALID_PARAMETER;
2300     }
2301 
2302     if (OwningPid == 0)
2303     {
2304         return ERROR_NOT_FOUND;
2305     }
2306 
2307     Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, OwningPid);
2308     if (Process == NULL)
2309     {
2310         return GetLastError();
2311     }
2312 
2313     FileLen = GetModuleBaseNameW(Process, NULL, File, MAX_PATH);
2314     if (FileLen != 0)
2315     {
2316         PathLen = GetModuleFileNameExW(Process, NULL, Path, MAX_PATH);
2317         if (PathLen == 0)
2318         {
2319             CloseHandle(Process);
2320             return GetLastError();
2321         }
2322 
2323         /* Add NULL char */
2324         ++FileLen;
2325         ++PathLen;
2326         PathLen *= sizeof(WCHAR);
2327         FileLen *= sizeof(WCHAR);
2328     }
2329     else
2330     {
2331         Error = GetLastError();
2332 
2333         if (Error == ERROR_PARTIAL_COPY)
2334         {
2335             wcscpy(File, L"System");
2336             wcscpy(Path, L"System");
2337 
2338             PathLen = sizeof(L"System");
2339             FileLen = sizeof(L"System");
2340         }
2341         else
2342         {
2343             CloseHandle(Process);
2344             return Error;
2345         }
2346     }
2347 
2348     CloseHandle(Process);
2349 
2350     if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen)
2351     {
2352         *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2353         return ERROR_INSUFFICIENT_BUFFER;
2354     }
2355 
2356     BasicInfo = Buffer;
2357     BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2358     BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + FileLen);
2359     wcscpy(BasicInfo->pModuleName, File);
2360     wcscpy(BasicInfo->pModulePath, Path);
2361     *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2362 
2363     return NO_ERROR;
2364 }
2365 
2366 static DWORD GetOwnerModuleFromTagEntry(DWORD OwningPid, DWORD OwningTag, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2367 {
2368     UINT Size;
2369     HRESULT Res;
2370     HANDLE hAdvapi32;
2371     WCHAR SysDir[MAX_PATH];
2372     PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2373     ULONG (NTAPI *_I_QueryTagInformation)(PVOID, DWORD, PVOID);
2374     struct
2375     {
2376         DWORD ProcessId;
2377         DWORD ServiceTag;
2378         DWORD TagType;
2379         PWSTR Buffer;
2380     } ServiceQuery;
2381 
2382     if (IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
2383         IsBadWritePtr(Buffer, *pdwSize))
2384     {
2385         return ERROR_INVALID_PARAMETER;
2386     }
2387 
2388     /* First, secure (avoid injections) load advapi32.dll */
2389     Size = GetSystemDirectoryW(SysDir, MAX_PATH);
2390     if (Size == 0)
2391     {
2392         return GetLastError();
2393     }
2394 
2395     Res = StringCchCatW(&SysDir[Size], MAX_PATH - Size, L"\\advapi32.dll");
2396     if (FAILED(Res))
2397     {
2398         return Res;
2399     }
2400 
2401     hAdvapi32 = GetModuleHandleW(SysDir);
2402     if (hAdvapi32 == NULL)
2403     {
2404         return GetLastError();
2405     }
2406 
2407     /* Now, we'll query the service associated with the tag */
2408     _I_QueryTagInformation = (PVOID)GetProcAddress(hAdvapi32, "I_QueryTagInformation");
2409     if (_I_QueryTagInformation == NULL)
2410     {
2411         return GetLastError();
2412     }
2413 
2414     /* Set tag and PID for the query */
2415     ServiceQuery.ProcessId = OwningPid;
2416     ServiceQuery.ServiceTag = OwningTag;
2417     ServiceQuery.TagType = 0;
2418     ServiceQuery.Buffer = NULL;
2419 
2420     /* And query */
2421     Res = _I_QueryTagInformation(NULL, 1, &ServiceQuery);
2422     if (Res != ERROR_SUCCESS)
2423     {
2424         return Res;
2425     }
2426 
2427     /* Compute service name length */
2428     Size = wcslen(ServiceQuery.Buffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
2429 
2430     /* We'll copy it twice, so make sure we have enough room */
2431     if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size)
2432     {
2433         *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size;
2434         LocalFree(ServiceQuery.Buffer);
2435         return ERROR_INSUFFICIENT_BUFFER;
2436     }
2437 
2438     /* Copy back data */
2439     BasicInfo = Buffer;
2440     BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2441     BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + Size);
2442     wcscpy(BasicInfo->pModuleName, ServiceQuery.Buffer);
2443     wcscpy(BasicInfo->pModulePath, ServiceQuery.Buffer);
2444     *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size;
2445     LocalFree(ServiceQuery.Buffer);
2446 
2447     return NO_ERROR;
2448 }
2449 
2450 /******************************************************************
2451  *    GetOwnerModuleFromTcpEntry (IPHLPAPI.@)
2452  *
2453  * Get data about the module that issued the context bind for a specific IPv4 TCP endpoint in a MIB table row
2454  *
2455  * PARAMS
2456  *  pTcpEntry [in]    pointer to a MIB_TCPROW_OWNER_MODULE structure
2457  *  Class [in]    	TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2458  *  Buffer [out]     	pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2459  *  pdwSize [in, out]	estimated size of the structure returned in Buffer, in bytes
2460  *
2461  * RETURNS
2462  *  Success: NO_ERROR
2463  *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2464  * 	       ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2465  *
2466  * NOTES
2467  * The type of data returned in Buffer is indicated by the value of the Class parameter.
2468  */
2469 DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2470 {
2471     /* If we have a service tag, that's a service connection */
2472     if (pTcpEntry->OwningModuleInfo[0] != 0)
2473     {
2474         return GetOwnerModuleFromTagEntry(pTcpEntry->dwOwningPid, (DWORD)(pTcpEntry->OwningModuleInfo[0]), Class, Buffer, pdwSize);
2475     }
2476     else
2477     {
2478         return GetOwnerModuleFromPidEntry(pTcpEntry->dwOwningPid, Class, Buffer, pdwSize);
2479     }
2480 }
2481 
2482 /******************************************************************
2483  *    GetOwnerModuleFromUdpEntry (IPHLPAPI.@)
2484  *
2485  * Get data about the module that issued the context bind for a specific IPv4 UDP endpoint in a MIB table row
2486  *
2487  * PARAMS
2488  *  pUdpEntry [in]    pointer to a MIB_UDPROW_OWNER_MODULE structure
2489  *  Class [in]    	TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2490  *  Buffer [out]     	pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2491  *  pdwSize [in, out]	estimated size of the structure returned in Buffer, in bytes
2492  *
2493  * RETURNS
2494  *  Success: NO_ERROR
2495  *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2496  * 	       ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2497  *
2498  * NOTES
2499  * The type of data returned in Buffer is indicated by the value of the Class parameter.
2500  */
2501 DWORD WINAPI GetOwnerModuleFromUdpEntry( PMIB_UDPROW_OWNER_MODULE pUdpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2502 {
2503     /* If we have a service tag, that's a service connection */
2504     if (pUdpEntry->OwningModuleInfo[0] != 0)
2505     {
2506         return GetOwnerModuleFromTagEntry(pUdpEntry->dwOwningPid, (DWORD)(pUdpEntry->OwningModuleInfo[0]), Class, Buffer, pdwSize);
2507     }
2508     else
2509     {
2510         return GetOwnerModuleFromPidEntry(pUdpEntry->dwOwningPid, Class, Buffer, pdwSize);
2511     }
2512 }
2513 
2514 static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
2515 {
2516   IP_ADDR_STRING *pNext;
2517   PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
2518 
2519   if (!Context->NumServers)
2520   {
2521     if (Context->uSizeAvailable >= Context->uSizeRequired)
2522     {
2523       WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
2524       Context->pData->DnsServerList.IpAddress.String[15] = '\0';
2525       Context->pLastAddr = &Context->pData->DnsServerList;
2526     }
2527   }
2528   else
2529   {
2530      Context->uSizeRequired += sizeof(IP_ADDR_STRING);
2531      if (Context->uSizeAvailable >= Context->uSizeRequired)
2532      {
2533          pNext = (IP_ADDR_STRING*)(((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING));
2534          WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
2535          pNext->IpAddress.String[15] = '\0';
2536          Context->pLastAddr->Next = pNext;
2537          Context->pLastAddr = pNext;
2538          pNext->Next = NULL;
2539      }
2540   }
2541   Context->NumServers++;
2542 }
2543 
2544 /******************************************************************
2545  *    GetPerAdapterInfo (IPHLPAPI.@)
2546  *
2547  *
2548  * PARAMS
2549  *
2550  *  IfIndex [In]
2551  *  pPerAdapterInfo [In/Out]
2552  *  pOutBufLen [In/Out]
2553  *
2554  * RETURNS
2555  *
2556  *  DWORD
2557  *
2558  */
2559 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
2560 {
2561   HKEY hkey;
2562   DWORD dwSize = 0;
2563   const char *ifName;
2564   NAME_SERVER_LIST_CONTEXT Context;
2565   WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
2566 
2567   if (!pOutBufLen)
2568     return ERROR_INVALID_PARAMETER;
2569 
2570   if (!pPerAdapterInfo || *pOutBufLen < sizeof(IP_PER_ADAPTER_INFO))
2571   {
2572     *pOutBufLen = sizeof(IP_PER_ADAPTER_INFO);
2573     return ERROR_BUFFER_OVERFLOW;
2574   }
2575 
2576   ifName = getInterfaceNameByIndex(IfIndex);
2577   if (!ifName)
2578     return ERROR_INVALID_PARAMETER;
2579 
2580   MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
2581   HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
2582 
2583   if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
2584   {
2585     return ERROR_NOT_SUPPORTED;
2586   }
2587   Context.NumServers = 0;
2588   Context.uSizeAvailable = *pOutBufLen;
2589   Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
2590   Context.pData = pPerAdapterInfo;
2591 
2592   if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
2593     ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
2594 
2595   EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
2596 
2597   if (Context.uSizeRequired > Context.uSizeAvailable)
2598   {
2599     *pOutBufLen = Context.uSizeRequired;
2600     RegCloseKey(hkey);
2601     return ERROR_BUFFER_OVERFLOW;
2602   }
2603 
2604   if(RegQueryValueExW(hkey, L"NameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
2605   {
2606     pPerAdapterInfo->AutoconfigActive = FALSE;
2607   }
2608   else
2609   {
2610     pPerAdapterInfo->AutoconfigActive = TRUE;
2611   }
2612 
2613   RegCloseKey(hkey);
2614   return NOERROR;
2615 }
2616 
2617 
2618 /******************************************************************
2619  *    GetRTTAndHopCount (IPHLPAPI.@)
2620  *
2621  *
2622  * PARAMS
2623  *
2624  *  DestIpAddress [In]
2625  *  HopCount [In/Out]
2626  *  MaxHops [In]
2627  *  RTT [In/Out]
2628  *
2629  * RETURNS
2630  *
2631  *  BOOL
2632  *
2633  */
2634 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2635 {
2636   TRACE("DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p\n",
2637    DestIpAddress, HopCount, MaxHops, RTT);
2638   FIXME(":stub\n");
2639   return (BOOL) 0;
2640 }
2641 
2642 
2643 /******************************************************************
2644  *    GetTcpStatisticsEx (IPHLPAPI.@)
2645  *
2646  *
2647  * PARAMS
2648  *
2649  *  pStats [In/Out]
2650  *  dwFamily [In]
2651  *
2652  * RETURNS
2653  *
2654  *  DWORD
2655  *
2656  */
2657 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily)
2658 {
2659   DWORD ret;
2660 
2661   TRACE("pStats %p\n", pStats);
2662   ret = getTCPStats(pStats, dwFamily);
2663   TRACE("returning %ld\n", ret);
2664   return ret;
2665 }
2666 
2667 /******************************************************************
2668  *    GetTcpStatistics (IPHLPAPI.@)
2669  *
2670  *
2671  * PARAMS
2672  *
2673  *  pStats [In/Out]
2674  *
2675  * RETURNS
2676  *
2677  *  DWORD
2678  *
2679  */
2680 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
2681 {
2682     return GetTcpStatisticsEx(pStats, PF_INET);
2683 }
2684 
2685 
2686 /******************************************************************
2687  *    GetTcpTable (IPHLPAPI.@)
2688  *
2689  * Get the table of active TCP connections.
2690  *
2691  * PARAMS
2692  *  pTcpTable [Out]    buffer for TCP connections table
2693  *  pdwSize   [In/Out] length of output buffer
2694  *  bOrder    [In]     whether to order the table
2695  *
2696  * RETURNS
2697  *  Success: NO_ERROR
2698  *  Failure: error code from winerror.h
2699  *
2700  * NOTES
2701  *  If pdwSize is less than required, the function will return
2702  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
2703  *  the required byte size.
2704  *  If bOrder is true, the returned table will be sorted, first by
2705  *  local address and port number, then by remote address and port
2706  *  number.
2707  */
2708 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
2709 {
2710   return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, AF_INET, TCP_TABLE_BASIC_ALL, 0);
2711 }
2712 
2713 
2714 /******************************************************************
2715  *    GetUdpStatisticsEx (IPHLPAPI.@)
2716  *
2717  *
2718  * PARAMS
2719  *
2720  *  pStats [In/Out]
2721  *  dwFamily [In]
2722  *
2723  * RETURNS
2724  *
2725  *  DWORD
2726  *
2727  */
2728 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS pStats, DWORD dwFamily)
2729 {
2730   DWORD ret;
2731 
2732   TRACE("pStats %p\n", pStats);
2733   ret = getUDPStats(pStats, dwFamily);
2734   TRACE("returning %ld\n", ret);
2735   return ret;
2736 }
2737 
2738 /******************************************************************
2739  *    GetUdpStatistics (IPHLPAPI.@)
2740  *
2741  *
2742  * PARAMS
2743  *
2744  *  pStats [In/Out]
2745  *
2746  * RETURNS
2747  *
2748  *  DWORD
2749  *
2750  */
2751 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
2752 {
2753     return GetUdpStatisticsEx(pStats, PF_INET);
2754 }
2755 
2756 
2757 /******************************************************************
2758  *    GetUdpTable (IPHLPAPI.@)
2759  *
2760  *
2761  * PARAMS
2762  *
2763  *  pUdpTable [In/Out]
2764  *  pdwSize [In/Out]
2765  *  bOrder [In]
2766  *
2767  * RETURNS
2768  *
2769  *  DWORD
2770  *
2771  */
2772 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2773 {
2774   return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, AF_INET, UDP_TABLE_BASIC, 0);
2775 }
2776 
2777 
2778 /******************************************************************
2779  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
2780  *
2781  * This is a Win98-only function to get information on "unidirectional"
2782  * adapters.  Since this is pretty nonsensical in other contexts, it
2783  * never returns anything.
2784  *
2785  * PARAMS
2786  *  pIPIfInfo   [Out] buffer for adapter infos
2787  *  dwOutBufLen [Out] length of the output buffer
2788  *
2789  * RETURNS
2790  *  Success: NO_ERROR
2791  *  Failure: error code from winerror.h
2792  *
2793  * FIXME
2794  *  Stub, returns ERROR_NOT_SUPPORTED.
2795  */
2796 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
2797 {
2798   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
2799   /* a unidirectional adapter?? not bloody likely! */
2800   return ERROR_NOT_SUPPORTED;
2801 }
2802 
2803 
2804 /******************************************************************
2805  *    IpReleaseAddress (IPHLPAPI.@)
2806  *
2807  * Release an IP obtained through DHCP,
2808  *
2809  * PARAMS
2810  *  AdapterInfo [In] adapter to release IP address
2811  *
2812  * RETURNS
2813  *  Success: NO_ERROR
2814  *  Failure: error code from winerror.h
2815  *
2816  */
2817 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2818 {
2819   DWORD Status, Version = 0;
2820 
2821   if (!AdapterInfo)
2822       return ERROR_INVALID_PARAMETER;
2823 
2824   /* Maybe we should do this in DllMain */
2825   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2826       return ERROR_PROC_NOT_FOUND;
2827 
2828   if (DhcpReleaseIpAddressLease(AdapterInfo->Index))
2829       Status = ERROR_SUCCESS;
2830   else
2831       Status = ERROR_PROC_NOT_FOUND;
2832 
2833   DhcpCApiCleanup();
2834 
2835   return Status;
2836 }
2837 
2838 
2839 /******************************************************************
2840  *    IpRenewAddress (IPHLPAPI.@)
2841  *
2842  * Renew an IP obtained through DHCP.
2843  *
2844  * PARAMS
2845  *  AdapterInfo [In] adapter to renew IP address
2846  *
2847  * RETURNS
2848  *  Success: NO_ERROR
2849  *  Failure: error code from winerror.h
2850  */
2851 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2852 {
2853   DWORD Status, Version = 0;
2854 
2855   if (!AdapterInfo)
2856       return ERROR_INVALID_PARAMETER;
2857 
2858   /* Maybe we should do this in DllMain */
2859   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2860       return ERROR_PROC_NOT_FOUND;
2861 
2862   if (DhcpRenewIpAddressLease(AdapterInfo->Index))
2863       Status = ERROR_SUCCESS;
2864   else
2865       Status = ERROR_PROC_NOT_FOUND;
2866 
2867   DhcpCApiCleanup();
2868 
2869   return Status;
2870 }
2871 
2872 
2873 /******************************************************************
2874  *    NotifyAddrChange (IPHLPAPI.@)
2875  *
2876  * Notify caller whenever the ip-interface map is changed.
2877  *
2878  * PARAMS
2879  *  Handle     [Out] handle usable in asynchronous notification
2880  *  overlapped [In]  overlapped structure that notifies the caller
2881  *
2882  * RETURNS
2883  *  Success: NO_ERROR
2884  *  Failure: error code from winerror.h
2885  *
2886  * FIXME
2887  *  Stub, returns ERROR_NOT_SUPPORTED.
2888  */
2889 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2890 {
2891   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2892   if (Handle) *Handle = INVALID_HANDLE_VALUE;
2893   if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING;
2894   return ERROR_IO_PENDING;
2895 }
2896 
2897 
2898 /******************************************************************
2899  *    NotifyRouteChange (IPHLPAPI.@)
2900  *
2901  * Notify caller whenever the ip routing table is changed.
2902  *
2903  * PARAMS
2904  *  Handle     [Out] handle usable in asynchronous notification
2905  *  overlapped [In]  overlapped structure that notifies the caller
2906  *
2907  * RETURNS
2908  *  Success: NO_ERROR
2909  *  Failure: error code from winerror.h
2910  *
2911  * FIXME
2912  *  Stub, returns ERROR_NOT_SUPPORTED.
2913  */
2914 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2915 {
2916   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2917   return ERROR_NOT_SUPPORTED;
2918 }
2919 
2920 /******************************************************************
2921  *    SendARP (IPHLPAPI.@)
2922  *
2923  * Send an ARP request.
2924  *
2925  * PARAMS
2926  *  DestIP     [In]     attempt to obtain this IP
2927  *  SrcIP      [In]     optional sender IP address
2928  *  pMacAddr   [Out]    buffer for the mac address
2929  *  PhyAddrLen [In/Out] length of the output buffer
2930  *
2931  * RETURNS
2932  *  Success: NO_ERROR
2933  *  Failure: error code from winerror.h
2934  */
2935 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2936 {
2937   IPAddr IPs[2];
2938   ULONG Size;
2939 
2940   if (IsBadWritePtr(pMacAddr, sizeof(ULONG)) || IsBadWritePtr(PhyAddrLen, sizeof(ULONG)))
2941     return ERROR_INVALID_PARAMETER;
2942 
2943   IPs[0] = DestIP;
2944   IPs[1] = SrcIP;
2945   Size = sizeof(IPs);
2946   return TCPSendIoctl(INVALID_HANDLE_VALUE, IOCTL_QUERY_IP_HW_ADDRESS, IPs, &Size, pMacAddr, PhyAddrLen);
2947 }
2948 
2949 
2950 /******************************************************************
2951  *    SetIfEntry (IPHLPAPI.@)
2952  *
2953  * Set the administrative status of an interface.
2954  *
2955  * PARAMS
2956  *  pIfRow [In] dwAdminStatus member specifies the new status.
2957  *
2958  * RETURNS
2959  *  Success: NO_ERROR
2960  *  Failure: error code from winerror.h
2961  *
2962  * FIXME
2963  *  Stub, returns ERROR_NOT_SUPPORTED.
2964  */
2965 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
2966 {
2967   FIXME("(pIfRow %p): stub\n", pIfRow);
2968   /* this is supposed to set an interface administratively up or down.
2969      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2970      this sort of down is indistinguishable from other sorts of down (e.g. no
2971      link). */
2972   return ERROR_NOT_SUPPORTED;
2973 }
2974 
2975 
2976 /******************************************************************
2977  *    SetIpForwardEntry (IPHLPAPI.@)
2978  *
2979  * Modify an existing route.
2980  *
2981  * PARAMS
2982  *  pRoute [In] route with the new information
2983  *
2984  * RETURNS
2985  *  Success: NO_ERROR
2986  *  Failure: error code from winerror.h
2987  *
2988  */
2989 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
2990 {
2991     return setIpForwardEntry( pRoute );
2992 }
2993 
2994 
2995 /******************************************************************
2996  *    SetIpNetEntry (IPHLPAPI.@)
2997  *
2998  * Modify an existing ARP entry.
2999  *
3000  * PARAMS
3001  *  pArpEntry [In] ARP entry with the new information
3002  *
3003  * RETURNS
3004  *  Success: NO_ERROR
3005  *  Failure: error code from winerror.h
3006  */
3007 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
3008 {
3009   HANDLE tcpFile;
3010   NTSTATUS status;
3011   TCP_REQUEST_SET_INFORMATION_EX_ARP_ENTRY req =
3012       TCP_REQUEST_SET_INFORMATION_INIT;
3013   TDIEntityID id;
3014   DWORD returnSize;
3015   PMIB_IPNETROW arpBuff;
3016 
3017   if (!pArpEntry)
3018       return ERROR_INVALID_PARAMETER;
3019 
3020   if (!NT_SUCCESS(openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA )))
3021       return ERROR_NOT_SUPPORTED;
3022 
3023   if (!NT_SUCCESS(getNthIpEntity( tcpFile, pArpEntry->dwIndex, &id )))
3024   {
3025       closeTcpFile(tcpFile);
3026       return ERROR_INVALID_PARAMETER;
3027   }
3028 
3029   req.Req.ID.toi_class = INFO_CLASS_PROTOCOL;
3030   req.Req.ID.toi_type = INFO_TYPE_PROVIDER;
3031   req.Req.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
3032   req.Req.ID.toi_entity.tei_instance = id.tei_instance;
3033   req.Req.ID.toi_entity.tei_entity = AT_ENTITY;
3034   req.Req.BufferSize = sizeof(MIB_IPNETROW);
3035   arpBuff = (PMIB_IPNETROW)&req.Req.Buffer[0];
3036 
3037   RtlCopyMemory(arpBuff, pArpEntry, sizeof(MIB_IPNETROW));
3038 
3039   status = DeviceIoControl( tcpFile,
3040                             IOCTL_TCP_SET_INFORMATION_EX,
3041                             &req,
3042                             sizeof(req),
3043                             NULL,
3044                             0,
3045                             &returnSize,
3046                             NULL );
3047 
3048   closeTcpFile(tcpFile);
3049 
3050   if (status)
3051      return NO_ERROR;
3052   else
3053      return ERROR_INVALID_PARAMETER;
3054 }
3055 
3056 
3057 /******************************************************************
3058  *    SetIpStatistics (IPHLPAPI.@)
3059  *
3060  * Toggle IP forwarding and det the default TTL value.
3061  *
3062  * PARAMS
3063  *  pIpStats [In] IP statistics with the new information
3064  *
3065  * RETURNS
3066  *  Success: NO_ERROR
3067  *  Failure: error code from winerror.h
3068  *
3069  * FIXME
3070  *  Stub, returns NO_ERROR.
3071  */
3072 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
3073 {
3074   FIXME("(pIpStats %p): stub\n", pIpStats);
3075   return 0;
3076 }
3077 
3078 
3079 /******************************************************************
3080  *    SetIpTTL (IPHLPAPI.@)
3081  *
3082  * Set the default TTL value.
3083  *
3084  * PARAMS
3085  *  nTTL [In] new TTL value
3086  *
3087  * RETURNS
3088  *  Success: NO_ERROR
3089  *  Failure: error code from winerror.h
3090  *
3091  * FIXME
3092  *  Stub, returns NO_ERROR.
3093  */
3094 DWORD WINAPI SetIpTTL(UINT nTTL)
3095 {
3096   FIXME("(nTTL %d): stub\n", nTTL);
3097   return 0;
3098 }
3099 
3100 
3101 /******************************************************************
3102  *    SetTcpEntry (IPHLPAPI.@)
3103  *
3104  * Set the state of a TCP connection.
3105  *
3106  * PARAMS
3107  *  pTcpRow [In] specifies connection with new state
3108  *
3109  * RETURNS
3110  *  Success: NO_ERROR
3111  *  Failure: error code from winerror.h
3112  *
3113  * FIXME
3114  *  Stub, returns NO_ERROR.
3115  */
3116 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
3117 {
3118   FIXME("(pTcpRow %p): stub\n", pTcpRow);
3119   return 0;
3120 }
3121 
3122 
3123 /******************************************************************
3124  *    UnenableRouter (IPHLPAPI.@)
3125  *
3126  * Decrement the IP-forwarding reference count. Turn off IP-forwarding
3127  * if it reaches zero.
3128  *
3129  * PARAMS
3130  *  pOverlapped     [In/Out] should be the same as in EnableRouter()
3131  *  lpdwEnableCount [Out]    optional, receives reference count
3132  *
3133  * RETURNS
3134  *  Success: NO_ERROR
3135  *  Failure: error code from winerror.h
3136  *
3137  * FIXME
3138  *  Stub, returns ERROR_NOT_SUPPORTED.
3139  */
3140 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
3141 {
3142   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
3143    lpdwEnableCount);
3144   return ERROR_NOT_SUPPORTED;
3145 }
3146 
3147 /*
3148  * @unimplemented
3149  */
3150 DWORD WINAPI GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)
3151 {
3152     FIXME(":stub\n");
3153     return 0L;
3154 }
3155 
3156 
3157 /*
3158  * @unimplemented
3159  */
3160 PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
3161 {
3162     FIXME(":stub\n");
3163     return 0L;
3164 }
3165 
3166 /*
3167  * @implemented
3168  */
3169 #ifdef GetAdaptersAddressesV1
3170 DWORD WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
3171 {
3172     InterfaceIndexTable *indexTable;
3173     IFInfo ifInfo;
3174     int i;
3175     ULONG ret, requiredSize = 0;
3176     PIP_ADAPTER_ADDRESSES currentAddress;
3177     PUCHAR currentLocation;
3178     HANDLE tcpFile;
3179 
3180     if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
3181     if (Reserved) return ERROR_INVALID_PARAMETER;
3182 
3183     indexTable = getInterfaceIndexTable();
3184     if (!indexTable)
3185         return ERROR_NOT_ENOUGH_MEMORY;
3186 
3187     ret = openTcpFile(&tcpFile, FILE_READ_DATA);
3188     if (!NT_SUCCESS(ret))
3189         return ERROR_NO_DATA;
3190 
3191     for (i = indexTable->numIndexes; i >= 0; i--)
3192     {
3193         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3194                                            NULL,
3195                                            indexTable->indexes[i],
3196                                            &ifInfo)))
3197         {
3198             /* The whole struct */
3199             requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
3200 
3201             /* Friendly name */
3202             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3203                 requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1; //FIXME
3204 
3205             /* Adapter name */
3206             requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
3207 
3208             /* Unicast address */
3209             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3210                 requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3211 
3212             /* FIXME: Implement multicast, anycast, and dns server stuff */
3213 
3214             /* FIXME: Implement dns suffix and description */
3215             requiredSize += 2 * sizeof(WCHAR);
3216 
3217             /* We're only going to implement what's required for XP SP0 */
3218         }
3219     }
3220     TRACE("size: %d, requiredSize: %d\n", *pOutBufLen, requiredSize);
3221     if (!pAdapterAddresses || *pOutBufLen < requiredSize)
3222     {
3223         *pOutBufLen = requiredSize;
3224         closeTcpFile(tcpFile);
3225         free(indexTable);
3226         return ERROR_BUFFER_OVERFLOW;
3227     }
3228 
3229     RtlZeroMemory(pAdapterAddresses, requiredSize);
3230 
3231     /* Let's set up the pointers */
3232     currentAddress = pAdapterAddresses;
3233     for (i = indexTable->numIndexes; i >= 0; i--)
3234     {
3235         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3236                                            NULL,
3237                                            indexTable->indexes[i],
3238                                            &ifInfo)))
3239         {
3240             currentLocation = (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
3241 
3242             /* FIXME: Friendly name */
3243             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3244             {
3245                 currentAddress->FriendlyName = (PVOID)currentLocation;
3246                 currentLocation += sizeof(WCHAR);
3247             }
3248 
3249             /* Adapter name */
3250             currentAddress->AdapterName = (PVOID)currentLocation;
3251             currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
3252 
3253             /* Unicast address */
3254             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3255             {
3256                 currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
3257                 currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3258                 currentAddress->FirstUnicastAddress->Address.lpSockaddr = (PVOID)currentLocation;
3259                 currentLocation += sizeof(struct sockaddr);
3260             }
3261 
3262             /* FIXME: Implement multicast, anycast, and dns server stuff */
3263 
3264             /* FIXME: Implement dns suffix and description */
3265             currentAddress->DnsSuffix = (PVOID)currentLocation;
3266             currentLocation += sizeof(WCHAR);
3267 
3268             currentAddress->Description = (PVOID)currentLocation;
3269             currentLocation += sizeof(WCHAR);
3270 
3271             currentAddress->Next = (PVOID)currentLocation;
3272             /* Terminate the last address correctly */
3273             if(i==0)
3274                 currentAddress->Next = NULL;
3275 
3276             /* We're only going to implement what's required for XP SP0 */
3277 
3278             currentAddress = currentAddress->Next;
3279         }
3280     }
3281 
3282     /* Now again, for real this time */
3283 
3284     currentAddress = pAdapterAddresses;
3285     for (i = indexTable->numIndexes; i >= 0; i--)
3286     {
3287         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3288                                            NULL,
3289                                            indexTable->indexes[i],
3290                                            &ifInfo)))
3291         {
3292             /* Make sure we're not looping more than we hoped for */
3293             ASSERT(currentAddress);
3294 
3295             /* Alignment information */
3296             currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
3297             currentAddress->IfIndex = indexTable->indexes[i];
3298 
3299             /* Adapter name */
3300             strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr);
3301 
3302             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3303             {
3304                 currentAddress->FirstUnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3305                 currentAddress->FirstUnicastAddress->Flags = 0; //FIXME
3306                 currentAddress->FirstUnicastAddress->Next = NULL; //FIXME: Support more than one address per adapter
3307                 currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
3308                 memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
3309                        &ifInfo.ip_addr.iae_addr,
3310                        sizeof(ifInfo.ip_addr.iae_addr));
3311                 currentAddress->FirstUnicastAddress->Address.iSockaddrLength = sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
3312                 currentAddress->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; //FIXME
3313                 currentAddress->FirstUnicastAddress->SuffixOrigin = IpPrefixOriginOther; //FIXME
3314                 currentAddress->FirstUnicastAddress->DadState = IpDadStatePreferred; //FIXME
3315                 currentAddress->FirstUnicastAddress->ValidLifetime = 0xFFFFFFFF; //FIXME
3316                 currentAddress->FirstUnicastAddress->PreferredLifetime = 0xFFFFFFFF; //FIXME
3317                 currentAddress->FirstUnicastAddress->LeaseLifetime = 0xFFFFFFFF; //FIXME
3318             }
3319 
3320             /* FIXME: Implement multicast, anycast, and dns server stuff */
3321             currentAddress->FirstAnycastAddress = NULL;
3322             currentAddress->FirstMulticastAddress = NULL;
3323             currentAddress->FirstDnsServerAddress = NULL;
3324 
3325             /* FIXME: Implement dns suffix, description, and friendly name */
3326             currentAddress->DnsSuffix[0] = UNICODE_NULL;
3327             currentAddress->Description[0] = UNICODE_NULL;
3328             currentAddress->FriendlyName[0] = UNICODE_NULL;
3329 
3330             /* Physical Address */
3331             memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, ifInfo.if_info.ent.if_physaddrlen);
3332             currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
3333 
3334             /* Flags */
3335             currentAddress->Flags = 0; //FIXME
3336 
3337             /* MTU */
3338             currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
3339 
3340             /* Interface type */
3341             currentAddress->IfType = ifInfo.if_info.ent.if_type;
3342 
3343             /* Operational status */
3344             if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
3345                 currentAddress->OperStatus = IfOperStatusUp;
3346             else
3347                 currentAddress->OperStatus = IfOperStatusDown;
3348 
3349             /* We're only going to implement what's required for XP SP0 */
3350 
3351             /* Move to the next address */
3352             currentAddress = currentAddress->Next;
3353         }
3354     }
3355 
3356     closeTcpFile(tcpFile);
3357     free(indexTable);
3358 
3359     return NO_ERROR;
3360 }
3361 #endif
3362 
3363 /*
3364  * @unimplemented
3365  */
3366 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)
3367 {
3368     FIXME(":stub\n");
3369     return 0L;
3370 }
3371 
3372 /*
3373  * @unimplemented
3374  */
3375 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex)
3376 {
3377     FIXME(":stub\n");
3378     return 0L;
3379 }
3380 
3381 /*
3382  * @unimplemented
3383  */
3384 DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)
3385 {
3386     FIXME(":stub\n");
3387     return 0L;
3388 }
3389 
3390 /*
3391  * @unimplemented
3392  */
3393 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
3394 {
3395     FIXME(":stub\n");
3396 
3397     if (!pStats)
3398         return ERROR_INVALID_PARAMETER;
3399 
3400     if (dwFamily != AF_INET && dwFamily != AF_INET6)
3401         return ERROR_INVALID_PARAMETER;
3402 
3403     return 0L;
3404 }
3405 
3406 DWORD WINAPI
3407 SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)
3408 {
3409     FIXME("SetIpForwardEntryToStack() stub\n");
3410     return 0L;
3411 }
3412 
3413 DWORD GetInterfaceNameInternal(_In_ const GUID * pInterfaceGUID,
3414                                _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3415                                _Inout_ PULONG pOutBufLen)
3416 {
3417     UNICODE_STRING GuidString;
3418     DWORD result, type;
3419     WCHAR szKeyName[2*MAX_PATH];
3420     HRESULT hr;
3421     HKEY hKey;
3422 
3423     if (pInterfaceGUID == NULL || pOutBufLen == NULL)
3424         return ERROR_INVALID_PARAMETER;
3425 
3426     result = RtlStringFromGUID(pInterfaceGUID, &GuidString);
3427 
3428     if (!NT_SUCCESS(result))
3429     {
3430         // failed to convert guid to string
3431         return RtlNtStatusToDosError(result);
3432     }
3433 
3434     hr = StringCbPrintfW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", GuidString.Buffer);
3435     RtlFreeUnicodeString(&GuidString);
3436 
3437     if (FAILED(hr))
3438     {
3439         // key name is too long
3440         return ERROR_BUFFER_OVERFLOW;
3441     }
3442 
3443     result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKey);
3444 
3445     if (result != ERROR_SUCCESS)
3446     {
3447         // failed to find adapter entry
3448         return ERROR_NOT_FOUND;
3449     }
3450 
3451     result = RegQueryValueExW(hKey, L"Name", NULL, &type, (PVOID)pInterfaceName, pOutBufLen);
3452 
3453     RegCloseKey(hKey);
3454 
3455     if (result == ERROR_MORE_DATA)
3456     {
3457         *pOutBufLen = MAX_INTERFACE_NAME_LEN * 2;
3458         return ERROR_INSUFFICIENT_BUFFER;
3459     }
3460 
3461     if (result != ERROR_SUCCESS || type != REG_SZ)
3462     {
3463         // failed to read adapter name
3464         return ERROR_NO_DATA;
3465     }
3466     return ERROR_SUCCESS;
3467 }
3468 
3469 /*
3470  * @implemented
3471  */
3472 DWORD WINAPI
3473 NhGetInterfaceNameFromDeviceGuid(_In_ const GUID * pInterfaceGUID,
3474                                  _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3475                                  _Inout_ PULONG pOutBufLen,
3476                                  DWORD dwUnknown4,
3477                                  DWORD dwUnknown5)
3478 {
3479     SetLastError(ERROR_SUCCESS);
3480 
3481     if (pInterfaceName == NULL)
3482         return ERROR_INVALID_PARAMETER;
3483 
3484     return GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3485 }
3486 
3487 /*
3488  * @implemented
3489  */
3490 DWORD WINAPI
3491 NhGetInterfaceNameFromGuid(_In_ const GUID * pInterfaceGUID,
3492                            _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3493                            _Inout_ PULONG pOutBufLen,
3494                            DWORD dwUnknown4,
3495                            DWORD dwUnknown5)
3496 {
3497     DWORD result;
3498 
3499     result = GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3500 
3501     if (result == ERROR_NOT_FOUND)
3502         SetLastError(ERROR_PATH_NOT_FOUND);
3503 
3504     return result;
3505 }
3506