[IPHLPAPI] Add support for service tags in GetOwnerModuleFromTcp/UdpEntry
[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%08lx, flags 0x%08lx\n", ppIfTable,
113 (DWORD)bOrder, (DWORD)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%08lx, flags 0x%08lx\n",
157 ppIpAddrTable, (DWORD)bOrder, (DWORD)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%08lx, flags 0x%08lx\n",
199 ppIpForwardTable, (DWORD)bOrder, (DWORD)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%08lx, flags 0x%08lx\n",
243 ppIpNetTable, (DWORD)bOrder, (DWORD)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%08lx, flags 0x%08lx\n",
287 ppTcpTable, (DWORD)bOrder, (DWORD)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%08lx, flags 0x%08lx, family 0x%08lx\n",
332 ppTcpTable, (DWORD)bOrder, (DWORD)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%08lx, flags 0x%08lx, family %ld, class %ld\n",
378 ppTcpTable, (DWORD)bOrder, (DWORD)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%08lx, flags 0x%08lx\n",
422 ppUdpTable, (DWORD)bOrder, (DWORD)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%08lx, flags 0x%08lx, family 0x%08lx\n",
467 ppUdpTable, (DWORD)bOrder, (DWORD)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%08lx, flags 0x%08lx, family %ld, class %ld\n",
513 ppUdpTable, (DWORD)bOrder, (DWORD)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;
2293 WCHAR File[MAX_PATH], Path[MAX_PATH];
2294 PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2295
2296 if (OwningPid == 0)
2297 {
2298 return ERROR_NOT_FOUND;
2299 }
2300
2301 Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, OwningPid);
2302 if (Process == NULL)
2303 {
2304 return GetLastError();
2305 }
2306
2307 FileLen = GetModuleBaseNameW(Process, NULL, File, MAX_PATH);
2308 if (FileLen != 0)
2309 {
2310 PathLen = GetModuleFileNameExW(Process, NULL, Path, MAX_PATH);
2311 if (PathLen == 0)
2312 {
2313 CloseHandle(Process);
2314 return GetLastError();
2315 }
2316
2317 /* Add NULL char */
2318 ++FileLen;
2319 ++PathLen;
2320 PathLen *= sizeof(WCHAR);
2321 FileLen *= sizeof(WCHAR);
2322 }
2323 else if (GetLastError() == ERROR_PARTIAL_COPY)
2324 {
2325 wcscpy(File, L"System");
2326 wcscpy(Path, L"System");
2327
2328 PathLen = sizeof(L"System");
2329 FileLen = sizeof(L"System");
2330 }
2331
2332 CloseHandle(Process);
2333
2334 if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen)
2335 {
2336 *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2337 return ERROR_INSUFFICIENT_BUFFER;
2338 }
2339
2340 BasicInfo = Buffer;
2341 BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2342 BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + FileLen);
2343 wcscpy(BasicInfo->pModuleName, File);
2344 wcscpy(BasicInfo->pModulePath, Path);
2345 *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2346
2347 return NO_ERROR;
2348 }
2349
2350 static DWORD GetOwnerModuleFromTagEntry(DWORD OwningPid, DWORD OwningTag, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2351 {
2352 UINT Size;
2353 HRESULT Res;
2354 HANDLE hAdvapi32;
2355 WCHAR SysDir[MAX_PATH];
2356 PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2357 ULONG (NTAPI *_I_QueryTagInformation)(PVOID, DWORD, PVOID);
2358 struct
2359 {
2360 DWORD ProcessId;
2361 DWORD ServiceTag;
2362 DWORD TagType;
2363 PWSTR Buffer;
2364 } ServiceQuery;
2365
2366 /* First, secure (avoid injections) load advapi32.dll */
2367 Size = GetSystemDirectoryW(SysDir, MAX_PATH);
2368 if (Size == 0)
2369 {
2370 return GetLastError();
2371 }
2372
2373 Res = StringCchCatW(&SysDir[Size], MAX_PATH - Size, L"\\advapi32.dll");
2374 if (FAILED(Res))
2375 {
2376 return Res;
2377 }
2378
2379 hAdvapi32 = GetModuleHandleW(SysDir);
2380 if (hAdvapi32 == NULL)
2381 {
2382 return GetLastError();
2383 }
2384
2385 /* Now, we'll query the service associated with the tag */
2386 _I_QueryTagInformation = (PVOID)GetProcAddress(hAdvapi32, "I_QueryTagInformation");
2387 if (_I_QueryTagInformation == NULL)
2388 {
2389 return GetLastError();
2390 }
2391
2392 /* Set tag and PID for the query */
2393 ServiceQuery.ProcessId = OwningPid;
2394 ServiceQuery.ServiceTag = OwningTag;
2395 ServiceQuery.TagType = 0;
2396 ServiceQuery.Buffer = NULL;
2397
2398 /* And query */
2399 Res = _I_QueryTagInformation(NULL, 1, &ServiceQuery);
2400 if (Res != ERROR_SUCCESS)
2401 {
2402 return Res;
2403 }
2404
2405 /* Compute service name length */
2406 Size = wcslen(ServiceQuery.Buffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
2407
2408 /* We'll copy it twice, so make sure we have enough room */
2409 if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size)
2410 {
2411 *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size;
2412 LocalFree(ServiceQuery.Buffer);
2413 return ERROR_INSUFFICIENT_BUFFER;
2414 }
2415
2416 /* Copy back data */
2417 BasicInfo = Buffer;
2418 BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2419 BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + Size);
2420 wcscpy(BasicInfo->pModuleName, ServiceQuery.Buffer);
2421 wcscpy(BasicInfo->pModulePath, ServiceQuery.Buffer);
2422 *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size;
2423 LocalFree(ServiceQuery.Buffer);
2424
2425 return NO_ERROR;
2426 }
2427
2428 /******************************************************************
2429 * GetOwnerModuleFromTcpEntry (IPHLPAPI.@)
2430 *
2431 * Get data about the module that issued the context bind for a specific IPv4 TCP endpoint in a MIB table row
2432 *
2433 * PARAMS
2434 * pTcpEntry [in] pointer to a MIB_TCPROW_OWNER_MODULE structure
2435 * Class [in] TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2436 * Buffer [out] pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2437 * pdwSize [in, out] estimated size of the structure returned in Buffer, in bytes
2438 *
2439 * RETURNS
2440 * Success: NO_ERROR
2441 * Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2442 * ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2443 *
2444 * NOTES
2445 * The type of data returned in Buffer is indicated by the value of the Class parameter.
2446 */
2447 DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2448 {
2449 /* If we have a service tag, that's a service connection */
2450 if (pTcpEntry->OwningModuleInfo[0] != 0)
2451 {
2452 return GetOwnerModuleFromTagEntry(pTcpEntry->dwOwningPid, (DWORD)(pTcpEntry->OwningModuleInfo[0]), Class, Buffer, pdwSize);
2453 }
2454 else
2455 {
2456 return GetOwnerModuleFromPidEntry(pTcpEntry->dwOwningPid, Class, Buffer, pdwSize);
2457 }
2458 }
2459
2460 /******************************************************************
2461 * GetOwnerModuleFromUdpEntry (IPHLPAPI.@)
2462 *
2463 * Get data about the module that issued the context bind for a specific IPv4 UDP endpoint in a MIB table row
2464 *
2465 * PARAMS
2466 * pUdpEntry [in] pointer to a MIB_UDPROW_OWNER_MODULE structure
2467 * Class [in] TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2468 * Buffer [out] pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2469 * pdwSize [in, out] estimated size of the structure returned in Buffer, in bytes
2470 *
2471 * RETURNS
2472 * Success: NO_ERROR
2473 * Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2474 * ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2475 *
2476 * NOTES
2477 * The type of data returned in Buffer is indicated by the value of the Class parameter.
2478 */
2479 DWORD WINAPI GetOwnerModuleFromUdpEntry( PMIB_UDPROW_OWNER_MODULE pUdpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2480 {
2481 /* If we have a service tag, that's a service connection */
2482 if (pUdpEntry->OwningModuleInfo[0] != 0)
2483 {
2484 return GetOwnerModuleFromTagEntry(pUdpEntry->dwOwningPid, (DWORD)(pUdpEntry->OwningModuleInfo[0]), Class, Buffer, pdwSize);
2485 }
2486 else
2487 {
2488 return GetOwnerModuleFromPidEntry(pUdpEntry->dwOwningPid, Class, Buffer, pdwSize);
2489 }
2490 }
2491
2492 static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
2493 {
2494 IP_ADDR_STRING *pNext;
2495 PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
2496
2497 if (!Context->NumServers)
2498 {
2499 if (Context->uSizeAvailable >= Context->uSizeRequired)
2500 {
2501 WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
2502 Context->pData->DnsServerList.IpAddress.String[15] = '\0';
2503 Context->pLastAddr = &Context->pData->DnsServerList;
2504 }
2505 }
2506 else
2507 {
2508 Context->uSizeRequired += sizeof(IP_ADDR_STRING);
2509 if (Context->uSizeAvailable >= Context->uSizeRequired)
2510 {
2511 pNext = (IP_ADDR_STRING*)(((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING));
2512 WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
2513 pNext->IpAddress.String[15] = '\0';
2514 Context->pLastAddr->Next = pNext;
2515 Context->pLastAddr = pNext;
2516 pNext->Next = NULL;
2517 }
2518 }
2519 Context->NumServers++;
2520 }
2521
2522 /******************************************************************
2523 * GetPerAdapterInfo (IPHLPAPI.@)
2524 *
2525 *
2526 * PARAMS
2527 *
2528 * IfIndex [In]
2529 * pPerAdapterInfo [In/Out]
2530 * pOutBufLen [In/Out]
2531 *
2532 * RETURNS
2533 *
2534 * DWORD
2535 *
2536 */
2537 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
2538 {
2539 HKEY hkey;
2540 DWORD dwSize = 0;
2541 const char *ifName;
2542 NAME_SERVER_LIST_CONTEXT Context;
2543 WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
2544
2545 if (!pOutBufLen)
2546 return ERROR_INVALID_PARAMETER;
2547
2548 if (!pPerAdapterInfo || *pOutBufLen < sizeof(IP_PER_ADAPTER_INFO))
2549 {
2550 *pOutBufLen = sizeof(IP_PER_ADAPTER_INFO);
2551 return ERROR_BUFFER_OVERFLOW;
2552 }
2553
2554 ifName = getInterfaceNameByIndex(IfIndex);
2555 if (!ifName)
2556 return ERROR_INVALID_PARAMETER;
2557
2558 MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
2559 HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
2560
2561 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
2562 {
2563 return ERROR_NOT_SUPPORTED;
2564 }
2565 Context.NumServers = 0;
2566 Context.uSizeAvailable = *pOutBufLen;
2567 Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
2568 Context.pData = pPerAdapterInfo;
2569
2570 if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
2571 ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
2572
2573 EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
2574
2575 if (Context.uSizeRequired > Context.uSizeAvailable)
2576 {
2577 *pOutBufLen = Context.uSizeRequired;
2578 RegCloseKey(hkey);
2579 return ERROR_BUFFER_OVERFLOW;
2580 }
2581
2582 if(RegQueryValueExW(hkey, L"NameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
2583 {
2584 pPerAdapterInfo->AutoconfigActive = FALSE;
2585 }
2586 else
2587 {
2588 pPerAdapterInfo->AutoconfigActive = TRUE;
2589 }
2590
2591 RegCloseKey(hkey);
2592 return NOERROR;
2593 }
2594
2595
2596 /******************************************************************
2597 * GetRTTAndHopCount (IPHLPAPI.@)
2598 *
2599 *
2600 * PARAMS
2601 *
2602 * DestIpAddress [In]
2603 * HopCount [In/Out]
2604 * MaxHops [In]
2605 * RTT [In/Out]
2606 *
2607 * RETURNS
2608 *
2609 * BOOL
2610 *
2611 */
2612 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2613 {
2614 TRACE("DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p\n",
2615 DestIpAddress, HopCount, MaxHops, RTT);
2616 FIXME(":stub\n");
2617 return (BOOL) 0;
2618 }
2619
2620
2621 /******************************************************************
2622 * GetTcpStatisticsEx (IPHLPAPI.@)
2623 *
2624 *
2625 * PARAMS
2626 *
2627 * pStats [In/Out]
2628 * dwFamily [In]
2629 *
2630 * RETURNS
2631 *
2632 * DWORD
2633 *
2634 */
2635 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily)
2636 {
2637 DWORD ret;
2638
2639 TRACE("pStats %p\n", pStats);
2640 ret = getTCPStats(pStats, dwFamily);
2641 TRACE("returning %ld\n", ret);
2642 return ret;
2643 }
2644
2645 /******************************************************************
2646 * GetTcpStatistics (IPHLPAPI.@)
2647 *
2648 *
2649 * PARAMS
2650 *
2651 * pStats [In/Out]
2652 *
2653 * RETURNS
2654 *
2655 * DWORD
2656 *
2657 */
2658 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
2659 {
2660 return GetTcpStatisticsEx(pStats, PF_INET);
2661 }
2662
2663
2664 /******************************************************************
2665 * GetTcpTable (IPHLPAPI.@)
2666 *
2667 * Get the table of active TCP connections.
2668 *
2669 * PARAMS
2670 * pTcpTable [Out] buffer for TCP connections table
2671 * pdwSize [In/Out] length of output buffer
2672 * bOrder [In] whether to order the table
2673 *
2674 * RETURNS
2675 * Success: NO_ERROR
2676 * Failure: error code from winerror.h
2677 *
2678 * NOTES
2679 * If pdwSize is less than required, the function will return
2680 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
2681 * the required byte size.
2682 * If bOrder is true, the returned table will be sorted, first by
2683 * local address and port number, then by remote address and port
2684 * number.
2685 */
2686 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
2687 {
2688 return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, AF_INET, TCP_TABLE_BASIC_ALL, 0);
2689 }
2690
2691
2692 /******************************************************************
2693 * GetUdpStatisticsEx (IPHLPAPI.@)
2694 *
2695 *
2696 * PARAMS
2697 *
2698 * pStats [In/Out]
2699 * dwFamily [In]
2700 *
2701 * RETURNS
2702 *
2703 * DWORD
2704 *
2705 */
2706 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS pStats, DWORD dwFamily)
2707 {
2708 DWORD ret;
2709
2710 TRACE("pStats %p\n", pStats);
2711 ret = getUDPStats(pStats, dwFamily);
2712 TRACE("returning %ld\n", ret);
2713 return ret;
2714 }
2715
2716 /******************************************************************
2717 * GetUdpStatistics (IPHLPAPI.@)
2718 *
2719 *
2720 * PARAMS
2721 *
2722 * pStats [In/Out]
2723 *
2724 * RETURNS
2725 *
2726 * DWORD
2727 *
2728 */
2729 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
2730 {
2731 return GetUdpStatisticsEx(pStats, PF_INET);
2732 }
2733
2734
2735 /******************************************************************
2736 * GetUdpTable (IPHLPAPI.@)
2737 *
2738 *
2739 * PARAMS
2740 *
2741 * pUdpTable [In/Out]
2742 * pdwSize [In/Out]
2743 * bOrder [In]
2744 *
2745 * RETURNS
2746 *
2747 * DWORD
2748 *
2749 */
2750 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2751 {
2752 return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, AF_INET, UDP_TABLE_BASIC, 0);
2753 }
2754
2755
2756 /******************************************************************
2757 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
2758 *
2759 * This is a Win98-only function to get information on "unidirectional"
2760 * adapters. Since this is pretty nonsensical in other contexts, it
2761 * never returns anything.
2762 *
2763 * PARAMS
2764 * pIPIfInfo [Out] buffer for adapter infos
2765 * dwOutBufLen [Out] length of the output buffer
2766 *
2767 * RETURNS
2768 * Success: NO_ERROR
2769 * Failure: error code from winerror.h
2770 *
2771 * FIXME
2772 * Stub, returns ERROR_NOT_SUPPORTED.
2773 */
2774 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
2775 {
2776 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
2777 /* a unidirectional adapter?? not bloody likely! */
2778 return ERROR_NOT_SUPPORTED;
2779 }
2780
2781
2782 /******************************************************************
2783 * IpReleaseAddress (IPHLPAPI.@)
2784 *
2785 * Release an IP obtained through DHCP,
2786 *
2787 * PARAMS
2788 * AdapterInfo [In] adapter to release IP address
2789 *
2790 * RETURNS
2791 * Success: NO_ERROR
2792 * Failure: error code from winerror.h
2793 *
2794 */
2795 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2796 {
2797 DWORD Status, Version = 0;
2798
2799 if (!AdapterInfo)
2800 return ERROR_INVALID_PARAMETER;
2801
2802 /* Maybe we should do this in DllMain */
2803 if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2804 return ERROR_PROC_NOT_FOUND;
2805
2806 if (DhcpReleaseIpAddressLease(AdapterInfo->Index))
2807 Status = ERROR_SUCCESS;
2808 else
2809 Status = ERROR_PROC_NOT_FOUND;
2810
2811 DhcpCApiCleanup();
2812
2813 return Status;
2814 }
2815
2816
2817 /******************************************************************
2818 * IpRenewAddress (IPHLPAPI.@)
2819 *
2820 * Renew an IP obtained through DHCP.
2821 *
2822 * PARAMS
2823 * AdapterInfo [In] adapter to renew IP address
2824 *
2825 * RETURNS
2826 * Success: NO_ERROR
2827 * Failure: error code from winerror.h
2828 */
2829 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2830 {
2831 DWORD Status, Version = 0;
2832
2833 if (!AdapterInfo)
2834 return ERROR_INVALID_PARAMETER;
2835
2836 /* Maybe we should do this in DllMain */
2837 if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2838 return ERROR_PROC_NOT_FOUND;
2839
2840 if (DhcpRenewIpAddressLease(AdapterInfo->Index))
2841 Status = ERROR_SUCCESS;
2842 else
2843 Status = ERROR_PROC_NOT_FOUND;
2844
2845 DhcpCApiCleanup();
2846
2847 return Status;
2848 }
2849
2850
2851 /******************************************************************
2852 * NotifyAddrChange (IPHLPAPI.@)
2853 *
2854 * Notify caller whenever the ip-interface map is changed.
2855 *
2856 * PARAMS
2857 * Handle [Out] handle usable in asynchronous notification
2858 * overlapped [In] overlapped structure that notifies the caller
2859 *
2860 * RETURNS
2861 * Success: NO_ERROR
2862 * Failure: error code from winerror.h
2863 *
2864 * FIXME
2865 * Stub, returns ERROR_NOT_SUPPORTED.
2866 */
2867 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2868 {
2869 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2870 if (Handle) *Handle = INVALID_HANDLE_VALUE;
2871 if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING;
2872 return ERROR_IO_PENDING;
2873 }
2874
2875
2876 /******************************************************************
2877 * NotifyRouteChange (IPHLPAPI.@)
2878 *
2879 * Notify caller whenever the ip routing table is changed.
2880 *
2881 * PARAMS
2882 * Handle [Out] handle usable in asynchronous notification
2883 * overlapped [In] overlapped structure that notifies the caller
2884 *
2885 * RETURNS
2886 * Success: NO_ERROR
2887 * Failure: error code from winerror.h
2888 *
2889 * FIXME
2890 * Stub, returns ERROR_NOT_SUPPORTED.
2891 */
2892 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2893 {
2894 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2895 return ERROR_NOT_SUPPORTED;
2896 }
2897
2898 /******************************************************************
2899 * SendARP (IPHLPAPI.@)
2900 *
2901 * Send an ARP request.
2902 *
2903 * PARAMS
2904 * DestIP [In] attempt to obtain this IP
2905 * SrcIP [In] optional sender IP address
2906 * pMacAddr [Out] buffer for the mac address
2907 * PhyAddrLen [In/Out] length of the output buffer
2908 *
2909 * RETURNS
2910 * Success: NO_ERROR
2911 * Failure: error code from winerror.h
2912 */
2913 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2914 {
2915 IPAddr IPs[2];
2916 ULONG Size;
2917
2918 if (IsBadWritePtr(pMacAddr, sizeof(ULONG)) || IsBadWritePtr(PhyAddrLen, sizeof(ULONG)))
2919 return ERROR_INVALID_PARAMETER;
2920
2921 IPs[0] = DestIP;
2922 IPs[1] = SrcIP;
2923 Size = sizeof(IPs);
2924 return TCPSendIoctl(INVALID_HANDLE_VALUE, IOCTL_QUERY_IP_HW_ADDRESS, IPs, &Size, pMacAddr, PhyAddrLen);
2925 }
2926
2927
2928 /******************************************************************
2929 * SetIfEntry (IPHLPAPI.@)
2930 *
2931 * Set the administrative status of an interface.
2932 *
2933 * PARAMS
2934 * pIfRow [In] dwAdminStatus member specifies the new status.
2935 *
2936 * RETURNS
2937 * Success: NO_ERROR
2938 * Failure: error code from winerror.h
2939 *
2940 * FIXME
2941 * Stub, returns ERROR_NOT_SUPPORTED.
2942 */
2943 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
2944 {
2945 FIXME("(pIfRow %p): stub\n", pIfRow);
2946 /* this is supposed to set an interface administratively up or down.
2947 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2948 this sort of down is indistinguishable from other sorts of down (e.g. no
2949 link). */
2950 return ERROR_NOT_SUPPORTED;
2951 }
2952
2953
2954 /******************************************************************
2955 * SetIpForwardEntry (IPHLPAPI.@)
2956 *
2957 * Modify an existing route.
2958 *
2959 * PARAMS
2960 * pRoute [In] route with the new information
2961 *
2962 * RETURNS
2963 * Success: NO_ERROR
2964 * Failure: error code from winerror.h
2965 *
2966 */
2967 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
2968 {
2969 return setIpForwardEntry( pRoute );
2970 }
2971
2972
2973 /******************************************************************
2974 * SetIpNetEntry (IPHLPAPI.@)
2975 *
2976 * Modify an existing ARP entry.
2977 *
2978 * PARAMS
2979 * pArpEntry [In] ARP entry with the new information
2980 *
2981 * RETURNS
2982 * Success: NO_ERROR
2983 * Failure: error code from winerror.h
2984 */
2985 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
2986 {
2987 HANDLE tcpFile;
2988 NTSTATUS status;
2989 TCP_REQUEST_SET_INFORMATION_EX_ARP_ENTRY req =
2990 TCP_REQUEST_SET_INFORMATION_INIT;
2991 TDIEntityID id;
2992 DWORD returnSize;
2993 PMIB_IPNETROW arpBuff;
2994
2995 if (!pArpEntry)
2996 return ERROR_INVALID_PARAMETER;
2997
2998 if (!NT_SUCCESS(openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA )))
2999 return ERROR_NOT_SUPPORTED;
3000
3001 if (!NT_SUCCESS(getNthIpEntity( tcpFile, pArpEntry->dwIndex, &id )))
3002 {
3003 closeTcpFile(tcpFile);
3004 return ERROR_INVALID_PARAMETER;
3005 }
3006
3007 req.Req.ID.toi_class = INFO_CLASS_PROTOCOL;
3008 req.Req.ID.toi_type = INFO_TYPE_PROVIDER;
3009 req.Req.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
3010 req.Req.ID.toi_entity.tei_instance = id.tei_instance;
3011 req.Req.ID.toi_entity.tei_entity = AT_ENTITY;
3012 req.Req.BufferSize = sizeof(MIB_IPNETROW);
3013 arpBuff = (PMIB_IPNETROW)&req.Req.Buffer[0];
3014
3015 RtlCopyMemory(arpBuff, pArpEntry, sizeof(MIB_IPNETROW));
3016
3017 status = DeviceIoControl( tcpFile,
3018 IOCTL_TCP_SET_INFORMATION_EX,
3019 &req,
3020 sizeof(req),
3021 NULL,
3022 0,
3023 &returnSize,
3024 NULL );
3025
3026 closeTcpFile(tcpFile);
3027
3028 if (status)
3029 return NO_ERROR;
3030 else
3031 return ERROR_INVALID_PARAMETER;
3032 }
3033
3034
3035 /******************************************************************
3036 * SetIpStatistics (IPHLPAPI.@)
3037 *
3038 * Toggle IP forwarding and det the default TTL value.
3039 *
3040 * PARAMS
3041 * pIpStats [In] IP statistics with the new information
3042 *
3043 * RETURNS
3044 * Success: NO_ERROR
3045 * Failure: error code from winerror.h
3046 *
3047 * FIXME
3048 * Stub, returns NO_ERROR.
3049 */
3050 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
3051 {
3052 FIXME("(pIpStats %p): stub\n", pIpStats);
3053 return 0;
3054 }
3055
3056
3057 /******************************************************************
3058 * SetIpTTL (IPHLPAPI.@)
3059 *
3060 * Set the default TTL value.
3061 *
3062 * PARAMS
3063 * nTTL [In] new TTL value
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 SetIpTTL(UINT nTTL)
3073 {
3074 FIXME("(nTTL %d): stub\n", nTTL);
3075 return 0;
3076 }
3077
3078
3079 /******************************************************************
3080 * SetTcpEntry (IPHLPAPI.@)
3081 *
3082 * Set the state of a TCP connection.
3083 *
3084 * PARAMS
3085 * pTcpRow [In] specifies connection with new state
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 SetTcpEntry(PMIB_TCPROW pTcpRow)
3095 {
3096 FIXME("(pTcpRow %p): stub\n", pTcpRow);
3097 return 0;
3098 }
3099
3100
3101 /******************************************************************
3102 * UnenableRouter (IPHLPAPI.@)
3103 *
3104 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
3105 * if it reaches zero.
3106 *
3107 * PARAMS
3108 * pOverlapped [In/Out] should be the same as in EnableRouter()
3109 * lpdwEnableCount [Out] optional, receives reference count
3110 *
3111 * RETURNS
3112 * Success: NO_ERROR
3113 * Failure: error code from winerror.h
3114 *
3115 * FIXME
3116 * Stub, returns ERROR_NOT_SUPPORTED.
3117 */
3118 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
3119 {
3120 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
3121 lpdwEnableCount);
3122 return ERROR_NOT_SUPPORTED;
3123 }
3124
3125 /*
3126 * @unimplemented
3127 */
3128 DWORD WINAPI GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)
3129 {
3130 FIXME(":stub\n");
3131 return 0L;
3132 }
3133
3134
3135 /*
3136 * @unimplemented
3137 */
3138 PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
3139 {
3140 FIXME(":stub\n");
3141 return 0L;
3142 }
3143
3144 /*
3145 * @implemented
3146 */
3147 #ifdef GetAdaptersAddressesV1
3148 DWORD WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
3149 {
3150 InterfaceIndexTable *indexTable;
3151 IFInfo ifInfo;
3152 int i;
3153 ULONG ret, requiredSize = 0;
3154 PIP_ADAPTER_ADDRESSES currentAddress;
3155 PUCHAR currentLocation;
3156 HANDLE tcpFile;
3157
3158 if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
3159 if (Reserved) return ERROR_INVALID_PARAMETER;
3160
3161 indexTable = getInterfaceIndexTable();
3162 if (!indexTable)
3163 return ERROR_NOT_ENOUGH_MEMORY;
3164
3165 ret = openTcpFile(&tcpFile, FILE_READ_DATA);
3166 if (!NT_SUCCESS(ret))
3167 return ERROR_NO_DATA;
3168
3169 for (i = indexTable->numIndexes; i >= 0; i--)
3170 {
3171 if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3172 NULL,
3173 indexTable->indexes[i],
3174 &ifInfo)))
3175 {
3176 /* The whole struct */
3177 requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
3178
3179 /* Friendly name */
3180 if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3181 requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1; //FIXME
3182
3183 /* Adapter name */
3184 requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
3185
3186 /* Unicast address */
3187 if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3188 requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3189
3190 /* FIXME: Implement multicast, anycast, and dns server stuff */
3191
3192 /* FIXME: Implement dns suffix and description */
3193 requiredSize += 2 * sizeof(WCHAR);
3194
3195 /* We're only going to implement what's required for XP SP0 */
3196 }
3197 }
3198 TRACE("size: %d, requiredSize: %d\n", *pOutBufLen, requiredSize);
3199 if (!pAdapterAddresses || *pOutBufLen < requiredSize)
3200 {
3201 *pOutBufLen = requiredSize;
3202 closeTcpFile(tcpFile);
3203 free(indexTable);
3204 return ERROR_BUFFER_OVERFLOW;
3205 }
3206
3207 RtlZeroMemory(pAdapterAddresses, requiredSize);
3208
3209 /* Let's set up the pointers */
3210 currentAddress = pAdapterAddresses;
3211 for (i = indexTable->numIndexes; i >= 0; i--)
3212 {
3213 if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3214 NULL,
3215 indexTable->indexes[i],
3216 &ifInfo)))
3217 {
3218 currentLocation = (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
3219
3220 /* FIXME: Friendly name */
3221 if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3222 {
3223 currentAddress->FriendlyName = (PVOID)currentLocation;
3224 currentLocation += sizeof(WCHAR);
3225 }
3226
3227 /* Adapter name */
3228 currentAddress->AdapterName = (PVOID)currentLocation;
3229 currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
3230
3231 /* Unicast address */
3232 if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3233 {
3234 currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
3235 currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3236 currentAddress->FirstUnicastAddress->Address.lpSockaddr = (PVOID)currentLocation;
3237 currentLocation += sizeof(struct sockaddr);
3238 }
3239
3240 /* FIXME: Implement multicast, anycast, and dns server stuff */
3241
3242 /* FIXME: Implement dns suffix and description */
3243 currentAddress->DnsSuffix = (PVOID)currentLocation;
3244 currentLocation += sizeof(WCHAR);
3245
3246 currentAddress->Description = (PVOID)currentLocation;
3247 currentLocation += sizeof(WCHAR);
3248
3249 currentAddress->Next = (PVOID)currentLocation;
3250 /* Terminate the last address correctly */
3251 if(i==0)
3252 currentAddress->Next = NULL;
3253
3254 /* We're only going to implement what's required for XP SP0 */
3255
3256 currentAddress = currentAddress->Next;
3257 }
3258 }
3259
3260 /* Now again, for real this time */
3261
3262 currentAddress = pAdapterAddresses;
3263 for (i = indexTable->numIndexes; i >= 0; i--)
3264 {
3265 if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3266 NULL,
3267 indexTable->indexes[i],
3268 &ifInfo)))
3269 {
3270 /* Make sure we're not looping more than we hoped for */
3271 ASSERT(currentAddress);
3272
3273 /* Alignment information */
3274 currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
3275 currentAddress->IfIndex = indexTable->indexes[i];
3276
3277 /* Adapter name */
3278 strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr);
3279
3280 if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3281 {
3282 currentAddress->FirstUnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3283 currentAddress->FirstUnicastAddress->Flags = 0; //FIXME
3284 currentAddress->FirstUnicastAddress->Next = NULL; //FIXME: Support more than one address per adapter
3285 currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
3286 memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
3287 &ifInfo.ip_addr.iae_addr,
3288 sizeof(ifInfo.ip_addr.iae_addr));
3289 currentAddress->FirstUnicastAddress->Address.iSockaddrLength = sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
3290 currentAddress->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; //FIXME
3291 currentAddress->FirstUnicastAddress->SuffixOrigin = IpPrefixOriginOther; //FIXME
3292 currentAddress->FirstUnicastAddress->DadState = IpDadStatePreferred; //FIXME
3293 currentAddress->FirstUnicastAddress->ValidLifetime = 0xFFFFFFFF; //FIXME
3294 currentAddress->FirstUnicastAddress->PreferredLifetime = 0xFFFFFFFF; //FIXME
3295 currentAddress->FirstUnicastAddress->LeaseLifetime = 0xFFFFFFFF; //FIXME
3296 }
3297
3298 /* FIXME: Implement multicast, anycast, and dns server stuff */
3299 currentAddress->FirstAnycastAddress = NULL;
3300 currentAddress->FirstMulticastAddress = NULL;
3301 currentAddress->FirstDnsServerAddress = NULL;
3302
3303 /* FIXME: Implement dns suffix, description, and friendly name */
3304 currentAddress->DnsSuffix[0] = UNICODE_NULL;
3305 currentAddress->Description[0] = UNICODE_NULL;
3306 currentAddress->FriendlyName[0] = UNICODE_NULL;
3307
3308 /* Physical Address */
3309 memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, ifInfo.if_info.ent.if_physaddrlen);
3310 currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
3311
3312 /* Flags */
3313 currentAddress->Flags = 0; //FIXME
3314
3315 /* MTU */
3316 currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
3317
3318 /* Interface type */
3319 currentAddress->IfType = ifInfo.if_info.ent.if_type;
3320
3321 /* Operational status */
3322 if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
3323 currentAddress->OperStatus = IfOperStatusUp;
3324 else
3325 currentAddress->OperStatus = IfOperStatusDown;
3326
3327 /* We're only going to implement what's required for XP SP0 */
3328
3329 /* Move to the next address */
3330 currentAddress = currentAddress->Next;
3331 }
3332 }
3333
3334 closeTcpFile(tcpFile);
3335 free(indexTable);
3336
3337 return NO_ERROR;
3338 }
3339 #endif
3340
3341 /*
3342 * @unimplemented
3343 */
3344 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)
3345 {
3346 FIXME(":stub\n");
3347 return 0L;
3348 }
3349
3350 /*
3351 * @unimplemented
3352 */
3353 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex)
3354 {
3355 FIXME(":stub\n");
3356 return 0L;
3357 }
3358
3359 /*
3360 * @unimplemented
3361 */
3362 DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)
3363 {
3364 FIXME(":stub\n");
3365 return 0L;
3366 }
3367
3368 /*
3369 * @unimplemented
3370 */
3371 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
3372 {
3373 FIXME(":stub\n");
3374
3375 if (!pStats)
3376 return ERROR_INVALID_PARAMETER;
3377
3378 if (dwFamily != AF_INET && dwFamily != AF_INET6)
3379 return ERROR_INVALID_PARAMETER;
3380
3381 return 0L;
3382 }
3383
3384 DWORD WINAPI
3385 SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)
3386 {
3387 FIXME("SetIpForwardEntryToStack() stub\n");
3388 return 0L;
3389 }
3390
3391 DWORD GetInterfaceNameInternal(_In_ const GUID * pInterfaceGUID,
3392 _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3393 _Inout_ PULONG pOutBufLen)
3394 {
3395 UNICODE_STRING GuidString;
3396 DWORD result, type;
3397 WCHAR szKeyName[2*MAX_PATH];
3398 HRESULT hr;
3399 HKEY hKey;
3400
3401 if (pInterfaceGUID == NULL || pOutBufLen == NULL)
3402 return ERROR_INVALID_PARAMETER;
3403
3404 result = RtlStringFromGUID(pInterfaceGUID, &GuidString);
3405
3406 if (!NT_SUCCESS(result))
3407 {
3408 // failed to convert guid to string
3409 return RtlNtStatusToDosError(result);
3410 }
3411
3412 hr = StringCbPrintfW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", GuidString.Buffer);
3413 RtlFreeUnicodeString(&GuidString);
3414
3415 if (FAILED(hr))
3416 {
3417 // key name is too long
3418 return ERROR_BUFFER_OVERFLOW;
3419 }
3420
3421 result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKey);
3422
3423 if (result != ERROR_SUCCESS)
3424 {
3425 // failed to find adapter entry
3426 return ERROR_NOT_FOUND;
3427 }
3428
3429 result = RegQueryValueExW(hKey, L"Name", NULL, &type, (PVOID)pInterfaceName, pOutBufLen);
3430
3431 RegCloseKey(hKey);
3432
3433 if (result == ERROR_MORE_DATA)
3434 {
3435 *pOutBufLen = MAX_INTERFACE_NAME_LEN * 2;
3436 return ERROR_INSUFFICIENT_BUFFER;
3437 }
3438
3439 if (result != ERROR_SUCCESS || type != REG_SZ)
3440 {
3441 // failed to read adapter name
3442 return ERROR_NO_DATA;
3443 }
3444 return ERROR_SUCCESS;
3445 }
3446
3447 /*
3448 * @implemented
3449 */
3450 DWORD WINAPI
3451 NhGetInterfaceNameFromDeviceGuid(_In_ const GUID * pInterfaceGUID,
3452 _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3453 _Inout_ PULONG pOutBufLen,
3454 DWORD dwUnknown4,
3455 DWORD dwUnknown5)
3456 {
3457 SetLastError(ERROR_SUCCESS);
3458
3459 if (pInterfaceName == NULL)
3460 return ERROR_INVALID_PARAMETER;
3461
3462 return GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3463 }
3464
3465 /*
3466 * @implemented
3467 */
3468 DWORD WINAPI
3469 NhGetInterfaceNameFromGuid(_In_ const GUID * pInterfaceGUID,
3470 _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3471 _Inout_ PULONG pOutBufLen,
3472 DWORD dwUnknown4,
3473 DWORD dwUnknown5)
3474 {
3475 DWORD result;
3476
3477 result = GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3478
3479 if (result == ERROR_NOT_FOUND)
3480 SetLastError(ERROR_PATH_NOT_FOUND);
3481
3482 return result;
3483 }