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