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