[IPHLPAPI] Implement GetOwnerModuleFromTcpEntry()
[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;
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();
1044 PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
1045
1046 if (pOurTcpTable)
1047 {
1048 if (sizeof(DWORD) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW) > *pdwSize || !pTheirTcpTable)
1049 {
1050 *pdwSize = sizeof(DWORD) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW);
1051 ret = ERROR_INSUFFICIENT_BUFFER;
1052 }
1053 else
1054 {
1055 memcpy(pTheirTcpTable, pOurTcpTable, sizeof(DWORD) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW));
1056
1057 if (bOrder)
1058 qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1059 sizeof(MIB_TCPROW), TcpTableSorter);
1060 }
1061
1062 free(pOurTcpTable);
1063 }
1064 }
1065 break;
1066
1067 case TCP_TABLE_BASIC_CONNECTIONS:
1068 {
1069 PMIB_TCPTABLE pOurTcpTable = getTcpTable();
1070 PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
1071
1072 if (pOurTcpTable)
1073 {
1074 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1075 {
1076 if (pOurTcpTable->table[i].State != MIB_TCP_STATE_LISTEN)
1077 {
1078 ++count;
1079 }
1080 }
1081
1082 if (sizeof(DWORD) + count * sizeof(MIB_TCPROW) > *pdwSize || !pTheirTcpTable)
1083 {
1084 *pdwSize = sizeof(DWORD) + count * sizeof(MIB_TCPROW);
1085 ret = ERROR_INSUFFICIENT_BUFFER;
1086 }
1087 else
1088 {
1089 pTheirTcpTable->dwNumEntries = count;
1090
1091 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1092 {
1093 if (pOurTcpTable->table[i].State != MIB_TCP_STATE_LISTEN)
1094 {
1095 memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW));
1096 ++count;
1097 }
1098 }
1099 ASSERT(count == pTheirTcpTable->dwNumEntries);
1100
1101 if (bOrder)
1102 qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1103 sizeof(MIB_TCPROW), TcpTableSorter);
1104 }
1105
1106 free(pOurTcpTable);
1107 }
1108 }
1109 break;
1110
1111 case TCP_TABLE_BASIC_LISTENER:
1112 {
1113 PMIB_TCPTABLE pOurTcpTable = getTcpTable();
1114 PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
1115
1116 if (pOurTcpTable)
1117 {
1118 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1119 {
1120 if (pOurTcpTable->table[i].State == MIB_TCP_STATE_LISTEN)
1121 {
1122 ++count;
1123 }
1124 }
1125
1126 if (sizeof(DWORD) + count * sizeof(MIB_TCPROW) > *pdwSize || !pTheirTcpTable)
1127 {
1128 *pdwSize = sizeof(DWORD) + count * sizeof(MIB_TCPROW);
1129 ret = ERROR_INSUFFICIENT_BUFFER;
1130 }
1131 else
1132 {
1133 pTheirTcpTable->dwNumEntries = count;
1134
1135 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1136 {
1137 if (pOurTcpTable->table[i].State == MIB_TCP_STATE_LISTEN)
1138 {
1139 memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW));
1140 ++count;
1141 }
1142 }
1143 ASSERT(count == pTheirTcpTable->dwNumEntries);
1144
1145 if (bOrder)
1146 qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1147 sizeof(MIB_TCPROW), TcpTableSorter);
1148 }
1149
1150 free(pOurTcpTable);
1151 }
1152 }
1153 break;
1154
1155 case TCP_TABLE_OWNER_PID_ALL:
1156 {
1157 PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getOwnerTcpTable();
1158 PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1159
1160 if (pOurTcpTable)
1161 {
1162 if (sizeof(DWORD) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_PID) > *pdwSize || !pTheirTcpTable)
1163 {
1164 *pdwSize = sizeof(DWORD) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_PID);
1165 ret = ERROR_INSUFFICIENT_BUFFER;
1166 }
1167 else
1168 {
1169 memcpy(pTheirTcpTable, pOurTcpTable, sizeof(DWORD) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_PID));
1170
1171 /* Don't sort on PID, so use basic helper */
1172 if (bOrder)
1173 qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1174 sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1175 }
1176
1177 free(pOurTcpTable);
1178 }
1179 }
1180 break;
1181
1182 case TCP_TABLE_OWNER_PID_CONNECTIONS:
1183 {
1184 PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getOwnerTcpTable();
1185 PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1186
1187 if (pOurTcpTable)
1188 {
1189 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1190 {
1191 if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1192 {
1193 ++count;
1194 }
1195 }
1196
1197 if (sizeof(DWORD) + count * sizeof(MIB_TCPROW_OWNER_PID) > *pdwSize || !pTheirTcpTable)
1198 {
1199 *pdwSize = sizeof(DWORD) + count * sizeof(MIB_TCPROW_OWNER_PID);
1200 ret = ERROR_INSUFFICIENT_BUFFER;
1201 }
1202 else
1203 {
1204 pTheirTcpTable->dwNumEntries = count;
1205
1206 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1207 {
1208 if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1209 {
1210 memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_PID));
1211 ++count;
1212 }
1213 }
1214 ASSERT(count == pTheirTcpTable->dwNumEntries);
1215
1216 /* Don't sort on PID, so use basic helper */
1217 if (bOrder)
1218 qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1219 sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1220 }
1221
1222 free(pOurTcpTable);
1223 }
1224 }
1225 break;
1226
1227 case TCP_TABLE_OWNER_PID_LISTENER:
1228 {
1229 PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getOwnerTcpTable();
1230 PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1231
1232 if (pOurTcpTable)
1233 {
1234 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1235 {
1236 if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1237 {
1238 ++count;
1239 }
1240 }
1241
1242 if (sizeof(DWORD) + count * sizeof(MIB_TCPROW_OWNER_PID) > *pdwSize || !pTheirTcpTable)
1243 {
1244 *pdwSize = sizeof(DWORD) + count * sizeof(MIB_TCPROW_OWNER_PID);
1245 ret = ERROR_INSUFFICIENT_BUFFER;
1246 }
1247 else
1248 {
1249 pTheirTcpTable->dwNumEntries = count;
1250
1251 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1252 {
1253 if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1254 {
1255 memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_PID));
1256 ++count;
1257 }
1258 }
1259 ASSERT(count == pTheirTcpTable->dwNumEntries);
1260
1261 /* Don't sort on PID, so use basic helper */
1262 if (bOrder)
1263 qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1264 sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1265 }
1266
1267 free(pOurTcpTable);
1268 }
1269 }
1270 break;
1271
1272 case TCP_TABLE_OWNER_MODULE_ALL:
1273 {
1274 PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getOwnerModTcpTable();
1275 PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1276
1277 if (pOurTcpTable)
1278 {
1279 if (sizeof(DWORD) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_MODULE) > *pdwSize || !pTheirTcpTable)
1280 {
1281 *pdwSize = sizeof(DWORD) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_MODULE);
1282 ret = ERROR_INSUFFICIENT_BUFFER;
1283 }
1284 else
1285 {
1286 memcpy(pTheirTcpTable, pOurTcpTable, sizeof(DWORD) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_MODULE));
1287
1288 /* Don't sort on PID, so use basic helper */
1289 if (bOrder)
1290 qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1291 sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1292 }
1293
1294 free(pOurTcpTable);
1295 }
1296 }
1297 break;
1298
1299 case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
1300 {
1301 PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getOwnerModTcpTable();
1302 PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1303
1304 if (pOurTcpTable)
1305 {
1306 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1307 {
1308 if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1309 {
1310 ++count;
1311 }
1312 }
1313
1314 if (sizeof(DWORD) + count * sizeof(MIB_TCPROW_OWNER_MODULE) > *pdwSize || !pTheirTcpTable)
1315 {
1316 *pdwSize = sizeof(DWORD) + count * sizeof(MIB_TCPROW_OWNER_MODULE);
1317 ret = ERROR_INSUFFICIENT_BUFFER;
1318 }
1319 else
1320 {
1321 pTheirTcpTable->dwNumEntries = count;
1322
1323 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1324 {
1325 if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1326 {
1327 memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_MODULE));
1328 ++count;
1329 }
1330 }
1331 ASSERT(count == pTheirTcpTable->dwNumEntries);
1332
1333 /* Don't sort on PID, so use basic helper */
1334 if (bOrder)
1335 qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1336 sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1337 }
1338
1339 free(pOurTcpTable);
1340 }
1341 }
1342 break;
1343
1344 case TCP_TABLE_OWNER_MODULE_LISTENER:
1345 {
1346 PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getOwnerModTcpTable();
1347 PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1348
1349 if (pOurTcpTable)
1350 {
1351 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1352 {
1353 if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1354 {
1355 ++count;
1356 }
1357 }
1358
1359 if (sizeof(DWORD) + count * sizeof(MIB_TCPROW_OWNER_MODULE) > *pdwSize || !pTheirTcpTable)
1360 {
1361 *pdwSize = sizeof(DWORD) + count * sizeof(MIB_TCPROW_OWNER_MODULE);
1362 ret = ERROR_INSUFFICIENT_BUFFER;
1363 }
1364 else
1365 {
1366 pTheirTcpTable->dwNumEntries = count;
1367
1368 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1369 {
1370 if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1371 {
1372 memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_MODULE));
1373 ++count;
1374 }
1375 }
1376 ASSERT(count == pTheirTcpTable->dwNumEntries);
1377
1378 /* Don't sort on PID, so use basic helper */
1379 if (bOrder)
1380 qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1381 sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1382 }
1383
1384 free(pOurTcpTable);
1385 }
1386 }
1387 break;
1388
1389 default:
1390 ret = ERROR_INVALID_PARAMETER;
1391 break;
1392 }
1393
1394 return ret;
1395 }
1396
1397
1398 static int UdpTableSorter(const void *a, const void *b)
1399 {
1400 int ret;
1401
1402 if (a && b) {
1403 PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
1404
1405 ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1406 if (ret == 0)
1407 ret = rowA->dwLocalPort - rowB->dwLocalPort;
1408 }
1409 else
1410 ret = 0;
1411 return ret;
1412 }
1413
1414 /******************************************************************
1415 * GetExtendedUdpTable (IPHLPAPI.@)
1416 *
1417 * Get the table of UDP endpoints available to the application.
1418 *
1419 * PARAMS
1420 * pUdpTable [Out] table struct with the filtered UDP endpoints available to application
1421 * pdwSize [In/Out] estimated size of the structure returned in pUdpTable, in bytes
1422 * bOrder [In] whether to order the table
1423 * ulAf [in] version of IP used by the UDP endpoints
1424 * TableClass [in] type of the UDP table structure from UDP_TABLE_CLASS
1425 * Reserved [in] reserved - this value must be zero
1426 *
1427 * RETURNS
1428 * Success: NO_ERROR
1429 * Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
1430 *
1431 * NOTES
1432 */
1433
1434 DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved)
1435 {
1436 DWORD ret = NO_ERROR;
1437
1438 if (!pdwSize)
1439 {
1440 return ERROR_INVALID_PARAMETER;
1441 }
1442
1443 if (ulAf != AF_INET)
1444 {
1445 UNIMPLEMENTED;
1446 return ERROR_INVALID_PARAMETER;
1447 }
1448
1449 switch (TableClass)
1450 {
1451 case UDP_TABLE_BASIC:
1452 {
1453 PMIB_UDPTABLE pOurUdpTable = getUdpTable();
1454 PMIB_UDPTABLE pTheirUdpTable = pUdpTable;
1455
1456 if (pOurUdpTable)
1457 {
1458 if (sizeof(DWORD) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW) > *pdwSize || !pTheirUdpTable)
1459 {
1460 *pdwSize = sizeof(DWORD) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW);
1461 ret = ERROR_INSUFFICIENT_BUFFER;
1462 }
1463 else
1464 {
1465 memcpy(pTheirUdpTable, pOurUdpTable, sizeof(DWORD) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_PID));
1466
1467 if (bOrder)
1468 qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1469 sizeof(MIB_UDPROW), UdpTableSorter);
1470 }
1471
1472 free(pOurUdpTable);
1473 }
1474 }
1475 break;
1476
1477 case UDP_TABLE_OWNER_PID:
1478 {
1479 PMIB_UDPTABLE_OWNER_PID pOurUdpTable = getOwnerUdpTable();
1480 PMIB_UDPTABLE_OWNER_PID pTheirUdpTable = pUdpTable;
1481
1482 if (pOurUdpTable)
1483 {
1484 if (sizeof(DWORD) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_PID) > *pdwSize || !pTheirUdpTable)
1485 {
1486 *pdwSize = sizeof(DWORD) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_PID);
1487 ret = ERROR_INSUFFICIENT_BUFFER;
1488 }
1489 else
1490 {
1491 memcpy(pTheirUdpTable, pOurUdpTable, sizeof(DWORD) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_PID));
1492
1493 if (bOrder)
1494 qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1495 sizeof(MIB_UDPROW_OWNER_PID), UdpTableSorter);
1496 }
1497
1498 free(pOurUdpTable);
1499 }
1500 }
1501 break;
1502
1503 case UDP_TABLE_OWNER_MODULE:
1504 {
1505 PMIB_UDPTABLE_OWNER_MODULE pOurUdpTable = getOwnerModUdpTable();
1506 PMIB_UDPTABLE_OWNER_MODULE pTheirUdpTable = pUdpTable;
1507
1508 if (pOurUdpTable)
1509 {
1510 if (sizeof(DWORD) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_MODULE) > *pdwSize || !pTheirUdpTable)
1511 {
1512 *pdwSize = sizeof(DWORD) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_MODULE);
1513 ret = ERROR_INSUFFICIENT_BUFFER;
1514 }
1515 else
1516 {
1517 memcpy(pTheirUdpTable, pOurUdpTable, sizeof(DWORD) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_MODULE));
1518
1519 if (bOrder)
1520 qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1521 sizeof(MIB_UDPROW_OWNER_MODULE), UdpTableSorter);
1522 }
1523
1524 free(pOurUdpTable);
1525 }
1526 }
1527 break;
1528
1529 default:
1530 ret = ERROR_INVALID_PARAMETER;
1531 break;
1532 }
1533
1534 return ret;
1535 }
1536
1537
1538 /******************************************************************
1539 * GetFriendlyIfIndex (IPHLPAPI.@)
1540 *
1541 *
1542 * PARAMS
1543 *
1544 * IfIndex [In]
1545 *
1546 * RETURNS
1547 *
1548 * DWORD
1549 *
1550 */
1551 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1552 {
1553 /* windows doesn't validate these, either, just makes sure the top byte is
1554 cleared. I assume my ifenum module never gives an index with the top
1555 byte set. */
1556 TRACE("returning %ld\n", IfIndex);
1557 return IfIndex;
1558 }
1559
1560
1561 /******************************************************************
1562 * GetIcmpStatistics (IPHLPAPI.@)
1563 *
1564 *
1565 * PARAMS
1566 *
1567 * pStats [In/Out]
1568 *
1569 * RETURNS
1570 *
1571 * DWORD
1572 *
1573 */
1574 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
1575 {
1576 DWORD ret;
1577
1578 TRACE("pStats %p\n", pStats);
1579 ret = getICMPStats(pStats);
1580 TRACE("returning %ld\n", ret);
1581 return ret;
1582 }
1583
1584
1585 /******************************************************************
1586 * GetIfEntry (IPHLPAPI.@)
1587 *
1588 *
1589 * PARAMS
1590 *
1591 * pIfRow [In/Out]
1592 *
1593 * RETURNS
1594 *
1595 * DWORD
1596 *
1597 */
1598 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
1599 {
1600 DWORD ret;
1601 const char *name;
1602
1603 TRACE("pIfRow %p\n", pIfRow);
1604 if (!pIfRow)
1605 return ERROR_INVALID_PARAMETER;
1606
1607 name = getInterfaceNameByIndex(pIfRow->dwIndex);
1608 if (name) {
1609 ret = getInterfaceEntryByIndex(pIfRow->dwIndex, pIfRow);
1610 if (ret == NO_ERROR)
1611 ret = getInterfaceStatsByName(name, pIfRow);
1612 consumeInterfaceName(name);
1613 }
1614 else
1615 ret = ERROR_INVALID_DATA;
1616 TRACE("returning %ld\n", ret);
1617 return ret;
1618 }
1619
1620
1621 static int IfTableSorter(const void *a, const void *b)
1622 {
1623 int ret;
1624
1625 if (a && b)
1626 ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
1627 else
1628 ret = 0;
1629 return ret;
1630 }
1631
1632
1633 /******************************************************************
1634 * GetIfTable (IPHLPAPI.@)
1635 *
1636 *
1637 * PARAMS
1638 *
1639 * pIfTable [In/Out]
1640 * pdwSize [In/Out]
1641 * bOrder [In]
1642 *
1643 * RETURNS
1644 *
1645 * DWORD
1646 *
1647 */
1648 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
1649 {
1650 DWORD ret;
1651
1652 TRACE("pIfTable %p, pdwSize %p, bOrder %ld\n", pdwSize, pdwSize,
1653 (DWORD)bOrder);
1654 if (!pdwSize)
1655 ret = ERROR_INVALID_PARAMETER;
1656 else {
1657 DWORD numInterfaces = getNumInterfaces();
1658 ULONG size;
1659 TRACE("GetIfTable: numInterfaces = %d\n", (int)numInterfaces);
1660 size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
1661
1662 if (!pIfTable || *pdwSize < size) {
1663 *pdwSize = size;
1664 ret = ERROR_INSUFFICIENT_BUFFER;
1665 }
1666 else {
1667 InterfaceIndexTable *table = getInterfaceIndexTable();
1668
1669 if (table) {
1670 size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
1671 sizeof(MIB_IFROW);
1672 if (*pdwSize < size) {
1673 *pdwSize = size;
1674 ret = ERROR_INSUFFICIENT_BUFFER;
1675 }
1676 else {
1677 DWORD ndx;
1678
1679 pIfTable->dwNumEntries = 0;
1680 for (ndx = 0; ndx < table->numIndexes; ndx++) {
1681 pIfTable->table[ndx].dwIndex = table->indexes[ndx];
1682 GetIfEntry(&pIfTable->table[ndx]);
1683 pIfTable->dwNumEntries++;
1684 }
1685 if (bOrder)
1686 qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
1687 IfTableSorter);
1688 ret = NO_ERROR;
1689 }
1690 free(table);
1691 }
1692 else
1693 ret = ERROR_OUTOFMEMORY;
1694 }
1695 }
1696 TRACE("returning %ld\n", ret);
1697 return ret;
1698 }
1699
1700
1701 /******************************************************************
1702 * GetInterfaceInfo (IPHLPAPI.@)
1703 *
1704 *
1705 * PARAMS
1706 *
1707 * pIfTable [In/Out]
1708 * dwOutBufLen [In/Out]
1709 *
1710 * RETURNS
1711 *
1712 * DWORD
1713 *
1714 */
1715 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
1716 {
1717 DWORD ret;
1718
1719 TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
1720 if (!dwOutBufLen)
1721 ret = ERROR_INVALID_PARAMETER;
1722 else {
1723 DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
1724 ULONG size;
1725 TRACE("numNonLoopbackInterfaces == 0x%x\n", numNonLoopbackInterfaces);
1726 size = sizeof(IP_INTERFACE_INFO) + (numNonLoopbackInterfaces) *
1727 sizeof(IP_ADAPTER_INDEX_MAP);
1728
1729 if (!pIfTable || *dwOutBufLen < size) {
1730 *dwOutBufLen = size;
1731 ret = ERROR_INSUFFICIENT_BUFFER;
1732 }
1733 else {
1734 InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
1735
1736 if (table) {
1737 TRACE("table->numIndexes == 0x%x\n", table->numIndexes);
1738 size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes) *
1739 sizeof(IP_ADAPTER_INDEX_MAP);
1740 if (*dwOutBufLen < size) {
1741 *dwOutBufLen = size;
1742 ret = ERROR_INSUFFICIENT_BUFFER;
1743 }
1744 else {
1745 DWORD ndx;
1746
1747 pIfTable->NumAdapters = 0;
1748 for (ndx = 0; ndx < table->numIndexes; ndx++) {
1749 const char *walker, *name;
1750 WCHAR *assigner;
1751
1752 pIfTable->Adapter[ndx].Index = table->indexes[ndx];
1753 name = getInterfaceNameByIndex(table->indexes[ndx]);
1754 for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
1755 walker && *walker &&
1756 assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
1757 walker++, assigner++)
1758 *assigner = *walker;
1759 *assigner = 0;
1760 consumeInterfaceName(name);
1761 pIfTable->NumAdapters++;
1762 }
1763 ret = NO_ERROR;
1764 }
1765 free(table);
1766 }
1767 else
1768 ret = ERROR_OUTOFMEMORY;
1769 }
1770 }
1771 TRACE("returning %ld\n", ret);
1772 return ret;
1773 }
1774
1775
1776 static int IpAddrTableSorter(const void *a, const void *b)
1777 {
1778 int ret;
1779
1780 if (a && b)
1781 ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
1782 else
1783 ret = 0;
1784 return ret;
1785 }
1786
1787
1788 /******************************************************************
1789 * GetIpAddrTable (IPHLPAPI.@)
1790 *
1791 *
1792 * PARAMS
1793 *
1794 * pIpAddrTable [In/Out]
1795 * pdwSize [In/Out]
1796 * bOrder [In]
1797 *
1798 * RETURNS
1799 *
1800 * DWORD
1801 *
1802 */
1803 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1804 {
1805 DWORD ret;
1806
1807 TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
1808 (DWORD)bOrder);
1809 if (!pdwSize)
1810 ret = ERROR_INVALID_PARAMETER;
1811 else {
1812 DWORD numInterfaces = getNumInterfaces();
1813 ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
1814 sizeof(MIB_IPADDRROW);
1815
1816 if (!pIpAddrTable || *pdwSize < size) {
1817 *pdwSize = size;
1818 ret = ERROR_INSUFFICIENT_BUFFER;
1819 }
1820 else {
1821 InterfaceIndexTable *table = getInterfaceIndexTable();
1822
1823 if (table) {
1824 size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
1825 sizeof(MIB_IPADDRROW);
1826 if (*pdwSize < size) {
1827 *pdwSize = size;
1828 ret = ERROR_INSUFFICIENT_BUFFER;
1829 }
1830 else {
1831 DWORD ndx, bcast;
1832
1833 pIpAddrTable->dwNumEntries = 0;
1834 for (ndx = 0; ndx < table->numIndexes; ndx++) {
1835 pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
1836 pIpAddrTable->table[ndx].dwAddr =
1837 getInterfaceIPAddrByIndex(table->indexes[ndx]);
1838 pIpAddrTable->table[ndx].dwMask =
1839 getInterfaceMaskByIndex(table->indexes[ndx]);
1840 /* the dwBCastAddr member isn't the broadcast address, it indicates
1841 * whether the interface uses the 1's broadcast address (1) or the
1842 * 0's broadcast address (0).
1843 */
1844 bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
1845 pIpAddrTable->table[ndx].dwBCastAddr =
1846 (bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
1847 /* FIXME: hardcoded reasm size, not sure where to get it */
1848 pIpAddrTable->table[ndx].dwReasmSize = 65535;
1849 pIpAddrTable->table[ndx].unused1 = 0;
1850 pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
1851 pIpAddrTable->dwNumEntries++;
1852 }
1853 if (bOrder)
1854 qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1855 sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1856 ret = NO_ERROR;
1857 }
1858 free(table);
1859 }
1860 else
1861 ret = ERROR_OUTOFMEMORY;
1862 }
1863 }
1864 TRACE("returning %ld\n", ret);
1865 return ret;
1866 }
1867
1868
1869 static int IpForwardTableSorter(const void *a, const void *b)
1870 {
1871 int ret;
1872
1873 if (a && b) {
1874 PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
1875
1876 ret = rowA->dwForwardDest - rowB->dwForwardDest;
1877 if (ret == 0) {
1878 ret = rowA->dwForwardProto - rowB->dwForwardProto;
1879 if (ret == 0) {
1880 ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
1881 if (ret == 0)
1882 ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1883 }
1884 }
1885 }
1886 else
1887 ret = 0;
1888 return ret;
1889 }
1890
1891
1892 /******************************************************************
1893 * GetIpForwardTable (IPHLPAPI.@)
1894 *
1895 *
1896 * PARAMS
1897 *
1898 * pIpForwardTable [In/Out]
1899 * pdwSize [In/Out]
1900 * bOrder [In]
1901 *
1902 * RETURNS
1903 *
1904 * DWORD
1905 *
1906 */
1907 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1908 {
1909 DWORD ret;
1910
1911 TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
1912 pdwSize, (DWORD)bOrder);
1913 if (!pdwSize)
1914 ret = ERROR_INVALID_PARAMETER;
1915 else {
1916 DWORD numRoutes = getNumRoutes();
1917 ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1918 sizeof(MIB_IPFORWARDROW);
1919
1920 if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1921 *pdwSize = sizeNeeded;
1922 ret = ERROR_INSUFFICIENT_BUFFER;
1923 }
1924 else {
1925 RouteTable *table = getRouteTable();
1926 if (table) {
1927 sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1928 sizeof(MIB_IPFORWARDROW);
1929 if (*pdwSize < sizeNeeded) {
1930 *pdwSize = sizeNeeded;
1931 ret = ERROR_INSUFFICIENT_BUFFER;
1932 }
1933 else {
1934 DWORD ndx;
1935
1936 pIpForwardTable->dwNumEntries = table->numRoutes;
1937 for (ndx = 0; ndx < numRoutes; ndx++) {
1938 pIpForwardTable->table[ndx].dwForwardIfIndex =
1939 table->routes[ndx].ifIndex;
1940 pIpForwardTable->table[ndx].dwForwardDest =
1941 table->routes[ndx].dest;
1942 pIpForwardTable->table[ndx].dwForwardMask =
1943 table->routes[ndx].mask;
1944 pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1945 pIpForwardTable->table[ndx].dwForwardNextHop =
1946 table->routes[ndx].gateway;
1947 /* FIXME: this type is appropriate for local interfaces; may not
1948 always be appropriate */
1949 pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1950 /* FIXME: other protos might be appropriate, e.g. the default route
1951 is typically set with MIB_IPPROTO_NETMGMT instead */
1952 pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1953 /* punt on age and AS */
1954 pIpForwardTable->table[ndx].dwForwardAge = 0;
1955 pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1956 pIpForwardTable->table[ndx].dwForwardMetric1 =
1957 table->routes[ndx].metric;
1958 /* rest of the metrics are 0.. */
1959 pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1960 pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1961 pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1962 pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1963 }
1964 if (bOrder)
1965 qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1966 sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1967 ret = NO_ERROR;
1968 }
1969 HeapFree(GetProcessHeap(), 0, table);
1970 }
1971 else
1972 ret = ERROR_OUTOFMEMORY;
1973 }
1974 }
1975 TRACE("returning %ld\n", ret);
1976 return ret;
1977 }
1978
1979
1980 static int IpNetTableSorter(const void *a, const void *b)
1981 {
1982 int ret;
1983
1984 if (a && b)
1985 ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
1986 else
1987 ret = 0;
1988 return ret;
1989 }
1990
1991
1992 /******************************************************************
1993 * GetIpNetTable (IPHLPAPI.@)
1994 *
1995 *
1996 * PARAMS
1997 *
1998 * pIpNetTable [In/Out]
1999 * pdwSize [In/Out]
2000 * bOrder [In]
2001 *
2002 * RETURNS
2003 *
2004 * DWORD
2005 *
2006 */
2007 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
2008 {
2009 DWORD ret = NO_ERROR;
2010
2011 TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize,
2012 (DWORD)bOrder);
2013 if (!pdwSize)
2014 ret = ERROR_INVALID_PARAMETER;
2015 else {
2016 DWORD numEntries = getNumArpEntries();
2017 ULONG size = sizeof(MIB_IPNETTABLE);
2018
2019 if (numEntries > 1)
2020 size += (numEntries - 1) * sizeof(MIB_IPNETROW);
2021 if (!pIpNetTable || *pdwSize < size) {
2022 *pdwSize = size;
2023 ret = ERROR_INSUFFICIENT_BUFFER;
2024 }
2025 else {
2026 PMIB_IPNETTABLE table = getArpTable();
2027 if (table) {
2028 size = sizeof(MIB_IPNETTABLE);
2029 if (table->dwNumEntries > 1)
2030 size += (table->dwNumEntries - 1) * sizeof(MIB_IPNETROW);
2031 if (*pdwSize < size) {
2032 *pdwSize = size;
2033 ret = ERROR_INSUFFICIENT_BUFFER;
2034 }
2035 else {
2036 *pdwSize = size;
2037 memcpy(pIpNetTable, table, size);
2038 if (bOrder)
2039 qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
2040 sizeof(MIB_IPNETROW), IpNetTableSorter);
2041 ret = NO_ERROR;
2042 }
2043 HeapFree(GetProcessHeap(), 0, table);
2044 }
2045 }
2046 }
2047 TRACE("returning %d\n", ret);
2048 return ret;
2049 }
2050
2051
2052 /******************************************************************
2053 * GetIpStatistics (IPHLPAPI.@)
2054 *
2055 *
2056 * PARAMS
2057 *
2058 * pStats [In/Out]
2059 *
2060 * RETURNS
2061 *
2062 * DWORD
2063 *
2064 */
2065 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
2066 {
2067 return GetIpStatisticsEx(pStats, PF_INET);
2068 }
2069
2070 /******************************************************************
2071 * GetIpStatisticsEx (IPHLPAPI.@)
2072 *
2073 *
2074 * PARAMS
2075 *
2076 * pStats [In/Out]
2077 * dwFamily [In]
2078 *
2079 * RETURNS
2080 *
2081 * DWORD
2082 *
2083 */
2084 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily)
2085 {
2086 DWORD ret;
2087
2088 TRACE("pStats %p\n", pStats);
2089 ret = getIPStats(pStats, dwFamily);
2090 TRACE("returning %ld\n", ret);
2091 return ret;
2092 }
2093
2094 /******************************************************************
2095 * GetNetworkParams (IPHLPAPI.@)
2096 *
2097 *
2098 * PARAMS
2099 *
2100 * pFixedInfo [In/Out]
2101 * pOutBufLen [In/Out]
2102 *
2103 * RETURNS
2104 *
2105 * DWORD
2106 *
2107 */
2108 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
2109 {
2110 DWORD ret, size, type;
2111 LONG regReturn;
2112 HKEY hKey;
2113 PIPHLP_RES_INFO resInfo;
2114
2115 TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
2116 if (!pOutBufLen)
2117 return ERROR_INVALID_PARAMETER;
2118
2119 resInfo = getResInfo();
2120 if (!resInfo)
2121 return ERROR_OUTOFMEMORY;
2122
2123 size = sizeof(FIXED_INFO) + (resInfo->riCount > 1 ? (resInfo->riCount-1) *
2124 sizeof(IP_ADDR_STRING) : 0);
2125 if (!pFixedInfo || *pOutBufLen < size) {
2126 *pOutBufLen = size;
2127 disposeResInfo( resInfo );
2128 return ERROR_BUFFER_OVERFLOW;
2129 }
2130
2131 memset(pFixedInfo, 0, size);
2132 /* Check for DhcpHostname and DhcpDomain first */
2133 regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2134 "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
2135 0,
2136 KEY_READ,
2137 &hKey);
2138 if (regReturn == ERROR_SUCCESS) {
2139 /* Windows doesn't honor DHCP option 12 even if RFC requires it if it is returned by DHCP server! */
2140 #if 0
2141 type = REG_SZ;
2142 size = sizeof(pFixedInfo->HostName);
2143 regReturn = RegQueryValueExA(hKey,
2144 "DhcpHostname",
2145 NULL,
2146 &type,
2147 (LPBYTE)pFixedInfo->HostName,
2148 &size);
2149 if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
2150 {
2151 #endif
2152 type = REG_SZ;
2153 size = sizeof(pFixedInfo->HostName);
2154 regReturn = RegQueryValueExA(hKey,
2155 "Hostname",
2156 NULL,
2157 &type,
2158 (LPBYTE)pFixedInfo->HostName,
2159 &size);
2160 #if 0
2161 }
2162 #endif
2163
2164 type = REG_SZ;
2165 size = sizeof(pFixedInfo->DomainName);
2166 regReturn = RegQueryValueExA(hKey,
2167 "DhcpDomain",
2168 NULL,
2169 &type,
2170 (LPBYTE)pFixedInfo->DomainName,
2171 &size);
2172 if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
2173 {
2174 type = REG_SZ;
2175 size = sizeof(pFixedInfo->DomainName);
2176 regReturn = RegQueryValueExA(hKey,
2177 "Domain",
2178 NULL,
2179 &type,
2180 (LPBYTE)pFixedInfo->DomainName,
2181 &size);
2182 }
2183 RegCloseKey(hKey);
2184 }
2185
2186 TRACE("GetComputerNameExA: %s\n", pFixedInfo->DomainName);
2187
2188 if (resInfo->riCount > 0)
2189 {
2190 CopyMemory(&pFixedInfo->DnsServerList, resInfo->DnsList, sizeof(IP_ADDR_STRING));
2191 if (resInfo->riCount > 1)
2192 {
2193 IP_ADDR_STRING *pSrc = resInfo->DnsList->Next;
2194 IP_ADDR_STRING *pTarget = (struct _IP_ADDR_STRING*)((char*)pFixedInfo + sizeof(FIXED_INFO));
2195
2196 pFixedInfo->DnsServerList.Next = pTarget;
2197
2198 do
2199 {
2200 CopyMemory(pTarget, pSrc, sizeof(IP_ADDR_STRING));
2201 resInfo->riCount--;
2202 if (resInfo->riCount > 1)
2203 {
2204 pTarget->Next = (IP_ADDR_STRING*)((char*)pTarget + sizeof(IP_ADDR_STRING));
2205 pTarget = pTarget->Next;
2206 pSrc = pSrc->Next;
2207 }
2208 else
2209 {
2210 pTarget->Next = NULL;
2211 break;
2212 }
2213 }
2214 while(TRUE);
2215 }
2216 else
2217 {
2218 pFixedInfo->DnsServerList.Next = NULL;
2219 }
2220 }
2221
2222 pFixedInfo->NodeType = HYBRID_NODETYPE;
2223 regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2224 "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
2225 if (regReturn != ERROR_SUCCESS)
2226 regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2227 "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
2228 &hKey);
2229 if (regReturn == ERROR_SUCCESS)
2230 {
2231 DWORD size = sizeof(pFixedInfo->ScopeId);
2232
2233 RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (PBYTE)pFixedInfo->ScopeId, &size);
2234 RegCloseKey(hKey);
2235 }
2236
2237 disposeResInfo( resInfo );
2238 /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
2239 I suppose could also check for a listener on port 53 to set EnableDns */
2240 ret = NO_ERROR;
2241 TRACE("returning %ld\n", ret);
2242
2243 return ret;
2244 }
2245
2246
2247 /******************************************************************
2248 * GetNumberOfInterfaces (IPHLPAPI.@)
2249 *
2250 *
2251 * PARAMS
2252 *
2253 * pdwNumIf [In/Out]
2254 *
2255 * RETURNS
2256 *
2257 * DWORD
2258 *
2259 */
2260 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
2261 {
2262 DWORD ret;
2263
2264 TRACE("pdwNumIf %p\n", pdwNumIf);
2265 if (!pdwNumIf)
2266 ret = ERROR_INVALID_PARAMETER;
2267 else {
2268 *pdwNumIf = getNumInterfaces();
2269 ret = NO_ERROR;
2270 }
2271 TRACE("returning %ld\n", ret);
2272 return ret;
2273 }
2274
2275
2276 /******************************************************************
2277 * GetOwnerModuleFromTcpEntry (IPHLPAPI.@)
2278 *
2279 * Get data about the module that issued the context bind for a specific IPv4 TCP endpoint in a MIB table row
2280 *
2281 * PARAMS
2282 * pTcpEntry [in] pointer to a MIB_TCPROW_OWNER_MODULE structure
2283 * Class [in] TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2284 * Buffer [out] pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2285 * pdwSize [in, out] estimated size of the structure returned in Buffer, in bytes
2286 *
2287 * RETURNS
2288 * Success: NO_ERROR
2289 * Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2290 * ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2291 *
2292 * NOTES
2293 * The type of data returned in Buffer is indicated by the value of the Class parameter.
2294 */
2295 DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2296 {
2297 HANDLE Process;
2298 DWORD FileLen, PathLen;
2299 WCHAR File[MAX_PATH], Path[MAX_PATH];
2300 PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2301
2302 if (pTcpEntry->dwOwningPid == 0)
2303 {
2304 return ERROR_NOT_FOUND;
2305 }
2306
2307 Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pTcpEntry->dwOwningPid);
2308 if (Process == NULL)
2309 {
2310 return GetLastError();
2311 }
2312
2313 FileLen = GetModuleBaseNameW(Process, NULL, File, MAX_PATH);
2314 if (FileLen != 0)
2315 {
2316 PathLen = GetModuleFileNameExW(Process, NULL, Path, MAX_PATH);
2317 if (PathLen == 0)
2318 {
2319 CloseHandle(Process);
2320 return GetLastError();
2321 }
2322
2323 /* Add NULL char */
2324 ++FileLen;
2325 ++PathLen;
2326 PathLen *= sizeof(WCHAR);
2327 FileLen *= sizeof(WCHAR);
2328 }
2329 else if (GetLastError() == ERROR_PARTIAL_COPY)
2330 {
2331 wcscpy(File, L"System");
2332 wcscpy(Path, L"System");
2333
2334 PathLen = sizeof(L"System");
2335 FileLen = sizeof(L"System");
2336 }
2337
2338 CloseHandle(Process);
2339
2340 if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen)
2341 {
2342 *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2343 return ERROR_INSUFFICIENT_BUFFER;
2344 }
2345
2346 BasicInfo = Buffer;
2347 BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2348 BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + FileLen);
2349 wcscpy(BasicInfo->pModuleName, File);
2350 wcscpy(BasicInfo->pModulePath, Path);
2351 *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2352
2353 return NO_ERROR;
2354 }
2355
2356 static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
2357 {
2358 IP_ADDR_STRING *pNext;
2359 PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
2360
2361 if (!Context->NumServers)
2362 {
2363 if (Context->uSizeAvailable >= Context->uSizeRequired)
2364 {
2365 WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
2366 Context->pData->DnsServerList.IpAddress.String[15] = '\0';
2367 Context->pLastAddr = &Context->pData->DnsServerList;
2368 }
2369 }
2370 else
2371 {
2372 Context->uSizeRequired += sizeof(IP_ADDR_STRING);
2373 if (Context->uSizeAvailable >= Context->uSizeRequired)
2374 {
2375 pNext = (IP_ADDR_STRING*)(((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING));
2376 WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
2377 pNext->IpAddress.String[15] = '\0';
2378 Context->pLastAddr->Next = pNext;
2379 Context->pLastAddr = pNext;
2380 pNext->Next = NULL;
2381 }
2382 }
2383 Context->NumServers++;
2384 }
2385
2386 /******************************************************************
2387 * GetPerAdapterInfo (IPHLPAPI.@)
2388 *
2389 *
2390 * PARAMS
2391 *
2392 * IfIndex [In]
2393 * pPerAdapterInfo [In/Out]
2394 * pOutBufLen [In/Out]
2395 *
2396 * RETURNS
2397 *
2398 * DWORD
2399 *
2400 */
2401 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
2402 {
2403 HKEY hkey;
2404 DWORD dwSize = 0;
2405 const char *ifName;
2406 NAME_SERVER_LIST_CONTEXT Context;
2407 WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
2408
2409 if (!pOutBufLen)
2410 return ERROR_INVALID_PARAMETER;
2411
2412 if (!pPerAdapterInfo || *pOutBufLen < sizeof(IP_PER_ADAPTER_INFO))
2413 {
2414 *pOutBufLen = sizeof(IP_PER_ADAPTER_INFO);
2415 return ERROR_BUFFER_OVERFLOW;
2416 }
2417
2418 ifName = getInterfaceNameByIndex(IfIndex);
2419 if (!ifName)
2420 return ERROR_INVALID_PARAMETER;
2421
2422 MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
2423 HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
2424
2425 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
2426 {
2427 return ERROR_NOT_SUPPORTED;
2428 }
2429 Context.NumServers = 0;
2430 Context.uSizeAvailable = *pOutBufLen;
2431 Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
2432 Context.pData = pPerAdapterInfo;
2433
2434 if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
2435 ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
2436
2437 EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
2438
2439 if (Context.uSizeRequired > Context.uSizeAvailable)
2440 {
2441 *pOutBufLen = Context.uSizeRequired;
2442 RegCloseKey(hkey);
2443 return ERROR_BUFFER_OVERFLOW;
2444 }
2445
2446 if(RegQueryValueExW(hkey, L"NameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
2447 {
2448 pPerAdapterInfo->AutoconfigActive = FALSE;
2449 }
2450 else
2451 {
2452 pPerAdapterInfo->AutoconfigActive = TRUE;
2453 }
2454
2455 RegCloseKey(hkey);
2456 return NOERROR;
2457 }
2458
2459
2460 /******************************************************************
2461 * GetRTTAndHopCount (IPHLPAPI.@)
2462 *
2463 *
2464 * PARAMS
2465 *
2466 * DestIpAddress [In]
2467 * HopCount [In/Out]
2468 * MaxHops [In]
2469 * RTT [In/Out]
2470 *
2471 * RETURNS
2472 *
2473 * BOOL
2474 *
2475 */
2476 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2477 {
2478 TRACE("DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p\n",
2479 DestIpAddress, HopCount, MaxHops, RTT);
2480 FIXME(":stub\n");
2481 return (BOOL) 0;
2482 }
2483
2484
2485 /******************************************************************
2486 * GetTcpStatisticsEx (IPHLPAPI.@)
2487 *
2488 *
2489 * PARAMS
2490 *
2491 * pStats [In/Out]
2492 * dwFamily [In]
2493 *
2494 * RETURNS
2495 *
2496 * DWORD
2497 *
2498 */
2499 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily)
2500 {
2501 DWORD ret;
2502
2503 TRACE("pStats %p\n", pStats);
2504 ret = getTCPStats(pStats, dwFamily);
2505 TRACE("returning %ld\n", ret);
2506 return ret;
2507 }
2508
2509 /******************************************************************
2510 * GetTcpStatistics (IPHLPAPI.@)
2511 *
2512 *
2513 * PARAMS
2514 *
2515 * pStats [In/Out]
2516 *
2517 * RETURNS
2518 *
2519 * DWORD
2520 *
2521 */
2522 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
2523 {
2524 return GetTcpStatisticsEx(pStats, PF_INET);
2525 }
2526
2527
2528 /******************************************************************
2529 * GetTcpTable (IPHLPAPI.@)
2530 *
2531 * Get the table of active TCP connections.
2532 *
2533 * PARAMS
2534 * pTcpTable [Out] buffer for TCP connections table
2535 * pdwSize [In/Out] length of output buffer
2536 * bOrder [In] whether to order the table
2537 *
2538 * RETURNS
2539 * Success: NO_ERROR
2540 * Failure: error code from winerror.h
2541 *
2542 * NOTES
2543 * If pdwSize is less than required, the function will return
2544 * ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
2545 * the required byte size.
2546 * If bOrder is true, the returned table will be sorted, first by
2547 * local address and port number, then by remote address and port
2548 * number.
2549 */
2550 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
2551 {
2552 return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, AF_INET, TCP_TABLE_BASIC_ALL, 0);
2553 }
2554
2555
2556 /******************************************************************
2557 * GetUdpStatisticsEx (IPHLPAPI.@)
2558 *
2559 *
2560 * PARAMS
2561 *
2562 * pStats [In/Out]
2563 * dwFamily [In]
2564 *
2565 * RETURNS
2566 *
2567 * DWORD
2568 *
2569 */
2570 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS pStats, DWORD dwFamily)
2571 {
2572 DWORD ret;
2573
2574 TRACE("pStats %p\n", pStats);
2575 ret = getUDPStats(pStats, dwFamily);
2576 TRACE("returning %ld\n", ret);
2577 return ret;
2578 }
2579
2580 /******************************************************************
2581 * GetUdpStatistics (IPHLPAPI.@)
2582 *
2583 *
2584 * PARAMS
2585 *
2586 * pStats [In/Out]
2587 *
2588 * RETURNS
2589 *
2590 * DWORD
2591 *
2592 */
2593 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
2594 {
2595 return GetUdpStatisticsEx(pStats, PF_INET);
2596 }
2597
2598
2599 /******************************************************************
2600 * GetUdpTable (IPHLPAPI.@)
2601 *
2602 *
2603 * PARAMS
2604 *
2605 * pUdpTable [In/Out]
2606 * pdwSize [In/Out]
2607 * bOrder [In]
2608 *
2609 * RETURNS
2610 *
2611 * DWORD
2612 *
2613 */
2614 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2615 {
2616 return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, AF_INET, UDP_TABLE_BASIC, 0);
2617 }
2618
2619
2620 /******************************************************************
2621 * GetUniDirectionalAdapterInfo (IPHLPAPI.@)
2622 *
2623 * This is a Win98-only function to get information on "unidirectional"
2624 * adapters. Since this is pretty nonsensical in other contexts, it
2625 * never returns anything.
2626 *
2627 * PARAMS
2628 * pIPIfInfo [Out] buffer for adapter infos
2629 * dwOutBufLen [Out] length of the output buffer
2630 *
2631 * RETURNS
2632 * Success: NO_ERROR
2633 * Failure: error code from winerror.h
2634 *
2635 * FIXME
2636 * Stub, returns ERROR_NOT_SUPPORTED.
2637 */
2638 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
2639 {
2640 TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
2641 /* a unidirectional adapter?? not bloody likely! */
2642 return ERROR_NOT_SUPPORTED;
2643 }
2644
2645
2646 /******************************************************************
2647 * IpReleaseAddress (IPHLPAPI.@)
2648 *
2649 * Release an IP obtained through DHCP,
2650 *
2651 * PARAMS
2652 * AdapterInfo [In] adapter to release IP address
2653 *
2654 * RETURNS
2655 * Success: NO_ERROR
2656 * Failure: error code from winerror.h
2657 *
2658 */
2659 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2660 {
2661 DWORD Status, Version = 0;
2662
2663 if (!AdapterInfo)
2664 return ERROR_INVALID_PARAMETER;
2665
2666 /* Maybe we should do this in DllMain */
2667 if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2668 return ERROR_PROC_NOT_FOUND;
2669
2670 if (DhcpReleaseIpAddressLease(AdapterInfo->Index))
2671 Status = ERROR_SUCCESS;
2672 else
2673 Status = ERROR_PROC_NOT_FOUND;
2674
2675 DhcpCApiCleanup();
2676
2677 return Status;
2678 }
2679
2680
2681 /******************************************************************
2682 * IpRenewAddress (IPHLPAPI.@)
2683 *
2684 * Renew an IP obtained through DHCP.
2685 *
2686 * PARAMS
2687 * AdapterInfo [In] adapter to renew IP address
2688 *
2689 * RETURNS
2690 * Success: NO_ERROR
2691 * Failure: error code from winerror.h
2692 */
2693 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2694 {
2695 DWORD Status, Version = 0;
2696
2697 if (!AdapterInfo)
2698 return ERROR_INVALID_PARAMETER;
2699
2700 /* Maybe we should do this in DllMain */
2701 if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2702 return ERROR_PROC_NOT_FOUND;
2703
2704 if (DhcpRenewIpAddressLease(AdapterInfo->Index))
2705 Status = ERROR_SUCCESS;
2706 else
2707 Status = ERROR_PROC_NOT_FOUND;
2708
2709 DhcpCApiCleanup();
2710
2711 return Status;
2712 }
2713
2714
2715 /******************************************************************
2716 * NotifyAddrChange (IPHLPAPI.@)
2717 *
2718 * Notify caller whenever the ip-interface map is changed.
2719 *
2720 * PARAMS
2721 * Handle [Out] handle usable in asynchronous notification
2722 * overlapped [In] overlapped structure that notifies the caller
2723 *
2724 * RETURNS
2725 * Success: NO_ERROR
2726 * Failure: error code from winerror.h
2727 *
2728 * FIXME
2729 * Stub, returns ERROR_NOT_SUPPORTED.
2730 */
2731 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2732 {
2733 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2734 if (Handle) *Handle = INVALID_HANDLE_VALUE;
2735 if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING;
2736 return ERROR_IO_PENDING;
2737 }
2738
2739
2740 /******************************************************************
2741 * NotifyRouteChange (IPHLPAPI.@)
2742 *
2743 * Notify caller whenever the ip routing table is changed.
2744 *
2745 * PARAMS
2746 * Handle [Out] handle usable in asynchronous notification
2747 * overlapped [In] overlapped structure that notifies the caller
2748 *
2749 * RETURNS
2750 * Success: NO_ERROR
2751 * Failure: error code from winerror.h
2752 *
2753 * FIXME
2754 * Stub, returns ERROR_NOT_SUPPORTED.
2755 */
2756 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2757 {
2758 FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2759 return ERROR_NOT_SUPPORTED;
2760 }
2761
2762 /******************************************************************
2763 * SendARP (IPHLPAPI.@)
2764 *
2765 * Send an ARP request.
2766 *
2767 * PARAMS
2768 * DestIP [In] attempt to obtain this IP
2769 * SrcIP [In] optional sender IP address
2770 * pMacAddr [Out] buffer for the mac address
2771 * PhyAddrLen [In/Out] length of the output buffer
2772 *
2773 * RETURNS
2774 * Success: NO_ERROR
2775 * Failure: error code from winerror.h
2776 */
2777 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2778 {
2779 IPAddr IPs[2];
2780 ULONG Size;
2781
2782 if (IsBadWritePtr(pMacAddr, sizeof(ULONG)) || IsBadWritePtr(PhyAddrLen, sizeof(ULONG)))
2783 return ERROR_INVALID_PARAMETER;
2784
2785 IPs[0] = DestIP;
2786 IPs[1] = SrcIP;
2787 Size = sizeof(IPs);
2788 return TCPSendIoctl(INVALID_HANDLE_VALUE, IOCTL_QUERY_IP_HW_ADDRESS, IPs, &Size, pMacAddr, PhyAddrLen);
2789 }
2790
2791
2792 /******************************************************************
2793 * SetIfEntry (IPHLPAPI.@)
2794 *
2795 * Set the administrative status of an interface.
2796 *
2797 * PARAMS
2798 * pIfRow [In] dwAdminStatus member specifies the new status.
2799 *
2800 * RETURNS
2801 * Success: NO_ERROR
2802 * Failure: error code from winerror.h
2803 *
2804 * FIXME
2805 * Stub, returns ERROR_NOT_SUPPORTED.
2806 */
2807 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
2808 {
2809 FIXME("(pIfRow %p): stub\n", pIfRow);
2810 /* this is supposed to set an interface administratively up or down.
2811 Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2812 this sort of down is indistinguishable from other sorts of down (e.g. no
2813 link). */
2814 return ERROR_NOT_SUPPORTED;
2815 }
2816
2817
2818 /******************************************************************
2819 * SetIpForwardEntry (IPHLPAPI.@)
2820 *
2821 * Modify an existing route.
2822 *
2823 * PARAMS
2824 * pRoute [In] route with the new information
2825 *
2826 * RETURNS
2827 * Success: NO_ERROR
2828 * Failure: error code from winerror.h
2829 *
2830 */
2831 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
2832 {
2833 return setIpForwardEntry( pRoute );
2834 }
2835
2836
2837 /******************************************************************
2838 * SetIpNetEntry (IPHLPAPI.@)
2839 *
2840 * Modify an existing ARP entry.
2841 *
2842 * PARAMS
2843 * pArpEntry [In] ARP entry with the new information
2844 *
2845 * RETURNS
2846 * Success: NO_ERROR
2847 * Failure: error code from winerror.h
2848 */
2849 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
2850 {
2851 HANDLE tcpFile;
2852 NTSTATUS status;
2853 TCP_REQUEST_SET_INFORMATION_EX_ARP_ENTRY req =
2854 TCP_REQUEST_SET_INFORMATION_INIT;
2855 TDIEntityID id;
2856 DWORD returnSize;
2857 PMIB_IPNETROW arpBuff;
2858
2859 if (!pArpEntry)
2860 return ERROR_INVALID_PARAMETER;
2861
2862 if (!NT_SUCCESS(openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA )))
2863 return ERROR_NOT_SUPPORTED;
2864
2865 if (!NT_SUCCESS(getNthIpEntity( tcpFile, pArpEntry->dwIndex, &id )))
2866 {
2867 closeTcpFile(tcpFile);
2868 return ERROR_INVALID_PARAMETER;
2869 }
2870
2871 req.Req.ID.toi_class = INFO_CLASS_PROTOCOL;
2872 req.Req.ID.toi_type = INFO_TYPE_PROVIDER;
2873 req.Req.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
2874 req.Req.ID.toi_entity.tei_instance = id.tei_instance;
2875 req.Req.ID.toi_entity.tei_entity = AT_ENTITY;
2876 req.Req.BufferSize = sizeof(MIB_IPNETROW);
2877 arpBuff = (PMIB_IPNETROW)&req.Req.Buffer[0];
2878
2879 RtlCopyMemory(arpBuff, pArpEntry, sizeof(MIB_IPNETROW));
2880
2881 status = DeviceIoControl( tcpFile,
2882 IOCTL_TCP_SET_INFORMATION_EX,
2883 &req,
2884 sizeof(req),
2885 NULL,
2886 0,
2887 &returnSize,
2888 NULL );
2889
2890 closeTcpFile(tcpFile);
2891
2892 if (status)
2893 return NO_ERROR;
2894 else
2895 return ERROR_INVALID_PARAMETER;
2896 }
2897
2898
2899 /******************************************************************
2900 * SetIpStatistics (IPHLPAPI.@)
2901 *
2902 * Toggle IP forwarding and det the default TTL value.
2903 *
2904 * PARAMS
2905 * pIpStats [In] IP statistics with the new information
2906 *
2907 * RETURNS
2908 * Success: NO_ERROR
2909 * Failure: error code from winerror.h
2910 *
2911 * FIXME
2912 * Stub, returns NO_ERROR.
2913 */
2914 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
2915 {
2916 FIXME("(pIpStats %p): stub\n", pIpStats);
2917 return 0;
2918 }
2919
2920
2921 /******************************************************************
2922 * SetIpTTL (IPHLPAPI.@)
2923 *
2924 * Set the default TTL value.
2925 *
2926 * PARAMS
2927 * nTTL [In] new TTL value
2928 *
2929 * RETURNS
2930 * Success: NO_ERROR
2931 * Failure: error code from winerror.h
2932 *
2933 * FIXME
2934 * Stub, returns NO_ERROR.
2935 */
2936 DWORD WINAPI SetIpTTL(UINT nTTL)
2937 {
2938 FIXME("(nTTL %d): stub\n", nTTL);
2939 return 0;
2940 }
2941
2942
2943 /******************************************************************
2944 * SetTcpEntry (IPHLPAPI.@)
2945 *
2946 * Set the state of a TCP connection.
2947 *
2948 * PARAMS
2949 * pTcpRow [In] specifies connection with new state
2950 *
2951 * RETURNS
2952 * Success: NO_ERROR
2953 * Failure: error code from winerror.h
2954 *
2955 * FIXME
2956 * Stub, returns NO_ERROR.
2957 */
2958 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
2959 {
2960 FIXME("(pTcpRow %p): stub\n", pTcpRow);
2961 return 0;
2962 }
2963
2964
2965 /******************************************************************
2966 * UnenableRouter (IPHLPAPI.@)
2967 *
2968 * Decrement the IP-forwarding reference count. Turn off IP-forwarding
2969 * if it reaches zero.
2970 *
2971 * PARAMS
2972 * pOverlapped [In/Out] should be the same as in EnableRouter()
2973 * lpdwEnableCount [Out] optional, receives reference count
2974 *
2975 * RETURNS
2976 * Success: NO_ERROR
2977 * Failure: error code from winerror.h
2978 *
2979 * FIXME
2980 * Stub, returns ERROR_NOT_SUPPORTED.
2981 */
2982 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
2983 {
2984 FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
2985 lpdwEnableCount);
2986 return ERROR_NOT_SUPPORTED;
2987 }
2988
2989 /*
2990 * @unimplemented
2991 */
2992 DWORD WINAPI GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)
2993 {
2994 FIXME(":stub\n");
2995 return 0L;
2996 }
2997
2998
2999 /*
3000 * @unimplemented
3001 */
3002 PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
3003 {
3004 FIXME(":stub\n");
3005 return 0L;
3006 }
3007
3008 /*
3009 * @implemented
3010 */
3011 #ifdef GetAdaptersAddressesV1
3012 DWORD WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
3013 {
3014 InterfaceIndexTable *indexTable;
3015 IFInfo ifInfo;
3016 int i;
3017 ULONG ret, requiredSize = 0;
3018 PIP_ADAPTER_ADDRESSES currentAddress;
3019 PUCHAR currentLocation;
3020 HANDLE tcpFile;
3021
3022 if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
3023 if (Reserved) return ERROR_INVALID_PARAMETER;
3024
3025 indexTable = getInterfaceIndexTable();
3026 if (!indexTable)
3027 return ERROR_NOT_ENOUGH_MEMORY;
3028
3029 ret = openTcpFile(&tcpFile, FILE_READ_DATA);
3030 if (!NT_SUCCESS(ret))
3031 return ERROR_NO_DATA;
3032
3033 for (i = indexTable->numIndexes; i >= 0; i--)
3034 {
3035 if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3036 NULL,
3037 indexTable->indexes[i],
3038 &ifInfo)))
3039 {
3040 /* The whole struct */
3041 requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
3042
3043 /* Friendly name */
3044 if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3045 requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1; //FIXME
3046
3047 /* Adapter name */
3048 requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
3049
3050 /* Unicast address */
3051 if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3052 requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3053
3054 /* FIXME: Implement multicast, anycast, and dns server stuff */
3055
3056 /* FIXME: Implement dns suffix and description */
3057 requiredSize += 2 * sizeof(WCHAR);
3058
3059 /* We're only going to implement what's required for XP SP0 */
3060 }
3061 }
3062 TRACE("size: %d, requiredSize: %d\n", *pOutBufLen, requiredSize);
3063 if (!pAdapterAddresses || *pOutBufLen < requiredSize)
3064 {
3065 *pOutBufLen = requiredSize;
3066 closeTcpFile(tcpFile);
3067 free(indexTable);
3068 return ERROR_BUFFER_OVERFLOW;
3069 }
3070
3071 RtlZeroMemory(pAdapterAddresses, requiredSize);
3072
3073 /* Let's set up the pointers */
3074 currentAddress = pAdapterAddresses;
3075 for (i = indexTable->numIndexes; i >= 0; i--)
3076 {
3077 if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3078 NULL,
3079 indexTable->indexes[i],
3080 &ifInfo)))
3081 {
3082 currentLocation = (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
3083
3084 /* FIXME: Friendly name */
3085 if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3086 {
3087 currentAddress->FriendlyName = (PVOID)currentLocation;
3088 currentLocation += sizeof(WCHAR);
3089 }
3090
3091 /* Adapter name */
3092 currentAddress->AdapterName = (PVOID)currentLocation;
3093 currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
3094
3095 /* Unicast address */
3096 if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3097 {
3098 currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
3099 currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3100 currentAddress->FirstUnicastAddress->Address.lpSockaddr = (PVOID)currentLocation;
3101 currentLocation += sizeof(struct sockaddr);
3102 }
3103
3104 /* FIXME: Implement multicast, anycast, and dns server stuff */
3105
3106 /* FIXME: Implement dns suffix and description */
3107 currentAddress->DnsSuffix = (PVOID)currentLocation;
3108 currentLocation += sizeof(WCHAR);
3109
3110 currentAddress->Description = (PVOID)currentLocation;
3111 currentLocation += sizeof(WCHAR);
3112
3113 currentAddress->Next = (PVOID)currentLocation;
3114 /* Terminate the last address correctly */
3115 if(i==0)
3116 currentAddress->Next = NULL;
3117
3118 /* We're only going to implement what's required for XP SP0 */
3119
3120 currentAddress = currentAddress->Next;
3121 }
3122 }
3123
3124 /* Now again, for real this time */
3125
3126 currentAddress = pAdapterAddresses;
3127 for (i = indexTable->numIndexes; i >= 0; i--)
3128 {
3129 if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3130 NULL,
3131 indexTable->indexes[i],
3132 &ifInfo)))
3133 {
3134 /* Make sure we're not looping more than we hoped for */
3135 ASSERT(currentAddress);
3136
3137 /* Alignment information */
3138 currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
3139 currentAddress->IfIndex = indexTable->indexes[i];
3140
3141 /* Adapter name */
3142 strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr);
3143
3144 if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3145 {
3146 currentAddress->FirstUnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3147 currentAddress->FirstUnicastAddress->Flags = 0; //FIXME
3148 currentAddress->FirstUnicastAddress->Next = NULL; //FIXME: Support more than one address per adapter
3149 currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
3150 memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
3151 &ifInfo.ip_addr.iae_addr,
3152 sizeof(ifInfo.ip_addr.iae_addr));
3153 currentAddress->FirstUnicastAddress->Address.iSockaddrLength = sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
3154 currentAddress->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; //FIXME
3155 currentAddress->FirstUnicastAddress->SuffixOrigin = IpPrefixOriginOther; //FIXME
3156 currentAddress->FirstUnicastAddress->DadState = IpDadStatePreferred; //FIXME
3157 currentAddress->FirstUnicastAddress->ValidLifetime = 0xFFFFFFFF; //FIXME
3158 currentAddress->FirstUnicastAddress->PreferredLifetime = 0xFFFFFFFF; //FIXME
3159 currentAddress->FirstUnicastAddress->LeaseLifetime = 0xFFFFFFFF; //FIXME
3160 }
3161
3162 /* FIXME: Implement multicast, anycast, and dns server stuff */
3163 currentAddress->FirstAnycastAddress = NULL;
3164 currentAddress->FirstMulticastAddress = NULL;
3165 currentAddress->FirstDnsServerAddress = NULL;
3166
3167 /* FIXME: Implement dns suffix, description, and friendly name */
3168 currentAddress->DnsSuffix[0] = UNICODE_NULL;
3169 currentAddress->Description[0] = UNICODE_NULL;
3170 currentAddress->FriendlyName[0] = UNICODE_NULL;
3171
3172 /* Physical Address */
3173 memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, ifInfo.if_info.ent.if_physaddrlen);
3174 currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
3175
3176 /* Flags */
3177 currentAddress->Flags = 0; //FIXME
3178
3179 /* MTU */
3180 currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
3181
3182 /* Interface type */
3183 currentAddress->IfType = ifInfo.if_info.ent.if_type;
3184
3185 /* Operational status */
3186 if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
3187 currentAddress->OperStatus = IfOperStatusUp;
3188 else
3189 currentAddress->OperStatus = IfOperStatusDown;
3190
3191 /* We're only going to implement what's required for XP SP0 */
3192
3193 /* Move to the next address */
3194 currentAddress = currentAddress->Next;
3195 }
3196 }
3197
3198 closeTcpFile(tcpFile);
3199 free(indexTable);
3200
3201 return NO_ERROR;
3202 }
3203 #endif
3204
3205 /*
3206 * @unimplemented
3207 */
3208 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)
3209 {
3210 FIXME(":stub\n");
3211 return 0L;
3212 }
3213
3214 /*
3215 * @unimplemented
3216 */
3217 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex)
3218 {
3219 FIXME(":stub\n");
3220 return 0L;
3221 }
3222
3223 /*
3224 * @unimplemented
3225 */
3226 DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)
3227 {
3228 FIXME(":stub\n");
3229 return 0L;
3230 }
3231
3232 /*
3233 * @unimplemented
3234 */
3235 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
3236 {
3237 FIXME(":stub\n");
3238
3239 if (!pStats)
3240 return ERROR_INVALID_PARAMETER;
3241
3242 if (dwFamily != AF_INET && dwFamily != AF_INET6)
3243 return ERROR_INVALID_PARAMETER;
3244
3245 return 0L;
3246 }
3247
3248 DWORD WINAPI
3249 SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)
3250 {
3251 FIXME("SetIpForwardEntryToStack() stub\n");
3252 return 0L;
3253 }
3254
3255 DWORD GetInterfaceNameInternal(_In_ const GUID * pInterfaceGUID,
3256 _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3257 _Inout_ PULONG pOutBufLen)
3258 {
3259 UNICODE_STRING GuidString;
3260 DWORD result, type;
3261 WCHAR szKeyName[2*MAX_PATH];
3262 HRESULT hr;
3263 HKEY hKey;
3264
3265 if (pInterfaceGUID == NULL || pOutBufLen == NULL)
3266 return ERROR_INVALID_PARAMETER;
3267
3268 result = RtlStringFromGUID(pInterfaceGUID, &GuidString);
3269
3270 if (!NT_SUCCESS(result))
3271 {
3272 // failed to convert guid to string
3273 return RtlNtStatusToDosError(result);
3274 }
3275
3276 hr = StringCbPrintfW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", GuidString.Buffer);
3277 RtlFreeUnicodeString(&GuidString);
3278
3279 if (FAILED(hr))
3280 {
3281 // key name is too long
3282 return ERROR_BUFFER_OVERFLOW;
3283 }
3284
3285 result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKey);
3286
3287 if (result != ERROR_SUCCESS)
3288 {
3289 // failed to find adapter entry
3290 return ERROR_NOT_FOUND;
3291 }
3292
3293 result = RegQueryValueExW(hKey, L"Name", NULL, &type, (PVOID)pInterfaceName, pOutBufLen);
3294
3295 RegCloseKey(hKey);
3296
3297 if (result == ERROR_MORE_DATA)
3298 {
3299 *pOutBufLen = MAX_INTERFACE_NAME_LEN * 2;
3300 return ERROR_INSUFFICIENT_BUFFER;
3301 }
3302
3303 if (result != ERROR_SUCCESS || type != REG_SZ)
3304 {
3305 // failed to read adapter name
3306 return ERROR_NO_DATA;
3307 }
3308 return ERROR_SUCCESS;
3309 }
3310
3311 /*
3312 * @implemented
3313 */
3314 DWORD WINAPI
3315 NhGetInterfaceNameFromDeviceGuid(_In_ const GUID * pInterfaceGUID,
3316 _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3317 _Inout_ PULONG pOutBufLen,
3318 DWORD dwUnknown4,
3319 DWORD dwUnknown5)
3320 {
3321 SetLastError(ERROR_SUCCESS);
3322
3323 if (pInterfaceName == NULL)
3324 return ERROR_INVALID_PARAMETER;
3325
3326 return GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3327 }
3328
3329 /*
3330 * @implemented
3331 */