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