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