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