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