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