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