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