1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS TCP/IP protocol driver 4 * FILE: datalink/lan.c 5 * PURPOSE: Local Area Network media routines 6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 * REVISIONS: 8 * CSH 01/08-2000 Created 9 */ 10 11 #include "precomp.h" 12 13 #include <ntifs.h> 14 #include <receive.h> 15 #include <wait.h> 16 17 UINT TransferDataCalled = 0; 18 UINT TransferDataCompleteCalled = 0; 19 20 #define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet" 21 #define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}" 22 23 typedef struct _LAN_WQ_ITEM { 24 LIST_ENTRY ListEntry; 25 PNDIS_PACKET Packet; 26 PLAN_ADAPTER Adapter; 27 UINT BytesTransferred; 28 BOOLEAN LegacyReceive; 29 } LAN_WQ_ITEM, *PLAN_WQ_ITEM; 30 31 typedef struct _RECONFIGURE_CONTEXT { 32 ULONG State; 33 PLAN_ADAPTER Adapter; 34 } RECONFIGURE_CONTEXT, *PRECONFIGURE_CONTEXT; 35 36 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL; 37 BOOLEAN ProtocolRegistered = FALSE; 38 LIST_ENTRY AdapterListHead; 39 KSPIN_LOCK AdapterListLock; 40 41 NDIS_STATUS NDISCall( 42 PLAN_ADAPTER Adapter, 43 NDIS_REQUEST_TYPE Type, 44 NDIS_OID OID, 45 PVOID Buffer, 46 UINT Length) 47 /* 48 * FUNCTION: Send a request to NDIS 49 * ARGUMENTS: 50 * Adapter = Pointer to a LAN_ADAPTER structure 51 * Type = Type of request (Set or Query) 52 * OID = Value to be set/queried for 53 * Buffer = Pointer to a buffer to use 54 * Length = Number of bytes in Buffer 55 * RETURNS: 56 * Status of operation 57 */ 58 { 59 NDIS_REQUEST Request; 60 NDIS_STATUS NdisStatus; 61 62 Request.RequestType = Type; 63 if (Type == NdisRequestSetInformation) { 64 Request.DATA.SET_INFORMATION.Oid = OID; 65 Request.DATA.SET_INFORMATION.InformationBuffer = Buffer; 66 Request.DATA.SET_INFORMATION.InformationBufferLength = Length; 67 } else { 68 Request.DATA.QUERY_INFORMATION.Oid = OID; 69 Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer; 70 Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length; 71 } 72 73 if (Adapter->State != LAN_STATE_RESETTING) { 74 NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request); 75 } else { 76 NdisStatus = NDIS_STATUS_NOT_ACCEPTED; 77 } 78 79 /* Wait for NDIS to complete the request */ 80 if (NdisStatus == NDIS_STATUS_PENDING) { 81 KeWaitForSingleObject(&Adapter->Event, 82 UserRequest, 83 KernelMode, 84 FALSE, 85 NULL); 86 NdisStatus = Adapter->NdisStatus; 87 } 88 89 return NdisStatus; 90 } 91 92 /* Used by legacy ProtocolReceive for packet type */ 93 NDIS_STATUS 94 GetPacketTypeFromHeaderBuffer(PLAN_ADAPTER Adapter, 95 PVOID HeaderBuffer, 96 ULONG HeaderBufferSize, 97 PULONG PacketType) 98 { 99 PETH_HEADER EthHeader = HeaderBuffer; 100 101 if (HeaderBufferSize < Adapter->HeaderSize) 102 { 103 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", HeaderBufferSize)); 104 return NDIS_STATUS_NOT_ACCEPTED; 105 } 106 107 switch (Adapter->Media) 108 { 109 case NdisMedium802_3: 110 /* Ethernet and IEEE 802.3 frames can be distinguished by 111 looking at the IEEE 802.3 length field. This field is 112 less than or equal to 1500 for a valid IEEE 802.3 frame 113 and larger than 1500 is it's a valid EtherType value. 114 See RFC 1122, section 2.3.3 for more information */ 115 116 *PacketType = EthHeader->EType; 117 break; 118 119 default: 120 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n")); 121 122 /* FIXME: Support other medias */ 123 return NDIS_STATUS_NOT_ACCEPTED; 124 } 125 126 TI_DbgPrint(DEBUG_DATALINK, ("EtherType (0x%X).\n", *PacketType)); 127 128 return NDIS_STATUS_SUCCESS; 129 } 130 131 /* Used by ProtocolReceivePacket for packet type */ 132 NDIS_STATUS 133 GetPacketTypeFromNdisPacket(PLAN_ADAPTER Adapter, 134 PNDIS_PACKET NdisPacket, 135 PULONG PacketType) 136 { 137 PVOID HeaderBuffer; 138 ULONG BytesCopied; 139 NDIS_STATUS Status; 140 141 HeaderBuffer = ExAllocatePoolWithTag(NonPagedPool, 142 Adapter->HeaderSize, 143 HEADER_TAG); 144 if (!HeaderBuffer) 145 return NDIS_STATUS_RESOURCES; 146 147 /* Copy the media header */ 148 BytesCopied = CopyPacketToBuffer(HeaderBuffer, 149 NdisPacket, 150 0, 151 Adapter->HeaderSize); 152 if (BytesCopied != Adapter->HeaderSize) 153 { 154 /* Runt frame */ 155 ExFreePoolWithTag(HeaderBuffer, HEADER_TAG); 156 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", BytesCopied)); 157 return NDIS_STATUS_NOT_ACCEPTED; 158 } 159 160 Status = GetPacketTypeFromHeaderBuffer(Adapter, 161 HeaderBuffer, 162 BytesCopied, 163 PacketType); 164 165 ExFreePoolWithTag(HeaderBuffer, HEADER_TAG); 166 167 return Status; 168 } 169 170 171 VOID FreeAdapter( 172 PLAN_ADAPTER Adapter) 173 /* 174 * FUNCTION: Frees memory for a LAN_ADAPTER structure 175 * ARGUMENTS: 176 * Adapter = Pointer to LAN_ADAPTER structure to free 177 */ 178 { 179 ExFreePoolWithTag(Adapter, LAN_ADAPTER_TAG); 180 } 181 182 183 NTSTATUS TcpipLanGetDwordOid 184 ( PIP_INTERFACE Interface, 185 NDIS_OID Oid, 186 PULONG Result ) { 187 /* Get maximum frame size */ 188 if( Interface->Context ) { 189 return NDISCall((PLAN_ADAPTER)Interface->Context, 190 NdisRequestQueryInformation, 191 Oid, 192 Result, 193 sizeof(ULONG)); 194 } else switch( Oid ) { /* Loopback Case */ 195 case OID_GEN_HARDWARE_STATUS: 196 *Result = NdisHardwareStatusReady; 197 return STATUS_SUCCESS; 198 case OID_GEN_MEDIA_CONNECT_STATUS: 199 *Result = NdisMediaStateConnected; 200 return STATUS_SUCCESS; 201 default: 202 return STATUS_INVALID_PARAMETER; 203 } 204 } 205 206 207 VOID NTAPI ProtocolOpenAdapterComplete( 208 NDIS_HANDLE BindingContext, 209 NDIS_STATUS Status, 210 NDIS_STATUS OpenErrorStatus) 211 /* 212 * FUNCTION: Called by NDIS to complete opening of an adapter 213 * ARGUMENTS: 214 * BindingContext = Pointer to a device context (LAN_ADAPTER) 215 * Status = Status of the operation 216 * OpenErrorStatus = Additional status information 217 */ 218 { 219 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; 220 221 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 222 223 Adapter->NdisStatus = Status; 224 225 KeSetEvent(&Adapter->Event, 0, FALSE); 226 } 227 228 229 VOID NTAPI ProtocolCloseAdapterComplete( 230 NDIS_HANDLE BindingContext, 231 NDIS_STATUS Status) 232 /* 233 * FUNCTION: Called by NDIS to complete closing an adapter 234 * ARGUMENTS: 235 * BindingContext = Pointer to a device context (LAN_ADAPTER) 236 * Status = Status of the operation 237 */ 238 { 239 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; 240 241 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 242 243 Adapter->NdisStatus = Status; 244 245 KeSetEvent(&Adapter->Event, 0, FALSE); 246 } 247 248 249 VOID NTAPI ProtocolResetComplete( 250 NDIS_HANDLE BindingContext, 251 NDIS_STATUS Status) 252 /* 253 * FUNCTION: Called by NDIS to complete resetting an adapter 254 * ARGUMENTS: 255 * BindingContext = Pointer to a device context (LAN_ADAPTER) 256 * Status = Status of the operation 257 */ 258 { 259 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; 260 261 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 262 263 Adapter->NdisStatus = Status; 264 265 KeSetEvent(&Adapter->Event, 0, FALSE); 266 } 267 268 269 VOID NTAPI ProtocolRequestComplete( 270 NDIS_HANDLE BindingContext, 271 PNDIS_REQUEST NdisRequest, 272 NDIS_STATUS Status) 273 /* 274 * FUNCTION: Called by NDIS to complete a request 275 * ARGUMENTS: 276 * BindingContext = Pointer to a device context (LAN_ADAPTER) 277 * NdisRequest = Pointer to an object describing the request 278 * Status = Status of the operation 279 */ 280 { 281 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; 282 283 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 284 285 /* Save status of request and signal an event */ 286 Adapter->NdisStatus = Status; 287 288 KeSetEvent(&Adapter->Event, 0, FALSE); 289 } 290 291 292 VOID NTAPI ProtocolSendComplete( 293 NDIS_HANDLE BindingContext, 294 PNDIS_PACKET Packet, 295 NDIS_STATUS Status) 296 /* 297 * FUNCTION: Called by NDIS to complete sending process 298 * ARGUMENTS: 299 * BindingContext = Pointer to a device context (LAN_ADAPTER) 300 * Packet = Pointer to a packet descriptor 301 * Status = Status of the operation 302 */ 303 { 304 FreeNdisPacket(Packet); 305 } 306 307 VOID LanReceiveWorker( PVOID Context ) { 308 ULONG PacketType; 309 PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context; 310 PNDIS_PACKET Packet; 311 PLAN_ADAPTER Adapter; 312 UINT BytesTransferred; 313 IP_PACKET IPPacket; 314 BOOLEAN LegacyReceive; 315 PIP_INTERFACE Interface; 316 317 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 318 319 Packet = WorkItem->Packet; 320 Adapter = WorkItem->Adapter; 321 BytesTransferred = WorkItem->BytesTransferred; 322 LegacyReceive = WorkItem->LegacyReceive; 323 324 ExFreePoolWithTag(WorkItem, WQ_CONTEXT_TAG); 325 326 Interface = Adapter->Context; 327 328 IPInitializePacket(&IPPacket, 0); 329 330 IPPacket.NdisPacket = Packet; 331 IPPacket.ReturnPacket = !LegacyReceive; 332 333 if (LegacyReceive) 334 { 335 /* Packet type is precomputed */ 336 PacketType = PC(IPPacket.NdisPacket)->PacketType; 337 338 /* Data is at position 0 */ 339 IPPacket.Position = 0; 340 341 /* Packet size is determined by bytes transferred */ 342 IPPacket.TotalSize = BytesTransferred; 343 } 344 else 345 { 346 /* Determine packet type from media header */ 347 if (GetPacketTypeFromNdisPacket(Adapter, 348 IPPacket.NdisPacket, 349 &PacketType) != NDIS_STATUS_SUCCESS) 350 { 351 /* Bad packet */ 352 IPPacket.Free(&IPPacket); 353 return; 354 } 355 356 /* Data is at the end of the media header */ 357 IPPacket.Position = Adapter->HeaderSize; 358 359 /* Calculate packet size (excluding media header) */ 360 NdisQueryPacketLength(IPPacket.NdisPacket, &IPPacket.TotalSize); 361 } 362 363 TI_DbgPrint 364 (DEBUG_DATALINK, 365 ("Ether Type = %x Total = %d\n", 366 PacketType, IPPacket.TotalSize)); 367 368 /* Update interface stats */ 369 Interface->Stats.InBytes += IPPacket.TotalSize + Adapter->HeaderSize; 370 371 /* NDIS packet is freed in all of these cases */ 372 switch (PacketType) { 373 case ETYPE_IPv4: 374 case ETYPE_IPv6: 375 TI_DbgPrint(MID_TRACE,("Received IP Packet\n")); 376 IPReceive(Adapter->Context, &IPPacket); 377 break; 378 case ETYPE_ARP: 379 TI_DbgPrint(MID_TRACE,("Received ARP Packet\n")); 380 ARPReceive(Adapter->Context, &IPPacket); 381 break; 382 default: 383 IPPacket.Free(&IPPacket); 384 break; 385 } 386 } 387 388 VOID LanSubmitReceiveWork( 389 NDIS_HANDLE BindingContext, 390 PNDIS_PACKET Packet, 391 UINT BytesTransferred, 392 BOOLEAN LegacyReceive) { 393 PLAN_WQ_ITEM WQItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_WQ_ITEM), 394 WQ_CONTEXT_TAG); 395 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; 396 397 TI_DbgPrint(DEBUG_DATALINK,("called\n")); 398 399 if (!WQItem) return; 400 401 WQItem->Packet = Packet; 402 WQItem->Adapter = Adapter; 403 WQItem->BytesTransferred = BytesTransferred; 404 WQItem->LegacyReceive = LegacyReceive; 405 406 if (!ChewCreate( LanReceiveWorker, WQItem )) 407 ExFreePoolWithTag(WQItem, WQ_CONTEXT_TAG); 408 } 409 410 VOID NTAPI ProtocolTransferDataComplete( 411 NDIS_HANDLE BindingContext, 412 PNDIS_PACKET Packet, 413 NDIS_STATUS Status, 414 UINT BytesTransferred) 415 /* 416 * FUNCTION: Called by NDIS to complete reception of data 417 * ARGUMENTS: 418 * BindingContext = Pointer to a device context (LAN_ADAPTER) 419 * Packet = Pointer to a packet descriptor 420 * Status = Status of the operation 421 * BytesTransferred = Number of bytes transferred 422 * NOTES: 423 * If the packet was successfully received, determine the protocol 424 * type and pass it to the correct receive handler 425 */ 426 { 427 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 428 429 TI_DbgPrint(DEBUG_DATALINK,("called\n")); 430 431 TransferDataCompleteCalled++; 432 ASSERT(TransferDataCompleteCalled <= TransferDataCalled); 433 434 if( Status != NDIS_STATUS_SUCCESS ) return; 435 436 LanSubmitReceiveWork(BindingContext, 437 Packet, 438 BytesTransferred, 439 TRUE); 440 } 441 442 INT NTAPI ProtocolReceivePacket( 443 NDIS_HANDLE BindingContext, 444 PNDIS_PACKET NdisPacket) 445 { 446 PLAN_ADAPTER Adapter = BindingContext; 447 448 if (Adapter->State != LAN_STATE_STARTED) { 449 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n")); 450 return 0; 451 } 452 453 LanSubmitReceiveWork(BindingContext, 454 NdisPacket, 455 0, /* Unused */ 456 FALSE); 457 458 /* Hold 1 reference on this packet */ 459 return 1; 460 } 461 462 NDIS_STATUS NTAPI ProtocolReceive( 463 NDIS_HANDLE BindingContext, 464 NDIS_HANDLE MacReceiveContext, 465 PVOID HeaderBuffer, 466 UINT HeaderBufferSize, 467 PVOID LookaheadBuffer, 468 UINT LookaheadBufferSize, 469 UINT PacketSize) 470 /* 471 * FUNCTION: Called by NDIS when a packet has been received on the physical link 472 * ARGUMENTS: 473 * BindingContext = Pointer to a device context (LAN_ADAPTER) 474 * MacReceiveContext = Handle used by underlying NIC driver 475 * HeaderBuffer = Pointer to a buffer containing the packet header 476 * HeaderBufferSize = Number of bytes in HeaderBuffer 477 * LookaheadBuffer = Pointer to a buffer containing buffered packet data 478 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for 479 * PacketSize = Overall size of the packet (not including header) 480 * RETURNS: 481 * Status of operation 482 */ 483 { 484 ULONG PacketType; 485 UINT BytesTransferred; 486 PCHAR BufferData; 487 NDIS_STATUS NdisStatus; 488 PNDIS_PACKET NdisPacket; 489 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; 490 491 TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize)); 492 493 if (Adapter->State != LAN_STATE_STARTED) { 494 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n")); 495 return NDIS_STATUS_NOT_ACCEPTED; 496 } 497 498 if (HeaderBufferSize < Adapter->HeaderSize) { 499 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n")); 500 return NDIS_STATUS_NOT_ACCEPTED; 501 } 502 503 NdisStatus = GetPacketTypeFromHeaderBuffer(Adapter, 504 HeaderBuffer, 505 HeaderBufferSize, 506 &PacketType); 507 if (NdisStatus != NDIS_STATUS_SUCCESS) 508 return NDIS_STATUS_NOT_ACCEPTED; 509 510 TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n", 511 Adapter, Adapter->MTU)); 512 513 /* Get a transfer data packet */ 514 NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, 515 PacketSize ); 516 if( NdisStatus != NDIS_STATUS_SUCCESS ) { 517 return NDIS_STATUS_NOT_ACCEPTED; 518 } 519 520 PC(NdisPacket)->PacketType = PacketType; 521 522 TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize)); 523 524 GetDataPtr( NdisPacket, 0, &BufferData, &PacketSize ); 525 526 TransferDataCalled++; 527 528 if (LookaheadBufferSize == PacketSize) 529 { 530 /* Optimized code path for packets that are fully contained in 531 * the lookahead buffer. */ 532 NdisCopyLookaheadData(BufferData, 533 LookaheadBuffer, 534 LookaheadBufferSize, 535 Adapter->MacOptions); 536 } 537 else 538 { 539 NdisTransferData(&NdisStatus, Adapter->NdisHandle, 540 MacReceiveContext, 0, PacketSize, 541 NdisPacket, &BytesTransferred); 542 } 543 TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n")); 544 545 if (NdisStatus != NDIS_STATUS_PENDING) 546 ProtocolTransferDataComplete(BindingContext, 547 NdisPacket, 548 NdisStatus, 549 PacketSize); 550 551 TI_DbgPrint(DEBUG_DATALINK, ("leaving\n")); 552 553 return NDIS_STATUS_SUCCESS; 554 } 555 556 557 VOID NTAPI ProtocolReceiveComplete( 558 NDIS_HANDLE BindingContext) 559 /* 560 * FUNCTION: Called by NDIS when we're done receiving data 561 * ARGUMENTS: 562 * BindingContext = Pointer to a device context (LAN_ADAPTER) 563 */ 564 { 565 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 566 } 567 568 BOOLEAN ReadIpConfiguration(PIP_INTERFACE Interface) 569 { 570 OBJECT_ATTRIBUTES ObjectAttributes; 571 HANDLE ParameterHandle; 572 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; 573 ULONG KeyValueInfoLength; 574 WCHAR Buffer[150]; 575 UNICODE_STRING IPAddress = RTL_CONSTANT_STRING(L"IPAddress"); 576 UNICODE_STRING Netmask = RTL_CONSTANT_STRING(L"SubnetMask"); 577 UNICODE_STRING Gateway = RTL_CONSTANT_STRING(L"DefaultGateway"); 578 UNICODE_STRING EnableDhcp = RTL_CONSTANT_STRING(L"EnableDHCP"); 579 UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"); 580 UNICODE_STRING TcpipRegistryPath; 581 UNICODE_STRING RegistryDataU; 582 ANSI_STRING RegistryDataA; 583 ULONG Unused; 584 NTSTATUS Status; 585 IP_ADDRESS DefaultMask, Router; 586 587 AddrInitIPv4(&DefaultMask, 0); 588 589 TcpipRegistryPath.MaximumLength = sizeof(WCHAR) * 150; 590 TcpipRegistryPath.Length = 0; 591 TcpipRegistryPath.Buffer = Buffer; 592 593 /* Build the registry path */ 594 RtlAppendUnicodeStringToString(&TcpipRegistryPath, &Prefix); 595 RtlAppendUnicodeStringToString(&TcpipRegistryPath, &Interface->Name); 596 597 InitializeObjectAttributes(&ObjectAttributes, 598 &TcpipRegistryPath, 599 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 600 0, 601 NULL); 602 603 /* Open a handle to the adapter parameters */ 604 Status = ZwOpenKey(&ParameterHandle, KEY_READ, &ObjectAttributes); 605 606 if (!NT_SUCCESS(Status)) 607 { 608 return FALSE; 609 } 610 else 611 { 612 KeyValueInfoLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + 16 * sizeof(WCHAR); 613 KeyValueInfo = ExAllocatePoolWithTag(PagedPool, 614 KeyValueInfoLength, 615 KEY_VALUE_TAG); 616 if (!KeyValueInfo) 617 { 618 ZwClose(ParameterHandle); 619 return FALSE; 620 } 621 622 /* Read the EnableDHCP entry */ 623 Status = ZwQueryValueKey(ParameterHandle, 624 &EnableDhcp, 625 KeyValuePartialInformation, 626 KeyValueInfo, 627 KeyValueInfoLength, 628 &Unused); 629 if (NT_SUCCESS(Status) && KeyValueInfo->DataLength == sizeof(ULONG) && (*(PULONG)KeyValueInfo->Data) == 0) 630 { 631 RegistryDataU.MaximumLength = KeyValueInfoLength - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); 632 RegistryDataU.Buffer = (PWCHAR)KeyValueInfo->Data; 633 634 /* Read the IP address */ 635 Status = ZwQueryValueKey(ParameterHandle, 636 &IPAddress, 637 KeyValuePartialInformation, 638 KeyValueInfo, 639 KeyValueInfoLength, 640 &Unused); 641 if (NT_SUCCESS(Status)) 642 { 643 RegistryDataU.Length = KeyValueInfo->DataLength; 644 645 Status = RtlUnicodeStringToAnsiString(&RegistryDataA, 646 &RegistryDataU, 647 TRUE); 648 if (NT_SUCCESS(Status)) 649 { 650 AddrInitIPv4(&Interface->Unicast, 651 inet_addr(RegistryDataA.Buffer)); 652 RtlFreeAnsiString(&RegistryDataA); 653 } 654 } 655 656 Status = ZwQueryValueKey(ParameterHandle, 657 &Netmask, 658 KeyValuePartialInformation, 659 KeyValueInfo, 660 KeyValueInfoLength, 661 &Unused); 662 if (NT_SUCCESS(Status)) 663 { 664 RegistryDataU.Length = KeyValueInfo->DataLength; 665 666 Status = RtlUnicodeStringToAnsiString(&RegistryDataA, 667 &RegistryDataU, 668 TRUE); 669 if (NT_SUCCESS(Status)) 670 { 671 AddrInitIPv4(&Interface->Netmask, 672 inet_addr(RegistryDataA.Buffer)); 673 RtlFreeAnsiString(&RegistryDataA); 674 } 675 } 676 677 /* We have to wait until both IP address and subnet mask 678 * are read to add the interface route, but we must do it 679 * before we add the default gateway */ 680 if (!AddrIsUnspecified(&Interface->Unicast) && 681 !AddrIsUnspecified(&Interface->Netmask)) 682 IPAddInterfaceRoute(Interface); 683 684 /* Read default gateway info */ 685 Status = ZwQueryValueKey(ParameterHandle, 686 &Gateway, 687 KeyValuePartialInformation, 688 KeyValueInfo, 689 KeyValueInfoLength, 690 &Unused); 691 if (NT_SUCCESS(Status)) 692 { 693 RegistryDataU.Length = KeyValueInfo->DataLength; 694 695 Status = RtlUnicodeStringToAnsiString(&RegistryDataA, 696 &RegistryDataU, 697 TRUE); 698 if (NT_SUCCESS(Status)) 699 { 700 AddrInitIPv4(&Router, inet_addr(RegistryDataA.Buffer)); 701 702 if (!AddrIsUnspecified(&Router)) 703 RouterCreateRoute(&DefaultMask, &DefaultMask, &Router, Interface, 1); 704 705 RtlFreeAnsiString(&RegistryDataA); 706 } 707 } 708 } 709 710 ExFreePoolWithTag(KeyValueInfo, KEY_VALUE_TAG); 711 ZwClose(ParameterHandle); 712 } 713 714 return TRUE; 715 } 716 717 BOOLEAN ReconfigureAdapter(PRECONFIGURE_CONTEXT Context) 718 { 719 PLAN_ADAPTER Adapter = Context->Adapter; 720 PIP_INTERFACE Interface = Adapter->Context; 721 NDIS_STATUS NdisStatus; 722 IP_ADDRESS DefaultMask; 723 724 /* Initialize the default unspecified address (0.0.0.0) */ 725 AddrInitIPv4(&DefaultMask, 0); 726 if (Context->State == LAN_STATE_STARTED && 727 !Context->Adapter->CompletingReset) 728 { 729 /* Read the IP configuration */ 730 ReadIpConfiguration(Interface); 731 732 /* Compute the broadcast address */ 733 Interface->Broadcast.Type = IP_ADDRESS_V4; 734 Interface->Broadcast.Address.IPv4Address = Interface->Unicast.Address.IPv4Address | 735 ~Interface->Netmask.Address.IPv4Address; 736 } 737 else if (!Context->Adapter->CompletingReset) 738 { 739 /* Clear IP configuration */ 740 Interface->Unicast = DefaultMask; 741 Interface->Netmask = DefaultMask; 742 Interface->Broadcast = DefaultMask; 743 744 /* Remove all interface routes */ 745 RouterRemoveRoutesForInterface(Interface); 746 747 /* Destroy all cached neighbors */ 748 NBDestroyNeighborsForInterface(Interface); 749 } 750 751 Context->Adapter->CompletingReset = FALSE; 752 753 if (Context->State == LAN_STATE_STARTED) 754 { 755 /* Get maximum link speed */ 756 NdisStatus = NDISCall(Adapter, 757 NdisRequestQueryInformation, 758 OID_GEN_LINK_SPEED, 759 &Interface->Speed, 760 sizeof(Interface->Speed)); 761 762 if (!NT_SUCCESS(NdisStatus)) 763 Interface->Speed = IP_DEFAULT_LINK_SPEED; 764 765 Adapter->Speed = Interface->Speed * 100L; 766 767 /* Get maximum frame size */ 768 NdisStatus = NDISCall(Adapter, 769 NdisRequestQueryInformation, 770 OID_GEN_MAXIMUM_FRAME_SIZE, 771 &Adapter->MTU, 772 sizeof(Adapter->MTU)); 773 if (NdisStatus != NDIS_STATUS_SUCCESS) 774 return FALSE; 775 776 Interface->MTU = Adapter->MTU; 777 778 /* Get maximum packet size */ 779 NdisStatus = NDISCall(Adapter, 780 NdisRequestQueryInformation, 781 OID_GEN_MAXIMUM_TOTAL_SIZE, 782 &Adapter->MaxPacketSize, 783 sizeof(Adapter->MaxPacketSize)); 784 if (NdisStatus != NDIS_STATUS_SUCCESS) 785 return FALSE; 786 } 787 788 Adapter->State = Context->State; 789 790 /* Update the IP and link status information cached in TCP */ 791 TCPUpdateInterfaceIPInformation(Interface); 792 TCPUpdateInterfaceLinkStatus(Interface); 793 794 return TRUE; 795 } 796 797 VOID ReconfigureAdapterWorker(PVOID Context) 798 { 799 PRECONFIGURE_CONTEXT ReconfigureContext = Context; 800 801 /* Complete the reconfiguration asynchronously */ 802 ReconfigureAdapter(ReconfigureContext); 803 804 /* Free the context */ 805 ExFreePool(ReconfigureContext); 806 } 807 808 VOID NTAPI ProtocolStatus( 809 NDIS_HANDLE BindingContext, 810 NDIS_STATUS GeneralStatus, 811 PVOID StatusBuffer, 812 UINT StatusBufferSize) 813 /* 814 * FUNCTION: Called by NDIS when the underlying driver has changed state 815 * ARGUMENTS: 816 * BindingContext = Pointer to a device context (LAN_ADAPTER) 817 * GeneralStatus = A general status code 818 * StatusBuffer = Pointer to a buffer with medium-specific data 819 * StatusBufferSize = Number of bytes in StatusBuffer 820 */ 821 { 822 PLAN_ADAPTER Adapter = BindingContext; 823 PRECONFIGURE_CONTEXT Context; 824 825 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 826 827 /* Ignore the status indication if we have no context yet. We'll get another later */ 828 if (!Adapter->Context) 829 return; 830 831 Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(RECONFIGURE_CONTEXT), CONTEXT_TAG); 832 if (!Context) 833 return; 834 835 Context->Adapter = Adapter; 836 837 switch(GeneralStatus) 838 { 839 case NDIS_STATUS_MEDIA_CONNECT: 840 DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n"); 841 842 if (Adapter->State == LAN_STATE_STARTED) 843 { 844 ExFreePoolWithTag(Context, CONTEXT_TAG); 845 return; 846 } 847 848 Context->State = LAN_STATE_STARTED; 849 break; 850 851 case NDIS_STATUS_MEDIA_DISCONNECT: 852 DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n"); 853 854 if (Adapter->State == LAN_STATE_STOPPED) 855 { 856 ExFreePoolWithTag(Context, CONTEXT_TAG); 857 return; 858 } 859 860 Context->State = LAN_STATE_STOPPED; 861 break; 862 863 case NDIS_STATUS_RESET_START: 864 Adapter->OldState = Adapter->State; 865 Adapter->State = LAN_STATE_RESETTING; 866 /* Nothing else to do here */ 867 ExFreePoolWithTag(Context, CONTEXT_TAG); 868 return; 869 870 case NDIS_STATUS_RESET_END: 871 Adapter->CompletingReset = TRUE; 872 Context->State = Adapter->OldState; 873 break; 874 875 default: 876 DbgPrint("Unhandled status: %x", GeneralStatus); 877 ExFreePoolWithTag(Context, CONTEXT_TAG); 878 return; 879 } 880 881 /* Queue the work item */ 882 if (!ChewCreate(ReconfigureAdapterWorker, Context)) 883 ExFreePoolWithTag(Context, CONTEXT_TAG); 884 } 885 886 VOID NTAPI ProtocolStatusComplete(NDIS_HANDLE NdisBindingContext) 887 /* 888 * FUNCTION: Called by NDIS when a status-change has occurred 889 * ARGUMENTS: 890 * BindingContext = Pointer to a device context (LAN_ADAPTER) 891 */ 892 { 893 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 894 } 895 896 NDIS_STATUS NTAPI 897 ProtocolPnPEvent( 898 NDIS_HANDLE NdisBindingContext, 899 PNET_PNP_EVENT PnPEvent) 900 { 901 switch(PnPEvent->NetEvent) 902 { 903 case NetEventSetPower: 904 DbgPrint("Device transitioned to power state %ld\n", PnPEvent->Buffer); 905 return NDIS_STATUS_SUCCESS; 906 907 case NetEventQueryPower: 908 DbgPrint("Device wants to go into power state %ld\n", PnPEvent->Buffer); 909 return NDIS_STATUS_SUCCESS; 910 911 case NetEventQueryRemoveDevice: 912 DbgPrint("Device is about to be removed\n"); 913 return NDIS_STATUS_SUCCESS; 914 915 case NetEventCancelRemoveDevice: 916 DbgPrint("Device removal cancelled\n"); 917 return NDIS_STATUS_SUCCESS; 918 919 default: 920 DbgPrint("Unhandled event type: %ld\n", PnPEvent->NetEvent); 921 return NDIS_STATUS_SUCCESS; 922 } 923 } 924 925 VOID NTAPI ProtocolBindAdapter( 926 OUT PNDIS_STATUS Status, 927 IN NDIS_HANDLE BindContext, 928 IN PNDIS_STRING DeviceName, 929 IN PVOID SystemSpecific1, 930 IN PVOID SystemSpecific2) 931 /* 932 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial 933 * bindings, and periodically thereafter as new adapters come online 934 * ARGUMENTS: 935 * Status: Return value to NDIS 936 * BindContext: Handle provided by NDIS to track pending binding operations 937 * DeviceName: Name of the miniport device to bind to 938 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information 939 * SystemSpecific2: Unused & must not be touched 940 */ 941 { 942 TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName)); 943 *Status = LANRegisterAdapter(DeviceName, SystemSpecific1); 944 } 945 946 947 VOID LANTransmit( 948 PVOID Context, 949 PNDIS_PACKET NdisPacket, 950 UINT Offset, 951 PVOID LinkAddress, 952 USHORT Type) 953 /* 954 * FUNCTION: Transmits a packet 955 * ARGUMENTS: 956 * Context = Pointer to context information (LAN_ADAPTER) 957 * NdisPacket = Pointer to NDIS packet to send 958 * Offset = Offset in packet where data starts 959 * LinkAddress = Pointer to link address of destination (NULL = broadcast) 960 * Type = LAN protocol type (LAN_PROTO_*) 961 */ 962 { 963 NDIS_STATUS NdisStatus; 964 PETH_HEADER EHeader; 965 PCHAR Data, OldData; 966 UINT Size, OldSize; 967 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context; 968 KIRQL OldIrql; 969 PNDIS_PACKET XmitPacket; 970 PIP_INTERFACE Interface = Adapter->Context; 971 972 TI_DbgPrint(DEBUG_DATALINK, 973 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n", 974 NdisPacket, Offset, Adapter)); 975 976 if (Adapter->State != LAN_STATE_STARTED) { 977 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_NOT_ACCEPTED); 978 return; 979 } 980 981 TI_DbgPrint(DEBUG_DATALINK, 982 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n", 983 Adapter->HWAddress[0] & 0xff, 984 Adapter->HWAddress[1] & 0xff, 985 Adapter->HWAddress[2] & 0xff, 986 Adapter->HWAddress[3] & 0xff, 987 Adapter->HWAddress[4] & 0xff, 988 Adapter->HWAddress[5] & 0xff)); 989 990 GetDataPtr( NdisPacket, 0, &OldData, &OldSize ); 991 992 NdisStatus = AllocatePacketWithBuffer(&XmitPacket, NULL, OldSize + Adapter->HeaderSize); 993 if (NdisStatus != NDIS_STATUS_SUCCESS) { 994 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_RESOURCES); 995 return; 996 } 997 998 GetDataPtr(XmitPacket, 0, &Data, &Size); 999 1000 RtlCopyMemory(Data + Adapter->HeaderSize, OldData, OldSize); 1001 1002 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_SUCCESS); 1003 1004 switch (Adapter->Media) { 1005 case NdisMedium802_3: 1006 EHeader = (PETH_HEADER)Data; 1007 1008 if (LinkAddress) { 1009 /* Unicast address */ 1010 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH); 1011 } else { 1012 /* Broadcast address */ 1013 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF); 1014 } 1015 1016 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH); 1017 1018 switch (Type) { 1019 case LAN_PROTO_IPv4: 1020 EHeader->EType = ETYPE_IPv4; 1021 break; 1022 case LAN_PROTO_ARP: 1023 EHeader->EType = ETYPE_ARP; 1024 break; 1025 case LAN_PROTO_IPv6: 1026 EHeader->EType = ETYPE_IPv6; 1027 break; 1028 default: 1029 ASSERT(FALSE); 1030 return; 1031 } 1032 break; 1033 1034 default: 1035 /* FIXME: Support other medias */ 1036 break; 1037 } 1038 1039 TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress)); 1040 if( LinkAddress ) { 1041 TI_DbgPrint 1042 ( MID_TRACE, 1043 ("Link Address [%02x %02x %02x %02x %02x %02x]\n", 1044 ((PCHAR)LinkAddress)[0] & 0xff, 1045 ((PCHAR)LinkAddress)[1] & 0xff, 1046 ((PCHAR)LinkAddress)[2] & 0xff, 1047 ((PCHAR)LinkAddress)[3] & 0xff, 1048 ((PCHAR)LinkAddress)[4] & 0xff, 1049 ((PCHAR)LinkAddress)[5] & 0xff)); 1050 } 1051 1052 if (Adapter->MTU < Size) { 1053 /* This is NOT a pointer. MSDN explicitly says so. */ 1054 NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket, 1055 TcpLargeSendPacketInfo) = (PVOID)((ULONG_PTR)Adapter->MTU); 1056 } 1057 1058 /* Update interface stats */ 1059 Interface->Stats.OutBytes += Size; 1060 1061 TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql ); 1062 TI_DbgPrint(MID_TRACE, ("NdisSend\n")); 1063 NdisSend(&NdisStatus, Adapter->NdisHandle, XmitPacket); 1064 TI_DbgPrint(MID_TRACE, ("NdisSend %s\n", 1065 NdisStatus == NDIS_STATUS_PENDING ? 1066 "Pending" : "Complete")); 1067 TcpipReleaseSpinLock( &Adapter->Lock, OldIrql ); 1068 1069 /* I had a talk with vizzini: these really ought to be here. 1070 * we're supposed to see these completed by ndis *only* when 1071 * status_pending is returned. Note that this is different from 1072 * the situation with IRPs. */ 1073 if (NdisStatus != NDIS_STATUS_PENDING) 1074 ProtocolSendComplete((NDIS_HANDLE)Context, XmitPacket, NdisStatus); 1075 } 1076 1077 static NTSTATUS 1078 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) { 1079 OBJECT_ATTRIBUTES Attributes; 1080 NTSTATUS Status; 1081 1082 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0); 1083 Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes); 1084 return Status; 1085 } 1086 1087 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle, 1088 PWCHAR RegistryValue, 1089 PUNICODE_STRING String ) { 1090 UNICODE_STRING ValueName; 1091 UNICODE_STRING UnicodeString; 1092 NTSTATUS Status; 1093 ULONG ResultLength; 1094 UCHAR buf[1024]; 1095 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf; 1096 1097 RtlInitUnicodeString(&ValueName, RegistryValue); 1098 Status = 1099 ZwQueryValueKey(RegHandle, 1100 &ValueName, 1101 KeyValuePartialInformation, 1102 Information, 1103 sizeof(buf), 1104 &ResultLength); 1105 1106 if (!NT_SUCCESS(Status)) 1107 return Status; 1108 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */ 1109 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength)); 1110 1111 UnicodeString.Buffer = (PWCHAR)&Information->Data; 1112 UnicodeString.Length = Information->DataLength - sizeof(WCHAR); 1113 UnicodeString.MaximumLength = Information->DataLength; 1114 1115 String->Buffer = 1116 (PWCHAR)ExAllocatePoolWithTag( NonPagedPool, 1117 UnicodeString.MaximumLength + sizeof(WCHAR), REG_STR_TAG ); 1118 1119 if( !String->Buffer ) return STATUS_NO_MEMORY; 1120 1121 String->MaximumLength = UnicodeString.MaximumLength; 1122 RtlCopyUnicodeString( String, &UnicodeString ); 1123 1124 return STATUS_SUCCESS; 1125 } 1126 1127 /* 1128 * Utility to copy and append two unicode strings. 1129 * 1130 * IN OUT PUNICODE_STRING ResultFirst -> First string and result 1131 * IN PUNICODE_STRING Second -> Second string to append 1132 * IN BOOL Deallocate -> TRUE: Deallocate First string before 1133 * overwriting. 1134 * 1135 * Returns NTSTATUS. 1136 */ 1137 1138 NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst, 1139 PUNICODE_STRING Second, 1140 BOOLEAN Deallocate) { 1141 NTSTATUS Status; 1142 UNICODE_STRING Ustr = *ResultFirst; 1143 PWSTR new_string = ExAllocatePoolWithTag 1144 (PagedPool, 1145 (ResultFirst->Length + Second->Length + sizeof(WCHAR)), TEMP_STRING_TAG); 1146 if( !new_string ) { 1147 return STATUS_NO_MEMORY; 1148 } 1149 memcpy( new_string, ResultFirst->Buffer, ResultFirst->Length ); 1150 memcpy( new_string + ResultFirst->Length / sizeof(WCHAR), 1151 Second->Buffer, Second->Length ); 1152 if( Deallocate ) RtlFreeUnicodeString(ResultFirst); 1153 ResultFirst->Length = Ustr.Length + Second->Length; 1154 ResultFirst->MaximumLength = ResultFirst->Length; 1155 new_string[ResultFirst->Length / sizeof(WCHAR)] = 0; 1156 Status = RtlCreateUnicodeString(ResultFirst,new_string) ? 1157 STATUS_SUCCESS : STATUS_NO_MEMORY; 1158 ExFreePoolWithTag(new_string, TEMP_STRING_TAG); 1159 return Status; 1160 } 1161 1162 static NTSTATUS CheckForDeviceDesc( PUNICODE_STRING EnumKeyName, 1163 PUNICODE_STRING TargetKeyName, 1164 PUNICODE_STRING Name, 1165 PUNICODE_STRING DeviceDesc ) { 1166 UNICODE_STRING RootDevice = { 0, 0, NULL }, LinkageKeyName = { 0, 0, NULL }; 1167 UNICODE_STRING DescKeyName = { 0, 0, NULL }, Linkage = { 0, 0, NULL }; 1168 UNICODE_STRING BackSlash = { 0, 0, NULL }; 1169 HANDLE DescKey = NULL, LinkageKey = NULL; 1170 NTSTATUS Status; 1171 1172 TI_DbgPrint(DEBUG_DATALINK,("EnumKeyName %wZ\n", EnumKeyName)); 1173 1174 RtlInitUnicodeString(&BackSlash, L"\\"); 1175 RtlInitUnicodeString(&Linkage, L"\\Linkage"); 1176 1177 RtlInitUnicodeString(&DescKeyName, L""); 1178 AppendUnicodeString( &DescKeyName, EnumKeyName, FALSE ); 1179 AppendUnicodeString( &DescKeyName, &BackSlash, TRUE ); 1180 AppendUnicodeString( &DescKeyName, TargetKeyName, TRUE ); 1181 1182 RtlInitUnicodeString(&LinkageKeyName, L""); 1183 AppendUnicodeString( &LinkageKeyName, &DescKeyName, FALSE ); 1184 AppendUnicodeString( &LinkageKeyName, &Linkage, TRUE ); 1185 1186 Status = OpenRegistryKey( &LinkageKeyName, &LinkageKey ); 1187 if( !NT_SUCCESS(Status) ) goto cleanup; 1188 1189 Status = ReadStringFromRegistry( LinkageKey, L"RootDevice", &RootDevice ); 1190 if( !NT_SUCCESS(Status) ) goto cleanup; 1191 1192 if( RtlCompareUnicodeString( &RootDevice, Name, TRUE ) == 0 ) { 1193 Status = OpenRegistryKey( &DescKeyName, &DescKey ); 1194 if( !NT_SUCCESS(Status) ) goto cleanup; 1195 1196 Status = ReadStringFromRegistry( DescKey, L"DriverDesc", DeviceDesc ); 1197 if( !NT_SUCCESS(Status) ) goto cleanup; 1198 1199 TI_DbgPrint(DEBUG_DATALINK,("ADAPTER DESC: %wZ\n", DeviceDesc)); 1200 } else Status = STATUS_UNSUCCESSFUL; 1201 1202 cleanup: 1203 RtlFreeUnicodeString( &RootDevice ); 1204 RtlFreeUnicodeString( &LinkageKeyName ); 1205 RtlFreeUnicodeString( &DescKeyName ); 1206 if( LinkageKey ) ZwClose( LinkageKey ); 1207 if( DescKey ) ZwClose( DescKey ); 1208 1209 TI_DbgPrint(DEBUG_DATALINK,("Returning %x\n", Status)); 1210 1211 return Status; 1212 } 1213 1214 static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name, 1215 PUNICODE_STRING DeviceDesc ) { 1216 UNICODE_STRING EnumKeyName, TargetKeyName; 1217 HANDLE EnumKey; 1218 NTSTATUS Status; 1219 ULONG i; 1220 KEY_BASIC_INFORMATION *Kbio = 1221 ExAllocatePoolWithTag(NonPagedPool, sizeof(KEY_BASIC_INFORMATION), KBIO_TAG); 1222 ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength; 1223 1224 RtlInitUnicodeString( DeviceDesc, NULL ); 1225 1226 if( !Kbio ) return STATUS_INSUFFICIENT_RESOURCES; 1227 1228 RtlInitUnicodeString 1229 (&EnumKeyName, CCS_ROOT L"\\Control\\Class\\" TCPIP_GUID); 1230 1231 Status = OpenRegistryKey( &EnumKeyName, &EnumKey ); 1232 1233 if( !NT_SUCCESS(Status) ) { 1234 TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n", 1235 &EnumKeyName, Status)); 1236 ExFreePoolWithTag( Kbio, KBIO_TAG ); 1237 return Status; 1238 } 1239 1240 for( i = 0; NT_SUCCESS(Status); i++ ) { 1241 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation, 1242 Kbio, KbioLength, &ResultLength ); 1243 1244 if( Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW ) { 1245 ExFreePoolWithTag( Kbio, KBIO_TAG ); 1246 KbioLength = ResultLength; 1247 Kbio = ExAllocatePoolWithTag( NonPagedPool, KbioLength, KBIO_TAG ); 1248 if( !Kbio ) { 1249 TI_DbgPrint(DEBUG_DATALINK,("Failed to allocate memory\n")); 1250 ZwClose( EnumKey ); 1251 return STATUS_NO_MEMORY; 1252 } 1253 1254 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation, 1255 Kbio, KbioLength, &ResultLength ); 1256 1257 if( !NT_SUCCESS(Status) ) { 1258 TI_DbgPrint(DEBUG_DATALINK,("Couldn't enum key child %d\n", i)); 1259 ZwClose( EnumKey ); 1260 ExFreePoolWithTag( Kbio, KBIO_TAG ); 1261 return Status; 1262 } 1263 } 1264 1265 if( NT_SUCCESS(Status) ) { 1266 TargetKeyName.Length = TargetKeyName.MaximumLength = 1267 Kbio->NameLength; 1268 TargetKeyName.Buffer = Kbio->Name; 1269 1270 Status = CheckForDeviceDesc 1271 ( &EnumKeyName, &TargetKeyName, Name, DeviceDesc ); 1272 if( NT_SUCCESS(Status) ) { 1273 ZwClose( EnumKey ); 1274 ExFreePoolWithTag( Kbio, KBIO_TAG ); 1275 return Status; 1276 } else Status = STATUS_SUCCESS; 1277 } 1278 } 1279 1280 ZwClose( EnumKey ); 1281 ExFreePoolWithTag( Kbio, KBIO_TAG ); 1282 return STATUS_UNSUCCESSFUL; 1283 } 1284 1285 VOID GetName( PUNICODE_STRING RegistryKey, 1286 PUNICODE_STRING OutName ) { 1287 PWCHAR Ptr; 1288 UNICODE_STRING PartialRegistryKey; 1289 1290 PartialRegistryKey.Buffer = 1291 RegistryKey->Buffer + wcslen(CCS_ROOT L"\\Services\\"); 1292 Ptr = PartialRegistryKey.Buffer; 1293 1294 while( *Ptr != L'\\' && 1295 ((PCHAR)Ptr) < ((PCHAR)RegistryKey->Buffer) + RegistryKey->Length ) 1296 Ptr++; 1297 1298 PartialRegistryKey.Length = PartialRegistryKey.MaximumLength = 1299 (Ptr - PartialRegistryKey.Buffer) * sizeof(WCHAR); 1300 1301 RtlInitUnicodeString( OutName, L"" ); 1302 AppendUnicodeString( OutName, &PartialRegistryKey, FALSE ); 1303 } 1304 1305 BOOLEAN BindAdapter( 1306 PLAN_ADAPTER Adapter, 1307 PNDIS_STRING RegistryPath) 1308 /* 1309 * FUNCTION: Binds a LAN adapter to IP layer 1310 * ARGUMENTS: 1311 * Adapter = Pointer to LAN_ADAPTER structure 1312 * NOTES: 1313 * We set the lookahead buffer size, set the packet filter and 1314 * bind the adapter to IP layer 1315 */ 1316 { 1317 PIP_INTERFACE IF; 1318 NDIS_STATUS NdisStatus; 1319 LLIP_BIND_INFO BindInfo; 1320 ULONG Lookahead = LOOKAHEAD_SIZE; 1321 NTSTATUS Status; 1322 NDIS_MEDIA_STATE MediaState; 1323 1324 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1325 1326 Adapter->State = LAN_STATE_OPENING; 1327 1328 NdisStatus = NDISCall(Adapter, 1329 NdisRequestSetInformation, 1330 OID_GEN_CURRENT_LOOKAHEAD, 1331 &Lookahead, 1332 sizeof(ULONG)); 1333 if (NdisStatus != NDIS_STATUS_SUCCESS) { 1334 TI_DbgPrint(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus)); 1335 return FALSE; 1336 } 1337 1338 /* Bind the adapter to IP layer */ 1339 BindInfo.Context = Adapter; 1340 BindInfo.HeaderSize = Adapter->HeaderSize; 1341 BindInfo.MinFrameSize = Adapter->MinFrameSize; 1342 BindInfo.Address = (PUCHAR)&Adapter->HWAddress; 1343 BindInfo.AddressLength = Adapter->HWAddressLength; 1344 BindInfo.Transmit = LANTransmit; 1345 1346 IF = IPCreateInterface(&BindInfo); 1347 1348 if (!IF) { 1349 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); 1350 return FALSE; 1351 } 1352 1353 /* 1354 * Query per-adapter configuration from the registry 1355 * In case anyone is curious: there *is* an Ndis configuration api 1356 * for this sort of thing, but it doesn't really support things like 1357 * REG_MULTI_SZ very well, and there is a note in the DDK that says that 1358 * protocol drivers developed for win2k and above just use the native 1359 * services (ZwOpenKey, etc). 1360 */ 1361 1362 GetName( RegistryPath, &IF->Name ); 1363 1364 Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description ); 1365 if (!NT_SUCCESS(Status)) { 1366 TI_DbgPrint(MIN_TRACE, ("Failed to get device description.\n")); 1367 IPDestroyInterface(IF); 1368 return FALSE; 1369 } 1370 1371 TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n", 1372 &IF->Description)); 1373 1374 /* Register interface with IP layer */ 1375 IPRegisterInterface(IF); 1376 1377 /* Store adapter context */ 1378 Adapter->Context = IF; 1379 1380 /* Get the media state */ 1381 NdisStatus = NDISCall(Adapter, 1382 NdisRequestQueryInformation, 1383 OID_GEN_MEDIA_CONNECT_STATUS, 1384 &MediaState, 1385 sizeof(MediaState)); 1386 if (NdisStatus != NDIS_STATUS_SUCCESS) { 1387 TI_DbgPrint(DEBUG_DATALINK, ("Could not query media status (0x%X).\n", NdisStatus)); 1388 IPUnregisterInterface(IF); 1389 IPDestroyInterface(IF); 1390 return FALSE; 1391 } 1392 1393 /* Indicate the current media state */ 1394 ProtocolStatus(Adapter, 1395 (MediaState == NdisMediaStateConnected) ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT, 1396 NULL, 0); 1397 1398 /* Set packet filter so we can send and receive packets */ 1399 NdisStatus = NDISCall(Adapter, 1400 NdisRequestSetInformation, 1401 OID_GEN_CURRENT_PACKET_FILTER, 1402 &Adapter->PacketFilter, 1403 sizeof(UINT)); 1404 1405 if (NdisStatus != NDIS_STATUS_SUCCESS) { 1406 TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus)); 1407 IPUnregisterInterface(IF); 1408 IPDestroyInterface(IF); 1409 return FALSE; 1410 } 1411 1412 return TRUE; 1413 } 1414 1415 1416 VOID UnbindAdapter( 1417 PLAN_ADAPTER Adapter) 1418 /* 1419 * FUNCTION: Unbinds a LAN adapter from IP layer 1420 * ARGUMENTS: 1421 * Adapter = Pointer to LAN_ADAPTER structure 1422 */ 1423 { 1424 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1425 1426 if (Adapter->State == LAN_STATE_STARTED) { 1427 PIP_INTERFACE IF = Adapter->Context; 1428 1429 IPUnregisterInterface(IF); 1430 1431 IPDestroyInterface(IF); 1432 } 1433 } 1434 1435 1436 NDIS_STATUS LANRegisterAdapter( 1437 PNDIS_STRING AdapterName, 1438 PNDIS_STRING RegistryPath) 1439 /* 1440 * FUNCTION: Registers protocol with an NDIS adapter 1441 * ARGUMENTS: 1442 * AdapterName = Pointer to string with name of adapter to register 1443 * Adapter = Address of pointer to a LAN_ADAPTER structure 1444 * RETURNS: 1445 * Status of operation 1446 */ 1447 { 1448 PLAN_ADAPTER IF; 1449 NDIS_STATUS NdisStatus; 1450 NDIS_STATUS OpenStatus; 1451 UINT MediaIndex; 1452 NDIS_MEDIUM MediaArray[MAX_MEDIA]; 1453 UINT AddressOID; 1454 1455 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1456 1457 IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_ADAPTER), LAN_ADAPTER_TAG); 1458 if (!IF) { 1459 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); 1460 return NDIS_STATUS_RESOURCES; 1461 } 1462 1463 RtlZeroMemory(IF, sizeof(LAN_ADAPTER)); 1464 1465 /* Put adapter in stopped state */ 1466 IF->State = LAN_STATE_STOPPED; 1467 1468 /* Initialize protecting spin lock */ 1469 KeInitializeSpinLock(&IF->Lock); 1470 1471 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE); 1472 1473 /* Initialize array with media IDs we support */ 1474 MediaArray[MEDIA_ETH] = NdisMedium802_3; 1475 1476 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName)); 1477 /* Open the adapter. */ 1478 NdisOpenAdapter(&NdisStatus, 1479 &OpenStatus, 1480 &IF->NdisHandle, 1481 &MediaIndex, 1482 MediaArray, 1483 MAX_MEDIA, 1484 NdisProtocolHandle, 1485 IF, 1486 AdapterName, 1487 0, 1488 NULL); 1489 1490 /* Wait until the adapter is opened */ 1491 if (NdisStatus == NDIS_STATUS_PENDING) 1492 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL); 1493 else if (NdisStatus != NDIS_STATUS_SUCCESS) { 1494 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName)); 1495 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG); 1496 return NdisStatus; 1497 } 1498 1499 IF->Media = MediaArray[MediaIndex]; 1500 1501 /* Fill LAN_ADAPTER structure with some adapter specific information */ 1502 switch (IF->Media) { 1503 case NdisMedium802_3: 1504 IF->HWAddressLength = IEEE_802_ADDR_LENGTH; 1505 IF->BCastMask = BCAST_ETH_MASK; 1506 IF->BCastCheck = BCAST_ETH_CHECK; 1507 IF->BCastOffset = BCAST_ETH_OFFSET; 1508 IF->HeaderSize = sizeof(ETH_HEADER); 1509 IF->MinFrameSize = 60; 1510 AddressOID = OID_802_3_CURRENT_ADDRESS; 1511 IF->PacketFilter = 1512 NDIS_PACKET_TYPE_BROADCAST | 1513 NDIS_PACKET_TYPE_DIRECTED | 1514 NDIS_PACKET_TYPE_MULTICAST; 1515 break; 1516 1517 default: 1518 /* Unsupported media */ 1519 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n")); 1520 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG); 1521 return NDIS_STATUS_NOT_SUPPORTED; 1522 } 1523 1524 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */ 1525 NdisStatus = NDISCall(IF, 1526 NdisRequestQueryInformation, 1527 OID_GEN_MAXIMUM_SEND_PACKETS, 1528 &IF->MaxSendPackets, 1529 sizeof(UINT)); 1530 if (NdisStatus != NDIS_STATUS_SUCCESS) 1531 /* Legacy NIC drivers may not support this query, if it fails we 1532 assume it can send at least one packet per call to NdisSend(Packets) */ 1533 IF->MaxSendPackets = 1; 1534 1535 /* Get current hardware address */ 1536 NdisStatus = NDISCall(IF, 1537 NdisRequestQueryInformation, 1538 AddressOID, 1539 &IF->HWAddress, 1540 IF->HWAddressLength); 1541 if (NdisStatus != NDIS_STATUS_SUCCESS) { 1542 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n")); 1543 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG); 1544 return NdisStatus; 1545 } 1546 1547 /* Bind adapter to IP layer */ 1548 if( !BindAdapter(IF, RegistryPath) ) { 1549 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName)); 1550 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG); 1551 return NDIS_STATUS_NOT_ACCEPTED; 1552 } 1553 1554 /* Add adapter to the adapter list */ 1555 ExInterlockedInsertTailList(&AdapterListHead, 1556 &IF->ListEntry, 1557 &AdapterListLock); 1558 1559 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n")); 1560 1561 return NDIS_STATUS_SUCCESS; 1562 } 1563 1564 1565 NDIS_STATUS LANUnregisterAdapter( 1566 PLAN_ADAPTER Adapter) 1567 /* 1568 * FUNCTION: Unregisters protocol with NDIS adapter 1569 * ARGUMENTS: 1570 * Adapter = Pointer to a LAN_ADAPTER structure 1571 * RETURNS: 1572 * Status of operation 1573 */ 1574 { 1575 KIRQL OldIrql; 1576 NDIS_HANDLE NdisHandle; 1577 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; 1578 1579 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1580 1581 /* Unlink the adapter from the list */ 1582 RemoveEntryList(&Adapter->ListEntry); 1583 1584 /* Unbind adapter from IP layer */ 1585 UnbindAdapter(Adapter); 1586 1587 TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql); 1588 NdisHandle = Adapter->NdisHandle; 1589 if (NdisHandle) { 1590 Adapter->NdisHandle = NULL; 1591 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql); 1592 1593 NdisCloseAdapter(&NdisStatus, NdisHandle); 1594 if (NdisStatus == NDIS_STATUS_PENDING) { 1595 TcpipWaitForSingleObject(&Adapter->Event, 1596 UserRequest, 1597 KernelMode, 1598 FALSE, 1599 NULL); 1600 NdisStatus = Adapter->NdisStatus; 1601 } 1602 } else 1603 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql); 1604 1605 FreeAdapter(Adapter); 1606 1607 return NdisStatus; 1608 } 1609 1610 VOID 1611 NTAPI 1612 LANUnregisterProtocol(VOID) 1613 /* 1614 * FUNCTION: Unregisters this protocol driver with NDIS 1615 * NOTES: Does not care wether we are already registered 1616 */ 1617 { 1618 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1619 1620 if (ProtocolRegistered) { 1621 NDIS_STATUS NdisStatus; 1622 PLIST_ENTRY CurrentEntry; 1623 PLIST_ENTRY NextEntry; 1624 PLAN_ADAPTER Current; 1625 KIRQL OldIrql; 1626 1627 TcpipAcquireSpinLock(&AdapterListLock, &OldIrql); 1628 1629 /* Search the list and remove every adapter we find */ 1630 CurrentEntry = AdapterListHead.Flink; 1631 while (CurrentEntry != &AdapterListHead) { 1632 NextEntry = CurrentEntry->Flink; 1633 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry); 1634 /* Unregister it */ 1635 LANUnregisterAdapter(Current); 1636 CurrentEntry = NextEntry; 1637 } 1638 1639 TcpipReleaseSpinLock(&AdapterListLock, OldIrql); 1640 1641 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle); 1642 ProtocolRegistered = FALSE; 1643 } 1644 } 1645 1646 VOID 1647 NTAPI 1648 ProtocolUnbindAdapter( 1649 PNDIS_STATUS Status, 1650 NDIS_HANDLE ProtocolBindingContext, 1651 NDIS_HANDLE UnbindContext) 1652 { 1653 /* We don't pend any unbinding so we can just ignore UnbindContext */ 1654 *Status = LANUnregisterAdapter((PLAN_ADAPTER)ProtocolBindingContext); 1655 } 1656 1657 NTSTATUS LANRegisterProtocol( 1658 PNDIS_STRING Name) 1659 /* 1660 * FUNCTION: Registers this protocol driver with NDIS 1661 * ARGUMENTS: 1662 * Name = Name of this protocol driver 1663 * RETURNS: 1664 * Status of operation 1665 */ 1666 { 1667 NDIS_STATUS NdisStatus; 1668 NDIS_PROTOCOL_CHARACTERISTICS ProtChars; 1669 1670 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1671 1672 InitializeListHead(&AdapterListHead); 1673 KeInitializeSpinLock(&AdapterListLock); 1674 1675 /* Set up protocol characteristics */ 1676 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); 1677 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR; 1678 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR; 1679 ProtChars.Name.Length = Name->Length; 1680 ProtChars.Name.Buffer = Name->Buffer; 1681 ProtChars.Name.MaximumLength = Name->MaximumLength; 1682 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete; 1683 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete; 1684 ProtChars.ResetCompleteHandler = ProtocolResetComplete; 1685 ProtChars.RequestCompleteHandler = ProtocolRequestComplete; 1686 ProtChars.SendCompleteHandler = ProtocolSendComplete; 1687 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete; 1688 ProtChars.ReceivePacketHandler = ProtocolReceivePacket; 1689 ProtChars.ReceiveHandler = ProtocolReceive; 1690 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete; 1691 ProtChars.StatusHandler = ProtocolStatus; 1692 ProtChars.StatusCompleteHandler = ProtocolStatusComplete; 1693 ProtChars.BindAdapterHandler = ProtocolBindAdapter; 1694 ProtChars.PnPEventHandler = ProtocolPnPEvent; 1695 ProtChars.UnbindAdapterHandler = ProtocolUnbindAdapter; 1696 ProtChars.UnloadHandler = LANUnregisterProtocol; 1697 1698 /* Try to register protocol */ 1699 NdisRegisterProtocol(&NdisStatus, 1700 &NdisProtocolHandle, 1701 &ProtChars, 1702 sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); 1703 if (NdisStatus != NDIS_STATUS_SUCCESS) 1704 { 1705 TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus)); 1706 return (NTSTATUS)NdisStatus; 1707 } 1708 1709 ProtocolRegistered = TRUE; 1710 1711 return STATUS_SUCCESS; 1712 } 1713 1714 /* EOF */ 1715