xref: /reactos/dll/win32/iphlpapi/iphlpapi_main.c (revision 19b18ce2)
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, minMaskSize, matchedNdx = 0;
771 
772     for (ndx = 0, minMaskSize = 255; ndx < table->dwNumEntries; ndx++) {
773       if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
774        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
775         DWORD hostMaskSize;
776 
777         if (!_BitScanForward(&hostMaskSize, ntohl(table->table[ndx].dwForwardMask)))
778         {
779             hostMaskSize = 32;
780         }
781         if (hostMaskSize < minMaskSize) {
782           minMaskSize = hostMaskSize;
783           matchedNdx = ndx;
784         }
785       }
786     }
787     memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
788     HeapFree(GetProcessHeap(), 0, table);
789     ret = ERROR_SUCCESS;
790   }
791   else
792     ret = ERROR_OUTOFMEMORY;
793   TRACE("returning %ld\n", ret);
794   return ret;
795 }
796 
797 /******************************************************************
798  *    GetExtendedTcpTable (IPHLPAPI.@)
799  *
800  * Get the table of TCP endpoints available to the application.
801  *
802  * PARAMS
803  *  pTcpTable [Out]    table struct with the filtered TCP endpoints available to application
804  *  pdwSize   [In/Out] estimated size of the structure returned in pTcpTable, in bytes
805  *  bOrder    [In]     whether to order the table
806  *  ulAf	[in]	version of IP used by the TCP endpoints
807  *  TableClass [in]	type of the TCP table structure from TCP_TABLE_CLASS
808  *  Reserved [in]	reserved - this value must be zero
809  *
810  * RETURNS
811  *  Success: NO_ERROR
812  *  Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
813  *
814  * NOTES
815  */
816 
817 DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
818 {
819 	DWORD ret = NO_ERROR;
820 
821   if (TableClass == TCP_TABLE_OWNER_PID_ALL) {
822     if (*pdwSize == 0) {
823       *pdwSize = sizeof(MIB_TCPTABLE_OWNER_PID);
824       return ERROR_INSUFFICIENT_BUFFER;
825     } else {
826       ZeroMemory(pTcpTable, sizeof(MIB_TCPTABLE_OWNER_PID));
827       return NO_ERROR;
828     }
829   }
830 
831 
832     UNIMPLEMENTED;
833     return ret;
834 }
835 
836 
837 /******************************************************************
838  *    GetFriendlyIfIndex (IPHLPAPI.@)
839  *
840  *
841  * PARAMS
842  *
843  *  IfIndex [In]
844  *
845  * RETURNS
846  *
847  *  DWORD
848  *
849  */
850 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
851 {
852   /* windows doesn't validate these, either, just makes sure the top byte is
853      cleared.  I assume my ifenum module never gives an index with the top
854      byte set. */
855   TRACE("returning %ld\n", IfIndex);
856   return IfIndex;
857 }
858 
859 
860 /******************************************************************
861  *    GetIcmpStatistics (IPHLPAPI.@)
862  *
863  *
864  * PARAMS
865  *
866  *  pStats [In/Out]
867  *
868  * RETURNS
869  *
870  *  DWORD
871  *
872  */
873 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
874 {
875   DWORD ret;
876 
877   TRACE("pStats %p\n", pStats);
878   ret = getICMPStats(pStats);
879   TRACE("returning %ld\n", ret);
880   return ret;
881 }
882 
883 
884 /******************************************************************
885  *    GetIfEntry (IPHLPAPI.@)
886  *
887  *
888  * PARAMS
889  *
890  *  pIfRow [In/Out]
891  *
892  * RETURNS
893  *
894  *  DWORD
895  *
896  */
897 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
898 {
899   DWORD ret;
900   const char *name;
901 
902   TRACE("pIfRow %p\n", pIfRow);
903   if (!pIfRow)
904     return ERROR_INVALID_PARAMETER;
905 
906   name = getInterfaceNameByIndex(pIfRow->dwIndex);
907   if (name) {
908     ret = getInterfaceEntryByIndex(pIfRow->dwIndex, pIfRow);
909     if (ret == NO_ERROR)
910       ret = getInterfaceStatsByName(name, pIfRow);
911     consumeInterfaceName(name);
912   }
913   else
914     ret = ERROR_INVALID_DATA;
915   TRACE("returning %ld\n", ret);
916   return ret;
917 }
918 
919 
920 static int IfTableSorter(const void *a, const void *b)
921 {
922   int ret;
923 
924   if (a && b)
925     ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
926   else
927     ret = 0;
928   return ret;
929 }
930 
931 
932 /******************************************************************
933  *    GetIfTable (IPHLPAPI.@)
934  *
935  *
936  * PARAMS
937  *
938  *  pIfTable [In/Out]
939  *  pdwSize [In/Out]
940  *  bOrder [In]
941  *
942  * RETURNS
943  *
944  *  DWORD
945  *
946  */
947 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
948 {
949   DWORD ret;
950 
951   TRACE("pIfTable %p, pdwSize %p, bOrder %ld\n", pdwSize, pdwSize,
952    (DWORD)bOrder);
953   if (!pdwSize)
954     ret = ERROR_INVALID_PARAMETER;
955   else {
956     DWORD numInterfaces = getNumInterfaces();
957     ULONG size;
958     TRACE("GetIfTable: numInterfaces = %d\n", (int)numInterfaces);
959     size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
960 
961     if (!pIfTable || *pdwSize < size) {
962       *pdwSize = size;
963       ret = ERROR_INSUFFICIENT_BUFFER;
964     }
965     else {
966       InterfaceIndexTable *table = getInterfaceIndexTable();
967 
968       if (table) {
969         size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
970          sizeof(MIB_IFROW);
971         if (*pdwSize < size) {
972           *pdwSize = size;
973           ret = ERROR_INSUFFICIENT_BUFFER;
974         }
975         else {
976           DWORD ndx;
977 
978           pIfTable->dwNumEntries = 0;
979           for (ndx = 0; ndx < table->numIndexes; ndx++) {
980             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
981             GetIfEntry(&pIfTable->table[ndx]);
982             pIfTable->dwNumEntries++;
983           }
984           if (bOrder)
985             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
986              IfTableSorter);
987           ret = NO_ERROR;
988         }
989         free(table);
990       }
991       else
992         ret = ERROR_OUTOFMEMORY;
993     }
994   }
995   TRACE("returning %ld\n", ret);
996   return ret;
997 }
998 
999 
1000 /******************************************************************
1001  *    GetInterfaceInfo (IPHLPAPI.@)
1002  *
1003  *
1004  * PARAMS
1005  *
1006  *  pIfTable [In/Out]
1007  *  dwOutBufLen [In/Out]
1008  *
1009  * RETURNS
1010  *
1011  *  DWORD
1012  *
1013  */
1014 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
1015 {
1016   DWORD ret;
1017 
1018   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
1019   if (!dwOutBufLen)
1020     ret = ERROR_INVALID_PARAMETER;
1021   else {
1022     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
1023     ULONG size;
1024     TRACE("numNonLoopbackInterfaces == 0x%x\n", numNonLoopbackInterfaces);
1025     size = sizeof(IP_INTERFACE_INFO) + (numNonLoopbackInterfaces) *
1026      sizeof(IP_ADAPTER_INDEX_MAP);
1027 
1028     if (!pIfTable || *dwOutBufLen < size) {
1029       *dwOutBufLen = size;
1030       ret = ERROR_INSUFFICIENT_BUFFER;
1031     }
1032     else {
1033       InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
1034 
1035       if (table) {
1036         TRACE("table->numIndexes == 0x%x\n", table->numIndexes);
1037         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes) *
1038          sizeof(IP_ADAPTER_INDEX_MAP);
1039         if (*dwOutBufLen < size) {
1040           *dwOutBufLen = size;
1041           ret = ERROR_INSUFFICIENT_BUFFER;
1042         }
1043         else {
1044           DWORD ndx;
1045 
1046           pIfTable->NumAdapters = 0;
1047           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1048             const char *walker, *name;
1049             WCHAR *assigner;
1050 
1051             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
1052             name = getInterfaceNameByIndex(table->indexes[ndx]);
1053             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
1054              walker && *walker &&
1055              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
1056              walker++, assigner++)
1057               *assigner = *walker;
1058             *assigner = 0;
1059             consumeInterfaceName(name);
1060             pIfTable->NumAdapters++;
1061           }
1062           ret = NO_ERROR;
1063         }
1064         free(table);
1065       }
1066       else
1067         ret = ERROR_OUTOFMEMORY;
1068     }
1069   }
1070   TRACE("returning %ld\n", ret);
1071   return ret;
1072 }
1073 
1074 
1075 static int IpAddrTableSorter(const void *a, const void *b)
1076 {
1077   int ret;
1078 
1079   if (a && b)
1080     ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
1081   else
1082     ret = 0;
1083   return ret;
1084 }
1085 
1086 
1087 /******************************************************************
1088  *    GetIpAddrTable (IPHLPAPI.@)
1089  *
1090  *
1091  * PARAMS
1092  *
1093  *  pIpAddrTable [In/Out]
1094  *  pdwSize [In/Out]
1095  *  bOrder [In]
1096  *
1097  * RETURNS
1098  *
1099  *  DWORD
1100  *
1101  */
1102 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1103 {
1104   DWORD ret;
1105 
1106   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
1107    (DWORD)bOrder);
1108   if (!pdwSize)
1109     ret = ERROR_INVALID_PARAMETER;
1110   else {
1111     DWORD numInterfaces = getNumInterfaces();
1112     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
1113      sizeof(MIB_IPADDRROW);
1114 
1115     if (!pIpAddrTable || *pdwSize < size) {
1116       *pdwSize = size;
1117       ret = ERROR_INSUFFICIENT_BUFFER;
1118     }
1119     else {
1120       InterfaceIndexTable *table = getInterfaceIndexTable();
1121 
1122       if (table) {
1123         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
1124          sizeof(MIB_IPADDRROW);
1125         if (*pdwSize < size) {
1126           *pdwSize = size;
1127           ret = ERROR_INSUFFICIENT_BUFFER;
1128         }
1129         else {
1130           DWORD ndx, bcast;
1131 
1132           pIpAddrTable->dwNumEntries = 0;
1133           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1134             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
1135             pIpAddrTable->table[ndx].dwAddr =
1136              getInterfaceIPAddrByIndex(table->indexes[ndx]);
1137             pIpAddrTable->table[ndx].dwMask =
1138              getInterfaceMaskByIndex(table->indexes[ndx]);
1139             /* the dwBCastAddr member isn't the broadcast address, it indicates
1140              * whether the interface uses the 1's broadcast address (1) or the
1141              * 0's broadcast address (0).
1142              */
1143             bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
1144             pIpAddrTable->table[ndx].dwBCastAddr =
1145              (bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
1146             /* FIXME: hardcoded reasm size, not sure where to get it */
1147             pIpAddrTable->table[ndx].dwReasmSize = 65535;
1148             pIpAddrTable->table[ndx].unused1 = 0;
1149             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
1150             pIpAddrTable->dwNumEntries++;
1151           }
1152           if (bOrder)
1153             qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1154              sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1155           ret = NO_ERROR;
1156         }
1157         free(table);
1158       }
1159       else
1160         ret = ERROR_OUTOFMEMORY;
1161     }
1162   }
1163   TRACE("returning %ld\n", ret);
1164   return ret;
1165 }
1166 
1167 
1168 static int IpForwardTableSorter(const void *a, const void *b)
1169 {
1170   int ret;
1171 
1172   if (a && b) {
1173     PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
1174 
1175     ret = rowA->dwForwardDest - rowB->dwForwardDest;
1176     if (ret == 0) {
1177       ret = rowA->dwForwardProto - rowB->dwForwardProto;
1178       if (ret == 0) {
1179         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
1180         if (ret == 0)
1181           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1182       }
1183     }
1184   }
1185   else
1186     ret = 0;
1187   return ret;
1188 }
1189 
1190 
1191 /******************************************************************
1192  *    GetIpForwardTable (IPHLPAPI.@)
1193  *
1194  *
1195  * PARAMS
1196  *
1197  *  pIpForwardTable [In/Out]
1198  *  pdwSize [In/Out]
1199  *  bOrder [In]
1200  *
1201  * RETURNS
1202  *
1203  *  DWORD
1204  *
1205  */
1206 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1207 {
1208   DWORD ret;
1209 
1210   TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
1211         pdwSize, (DWORD)bOrder);
1212   if (!pdwSize)
1213     ret = ERROR_INVALID_PARAMETER;
1214   else {
1215     DWORD numRoutes = getNumRoutes();
1216     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1217      sizeof(MIB_IPFORWARDROW);
1218 
1219     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1220       *pdwSize = sizeNeeded;
1221       ret = ERROR_INSUFFICIENT_BUFFER;
1222     }
1223     else {
1224       RouteTable *table = getRouteTable();
1225       if (table) {
1226         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1227          sizeof(MIB_IPFORWARDROW);
1228         if (*pdwSize < sizeNeeded) {
1229           *pdwSize = sizeNeeded;
1230           ret = ERROR_INSUFFICIENT_BUFFER;
1231         }
1232         else {
1233           DWORD ndx;
1234 
1235           pIpForwardTable->dwNumEntries = table->numRoutes;
1236           for (ndx = 0; ndx < numRoutes; ndx++) {
1237             pIpForwardTable->table[ndx].dwForwardIfIndex =
1238              table->routes[ndx].ifIndex;
1239             pIpForwardTable->table[ndx].dwForwardDest =
1240              table->routes[ndx].dest;
1241             pIpForwardTable->table[ndx].dwForwardMask =
1242              table->routes[ndx].mask;
1243             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1244             pIpForwardTable->table[ndx].dwForwardNextHop =
1245              table->routes[ndx].gateway;
1246             /* FIXME: this type is appropriate for local interfaces; may not
1247                always be appropriate */
1248             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1249             /* FIXME: other protos might be appropriate, e.g. the default route
1250                is typically set with MIB_IPPROTO_NETMGMT instead */
1251             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1252             /* punt on age and AS */
1253             pIpForwardTable->table[ndx].dwForwardAge = 0;
1254             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1255             pIpForwardTable->table[ndx].dwForwardMetric1 =
1256              table->routes[ndx].metric;
1257             /* rest of the metrics are 0.. */
1258             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1259             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1260             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1261             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1262           }
1263           if (bOrder)
1264             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1265              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1266           ret = NO_ERROR;
1267         }
1268         HeapFree(GetProcessHeap(), 0, table);
1269       }
1270       else
1271         ret = ERROR_OUTOFMEMORY;
1272     }
1273   }
1274   TRACE("returning %ld\n", ret);
1275   return ret;
1276 }
1277 
1278 
1279 static int IpNetTableSorter(const void *a, const void *b)
1280 {
1281   int ret;
1282 
1283   if (a && b)
1284     ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
1285   else
1286     ret = 0;
1287   return ret;
1288 }
1289 
1290 
1291 /******************************************************************
1292  *    GetIpNetTable (IPHLPAPI.@)
1293  *
1294  *
1295  * PARAMS
1296  *
1297  *  pIpNetTable [In/Out]
1298  *  pdwSize [In/Out]
1299  *  bOrder [In]
1300  *
1301  * RETURNS
1302  *
1303  *  DWORD
1304  *
1305  */
1306 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1307 {
1308   DWORD ret = NO_ERROR;
1309 
1310   TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize,
1311    (DWORD)bOrder);
1312   if (!pdwSize)
1313     ret = ERROR_INVALID_PARAMETER;
1314   else {
1315     DWORD numEntries = getNumArpEntries();
1316     ULONG size = sizeof(MIB_IPNETTABLE);
1317 
1318     if (numEntries > 1)
1319       size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1320     if (!pIpNetTable || *pdwSize < size) {
1321       *pdwSize = size;
1322       ret = ERROR_INSUFFICIENT_BUFFER;
1323     }
1324     else {
1325       PMIB_IPNETTABLE table = getArpTable();
1326       if (table) {
1327         size = sizeof(MIB_IPNETTABLE);
1328         if (table->dwNumEntries > 1)
1329           size += (table->dwNumEntries - 1) * sizeof(MIB_IPNETROW);
1330         if (*pdwSize < size) {
1331           *pdwSize = size;
1332           ret = ERROR_INSUFFICIENT_BUFFER;
1333         }
1334         else {
1335           *pdwSize = size;
1336           memcpy(pIpNetTable, table, size);
1337           if (bOrder)
1338             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
1339              sizeof(MIB_IPNETROW), IpNetTableSorter);
1340           ret = NO_ERROR;
1341         }
1342         HeapFree(GetProcessHeap(), 0, table);
1343       }
1344     }
1345   }
1346   TRACE("returning %d\n", ret);
1347   return ret;
1348 }
1349 
1350 
1351 /******************************************************************
1352  *    GetIpStatistics (IPHLPAPI.@)
1353  *
1354  *
1355  * PARAMS
1356  *
1357  *  pStats [In/Out]
1358  *
1359  * RETURNS
1360  *
1361  *  DWORD
1362  *
1363  */
1364 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
1365 {
1366     return GetIpStatisticsEx(pStats, PF_INET);
1367 }
1368 
1369 /******************************************************************
1370  *    GetIpStatisticsEx (IPHLPAPI.@)
1371  *
1372  *
1373  * PARAMS
1374  *
1375  *  pStats [In/Out]
1376  *  dwFamily [In]
1377  *
1378  * RETURNS
1379  *
1380  *  DWORD
1381  *
1382  */
1383 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily)
1384 {
1385   DWORD ret;
1386 
1387   TRACE("pStats %p\n", pStats);
1388   ret = getIPStats(pStats, dwFamily);
1389   TRACE("returning %ld\n", ret);
1390   return ret;
1391 }
1392 
1393 /******************************************************************
1394  *    GetNetworkParams (IPHLPAPI.@)
1395  *
1396  *
1397  * PARAMS
1398  *
1399  *  pFixedInfo [In/Out]
1400  *  pOutBufLen [In/Out]
1401  *
1402  * RETURNS
1403  *
1404  *  DWORD
1405  *
1406  */
1407 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1408 {
1409   DWORD ret, size, type;
1410   LONG regReturn;
1411   HKEY hKey;
1412   PIPHLP_RES_INFO resInfo;
1413 
1414   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
1415   if (!pOutBufLen)
1416     return ERROR_INVALID_PARAMETER;
1417 
1418   resInfo = getResInfo();
1419   if (!resInfo)
1420     return ERROR_OUTOFMEMORY;
1421 
1422   size = sizeof(FIXED_INFO) + (resInfo->riCount > 1 ? (resInfo->riCount-1) *
1423    sizeof(IP_ADDR_STRING) : 0);
1424   if (!pFixedInfo || *pOutBufLen < size) {
1425     *pOutBufLen = size;
1426     disposeResInfo( resInfo );
1427     return ERROR_BUFFER_OVERFLOW;
1428   }
1429 
1430   memset(pFixedInfo, 0, size);
1431   /* Check for DhcpHostname and DhcpDomain first */
1432   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1433                             "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
1434                             0,
1435                             KEY_READ,
1436                             &hKey);
1437   if (regReturn == ERROR_SUCCESS) {
1438       /* Windows doesn't honor DHCP option 12 even if RFC requires it if it is returned by DHCP server! */
1439 #if 0
1440       type = REG_SZ;
1441       size = sizeof(pFixedInfo->HostName);
1442       regReturn = RegQueryValueExA(hKey,
1443                                       "DhcpHostname",
1444                                       NULL,
1445                                       &type,
1446                                       (LPBYTE)pFixedInfo->HostName,
1447                                       &size);
1448       if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
1449       {
1450 #endif
1451           type = REG_SZ;
1452           size = sizeof(pFixedInfo->HostName);
1453           regReturn = RegQueryValueExA(hKey,
1454                                           "Hostname",
1455                                           NULL,
1456                                           &type,
1457                                           (LPBYTE)pFixedInfo->HostName,
1458                                           &size);
1459 #if 0
1460       }
1461 #endif
1462 
1463       type = REG_SZ;
1464       size = sizeof(pFixedInfo->DomainName);
1465       regReturn = RegQueryValueExA(hKey,
1466                                       "DhcpDomain",
1467                                       NULL,
1468                                       &type,
1469                                       (LPBYTE)pFixedInfo->DomainName,
1470                                       &size);
1471       if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
1472       {
1473           type = REG_SZ;
1474           size = sizeof(pFixedInfo->DomainName);
1475           regReturn = RegQueryValueExA(hKey,
1476                                           "Domain",
1477                                           NULL,
1478                                           &type,
1479                                           (LPBYTE)pFixedInfo->DomainName,
1480                                           &size);
1481       }
1482       RegCloseKey(hKey);
1483   }
1484 
1485   TRACE("GetComputerNameExA: %s\n", pFixedInfo->DomainName);
1486 
1487   if (resInfo->riCount > 0)
1488   {
1489     CopyMemory(&pFixedInfo->DnsServerList, resInfo->DnsList, sizeof(IP_ADDR_STRING));
1490     if (resInfo->riCount > 1)
1491     {
1492       IP_ADDR_STRING *pSrc = resInfo->DnsList->Next;
1493       IP_ADDR_STRING *pTarget = (struct _IP_ADDR_STRING*)((char*)pFixedInfo + sizeof(FIXED_INFO));
1494 
1495       pFixedInfo->DnsServerList.Next = pTarget;
1496 
1497       do
1498       {
1499         CopyMemory(pTarget, pSrc, sizeof(IP_ADDR_STRING));
1500         resInfo->riCount--;
1501         if (resInfo->riCount > 1)
1502         {
1503           pTarget->Next = (IP_ADDR_STRING*)((char*)pTarget + sizeof(IP_ADDR_STRING));
1504           pTarget = pTarget->Next;
1505           pSrc = pSrc->Next;
1506         }
1507         else
1508         {
1509           pTarget->Next = NULL;
1510           break;
1511         }
1512       }
1513       while(TRUE);
1514     }
1515     else
1516     {
1517       pFixedInfo->DnsServerList.Next = NULL;
1518     }
1519   }
1520 
1521   pFixedInfo->NodeType = HYBRID_NODETYPE;
1522   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1523    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
1524   if (regReturn != ERROR_SUCCESS)
1525     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1526      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
1527      &hKey);
1528   if (regReturn == ERROR_SUCCESS)
1529   {
1530     DWORD size = sizeof(pFixedInfo->ScopeId);
1531 
1532     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (PBYTE)pFixedInfo->ScopeId, &size);
1533     RegCloseKey(hKey);
1534   }
1535 
1536   disposeResInfo( resInfo );
1537   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1538      I suppose could also check for a listener on port 53 to set EnableDns */
1539   ret = NO_ERROR;
1540   TRACE("returning %ld\n", ret);
1541 
1542   return ret;
1543 }
1544 
1545 
1546 /******************************************************************
1547  *    GetNumberOfInterfaces (IPHLPAPI.@)
1548  *
1549  *
1550  * PARAMS
1551  *
1552  *  pdwNumIf [In/Out]
1553  *
1554  * RETURNS
1555  *
1556  *  DWORD
1557  *
1558  */
1559 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1560 {
1561   DWORD ret;
1562 
1563   TRACE("pdwNumIf %p\n", pdwNumIf);
1564   if (!pdwNumIf)
1565     ret = ERROR_INVALID_PARAMETER;
1566   else {
1567     *pdwNumIf = getNumInterfaces();
1568     ret = NO_ERROR;
1569   }
1570   TRACE("returning %ld\n", ret);
1571   return ret;
1572 }
1573 
1574 
1575 /******************************************************************
1576  *    GetOwnerModuleFromTcpEntry (IPHLPAPI.@)
1577  *
1578  * Get data about the module that issued the context bind for a specific IPv4 TCP endpoint in a MIB table row
1579  *
1580  * PARAMS
1581  *  pTcpEntry [in]    pointer to a MIB_TCPROW_OWNER_MODULE structure
1582  *  Class [in]    	TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
1583  *  Buffer [out]     	pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
1584  *  pdwSize [in, out]	estimated size of the structure returned in Buffer, in bytes
1585  *
1586  * RETURNS
1587  *  Success: NO_ERROR
1588  *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
1589  * 	       ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
1590  *
1591  * NOTES
1592  * The type of data returned in Buffer is indicated by the value of the Class parameter.
1593  */
1594 DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
1595 {
1596 	DWORD ret = NO_ERROR;
1597 	UNIMPLEMENTED;
1598 	return ret;
1599 }
1600 
1601 static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
1602 {
1603   IP_ADDR_STRING *pNext;
1604   PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
1605 
1606   if (!Context->NumServers)
1607   {
1608     if (Context->uSizeAvailable >= Context->uSizeRequired)
1609     {
1610       WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
1611       Context->pData->DnsServerList.IpAddress.String[15] = '\0';
1612       Context->pLastAddr = &Context->pData->DnsServerList;
1613     }
1614   }
1615   else
1616   {
1617      Context->uSizeRequired += sizeof(IP_ADDR_STRING);
1618      if (Context->uSizeAvailable >= Context->uSizeRequired)
1619      {
1620          pNext = (IP_ADDR_STRING*)(((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING));
1621          WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
1622          pNext->IpAddress.String[15] = '\0';
1623          Context->pLastAddr->Next = pNext;
1624          Context->pLastAddr = pNext;
1625          pNext->Next = NULL;
1626      }
1627   }
1628   Context->NumServers++;
1629 }
1630 
1631 /******************************************************************
1632  *    GetPerAdapterInfo (IPHLPAPI.@)
1633  *
1634  *
1635  * PARAMS
1636  *
1637  *  IfIndex [In]
1638  *  pPerAdapterInfo [In/Out]
1639  *  pOutBufLen [In/Out]
1640  *
1641  * RETURNS
1642  *
1643  *  DWORD
1644  *
1645  */
1646 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1647 {
1648   HKEY hkey;
1649   DWORD dwSize = 0;
1650   const char *ifName;
1651   NAME_SERVER_LIST_CONTEXT Context;
1652   WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
1653 
1654   if (!pOutBufLen)
1655     return ERROR_INVALID_PARAMETER;
1656 
1657   if (!pPerAdapterInfo || *pOutBufLen < sizeof(IP_PER_ADAPTER_INFO))
1658   {
1659     *pOutBufLen = sizeof(IP_PER_ADAPTER_INFO);
1660     return ERROR_BUFFER_OVERFLOW;
1661   }
1662 
1663   ifName = getInterfaceNameByIndex(IfIndex);
1664   if (!ifName)
1665     return ERROR_INVALID_PARAMETER;
1666 
1667   MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
1668   HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
1669 
1670   if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
1671   {
1672     return ERROR_NOT_SUPPORTED;
1673   }
1674   Context.NumServers = 0;
1675   Context.uSizeAvailable = *pOutBufLen;
1676   Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
1677   Context.pData = pPerAdapterInfo;
1678 
1679   if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
1680     ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
1681 
1682   EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
1683 
1684   if (Context.uSizeRequired > Context.uSizeAvailable)
1685   {
1686     *pOutBufLen = Context.uSizeRequired;
1687     RegCloseKey(hkey);
1688     return ERROR_BUFFER_OVERFLOW;
1689   }
1690 
1691   if(RegQueryValueExW(hkey, L"NameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
1692   {
1693     pPerAdapterInfo->AutoconfigActive = FALSE;
1694   }
1695   else
1696   {
1697     pPerAdapterInfo->AutoconfigActive = TRUE;
1698   }
1699 
1700   RegCloseKey(hkey);
1701   return NOERROR;
1702 }
1703 
1704 
1705 /******************************************************************
1706  *    GetRTTAndHopCount (IPHLPAPI.@)
1707  *
1708  *
1709  * PARAMS
1710  *
1711  *  DestIpAddress [In]
1712  *  HopCount [In/Out]
1713  *  MaxHops [In]
1714  *  RTT [In/Out]
1715  *
1716  * RETURNS
1717  *
1718  *  BOOL
1719  *
1720  */
1721 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
1722 {
1723   TRACE("DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p\n",
1724    DestIpAddress, HopCount, MaxHops, RTT);
1725   FIXME(":stub\n");
1726   return (BOOL) 0;
1727 }
1728 
1729 
1730 /******************************************************************
1731  *    GetTcpStatisticsEx (IPHLPAPI.@)
1732  *
1733  *
1734  * PARAMS
1735  *
1736  *  pStats [In/Out]
1737  *  dwFamily [In]
1738  *
1739  * RETURNS
1740  *
1741  *  DWORD
1742  *
1743  */
1744 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily)
1745 {
1746   DWORD ret;
1747 
1748   TRACE("pStats %p\n", pStats);
1749   ret = getTCPStats(pStats, dwFamily);
1750   TRACE("returning %ld\n", ret);
1751   return ret;
1752 }
1753 
1754 /******************************************************************
1755  *    GetTcpStatistics (IPHLPAPI.@)
1756  *
1757  *
1758  * PARAMS
1759  *
1760  *  pStats [In/Out]
1761  *
1762  * RETURNS
1763  *
1764  *  DWORD
1765  *
1766  */
1767 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
1768 {
1769     return GetTcpStatisticsEx(pStats, PF_INET);
1770 }
1771 
1772 
1773 static int TcpTableSorter(const void *a, const void *b)
1774 {
1775   int ret;
1776 
1777   if (a && b) {
1778     PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
1779 
1780     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1781     if (ret == 0) {
1782       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1783       if (ret == 0) {
1784         ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
1785         if (ret == 0)
1786           ret = rowA->dwRemotePort - rowB->dwRemotePort;
1787       }
1788     }
1789   }
1790   else
1791     ret = 0;
1792   return ret;
1793 }
1794 
1795 
1796 /******************************************************************
1797  *    GetTcpTable (IPHLPAPI.@)
1798  *
1799  * Get the table of active TCP connections.
1800  *
1801  * PARAMS
1802  *  pTcpTable [Out]    buffer for TCP connections table
1803  *  pdwSize   [In/Out] length of output buffer
1804  *  bOrder    [In]     whether to order the table
1805  *
1806  * RETURNS
1807  *  Success: NO_ERROR
1808  *  Failure: error code from winerror.h
1809  *
1810  * NOTES
1811  *  If pdwSize is less than required, the function will return
1812  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
1813  *  the required byte size.
1814  *  If bOrder is true, the returned table will be sorted, first by
1815  *  local address and port number, then by remote address and port
1816  *  number.
1817  */
1818 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1819 {
1820   DWORD ret = ERROR_NO_DATA;
1821 
1822   TRACE("pTcpTable %p, pdwSize %p, bOrder %d\n", pTcpTable, pdwSize,
1823    (DWORD)bOrder);
1824   if (!pdwSize)
1825     ret = ERROR_INVALID_PARAMETER;
1826   else {
1827     DWORD numEntries = getNumTcpEntries();
1828     DWORD size = sizeof(MIB_TCPTABLE);
1829 
1830     if (numEntries > 1)
1831       size += (numEntries - 1) * sizeof(MIB_TCPROW);
1832     if (!pTcpTable || *pdwSize < size) {
1833       *pdwSize = size;
1834       ret = ERROR_INSUFFICIENT_BUFFER;
1835     }
1836     else {
1837       PMIB_TCPTABLE pOurTcpTable = getTcpTable();
1838 	  if (pOurTcpTable)
1839       {
1840         size = sizeof(MIB_TCPTABLE);
1841         if (pOurTcpTable->dwNumEntries > 1)
1842             size += (pOurTcpTable->dwNumEntries - 1) * sizeof(MIB_TCPROW);
1843 
1844         if (*pdwSize < size)
1845         {
1846             *pdwSize = size;
1847 
1848             ret = ERROR_INSUFFICIENT_BUFFER;
1849         }
1850         else
1851         {
1852             memcpy(pTcpTable, pOurTcpTable, size);
1853 
1854             if (bOrder)
1855                 qsort(pTcpTable->table, pTcpTable->dwNumEntries,
1856                       sizeof(MIB_TCPROW), TcpTableSorter);
1857 
1858             ret = NO_ERROR;
1859         }
1860 
1861         free(pOurTcpTable);
1862 	  }
1863    	}
1864   }
1865   TRACE("returning %d\n", ret);
1866   return ret;
1867 }
1868 
1869 
1870 /******************************************************************
1871  *    GetUdpStatisticsEx (IPHLPAPI.@)
1872  *
1873  *
1874  * PARAMS
1875  *
1876  *  pStats [In/Out]
1877  *  dwFamily [In]
1878  *
1879  * RETURNS
1880  *
1881  *  DWORD
1882  *
1883  */
1884 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS pStats, DWORD dwFamily)
1885 {
1886   DWORD ret;
1887 
1888   TRACE("pStats %p\n", pStats);
1889   ret = getUDPStats(pStats, dwFamily);
1890   TRACE("returning %ld\n", ret);
1891   return ret;
1892 }
1893 
1894 /******************************************************************
1895  *    GetUdpStatistics (IPHLPAPI.@)
1896  *
1897  *
1898  * PARAMS
1899  *
1900  *  pStats [In/Out]
1901  *
1902  * RETURNS
1903  *
1904  *  DWORD
1905  *
1906  */
1907 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
1908 {
1909     return GetUdpStatisticsEx(pStats, PF_INET);
1910 }
1911 
1912 
1913 static int UdpTableSorter(const void *a, const void *b)
1914 {
1915   int ret;
1916 
1917   if (a && b) {
1918     PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
1919 
1920     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1921     if (ret == 0)
1922       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1923   }
1924   else
1925     ret = 0;
1926   return ret;
1927 }
1928 
1929 
1930 /******************************************************************
1931  *    GetUdpTable (IPHLPAPI.@)
1932  *
1933  *
1934  * PARAMS
1935  *
1936  *  pUdpTable [In/Out]
1937  *  pdwSize [In/Out]
1938  *  bOrder [In]
1939  *
1940  * RETURNS
1941  *
1942  *  DWORD
1943  *
1944  */
1945 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1946 {
1947   DWORD ret;
1948 
1949   TRACE("pUdpTable %p, pdwSize %p, bOrder %ld\n", pUdpTable, pdwSize,
1950    (DWORD)bOrder);
1951   if (!pdwSize)
1952     ret = ERROR_INVALID_PARAMETER;
1953   else {
1954     DWORD numEntries = getNumUdpEntries();
1955     ULONG size = sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW);
1956 
1957     if (!pUdpTable || *pdwSize < size) {
1958       *pdwSize = size;
1959       ret = ERROR_INSUFFICIENT_BUFFER;
1960     }
1961     else {
1962       PMIB_UDPTABLE table = getUdpTable();
1963 
1964       if (table) {
1965         size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) *
1966          sizeof(MIB_UDPROW);
1967         if (*pdwSize < size) {
1968           *pdwSize = size;
1969           ret = ERROR_INSUFFICIENT_BUFFER;
1970         }
1971         else {
1972           memcpy(pUdpTable, table, size);
1973           if (bOrder)
1974             qsort(pUdpTable->table, pUdpTable->dwNumEntries,
1975              sizeof(MIB_UDPROW), UdpTableSorter);
1976           ret = NO_ERROR;
1977         }
1978         free(table);
1979       }
1980       else
1981         ret = ERROR_OUTOFMEMORY;
1982     }
1983   }
1984   TRACE("returning %ld\n", ret);
1985   return ret;
1986 }
1987 
1988 
1989 /******************************************************************
1990  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1991  *
1992  * This is a Win98-only function to get information on "unidirectional"
1993  * adapters.  Since this is pretty nonsensical in other contexts, it
1994  * never returns anything.
1995  *
1996  * PARAMS
1997  *  pIPIfInfo   [Out] buffer for adapter infos
1998  *  dwOutBufLen [Out] length of the output buffer
1999  *
2000  * RETURNS
2001  *  Success: NO_ERROR
2002  *  Failure: error code from winerror.h
2003  *
2004  * FIXME
2005  *  Stub, returns ERROR_NOT_SUPPORTED.
2006  */
2007 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
2008 {
2009   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
2010   /* a unidirectional adapter?? not bloody likely! */
2011   return ERROR_NOT_SUPPORTED;
2012 }
2013 
2014 
2015 /******************************************************************
2016  *    IpReleaseAddress (IPHLPAPI.@)
2017  *
2018  * Release an IP obtained through DHCP,
2019  *
2020  * PARAMS
2021  *  AdapterInfo [In] adapter to release IP address
2022  *
2023  * RETURNS
2024  *  Success: NO_ERROR
2025  *  Failure: error code from winerror.h
2026  *
2027  */
2028 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2029 {
2030   DWORD Status, Version = 0;
2031 
2032   if (!AdapterInfo)
2033       return ERROR_INVALID_PARAMETER;
2034 
2035   /* Maybe we should do this in DllMain */
2036   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2037       return ERROR_PROC_NOT_FOUND;
2038 
2039   if (DhcpReleaseIpAddressLease(AdapterInfo->Index))
2040       Status = ERROR_SUCCESS;
2041   else
2042       Status = ERROR_PROC_NOT_FOUND;
2043 
2044   DhcpCApiCleanup();
2045 
2046   return Status;
2047 }
2048 
2049 
2050 /******************************************************************
2051  *    IpRenewAddress (IPHLPAPI.@)
2052  *
2053  * Renew an IP obtained through DHCP.
2054  *
2055  * PARAMS
2056  *  AdapterInfo [In] adapter to renew IP address
2057  *
2058  * RETURNS
2059  *  Success: NO_ERROR
2060  *  Failure: error code from winerror.h
2061  */
2062 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2063 {
2064   DWORD Status, Version = 0;
2065 
2066   if (!AdapterInfo)
2067       return ERROR_INVALID_PARAMETER;
2068 
2069   /* Maybe we should do this in DllMain */
2070   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2071       return ERROR_PROC_NOT_FOUND;
2072 
2073   if (DhcpRenewIpAddressLease(AdapterInfo->Index))
2074       Status = ERROR_SUCCESS;
2075   else
2076       Status = ERROR_PROC_NOT_FOUND;
2077 
2078   DhcpCApiCleanup();
2079 
2080   return Status;
2081 }
2082 
2083 
2084 /******************************************************************
2085  *    NotifyAddrChange (IPHLPAPI.@)
2086  *
2087  * Notify caller whenever the ip-interface map is changed.
2088  *
2089  * PARAMS
2090  *  Handle     [Out] handle usable in asynchronous notification
2091  *  overlapped [In]  overlapped structure that notifies the caller
2092  *
2093  * RETURNS
2094  *  Success: NO_ERROR
2095  *  Failure: error code from winerror.h
2096  *
2097  * FIXME
2098  *  Stub, returns ERROR_NOT_SUPPORTED.
2099  */
2100 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2101 {
2102   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2103   if (Handle) *Handle = INVALID_HANDLE_VALUE;
2104   if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING;
2105   return ERROR_IO_PENDING;
2106 }
2107 
2108 
2109 /******************************************************************
2110  *    NotifyRouteChange (IPHLPAPI.@)
2111  *
2112  * Notify caller whenever the ip routing table is changed.
2113  *
2114  * PARAMS
2115  *  Handle     [Out] handle usable in asynchronous notification
2116  *  overlapped [In]  overlapped structure that notifies the caller
2117  *
2118  * RETURNS
2119  *  Success: NO_ERROR
2120  *  Failure: error code from winerror.h
2121  *
2122  * FIXME
2123  *  Stub, returns ERROR_NOT_SUPPORTED.
2124  */
2125 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2126 {
2127   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2128   return ERROR_NOT_SUPPORTED;
2129 }
2130 
2131 /******************************************************************
2132  *    SendARP (IPHLPAPI.@)
2133  *
2134  * Send an ARP request.
2135  *
2136  * PARAMS
2137  *  DestIP     [In]     attempt to obtain this IP
2138  *  SrcIP      [In]     optional sender IP address
2139  *  pMacAddr   [Out]    buffer for the mac address
2140  *  PhyAddrLen [In/Out] length of the output buffer
2141  *
2142  * RETURNS
2143  *  Success: NO_ERROR
2144  *  Failure: error code from winerror.h
2145  */
2146 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2147 {
2148   IPAddr IPs[2];
2149   ULONG Size;
2150 
2151   if (IsBadWritePtr(pMacAddr, sizeof(ULONG)) || IsBadWritePtr(PhyAddrLen, sizeof(ULONG)))
2152     return ERROR_INVALID_PARAMETER;
2153 
2154   IPs[0] = DestIP;
2155   IPs[1] = SrcIP;
2156   Size = sizeof(IPs);
2157   return TCPSendIoctl(INVALID_HANDLE_VALUE, IOCTL_QUERY_IP_HW_ADDRESS, IPs, &Size, pMacAddr, PhyAddrLen);
2158 }
2159 
2160 
2161 /******************************************************************
2162  *    SetIfEntry (IPHLPAPI.@)
2163  *
2164  * Set the administrative status of an interface.
2165  *
2166  * PARAMS
2167  *  pIfRow [In] dwAdminStatus member specifies the new status.
2168  *
2169  * RETURNS
2170  *  Success: NO_ERROR
2171  *  Failure: error code from winerror.h
2172  *
2173  * FIXME
2174  *  Stub, returns ERROR_NOT_SUPPORTED.
2175  */
2176 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
2177 {
2178   FIXME("(pIfRow %p): stub\n", pIfRow);
2179   /* this is supposed to set an interface administratively up or down.
2180      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2181      this sort of down is indistinguishable from other sorts of down (e.g. no
2182      link). */
2183   return ERROR_NOT_SUPPORTED;
2184 }
2185 
2186 
2187 /******************************************************************
2188  *    SetIpForwardEntry (IPHLPAPI.@)
2189  *
2190  * Modify an existing route.
2191  *
2192  * PARAMS
2193  *  pRoute [In] route with the new information
2194  *
2195  * RETURNS
2196  *  Success: NO_ERROR
2197  *  Failure: error code from winerror.h
2198  *
2199  */
2200 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
2201 {
2202     return setIpForwardEntry( pRoute );
2203 }
2204 
2205 
2206 /******************************************************************
2207  *    SetIpNetEntry (IPHLPAPI.@)
2208  *
2209  * Modify an existing ARP entry.
2210  *
2211  * PARAMS
2212  *  pArpEntry [In] ARP entry with the new information
2213  *
2214  * RETURNS
2215  *  Success: NO_ERROR
2216  *  Failure: error code from winerror.h
2217  */
2218 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
2219 {
2220   HANDLE tcpFile;
2221   NTSTATUS status;
2222   TCP_REQUEST_SET_INFORMATION_EX_ARP_ENTRY req =
2223       TCP_REQUEST_SET_INFORMATION_INIT;
2224   TDIEntityID id;
2225   DWORD returnSize;
2226   PMIB_IPNETROW arpBuff;
2227 
2228   if (!pArpEntry)
2229       return ERROR_INVALID_PARAMETER;
2230 
2231   if (!NT_SUCCESS(openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA )))
2232       return ERROR_NOT_SUPPORTED;
2233 
2234   if (!NT_SUCCESS(getNthIpEntity( tcpFile, pArpEntry->dwIndex, &id )))
2235   {
2236       closeTcpFile(tcpFile);
2237       return ERROR_INVALID_PARAMETER;
2238   }
2239 
2240   req.Req.ID.toi_class = INFO_CLASS_PROTOCOL;
2241   req.Req.ID.toi_type = INFO_TYPE_PROVIDER;
2242   req.Req.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
2243   req.Req.ID.toi_entity.tei_instance = id.tei_instance;
2244   req.Req.ID.toi_entity.tei_entity = AT_ENTITY;
2245   req.Req.BufferSize = sizeof(MIB_IPNETROW);
2246   arpBuff = (PMIB_IPNETROW)&req.Req.Buffer[0];
2247 
2248   RtlCopyMemory(arpBuff, pArpEntry, sizeof(MIB_IPNETROW));
2249 
2250   status = DeviceIoControl( tcpFile,
2251                             IOCTL_TCP_SET_INFORMATION_EX,
2252                             &req,
2253                             sizeof(req),
2254                             NULL,
2255                             0,
2256                             &returnSize,
2257                             NULL );
2258 
2259   closeTcpFile(tcpFile);
2260 
2261   if (status)
2262      return NO_ERROR;
2263   else
2264      return ERROR_INVALID_PARAMETER;
2265 }
2266 
2267 
2268 /******************************************************************
2269  *    SetIpStatistics (IPHLPAPI.@)
2270  *
2271  * Toggle IP forwarding and det the default TTL value.
2272  *
2273  * PARAMS
2274  *  pIpStats [In] IP statistics with the new information
2275  *
2276  * RETURNS
2277  *  Success: NO_ERROR
2278  *  Failure: error code from winerror.h
2279  *
2280  * FIXME
2281  *  Stub, returns NO_ERROR.
2282  */
2283 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
2284 {
2285   FIXME("(pIpStats %p): stub\n", pIpStats);
2286   return 0;
2287 }
2288 
2289 
2290 /******************************************************************
2291  *    SetIpTTL (IPHLPAPI.@)
2292  *
2293  * Set the default TTL value.
2294  *
2295  * PARAMS
2296  *  nTTL [In] new TTL value
2297  *
2298  * RETURNS
2299  *  Success: NO_ERROR
2300  *  Failure: error code from winerror.h
2301  *
2302  * FIXME
2303  *  Stub, returns NO_ERROR.
2304  */
2305 DWORD WINAPI SetIpTTL(UINT nTTL)
2306 {
2307   FIXME("(nTTL %d): stub\n", nTTL);
2308   return 0;
2309 }
2310 
2311 
2312 /******************************************************************
2313  *    SetTcpEntry (IPHLPAPI.@)
2314  *
2315  * Set the state of a TCP connection.
2316  *
2317  * PARAMS
2318  *  pTcpRow [In] specifies connection with new state
2319  *
2320  * RETURNS
2321  *  Success: NO_ERROR
2322  *  Failure: error code from winerror.h
2323  *
2324  * FIXME
2325  *  Stub, returns NO_ERROR.
2326  */
2327 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
2328 {
2329   FIXME("(pTcpRow %p): stub\n", pTcpRow);
2330   return 0;
2331 }
2332 
2333 
2334 /******************************************************************
2335  *    UnenableRouter (IPHLPAPI.@)
2336  *
2337  * Decrement the IP-forwarding reference count. Turn off IP-forwarding
2338  * if it reaches zero.
2339  *
2340  * PARAMS
2341  *  pOverlapped     [In/Out] should be the same as in EnableRouter()
2342  *  lpdwEnableCount [Out]    optional, receives reference count
2343  *
2344  * RETURNS
2345  *  Success: NO_ERROR
2346  *  Failure: error code from winerror.h
2347  *
2348  * FIXME
2349  *  Stub, returns ERROR_NOT_SUPPORTED.
2350  */
2351 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
2352 {
2353   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
2354    lpdwEnableCount);
2355   return ERROR_NOT_SUPPORTED;
2356 }
2357 
2358 /*
2359  * @unimplemented
2360  */
2361 DWORD WINAPI GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)
2362 {
2363     FIXME(":stub\n");
2364     return 0L;
2365 }
2366 
2367 
2368 /*
2369  * @unimplemented
2370  */
2371 PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
2372 {
2373     FIXME(":stub\n");
2374     return 0L;
2375 }
2376 
2377 /*
2378  * @implemented
2379  */
2380 #ifdef GetAdaptersAddressesV1
2381 DWORD WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
2382 {
2383     InterfaceIndexTable *indexTable;
2384     IFInfo ifInfo;
2385     int i;
2386     ULONG ret, requiredSize = 0;
2387     PIP_ADAPTER_ADDRESSES currentAddress;
2388     PUCHAR currentLocation;
2389     HANDLE tcpFile;
2390 
2391     if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
2392     if (Reserved) return ERROR_INVALID_PARAMETER;
2393 
2394     indexTable = getInterfaceIndexTable();
2395     if (!indexTable)
2396         return ERROR_NOT_ENOUGH_MEMORY;
2397 
2398     ret = openTcpFile(&tcpFile, FILE_READ_DATA);
2399     if (!NT_SUCCESS(ret))
2400         return ERROR_NO_DATA;
2401 
2402     for (i = indexTable->numIndexes; i >= 0; i--)
2403     {
2404         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
2405                                            NULL,
2406                                            indexTable->indexes[i],
2407                                            &ifInfo)))
2408         {
2409             /* The whole struct */
2410             requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
2411 
2412             /* Friendly name */
2413             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
2414                 requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1; //FIXME
2415 
2416             /* Adapter name */
2417             requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
2418 
2419             /* Unicast address */
2420             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
2421                 requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
2422 
2423             /* FIXME: Implement multicast, anycast, and dns server stuff */
2424 
2425             /* FIXME: Implement dns suffix and description */
2426             requiredSize += 2 * sizeof(WCHAR);
2427 
2428             /* We're only going to implement what's required for XP SP0 */
2429         }
2430     }
2431     TRACE("size: %d, requiredSize: %d\n", *pOutBufLen, requiredSize);
2432     if (!pAdapterAddresses || *pOutBufLen < requiredSize)
2433     {
2434         *pOutBufLen = requiredSize;
2435         closeTcpFile(tcpFile);
2436         free(indexTable);
2437         return ERROR_BUFFER_OVERFLOW;
2438     }
2439 
2440     RtlZeroMemory(pAdapterAddresses, requiredSize);
2441 
2442     /* Let's set up the pointers */
2443     currentAddress = pAdapterAddresses;
2444     for (i = indexTable->numIndexes; i >= 0; i--)
2445     {
2446         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
2447                                            NULL,
2448                                            indexTable->indexes[i],
2449                                            &ifInfo)))
2450         {
2451             currentLocation = (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
2452 
2453             /* FIXME: Friendly name */
2454             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
2455             {
2456                 currentAddress->FriendlyName = (PVOID)currentLocation;
2457                 currentLocation += sizeof(WCHAR);
2458             }
2459 
2460             /* Adapter name */
2461             currentAddress->AdapterName = (PVOID)currentLocation;
2462             currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
2463 
2464             /* Unicast address */
2465             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
2466             {
2467                 currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
2468                 currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
2469                 currentAddress->FirstUnicastAddress->Address.lpSockaddr = (PVOID)currentLocation;
2470                 currentLocation += sizeof(struct sockaddr);
2471             }
2472 
2473             /* FIXME: Implement multicast, anycast, and dns server stuff */
2474 
2475             /* FIXME: Implement dns suffix and description */
2476             currentAddress->DnsSuffix = (PVOID)currentLocation;
2477             currentLocation += sizeof(WCHAR);
2478 
2479             currentAddress->Description = (PVOID)currentLocation;
2480             currentLocation += sizeof(WCHAR);
2481 
2482             currentAddress->Next = (PVOID)currentLocation;
2483             /* Terminate the last address correctly */
2484             if(i==0)
2485                 currentAddress->Next = NULL;
2486 
2487             /* We're only going to implement what's required for XP SP0 */
2488 
2489             currentAddress = currentAddress->Next;
2490         }
2491     }
2492 
2493     /* Now again, for real this time */
2494 
2495     currentAddress = pAdapterAddresses;
2496     for (i = indexTable->numIndexes; i >= 0; i--)
2497     {
2498         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
2499                                            NULL,
2500                                            indexTable->indexes[i],
2501                                            &ifInfo)))
2502         {
2503             /* Make sure we're not looping more than we hoped for */
2504             ASSERT(currentAddress);
2505 
2506             /* Alignment information */
2507             currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
2508             currentAddress->IfIndex = indexTable->indexes[i];
2509 
2510             /* Adapter name */
2511             strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr);
2512 
2513             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
2514             {
2515                 currentAddress->FirstUnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
2516                 currentAddress->FirstUnicastAddress->Flags = 0; //FIXME
2517                 currentAddress->FirstUnicastAddress->Next = NULL; //FIXME: Support more than one address per adapter
2518                 currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
2519                 memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
2520                        &ifInfo.ip_addr.iae_addr,
2521                        sizeof(ifInfo.ip_addr.iae_addr));
2522                 currentAddress->FirstUnicastAddress->Address.iSockaddrLength = sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
2523                 currentAddress->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; //FIXME
2524                 currentAddress->FirstUnicastAddress->SuffixOrigin = IpPrefixOriginOther; //FIXME
2525                 currentAddress->FirstUnicastAddress->DadState = IpDadStatePreferred; //FIXME
2526                 currentAddress->FirstUnicastAddress->ValidLifetime = 0xFFFFFFFF; //FIXME
2527                 currentAddress->FirstUnicastAddress->PreferredLifetime = 0xFFFFFFFF; //FIXME
2528                 currentAddress->FirstUnicastAddress->LeaseLifetime = 0xFFFFFFFF; //FIXME
2529             }
2530 
2531             /* FIXME: Implement multicast, anycast, and dns server stuff */
2532             currentAddress->FirstAnycastAddress = NULL;
2533             currentAddress->FirstMulticastAddress = NULL;
2534             currentAddress->FirstDnsServerAddress = NULL;
2535 
2536             /* FIXME: Implement dns suffix, description, and friendly name */
2537             currentAddress->DnsSuffix[0] = UNICODE_NULL;
2538             currentAddress->Description[0] = UNICODE_NULL;
2539             currentAddress->FriendlyName[0] = UNICODE_NULL;
2540 
2541             /* Physical Address */
2542             memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, ifInfo.if_info.ent.if_physaddrlen);
2543             currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
2544 
2545             /* Flags */
2546             currentAddress->Flags = 0; //FIXME
2547 
2548             /* MTU */
2549             currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
2550 
2551             /* Interface type */
2552             currentAddress->IfType = ifInfo.if_info.ent.if_type;
2553 
2554             /* Operational status */
2555             if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
2556                 currentAddress->OperStatus = IfOperStatusUp;
2557             else
2558                 currentAddress->OperStatus = IfOperStatusDown;
2559 
2560             /* We're only going to implement what's required for XP SP0 */
2561 
2562             /* Move to the next address */
2563             currentAddress = currentAddress->Next;
2564         }
2565     }
2566 
2567     closeTcpFile(tcpFile);
2568     free(indexTable);
2569 
2570     return NO_ERROR;
2571 }
2572 #endif
2573 
2574 /*
2575  * @unimplemented
2576  */
2577 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)
2578 {
2579     FIXME(":stub\n");
2580     return 0L;
2581 }
2582 
2583 /*
2584  * @unimplemented
2585  */
2586 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex)
2587 {
2588     FIXME(":stub\n");
2589     return 0L;
2590 }
2591 
2592 /*
2593  * @unimplemented
2594  */
2595 DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)
2596 {
2597     FIXME(":stub\n");
2598     return 0L;
2599 }
2600 
2601 /*
2602  * @unimplemented
2603  */
2604 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
2605 {
2606     FIXME(":stub\n");
2607 
2608     if (!pStats)
2609         return ERROR_INVALID_PARAMETER;
2610 
2611     if (dwFamily != AF_INET && dwFamily != AF_INET6)
2612         return ERROR_INVALID_PARAMETER;
2613 
2614     return 0L;
2615 }
2616 
2617 DWORD WINAPI
2618 SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)
2619 {
2620     FIXME("SetIpForwardEntryToStack() stub\n");
2621     return 0L;
2622 }
2623 
2624 DWORD GetInterfaceNameInternal(_In_ const GUID * pInterfaceGUID,
2625                                _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
2626                                _Inout_ PULONG pOutBufLen)
2627 {
2628     UNICODE_STRING GuidString;
2629     DWORD result, type;
2630     WCHAR szKeyName[2*MAX_PATH];
2631     HRESULT hr;
2632     HKEY hKey;
2633 
2634     if (pInterfaceGUID == NULL || pOutBufLen == NULL)
2635         return ERROR_INVALID_PARAMETER;
2636 
2637     result = RtlStringFromGUID(pInterfaceGUID, &GuidString);
2638 
2639     if (!NT_SUCCESS(result))
2640     {
2641         // failed to convert guid to string
2642         return RtlNtStatusToDosError(result);
2643     }
2644 
2645     hr = StringCbPrintfW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", GuidString.Buffer);
2646     RtlFreeUnicodeString(&GuidString);
2647 
2648     if (FAILED(hr))
2649     {
2650         // key name is too long
2651         return ERROR_BUFFER_OVERFLOW;
2652     }
2653 
2654     result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKey);
2655 
2656     if (result != ERROR_SUCCESS)
2657     {
2658         // failed to find adapter entry
2659         return ERROR_NOT_FOUND;
2660     }
2661 
2662     result = RegQueryValueExW(hKey, L"Name", NULL, &type, (PVOID)pInterfaceName, pOutBufLen);
2663 
2664     RegCloseKey(hKey);
2665 
2666     if (result == ERROR_MORE_DATA)
2667     {
2668         *pOutBufLen = MAX_INTERFACE_NAME_LEN * 2;
2669         return ERROR_INSUFFICIENT_BUFFER;
2670     }
2671 
2672     if (result != ERROR_SUCCESS || type != REG_SZ)
2673     {
2674         // failed to read adapter name
2675         return ERROR_NO_DATA;
2676     }
2677     return ERROR_SUCCESS;
2678 }
2679 
2680 /*
2681  * @implemented
2682  */
2683 DWORD WINAPI
2684 NhGetInterfaceNameFromDeviceGuid(_In_ const GUID * pInterfaceGUID,
2685                                  _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
2686                                  _Inout_ PULONG pOutBufLen,
2687                                  DWORD dwUnknown4,
2688                                  DWORD dwUnknown5)
2689 {
2690     SetLastError(ERROR_SUCCESS);
2691 
2692     if (pInterfaceName == NULL)
2693         return ERROR_INVALID_PARAMETER;
2694 
2695     return GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
2696 }
2697 
2698 /*
2699  * @implemented
2700  */
2701 DWORD WINAPI
2702 NhGetInterfaceNameFromGuid(_In_ const GUID * pInterfaceGUID,
2703                            _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
2704                            _Inout_ PULONG pOutBufLen,
2705                            DWORD dwUnknown4,
2706                            DWORD dwUnknown5)
2707 {
2708     DWORD result;
2709 
2710     result = GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
2711 
2712     if (result == ERROR_NOT_FOUND)
2713         SetLastError(ERROR_PATH_NOT_FOUND);
2714 
2715     return result;
2716 }
2717