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