Visual C++ backend for rbuild (for now just a hacked mingw backend) and related compi...
[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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "config.h"
22 #include "iphlpapi_private.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #ifdef HAVE_NETINET_IN_H
28 # include <netinet/in.h>
29 #endif
30 #ifdef HAVE_ARPA_INET_H
31 # include <arpa/inet.h>
32 #endif
33 #ifdef HAVE_ARPA_NAMESER_H
34 # include <arpa/nameser.h>
35 #endif
36 #ifdef HAVE_RESOLV_H
37 # include <resolv.h>
38 #endif
39
40 #define DEBUG
41 #include "windef.h"
42 #include "winbase.h"
43 #include "winreg.h"
44 #include "iphlpapi.h"
45 #include "dhcp.h"
46 #include "ifenum.h"
47 #include "ipstats.h"
48 #include "resinfo.h"
49 #include "route.h"
50 #include "wine/debug.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
53
54 typedef struct _NAME_SERVER_LIST_CONTEXT {
55 ULONG uSizeAvailable;
56 ULONG uSizeRequired;
57 PIP_PER_ADAPTER_INFO pData;
58 UINT NumServers;
59 IP_ADDR_STRING *pLastAddr;
60 } NAME_SERVER_LIST_CONTEXT, *PNAME_SERVER_LIST_CONTEXT;
61
62 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
63 {
64 switch (fdwReason) {
65 case DLL_PROCESS_ATTACH:
66 DisableThreadLibraryCalls( hinstDLL );
67 interfaceMapInit();
68 break;
69
70 case DLL_PROCESS_DETACH:
71 interfaceMapFree();
72 break;
73 }
74 return TRUE;
75 }
76
77 /******************************************************************
78 * AddIPAddress (IPHLPAPI.@)
79 *
80 *
81 * PARAMS
82 *
83 * Address [In]
84 * IpMask [In]
85 * IfIndex [In]
86 * NTEContext [In/Out]
87 * NTEInstance [In/Out]
88 *
89 * RETURNS
90 *
91 * DWORD
92 *
93 */
94 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask Netmask, DWORD IfIndex, PULONG NteContext, PULONG NteInstance)
95 {
96 return RtlNtStatusToDosError(addIPAddress(Address, Netmask, IfIndex, NteContext, NteInstance));
97 }
98
99 DWORD getInterfaceGatewayByIndex(DWORD index)
100 {
101 DWORD ndx, retVal = 0, numRoutes = getNumRoutes();
102 RouteTable *table = getRouteTable();
103
104 for (ndx = 0; ndx < numRoutes; ndx++)
105 {
106 if ((table->routes[ndx].ifIndex == (index - 1)) && (table->routes[ndx].dest == 0))
107 retVal = table->routes[ndx].gateway;
108 }
109 HeapFree(GetProcessHeap(), 0, table);
110 return retVal;
111 }
112
113 /******************************************************************
114 * AllocateAndGetIfTableFromStack (IPHLPAPI.@)
115 *
116 *
117 * PARAMS
118 *
119 * ppIfTable [Out] -- pointer into which the MIB_IFTABLE is
120 * allocated and returned.
121 * bOrder [In] -- passed to GetIfTable to order the table
122 * heap [In] -- heap from which the table is allocated
123 * flags [In] -- flags to HeapAlloc
124 *
125 * RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
126 * GetIfTable returns otherwise
127 *
128 */
129 DWORD WINAPI AllocateAndGetIfTableFromStack(PMIB_IFTABLE *ppIfTable,
130 BOOL bOrder, HANDLE heap, DWORD flags)
131 {
132 DWORD ret;
133
134 TRACE("ppIfTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n", ppIfTable,
135 (DWORD)bOrder, (DWORD)heap, flags);
136 if (!ppIfTable)
137 ret = ERROR_INVALID_PARAMETER;
138 else {
139 DWORD dwSize = 0;
140
141 ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
142 if (ret == ERROR_INSUFFICIENT_BUFFER) {
143 *ppIfTable = (PMIB_IFTABLE)HeapAlloc(heap, flags, dwSize);
144 ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
145 }
146 }
147 TRACE("returning %ld\n", ret);
148 return ret;
149 }
150
151
152 /******************************************************************
153 * AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
154 *
155 *
156 * PARAMS
157 *
158 * ppIpAddrTable [Out]
159 * bOrder [In] -- passed to GetIpAddrTable to order the table
160 * heap [In] -- heap from which the table is allocated
161 * flags [In] -- flags to HeapAlloc
162 *
163 * RETURNS
164 *
165 * DWORD
166 *
167 */
168 DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
169 BOOL bOrder, HANDLE heap, DWORD flags)
170 {
171 DWORD ret;
172
173 TRACE("ppIpAddrTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n",
174 ppIpAddrTable, (DWORD)bOrder, (DWORD)heap, flags);
175 if (!ppIpAddrTable)
176 ret = ERROR_INVALID_PARAMETER;
177 else {
178 DWORD dwSize = 0;
179
180 ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
181 if (ret == ERROR_INSUFFICIENT_BUFFER) {
182 *ppIpAddrTable = (PMIB_IPADDRTABLE)HeapAlloc(heap, flags, dwSize);
183 ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
184 }
185 }
186 TRACE("returning %ld\n", ret);
187 return ret;
188 }
189
190
191 /******************************************************************
192 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
193 *
194 *
195 * ppIpForwardTable [Out] -- pointer into which the MIB_IPFORWARDTABLE is
196 * allocated and returned.
197 * bOrder [In] -- passed to GetIfTable to order the table
198 * heap [In] -- heap from which the table is allocated
199 * flags [In] -- flags to HeapAlloc
200 *
201 * RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
202 * GetIpForwardTable returns otherwise
203 *
204 */
205 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *
206 ppIpForwardTable, BOOL bOrder, HANDLE heap, DWORD flags)
207 {
208 DWORD ret;
209
210 TRACE("ppIpForwardTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n",
211 ppIpForwardTable, (DWORD)bOrder, (DWORD)heap, flags);
212 if (!ppIpForwardTable)
213 ret = ERROR_INVALID_PARAMETER;
214 else {
215 DWORD dwSize = 0;
216
217 ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
218 if (ret == ERROR_INSUFFICIENT_BUFFER) {
219 *ppIpForwardTable = (PMIB_IPFORWARDTABLE)HeapAlloc(heap, flags, dwSize);
220 ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
221 }
222 }
223 TRACE("returning %ld\n", ret);
224 return ret;
225 }
226
227
228 /******************************************************************
229 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
230 *
231 *
232 * PARAMS
233 *
234 * ppIpNetTable [Out]
235 * bOrder [In] -- passed to GetIpNetTable to order the table
236 * heap [In] -- heap from which the table is allocated
237 * flags [In] -- flags to HeapAlloc
238 *
239 * RETURNS
240 *
241 * DWORD
242 *
243 */
244 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable,
245 BOOL bOrder, HANDLE heap, DWORD flags)
246 {
247 DWORD ret;
248
249 TRACE("ppIpNetTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n",
250 ppIpNetTable, (DWORD)bOrder, (DWORD)heap, flags);
251 if (!ppIpNetTable)
252 ret = ERROR_INVALID_PARAMETER;
253 else {
254 DWORD dwSize = 0;
255
256 ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
257 if (ret == ERROR_INSUFFICIENT_BUFFER) {
258 *ppIpNetTable = (PMIB_IPNETTABLE)HeapAlloc(heap, flags, dwSize);
259 ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
260 }
261 }
262 TRACE("returning %ld\n", ret);
263 return ret;
264 }
265
266
267 /******************************************************************
268 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
269 *
270 *
271 * PARAMS
272 *
273 * ppTcpTable [Out]
274 * bOrder [In] -- passed to GetTcpTable to order the table
275 * heap [In] -- heap from which the table is allocated
276 * flags [In] -- flags to HeapAlloc
277 *
278 * RETURNS
279 *
280 * DWORD
281 *
282 */
283 DWORD WINAPI AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE *ppTcpTable,
284 BOOL bOrder, HANDLE heap, DWORD flags)
285 {
286 DWORD ret;
287
288 TRACE("ppTcpTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n",
289 ppTcpTable, (DWORD)bOrder, (DWORD)heap, flags);
290 if (!ppTcpTable)
291 ret = ERROR_INVALID_PARAMETER;
292 else {
293 DWORD dwSize = 0;
294
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 }
300 }
301 TRACE("returning %ld\n", ret);
302 return ret;
303 }
304
305
306 /******************************************************************
307 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
308 *
309 *
310 * PARAMS
311 *
312 * ppUdpTable [Out]
313 * bOrder [In] -- passed to GetUdpTable to order the table
314 * heap [In] -- heap from which the table is allocated
315 * flags [In] -- flags to HeapAlloc
316 *
317 * RETURNS
318 *
319 * DWORD
320 *
321 */
322 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable,
323 BOOL bOrder, HANDLE heap, DWORD flags)
324 {
325 DWORD ret;
326
327 TRACE("ppUdpTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n",
328 ppUdpTable, (DWORD)bOrder, (DWORD)heap, flags);
329 if (!ppUdpTable)
330 ret = ERROR_INVALID_PARAMETER;
331 else {
332 DWORD dwSize = 0;
333
334 ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
335 if (ret == ERROR_INSUFFICIENT_BUFFER) {
336 *ppUdpTable = (PMIB_UDPTABLE)HeapAlloc(heap, flags, dwSize);
337 ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
338 }
339 }
340 TRACE("returning %ld\n", ret);
341 return ret;
342 }
343
344
345 /******************************************************************
346 * CreateIpForwardEntry (IPHLPAPI.@)
347 *
348 *
349 * PARAMS
350 *
351 * pRoute [In/Out]
352 *
353 * RETURNS
354 *
355 * DWORD
356 *
357 */
358 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
359 {
360 return createIpForwardEntry( pRoute );
361 }
362
363
364 /******************************************************************
365 * CreateIpNetEntry (IPHLPAPI.@)
366 *
367 *
368 * PARAMS
369 *
370 * pArpEntry [In/Out]
371 *
372 * RETURNS
373 *
374 * DWORD
375 *
376 */
377 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
378 {
379 TRACE("pArpEntry %p\n", pArpEntry);
380 /* could use SIOCSARP on systems that support it, not sure I want to */
381 FIXME(":stub\n");
382 return (DWORD) 0;
383 }
384
385
386 /******************************************************************
387 * CreateProxyArpEntry (IPHLPAPI.@)
388 *
389 *
390 * PARAMS
391 *
392 * dwAddress [In]
393 * dwMask [In]
394 * dwIfIndex [In]
395 *
396 * RETURNS
397 *
398 * DWORD
399 *
400 */
401 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
402 {
403 TRACE("dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx\n", dwAddress,
404 dwMask, dwIfIndex);
405 FIXME(":stub\n");
406 /* marking Win2K+ functions not supported */
407 return ERROR_NOT_SUPPORTED;
408 }
409
410
411 /******************************************************************
412 * DeleteIPAddress (IPHLPAPI.@)
413 *
414 *
415 * PARAMS
416 *
417 * NTEContext [In]
418 *
419 * RETURNS
420 *
421 * DWORD
422 *
423 */
424 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
425 {
426 TRACE("NTEContext %ld\n", NTEContext);
427 return RtlNtStatusToDosError(deleteIpAddress(NTEContext));
428 }
429
430
431 /******************************************************************
432 * DeleteIpForwardEntry (IPHLPAPI.@)
433 *
434 *
435 * PARAMS
436 *
437 * pRoute [In/Out]
438 *
439 * RETURNS
440 *
441 * DWORD
442 *
443 */
444 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
445 {
446 return deleteIpForwardEntry( pRoute );
447 }
448
449
450 /******************************************************************
451 * DeleteIpNetEntry (IPHLPAPI.@)
452 *
453 *
454 * PARAMS
455 *
456 * pArpEntry [In/Out]
457 *
458 * RETURNS
459 *
460 * DWORD
461 *
462 */
463 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
464 {
465 TRACE("pArpEntry %p\n", pArpEntry);
466 /* could use SIOCDARP on systems that support it, not sure I want to */
467 FIXME(":stub\n");
468 return (DWORD) 0;
469 }
470
471
472 /******************************************************************
473 * DeleteProxyArpEntry (IPHLPAPI.@)
474 *
475 *
476 * PARAMS
477 *
478 * dwAddress [In]
479 * dwMask [In]
480 * dwIfIndex [In]
481 *
482 * RETURNS
483 *
484 * DWORD
485 *
486 */
487 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
488 {
489 TRACE("dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx\n", dwAddress,
490 dwMask, dwIfIndex);
491 FIXME(":stub\n");
492 /* marking Win2K+ functions not supported */
493 return ERROR_NOT_SUPPORTED;
494 }
495
496 /******************************************************************
497 * EnableRouter (IPHLPAPI.@)
498 *
499 *
500 * PARAMS
501 *
502 * pHandle [In/Out]
503 * pOverlapped [In/Out]
504 *
505 * RETURNS
506 *
507 * DWORD
508 *
509 */
510 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
511 {
512 TRACE("pHandle %p, pOverlapped %p\n", pHandle, pOverlapped);
513 FIXME(":stub\n");
514 /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
515 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
516 marking Win2K+ functions not supported */
517 return ERROR_NOT_SUPPORTED;
518 }
519
520
521 /******************************************************************
522 * FlushIpNetTable (IPHLPAPI.@)
523 *
524 *
525 * PARAMS
526 *
527 * dwIfIndex [In]
528 *
529 * RETURNS
530 *
531 * DWORD
532 *
533 */
534 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
535 {
536 TRACE("dwIfIndex 0x%08lx\n", dwIfIndex);
537 FIXME(":stub\n");
538 /* this flushes the arp cache of the given index
539 marking Win2K+ functions not supported */
540 return ERROR_NOT_SUPPORTED;
541 }
542
543
544 /******************************************************************
545 * GetAdapterIndex (IPHLPAPI.@)
546 *
547 *
548 * PARAMS
549 *
550 * AdapterName [In/Out]
551 * IfIndex [In/Out]
552 *
553 * RETURNS
554 *
555 * DWORD
556 *
557 */
558 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
559 {
560 TRACE("AdapterName %p, IfIndex %p\n", AdapterName, IfIndex);
561 FIXME(":stub\n");
562 /* marking Win2K+ functions not supported */
563 return ERROR_NOT_SUPPORTED;
564 }
565
566
567 /******************************************************************
568 * GetAdaptersInfo (IPHLPAPI.@)
569 *
570 *
571 * PARAMS
572 *
573 * pAdapterInfo [In/Out]
574 * pOutBufLen [In/Out]
575 *
576 * RETURNS
577 *
578 * DWORD
579 *
580 */
581 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
582 {
583 DWORD ret;
584 BOOL dhcpEnabled;
585 DWORD dhcpServer;
586
587 TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
588 if (!pOutBufLen)
589 ret = ERROR_INVALID_PARAMETER;
590 else {
591 DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
592
593 if (numNonLoopbackInterfaces > 0) {
594 /* this calculation assumes only one address in the IP_ADDR_STRING lists.
595 that's okay, because:
596 - we don't get multiple addresses per adapter anyway
597 - we don't know about per-adapter gateways
598 - DHCP and WINS servers can have max one entry per list */
599 ULONG size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
600
601 if (!pAdapterInfo || *pOutBufLen < size) {
602 *pOutBufLen = size;
603 ret = ERROR_BUFFER_OVERFLOW;
604 }
605 else {
606 InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
607
608 if (table) {
609 size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
610 if (*pOutBufLen < size) {
611 *pOutBufLen = size;
612 ret = ERROR_INSUFFICIENT_BUFFER;
613 }
614 else {
615 DWORD ndx;
616 HKEY hKey;
617 BOOL winsEnabled = FALSE;
618 IP_ADDRESS_STRING primaryWINS, secondaryWINS;
619
620 memset(pAdapterInfo, 0, size);
621 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
622 "Software\\Wine\\Wine\\Config\\Network", 0, KEY_READ,
623 &hKey) == ERROR_SUCCESS) {
624 DWORD size = sizeof(primaryWINS.String);
625 unsigned long addr;
626
627 RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
628 (PBYTE)primaryWINS.String, &size);
629 addr = inet_addr(primaryWINS.String);
630 if (addr != INADDR_NONE && addr != INADDR_ANY)
631 winsEnabled = TRUE;
632 size = sizeof(secondaryWINS.String);
633 RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
634 (PBYTE)secondaryWINS.String, &size);
635 addr = inet_addr(secondaryWINS.String);
636 if (addr != INADDR_NONE && addr != INADDR_ANY)
637 winsEnabled = TRUE;
638 RegCloseKey(hKey);
639 }
640 TRACE("num of index is %lu\n", table->numIndexes);
641 for (ndx = 0; ndx < table->numIndexes; ndx++) {
642 PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
643 DWORD addrLen = sizeof(ptr->Address), type;
644 const char *ifname =
645 getInterfaceNameByIndex(table->indexes[ndx]);
646
647 /* on Win98 this is left empty, but whatever */
648
649 strncpy(ptr->AdapterName,ifname,sizeof(ptr->AdapterName));
650 consumeInterfaceName(ifname);
651 ptr->AdapterName[MAX_ADAPTER_NAME_LENGTH] = '\0';
652 getInterfacePhysicalByIndex(table->indexes[ndx], &addrLen,
653 ptr->Address, &type);
654 /* MS defines address length and type as UINT in some places and
655 DWORD in others, **sigh**. Don't want to assume that PUINT and
656 PDWORD are equiv (64-bit?) */
657 ptr->AddressLength = addrLen;
658 ptr->Type = type;
659 ptr->Index = table->indexes[ndx];
660 toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
661 ptr->IpAddressList.IpAddress.String);
662 toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
663 ptr->IpAddressList.IpMask.String);
664 toIPAddressString(getInterfaceGatewayByIndex(table->indexes[ndx]),
665 ptr->GatewayList.IpAddress.String);
666 getDhcpInfoForAdapter(table->indexes[ndx], &dhcpEnabled,
667 &dhcpServer, &ptr->LeaseObtained,
668 &ptr->LeaseExpires);
669 ptr->DhcpEnabled = (DWORD) dhcpEnabled;
670 toIPAddressString(dhcpServer,
671 ptr->DhcpServer.IpAddress.String);
672 if (winsEnabled) {
673 ptr->HaveWins = TRUE;
674 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
675 primaryWINS.String, sizeof(primaryWINS.String));
676 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
677 secondaryWINS.String, sizeof(secondaryWINS.String));
678 }
679 if (ndx < table->numIndexes - 1)
680 ptr->Next = &pAdapterInfo[ndx + 1];
681 else
682 ptr->Next = NULL;
683 }
684 ret = NO_ERROR;
685 }
686 free(table);
687 }
688 else
689 ret = ERROR_OUTOFMEMORY;
690 }
691 }
692 else
693 ret = ERROR_NO_DATA;
694 }
695 TRACE("returning %ld\n", ret);
696 return ret;
697 }
698
699
700 /******************************************************************
701 * GetBestInterface (IPHLPAPI.@)
702 *
703 *
704 * PARAMS
705 *
706 * dwDestAddr [In]
707 * pdwBestIfIndex [In/Out]
708 *
709 * RETURNS
710 *
711 * DWORD
712 *
713 */
714 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
715 {
716 DWORD ret;
717
718 TRACE("dwDestAddr 0x%08lx, pdwBestIfIndex %p\n", dwDestAddr, pdwBestIfIndex);
719 if (!pdwBestIfIndex)
720 ret = ERROR_INVALID_PARAMETER;
721 else {
722 MIB_IPFORWARDROW ipRow;
723
724 ret = GetBestRoute(dwDestAddr, 0, &ipRow);
725 if (ret == ERROR_SUCCESS)
726 *pdwBestIfIndex = ipRow.dwForwardIfIndex;
727 }
728 TRACE("returning %ld\n", ret);
729 return ret;
730 }
731
732
733 /******************************************************************
734 * GetBestRoute (IPHLPAPI.@)
735 *
736 *
737 * PARAMS
738 *
739 * dwDestAddr [In]
740 * dwSourceAddr [In]
741 * OUT [In]
742 *
743 * RETURNS
744 *
745 * DWORD
746 *
747 */
748 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
749 {
750 PMIB_IPFORWARDTABLE table;
751 DWORD ret;
752
753 TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr,
754 dwSourceAddr, pBestRoute);
755 if (!pBestRoute)
756 return ERROR_INVALID_PARAMETER;
757
758 AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
759 if (table) {
760 DWORD ndx, matchedBits, matchedNdx = 0;
761
762 for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
763 if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
764 (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
765 DWORD numShifts, mask;
766
767 for (numShifts = 0, mask = table->table[ndx].dwForwardMask;
768 mask && !(mask & 1); mask >>= 1, numShifts++)
769 ;
770 if (numShifts > matchedBits) {
771 matchedBits = numShifts;
772 matchedNdx = ndx;
773 }
774 }
775 }
776 memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
777 HeapFree(GetProcessHeap(), 0, table);
778 ret = ERROR_SUCCESS;
779 }
780 else
781 ret = ERROR_OUTOFMEMORY;
782 TRACE("returning %ld\n", ret);
783 return ret;
784 }
785
786
787 /******************************************************************
788 * GetFriendlyIfIndex (IPHLPAPI.@)
789 *
790 *
791 * PARAMS
792 *
793 * IfIndex [In]
794 *
795 * RETURNS
796 *
797 * DWORD
798 *
799 */
800 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
801 {
802 /* windows doesn't validate these, either, just makes sure the top byte is
803 cleared. I assume my ifenum module never gives an index with the top
804 byte set. */
805 TRACE("returning %ld\n", IfIndex);
806 return IfIndex;
807 }
808
809
810 /******************************************************************
811 * GetIcmpStatistics (IPHLPAPI.@)
812 *
813 *
814 * PARAMS
815 *
816 * pStats [In/Out]
817 *
818 * RETURNS
819 *
820 * DWORD
821 *
822 */
823 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
824 {
825 DWORD ret;
826
827 TRACE("pStats %p\n", pStats);
828 ret = getICMPStats(pStats);
829 TRACE("returning %ld\n", ret);
830 return ret;
831 }
832
833
834 /******************************************************************
835 * GetIfEntry (IPHLPAPI.@)
836 *
837 *
838 * PARAMS
839 *
840 * pIfRow [In/Out]
841 *
842 * RETURNS
843 *
844 * DWORD
845 *
846 */
847 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
848 {
849 DWORD ret;
850 const char *name;
851
852 TRACE("pIfRow %p\n", pIfRow);
853 if (!pIfRow)
854 return ERROR_INVALID_PARAMETER;
855
856 name = getInterfaceNameByIndex(pIfRow->dwIndex);
857 if (name) {
858 ret = getInterfaceEntryByIndex(pIfRow->dwIndex, pIfRow);
859 if (ret == NO_ERROR)
860 ret = getInterfaceStatsByName(name, pIfRow);
861 consumeInterfaceName(name);
862 }
863 else
864 ret = ERROR_INVALID_DATA;
865 TRACE("returning %ld\n", ret);
866 return ret;
867 }
868
869
870 static int IfTableSorter(const void *a, const void *b)
871 {
872 int ret;
873
874 if (a && b)
875 ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
876 else
877 ret = 0;
878 return ret;
879 }
880
881
882 /******************************************************************
883 * GetIfTable (IPHLPAPI.@)
884 *
885 *
886 * PARAMS
887 *
888 * pIfTable [In/Out]
889 * pdwSize [In/Out]
890 * bOrder [In]
891 *
892 * RETURNS
893 *
894 * DWORD
895 *
896 */
897 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
898 {
899 DWORD ret;
900
901 TRACE("pIfTable %p, pdwSize %p, bOrder %ld\n", pdwSize, pdwSize,
902 (DWORD)bOrder);
903 if (!pdwSize)
904 ret = ERROR_INVALID_PARAMETER;
905 else {
906 DWORD numInterfaces = getNumInterfaces();
907 TRACE("GetIfTable: numInterfaces = %d\n", (int)numInterfaces);
908 ULONG size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
909
910 if (!pIfTable || *pdwSize < size) {
911 *pdwSize = size;
912 ret = ERROR_INSUFFICIENT_BUFFER;
913 }
914 else {
915 InterfaceIndexTable *table = getInterfaceIndexTable();
916
917 if (table) {
918 size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
919 sizeof(MIB_IFROW);
920 if (*pdwSize < size) {
921 *pdwSize = size;
922 ret = ERROR_INSUFFICIENT_BUFFER;
923 }
924 else {
925 DWORD ndx;
926
927 pIfTable->dwNumEntries = 0;
928 for (ndx = 0; ndx < table->numIndexes; ndx++) {
929 pIfTable->table[ndx].dwIndex = table->indexes[ndx];
930 GetIfEntry(&pIfTable->table[ndx]);
931 pIfTable->dwNumEntries++;
932 }
933 if (bOrder)
934 qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
935 IfTableSorter);
936 ret = NO_ERROR;
937 }
938 free(table);
939 }
940 else
941 ret = ERROR_OUTOFMEMORY;
942 }
943 }
944 TRACE("returning %ld\n", ret);
945 return ret;
946 }
947
948
949 /******************************************************************
950 * GetInterfaceInfo (IPHLPAPI.@)
951 *
952 *
953 * PARAMS
954 *
955 * pIfTable [In/Out]
956 * dwOutBufLen [In/Out]
957 *
958 * RETURNS
959 *
960 * DWORD
961 *
962 */
963 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
964 {
965 DWORD ret;
966
967 TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
968 if (!dwOutBufLen)
969 ret = ERROR_INVALID_PARAMETER;
970 else {
971 DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
972 TRACE("numNonLoopbackInterfaces == 0x%x\n", numNonLoopbackInterfaces);
973 ULONG size = sizeof(IP_INTERFACE_INFO) + (numNonLoopbackInterfaces) *
974 sizeof(IP_ADAPTER_INDEX_MAP);
975
976 if (!pIfTable || *dwOutBufLen < size) {
977 *dwOutBufLen = size;
978 ret = ERROR_INSUFFICIENT_BUFFER;
979 }
980 else {
981 InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
982 TRACE("table->numIndexes == 0x%x\n", table->numIndexes);
983
984 if (table) {
985 size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes) *
986 sizeof(IP_ADAPTER_INDEX_MAP);
987 if (*dwOutBufLen < size) {
988 *dwOutBufLen = size;
989 ret = ERROR_INSUFFICIENT_BUFFER;
990 }
991 else {
992 DWORD ndx;
993
994 pIfTable->NumAdapters = 0;
995 for (ndx = 0; ndx < table->numIndexes; ndx++) {
996 const char *walker, *name;
997 WCHAR *assigner;
998
999 pIfTable->Adapter[ndx].Index = table->indexes[ndx];
1000 name = getInterfaceNameByIndex(table->indexes[ndx]);
1001 for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
1002 walker && *walker &&
1003 assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
1004 walker++, assigner++)
1005 *assigner = *walker;
1006 *assigner = 0;
1007 consumeInterfaceName(name);
1008 pIfTable->NumAdapters++;
1009 }
1010 ret = NO_ERROR;
1011 }
1012 free(table);
1013 }
1014 else
1015 ret = ERROR_OUTOFMEMORY;
1016 }
1017 }
1018 TRACE("returning %ld\n", ret);
1019 return ret;
1020 }
1021
1022
1023 static int IpAddrTableSorter(const void *a, const void *b)
1024 {
1025 int ret;
1026
1027 if (a && b)
1028 ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
1029 else
1030 ret = 0;
1031 return ret;
1032 }
1033
1034
1035 /******************************************************************
1036 * GetIpAddrTable (IPHLPAPI.@)
1037 *
1038 *
1039 * PARAMS
1040 *
1041 * pIpAddrTable [In/Out]
1042 * pdwSize [In/Out]
1043 * bOrder [In]
1044 *
1045 * RETURNS
1046 *
1047 * DWORD
1048 *
1049 */
1050 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1051 {
1052 DWORD ret;
1053
1054 TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
1055 (DWORD)bOrder);
1056 if (!pdwSize)
1057 ret = ERROR_INVALID_PARAMETER;
1058 else {
1059 DWORD numInterfaces = getNumInterfaces();
1060 ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
1061 sizeof(MIB_IPADDRROW);
1062
1063 if (!pIpAddrTable || *pdwSize < size) {
1064 *pdwSize = size;
1065 ret = ERROR_INSUFFICIENT_BUFFER;
1066 }
1067 else {
1068 InterfaceIndexTable *table = getInterfaceIndexTable();
1069
1070 if (table) {
1071 size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
1072 sizeof(MIB_IPADDRROW);
1073 if (*pdwSize < size) {
1074 *pdwSize = size;
1075 ret = ERROR_INSUFFICIENT_BUFFER;
1076 }
1077 else {
1078 DWORD ndx, bcast;
1079
1080 pIpAddrTable->dwNumEntries = 0;
1081 for (ndx = 0; ndx < table->numIndexes; ndx++) {
1082 pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
1083 pIpAddrTable->table[ndx].dwAddr =
1084 getInterfaceIPAddrByIndex(table->indexes[ndx]);
1085 pIpAddrTable->table[ndx].dwMask =
1086 getInterfaceMaskByIndex(table->indexes[ndx]);
1087 /* the dwBCastAddr member isn't the broadcast address, it indicates
1088 * whether the interface uses the 1's broadcast address (1) or the
1089 * 0's broadcast address (0).
1090 */
1091 bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
1092 pIpAddrTable->table[ndx].dwBCastAddr =
1093 (bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
1094 /* FIXME: hardcoded reasm size, not sure where to get it */
1095 pIpAddrTable->table[ndx].dwReasmSize = 65535;
1096 pIpAddrTable->table[ndx].unused1 = 0;
1097 pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
1098 pIpAddrTable->dwNumEntries++;
1099 }
1100 if (bOrder)
1101 qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1102 sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1103 ret = NO_ERROR;
1104 }
1105 free(table);
1106 }
1107 else
1108 ret = ERROR_OUTOFMEMORY;
1109 }
1110 }
1111 TRACE("returning %ld\n", ret);
1112 return ret;
1113 }
1114
1115
1116 static int IpForwardTableSorter(const void *a, const void *b)
1117 {
1118 int ret;
1119
1120 if (a && b) {
1121 PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
1122
1123 ret = rowA->dwForwardDest - rowB->dwForwardDest;
1124 if (ret == 0) {
1125 ret = rowA->dwForwardProto - rowB->dwForwardProto;
1126 if (ret == 0) {
1127 ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
1128 if (ret == 0)
1129 ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1130 }
1131 }
1132 }
1133 else
1134 ret = 0;
1135 return ret;
1136 }
1137
1138
1139 /******************************************************************
1140 * GetIpForwardTable (IPHLPAPI.@)
1141 *
1142 *
1143 * PARAMS
1144 *
1145 * pIpForwardTable [In/Out]
1146 * pdwSize [In/Out]
1147 * bOrder [In]
1148 *
1149 * RETURNS
1150 *
1151 * DWORD
1152 *
1153 */
1154 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1155 {
1156 DWORD ret;
1157
1158 TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
1159 pdwSize, (DWORD)bOrder);
1160 if (!pdwSize)
1161 ret = ERROR_INVALID_PARAMETER;
1162 else {
1163 DWORD numRoutes = getNumRoutes();
1164 ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1165 sizeof(MIB_IPFORWARDROW);
1166
1167 if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1168 *pdwSize = sizeNeeded;
1169 ret = ERROR_INSUFFICIENT_BUFFER;
1170 }
1171 else {
1172 RouteTable *table = getRouteTable();
1173 if (table) {
1174 sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1175 sizeof(MIB_IPFORWARDROW);
1176 if (*pdwSize < sizeNeeded) {
1177 *pdwSize = sizeNeeded;
1178 ret = ERROR_INSUFFICIENT_BUFFER;
1179 }
1180 else {
1181 DWORD ndx;
1182
1183 pIpForwardTable->dwNumEntries = table->numRoutes;
1184 for (ndx = 0; ndx < numRoutes; ndx++) {
1185 pIpForwardTable->table[ndx].dwForwardIfIndex =
1186 table->routes[ndx].ifIndex + 1;
1187 pIpForwardTable->table[ndx].dwForwardDest =
1188 table->routes[ndx].dest;
1189 pIpForwardTable->table[ndx].dwForwardMask =
1190 table->routes[ndx].mask;
1191 pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1192 pIpForwardTable->table[ndx].dwForwardNextHop =
1193 table->routes[ndx].gateway;
1194 /* FIXME: this type is appropriate for local interfaces; may not
1195 always be appropriate */
1196 pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1197 /* FIXME: other protos might be appropriate, e.g. the default route
1198 is typically set with MIB_IPPROTO_NETMGMT instead */
1199 pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1200 /* punt on age and AS */
1201 pIpForwardTable->table[ndx].dwForwardAge = 0;
1202 pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1203 pIpForwardTable->table[ndx].dwForwardMetric1 =
1204 table->routes[ndx].metric;
1205 /* rest of the metrics are 0.. */
1206 pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1207 pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1208 pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1209 pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1210 }
1211 if (bOrder)
1212 qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1213 sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1214 ret = NO_ERROR;
1215 }
1216 HeapFree(GetProcessHeap(), 0, table);
1217 }
1218 else
1219 ret = ERROR_OUTOFMEMORY;
1220 }
1221 }
1222 TRACE("returning %ld\n", ret);
1223 return ret;
1224 }
1225
1226
1227 static int IpNetTableSorter(const void *a, const void *b)
1228 {
1229 int ret;
1230
1231 if (a && b)
1232 ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
1233 else
1234 ret = 0;
1235 return ret;
1236 }
1237
1238
1239 /******************************************************************
1240 * GetIpNetTable (IPHLPAPI.@)
1241 *
1242 *
1243 * PARAMS
1244 *
1245 * pIpNetTable [In/Out]
1246 * pdwSize [In/Out]
1247 * bOrder [In]
1248 *
1249 * RETURNS
1250 *
1251 * DWORD
1252 *
1253 */
1254 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1255 {
1256 DWORD ret;
1257
1258 TRACE("pIpNetTable %p, pdwSize %p, bOrder %ld\n", pIpNetTable, pdwSize,
1259 (DWORD)bOrder);
1260 if (!pdwSize)
1261 ret = ERROR_INVALID_PARAMETER;
1262 else {
1263 DWORD numEntries = getNumArpEntries();
1264 ULONG size = sizeof(MIB_IPNETTABLE) + (numEntries - 1) *
1265 sizeof(MIB_IPNETROW);
1266
1267 if (!pIpNetTable || *pdwSize < size) {
1268 *pdwSize = size;
1269 ret = ERROR_INSUFFICIENT_BUFFER;
1270 }
1271 else {
1272 PMIB_IPNETTABLE table = getArpTable();
1273
1274 if (table) {
1275 size = sizeof(MIB_IPNETTABLE) + (table->dwNumEntries - 1) *
1276 sizeof(MIB_IPNETROW);
1277 if (*pdwSize < size) {
1278 *pdwSize = size;
1279 ret = ERROR_INSUFFICIENT_BUFFER;
1280 }
1281 else {
1282 memcpy(pIpNetTable, table, size);
1283 if (bOrder)
1284 qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
1285 sizeof(MIB_IPNETROW), IpNetTableSorter);
1286 ret = NO_ERROR;
1287 }
1288 free(table);
1289 }
1290 else
1291 ret = ERROR_OUTOFMEMORY;
1292 }
1293 }
1294 TRACE("returning %ld\n", ret);
1295 return ret;
1296 }
1297
1298
1299 /******************************************************************
1300 * GetIpStatistics (IPHLPAPI.@)
1301 *
1302 *
1303 * PARAMS
1304 *
1305 * pStats [In/Out]
1306 *
1307 * RETURNS
1308 *
1309 * DWORD
1310 *
1311 */
1312 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
1313 {
1314 return GetIpStatisticsEx(pStats, PF_INET);
1315 }
1316
1317 /******************************************************************
1318 * GetIpStatisticsEx (IPHLPAPI.@)
1319 *
1320 *
1321 * PARAMS
1322 *
1323 * pStats [In/Out]
1324 * dwFamily [In]
1325 *
1326 * RETURNS
1327 *
1328 * DWORD
1329 *
1330 */
1331 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily)
1332 {
1333 DWORD ret;
1334
1335 TRACE("pStats %p\n", pStats);
1336 ret = getIPStats(pStats, dwFamily);
1337 TRACE("returning %ld\n", ret);
1338 return ret;
1339 }
1340
1341 /******************************************************************
1342 * GetNetworkParams (IPHLPAPI.@)
1343 *
1344 *
1345 * PARAMS
1346 *
1347 * pFixedInfo [In/Out]
1348 * pOutBufLen [In/Out]
1349 *
1350 * RETURNS
1351 *
1352 * DWORD
1353 *
1354 */
1355 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1356 {
1357 DWORD ret, size;
1358 LONG regReturn;
1359 HKEY hKey;
1360 PIPHLP_RES_INFO resInfo;
1361
1362 TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
1363 if (!pOutBufLen)
1364 return ERROR_INVALID_PARAMETER;
1365
1366 resInfo = getResInfo();
1367 if (!resInfo)
1368 return ERROR_OUTOFMEMORY;
1369
1370 size = sizeof(FIXED_INFO) + (resInfo->riCount > 0 ? (resInfo->riCount - 1) *
1371 sizeof(IP_ADDR_STRING) : 0);
1372 if (!pFixedInfo || *pOutBufLen < size) {
1373 *pOutBufLen = size;
1374 disposeResInfo( resInfo );
1375 return ERROR_BUFFER_OVERFLOW;
1376 }
1377
1378 memset(pFixedInfo, 0, size);
1379 size = sizeof(pFixedInfo->HostName);
1380 GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
1381 size = sizeof(pFixedInfo->DomainName);
1382 GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
1383
1384 TRACE("GetComputerNameExA: %s\n", pFixedInfo->DomainName);
1385
1386 if (resInfo->riCount > 0) {
1387 PIP_ADDR_STRING ptr;
1388 int i;
1389
1390 for (i = 0, ptr = &pFixedInfo->DnsServerList; i < resInfo->riCount && ptr;
1391 i++, ptr = ptr->Next) {
1392 struct sockaddr_in *addr_v4 =
1393 (struct sockaddr_in *)&resInfo->riAddressList[i];
1394 toIPAddressString
1395 (addr_v4->sin_addr.s_addr,
1396 ptr->IpAddress.String);
1397 if (i == resInfo->riCount - 1)
1398 ptr->Next = NULL;
1399 else if (i == 0)
1400 ptr->Next = (PIP_ADDR_STRING)((LPBYTE)pFixedInfo + sizeof(FIXED_INFO));
1401 else
1402 ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING));
1403 }
1404 }
1405 pFixedInfo->NodeType = HYBRID_NODETYPE;
1406 regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1407 "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
1408 if (regReturn != ERROR_SUCCESS)
1409 regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1410 "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
1411 &hKey);
1412 if (regReturn == ERROR_SUCCESS)
1413 {
1414 DWORD size = sizeof(pFixedInfo->ScopeId);
1415
1416 RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (PBYTE)pFixedInfo->ScopeId, &size);
1417 RegCloseKey(hKey);
1418 }
1419
1420 disposeResInfo( resInfo );
1421 /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
1422 I suppose could also check for a listener on port 53 to set EnableDns */
1423 ret = NO_ERROR;
1424 TRACE("returning %ld\n", ret);
1425
1426 return ret;
1427 }
1428
1429
1430 /******************************************************************
1431 * GetNumberOfInterfaces (IPHLPAPI.@)
1432 *
1433 *
1434 * PARAMS
1435 *
1436 * pdwNumIf [In/Out]
1437 *
1438 * RETURNS
1439 *
1440 * DWORD
1441 *
1442 */
1443 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
1444 {
1445 DWORD ret;
1446
1447 TRACE("pdwNumIf %p\n", pdwNumIf);
1448 if (!pdwNumIf)
1449 ret = ERROR_INVALID_PARAMETER;
1450 else {
1451 *pdwNumIf = getNumInterfaces();
1452 ret = NO_ERROR;
1453 }
1454 TRACE("returning %ld\n", ret);
1455 return ret;
1456 }
1457
1458
1459 /******************************************************************
1460 * GetPerAdapterInfo (IPHLPAPI.@)
1461 *
1462 *
1463 * PARAMS
1464 *
1465 * IfIndex [In]
1466 * pPerAdapterInfo [In/Out]
1467 * pOutBufLen [In/Out]
1468 *
1469 * RETURNS
1470 *
1471 * DWORD
1472 *
1473 */
1474 static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
1475 {
1476 IP_ADDR_STRING *pNext;
1477 PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
1478
1479 if (!Context->NumServers)
1480 {
1481 if (Context->uSizeAvailable >= Context->uSizeRequired)
1482 {
1483 WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
1484 Context->pData->DnsServerList.IpAddress.String[15] = '\0';
1485 Context->pLastAddr = &Context->pData->DnsServerList;
1486 }
1487 }
1488 else
1489 {
1490 Context->uSizeRequired += sizeof(IP_ADDR_STRING);
1491 if (Context->uSizeAvailable >= Context->uSizeRequired)
1492 {
1493 pNext = ((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING);
1494 WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
1495 pNext->IpAddress.String[15] = '\0';
1496 Context->pLastAddr->Next = pNext;
1497 Context->pLastAddr = pNext;
1498 pNext->Next = NULL;
1499 }
1500 }
1501 Context->NumServers++;
1502 }
1503
1504 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
1505 {
1506 HKEY hkey;
1507 DWORD dwSize = 0;
1508 const char *ifName;
1509 NAME_SERVER_LIST_CONTEXT Context;
1510 WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
1511
1512 if (!pOutBufLen)
1513 return ERROR_INVALID_PARAMETER;
1514
1515 ifName = getInterfaceNameByIndex(IfIndex);
1516 if (!ifName)
1517 return ERROR_INVALID_PARAMETER;
1518
1519 MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
1520 HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
1521
1522 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
1523 {
1524 return ERROR_NOT_SUPPORTED;
1525 }
1526 Context.NumServers = 0;
1527 Context.uSizeAvailable = *pOutBufLen;
1528 Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
1529 Context.pData = pPerAdapterInfo;
1530
1531 if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
1532 ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
1533
1534 EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
1535
1536 if (Context.uSizeRequired > Context.uSizeAvailable)
1537 {
1538 *pOutBufLen = Context.uSizeRequired;
1539 RegCloseKey(hkey);
1540 return ERROR_BUFFER_OVERFLOW;
1541 }
1542
1543 if(RegQueryValueExW(hkey, L"DHCPNameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
1544 {
1545 pPerAdapterInfo->AutoconfigActive = TRUE;
1546 }
1547
1548 RegCloseKey(hkey);
1549 return NOERROR;
1550 }
1551
1552
1553 /******************************************************************
1554 * GetRTTAndHopCount (IPHLPAPI.@)
1555 *
1556 *
1557 * PARAMS
1558 *
1559 * DestIpAddress [In]
1560 * HopCount [In/Out]
1561 * MaxHops [In]
1562 * RTT [In/Out]
1563 *
1564 * RETURNS
1565 *
1566 * BOOL
1567 *
1568 */
1569 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
1570 {
1571 TRACE("DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p\n",
1572 DestIpAddress, HopCount, MaxHops, RTT);
1573 FIXME(":stub\n");
1574 return (BOOL) 0;
1575 }
1576
1577
1578 /******************************************************************
1579 * GetTcpStatisticsEx (IPHLPAPI.@)
1580 *
1581 *
1582 * PARAMS
1583 *
1584 * pStats [In/Out]
1585 * dwFamily [In]
1586 *
1587 * RETURNS
1588 *
1589 * DWORD
1590 *
1591 */
1592 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily)
1593 {
1594 DWORD ret;
1595
1596 TRACE("pStats %p\n", pStats);
1597 ret = getTCPStats(pStats, dwFamily);
1598 TRACE("returning %ld\n", ret);
1599 return ret;
1600 }
1601
1602 /******************************************************************
1603 * GetTcpStatistics (IPHLPAPI.@)
1604 *
1605 *
1606 * PARAMS
1607 *
1608 * pStats [In/Out]
1609 *
1610 * RETURNS
1611 *
1612 * DWORD
1613 *
1614 */
1615 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
1616 {
1617 return GetTcpStatisticsEx(pStats, PF_INET);
1618 }
1619
1620
1621 static int TcpTableSorter(const void *a, const void *b)
1622 {
1623 int ret;
1624
1625 if (a && b) {
1626 PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
1627
1628 ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1629 if (ret == 0) {
1630 ret = rowA->dwLocalPort - rowB->dwLocalPort;
1631 if (ret == 0) {
1632 ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
1633 if (ret == 0)
1634 ret = rowA->dwRemotePort - rowB->dwRemotePort;
1635 }
1636 }
1637 }
1638 else
1639 ret = 0;
1640 return ret;
1641 }
1642
1643
1644 /******************************************************************
1645 * GetTcpTable (IPHLPAPI.@)
1646 *
1647 *
1648 * PARAMS
1649 *
1650 * pTcpTable [In/Out]
1651 * pdwSize [In/Out]
1652 * bOrder [In]
1653 *
1654 * RETURNS
1655 *
1656 * DWORD
1657 *
1658 */
1659 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1660 {
1661 DWORD ret;
1662
1663 TRACE("pTcpTable %p, pdwSize %p, bOrder %ld\n", pTcpTable, pdwSize,
1664 (DWORD)bOrder);
1665 if (!pdwSize)
1666 ret = ERROR_INVALID_PARAMETER;
1667 else {
1668 DWORD numEntries = getNumTcpEntries();
1669 ULONG size = sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW);
1670
1671 if (!pTcpTable || *pdwSize < size) {
1672 *pdwSize = size;
1673 ret = ERROR_INSUFFICIENT_BUFFER;
1674 }
1675 else {
1676 PMIB_TCPTABLE table = getTcpTable();
1677
1678 if (table) {
1679 size = sizeof(MIB_TCPTABLE) + (table->dwNumEntries - 1) *
1680 sizeof(MIB_TCPROW);
1681 if (*pdwSize < size) {
1682 *pdwSize = size;
1683 ret = ERROR_INSUFFICIENT_BUFFER;
1684 }
1685 else {
1686 memcpy(pTcpTable, table, size);
1687 if (bOrder)
1688 qsort(pTcpTable->table, pTcpTable->dwNumEntries,
1689 sizeof(MIB_TCPROW), TcpTableSorter);
1690 ret = NO_ERROR;
1691 }
1692 free(table);
1693 }
1694 else
1695 ret = ERROR_OUTOFMEMORY;
1696 }
1697 }
1698 TRACE("returning %ld\n", ret);
1699 return ret;
1700 }
1701
1702
1703 /******************************************************************
1704 * GetUdpStatisticsEx (IPHLPAPI.@)
1705 *
1706 *
1707 * PARAMS
1708 *
1709 * pStats [In/Out]
1710 * dwFamily [In]
1711 *
1712 * RETURNS
1713 *
1714 * DWORD
1715 *
1716 */
1717 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS pStats, DWORD dwFamily)
1718 {
1719 DWORD ret;
1720
1721 TRACE("pStats %p\n", pStats);
1722 ret = getUDPStats(pStats, dwFamily);
1723 TRACE("returning %ld\n", ret);
1724 return ret;
1725 }
1726
1727 /******************************************************************
1728 * GetUdpStatistics (IPHLPAPI.@)
1729 *
1730 *
1731 * PARAMS
1732 *
1733 * pStats [In/Out]
1734 *
1735 * RETURNS
1736 *
1737 * DWORD
1738 *
1739 */
1740 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
1741 {
1742 return GetUdpStatisticsEx(pStats, PF_INET);
1743 }
1744
1745
1746 static int UdpTableSorter(const void *a, const void *b)
1747 {
1748 int ret;
1749
1750 if (a && b) {
1751 PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
1752
1753 ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1754 if (ret == 0)
1755 ret = rowA->dwLocalPort - rowB->dwLocalPort;
1756 }
1757 else
1758 ret = 0;
1759 return ret;
1760 }
1761
1762
1763 /******************************************************************
1764 * GetUdpTable (IPHLPAPI.@)
1765 *
1766 *
1767 * PARAMS
1768 *
1769 * pUdpTable [In/Out]
1770 * pdwSize [In/Out]
1771 * bOrder [In]
1772 *
1773 * RETURNS
1774 *
1775 * DWORD
1776 *
1777 */
1778 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1779 {
1780 DWORD ret;
1781
1782 TRACE("pUdpTable %p, pdwSize %p, bOrder %ld\n", pUdpTable, pdwSize,
1783 (DWORD)bOrder);
1784 if (!pdwSize)
1785 ret = ERROR_INVALID_PARAMETER;
1786 else {
1787 DWORD numEntries = getNumUdpEntries();
1788 ULONG size = sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW);
1789
1790 if (!pUdpTable || *pdwSize < size) {
1791 *pdwSize = size;
1792 ret = ERROR_INSUFFICIENT_BUFFER;
1793 }
1794 else {
1795 PMIB_UDPTABLE table = getUdpTable();
1796
1797 if (table) {
1798 size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) *
1799 sizeof(MIB_UDPROW);
1800 if (*pdwSize < size) {
1801 *pdwSize = size;
1802 ret = ERROR_INSUFFICIENT_BUFFER;
1803 }
1804 else {
1805 memcpy(pUdpTable, table, size);
1806 if (bOrder)
1807 qsort(pUdpTable->table, pUdpTable->dwNumEntries,
1808 sizeof(MIB_UDPROW), UdpTableSorter);
1809 ret = NO_ERROR;
1810 }
1811 free(table);
1812 }
1813 else
1814 ret = ERROR_OUTOFMEMORY;
1815 }
1816 }
1817 TRACE("returning %ld\n", ret);
1818 return ret;
1819 }
1820
1821
1822 /******************************************************************
1823 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1824 *
1825 *
1826 * PARAMS
1827 *
1828 * pIPIfInfo [In/Out]
1829 * dwOutBufLen [In/Out]
1830 *
1831 * RETURNS
1832 *
1833 * DWORD
1834 *
1835 */
1836 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1837 {
1838 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
1839 /* a unidirectional adapter?? not bloody likely! */
1840 return ERROR_NOT_SUPPORTED;
1841 }
1842
1843
1844 /******************************************************************
1845 * IpReleaseAddress (IPHLPAPI.@)
1846 *
1847 *
1848 * PARAMS
1849 *
1850 * AdapterInfo [In/Out]
1851 *
1852 * RETURNS
1853 *
1854 * DWORD
1855 *
1856 */
1857 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1858 {
1859 TRACE("AdapterInfo %p\n", AdapterInfo);
1860 /* not a stub, never going to support this (and I never mark an adapter as
1861 DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1862 return ERROR_NOT_SUPPORTED;
1863 }
1864
1865
1866 /******************************************************************
1867 * IpRenewAddress (IPHLPAPI.@)
1868 *
1869 *
1870 * PARAMS
1871 *
1872 * AdapterInfo [In/Out]
1873 *
1874 * RETURNS
1875 *
1876 * DWORD
1877 *
1878 */
1879 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1880 {
1881 TRACE("AdapterInfo %p\n", AdapterInfo);
1882 /* not a stub, never going to support this (and I never mark an adapter as
1883 DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1884 return ERROR_NOT_SUPPORTED;
1885 }
1886
1887
1888 /******************************************************************
1889 * NotifyAddrChange (IPHLPAPI.@)
1890 *
1891 *
1892 * PARAMS
1893 *
1894 * Handle [In/Out]
1895 * overlapped [In/Out]
1896 *
1897 * RETURNS
1898 *
1899 * DWORD
1900 *
1901 */
1902 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1903 {
1904 TRACE("Handle %p, overlapped %p\n", Handle, overlapped);
1905 FIXME(":stub\n");
1906 /* marking Win2K+ functions not supported */
1907 return ERROR_NOT_SUPPORTED;
1908 }
1909
1910
1911 /******************************************************************
1912 * NotifyRouteChange (IPHLPAPI.@)
1913 *
1914 *
1915 * PARAMS
1916 *
1917 * Handle [In/Out]
1918 * overlapped [In/Out]
1919 *
1920 * RETURNS
1921 *
1922 * DWORD
1923 *
1924 */
1925 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1926 {
1927 TRACE("Handle %p, overlapped %p\n", Handle, overlapped);
1928 FIXME(":stub\n");
1929 /* marking Win2K+ functions not supported */
1930 return ERROR_NOT_SUPPORTED;
1931 }
1932
1933
1934 /******************************************************************
1935 * SendARP (IPHLPAPI.@)
1936 *
1937 *
1938 * PARAMS
1939 *
1940 * DestIP [In]
1941 * SrcIP [In]
1942 * pMacAddr [In/Out]
1943 * PhyAddrLen [In/Out]
1944 *
1945 * RETURNS
1946 *
1947 * DWORD
1948 *
1949 */
1950 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
1951 {
1952 TRACE("DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p\n", DestIP,
1953 SrcIP, pMacAddr, PhyAddrLen);
1954 FIXME(":stub\n");
1955 /* marking Win2K+ functions not supported */
1956 return ERROR_NOT_SUPPORTED;
1957 }
1958
1959
1960 /******************************************************************
1961 * SetIfEntry (IPHLPAPI.@)
1962 *
1963 *
1964 * PARAMS
1965 *
1966 * pIfRow [In/Out]
1967 *
1968 * RETURNS
1969 *
1970 * DWORD
1971 *
1972 */
1973 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
1974 {
1975 TRACE("pIfRow %p\n", pIfRow);
1976 /* this is supposed to set an administratively interface up or down.
1977 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
1978 this sort of down is indistinguishable from other sorts of down (e.g. no
1979 link). */
1980 FIXME(":stub\n");
1981 return ERROR_NOT_SUPPORTED;
1982 }
1983
1984
1985 /******************************************************************
1986 * SetIpForwardEntry (IPHLPAPI.@)
1987 *
1988 *
1989 * PARAMS
1990 *
1991 * pRoute [In/Out]
1992 *
1993 * RETURNS
1994 *
1995 * DWORD
1996 *
1997 */
1998 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
1999 {
2000 return setIpForwardEntry( pRoute );
2001 }
2002
2003
2004 /******************************************************************
2005 * SetIpNetEntry (IPHLPAPI.@)
2006 *
2007 *
2008 * PARAMS
2009 *
2010 * pArpEntry [In/Out]
2011 *
2012 * RETURNS
2013 *
2014 * DWORD
2015 *
2016 */
2017 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
2018 {
2019 TRACE("pArpEntry %p\n", pArpEntry);
2020 /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
2021 FIXME(":stub\n");
2022 return (DWORD) 0;
2023 }
2024
2025
2026 /******************************************************************
2027 * SetIpStatistics (IPHLPAPI.@)
2028 *
2029 *
2030 * PARAMS
2031 *
2032 * pIpStats [In/Out]
2033 *
2034 * RETURNS
2035 *
2036 * DWORD
2037 *
2038 */
2039 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
2040 {
2041 TRACE("pIpStats %p\n", pIpStats);
2042 FIXME(":stub\n");
2043 return (DWORD) 0;
2044 }
2045
2046
2047 /******************************************************************
2048 * SetIpTTL (IPHLPAPI.@)
2049 *
2050 *
2051 * PARAMS
2052 *
2053 * nTTL [In]
2054 *
2055 * RETURNS
2056 *
2057 * DWORD
2058 *
2059 */
2060 DWORD WINAPI SetIpTTL(UINT nTTL)
2061 {
2062 TRACE("nTTL %d\n", nTTL);
2063 /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
2064 want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
2065 FIXME(":stub\n");
2066 return (DWORD) 0;
2067 }
2068
2069
2070 /******************************************************************
2071 * SetTcpEntry (IPHLPAPI.@)
2072 *
2073 *
2074 * PARAMS
2075 *
2076 * pTcpRow [In/Out]
2077 *
2078 * RETURNS
2079 *
2080 * DWORD
2081 *
2082 */
2083 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
2084 {
2085 TRACE("pTcpRow %p\n", pTcpRow);
2086 FIXME(":stub\n");
2087 return (DWORD) 0;
2088 }
2089
2090
2091 /******************************************************************
2092 * UnenableRouter (IPHLPAPI.@)
2093 *
2094 *
2095 * PARAMS
2096 *
2097 * pOverlapped [In/Out]
2098 * lpdwEnableCount [In/Out]
2099 *
2100 * RETURNS
2101 *
2102 * DWORD
2103 *
2104 */
2105 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
2106 {
2107 TRACE("pOverlapped %p, lpdwEnableCount %p\n", pOverlapped, lpdwEnableCount);
2108 FIXME(":stub\n");
2109 /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
2110 could map EACCESS to ERROR_ACCESS_DENIED, I suppose
2111 marking Win2K+ functions not supported */
2112 return ERROR_NOT_SUPPORTED;
2113 }
2114
2115 /*
2116 * @unimplemented
2117 */
2118 DWORD WINAPI GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)
2119 {
2120 FIXME(":stub\n");
2121 return 0L;
2122 }
2123
2124
2125 /*
2126 * @unimplemented
2127 */
2128 PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
2129 {
2130 FIXME(":stub\n");
2131 return 0L;
2132 }
2133
2134 /*
2135 * @unimplemented
2136 */
2137 DWORD WINAPI GetAdaptersAddresses(ULONG Family,DWORD Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
2138 {
2139 FIXME(":stub\n");
2140 return 0L;
2141 }
2142
2143 /*
2144 * @unimplemented
2145 */
2146 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)
2147 {
2148 FIXME(":stub\n");
2149 return 0L;
2150 }
2151
2152 /*
2153 * @unimplemented
2154 */
2155 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex)
2156 {
2157 FIXME(":stub\n");
2158 return 0L;
2159 }
2160
2161 /*
2162 * @unimplemented
2163 */
2164 DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)
2165 {
2166 FIXME(":stub\n");
2167 return 0L;
2168 }
2169
2170 /*
2171 * @unimplemented
2172 */
2173 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
2174 {
2175 FIXME(":stub\n");
2176 return 0L;
2177 }
2178
2179