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