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