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