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