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 /* Update the IP and link status information cached in TCP */ 754 TCPUpdateInterfaceIPInformation(Interface); 755 TCPUpdateInterfaceLinkStatus(Interface); 756 757 /* We're done here if the adapter isn't connected */ 758 if (Context->State != LAN_STATE_STARTED) 759 { 760 Adapter->State = Context->State; 761 return TRUE; 762 } 763 764 /* NDIS Bug! */ 765 #if 0 766 /* Get maximum link speed */ 767 NdisStatus = NDISCall(Adapter, 768 NdisRequestQueryInformation, 769 OID_GEN_LINK_SPEED, 770 &Interface->Speed, 771 sizeof(UINT)); 772 773 if (!NT_SUCCESS(NdisStatus)) 774 Interface->Speed = IP_DEFAULT_LINK_SPEED; 775 776 Adapter->Speed = Interface->Speed * 100L; 777 778 /* Get maximum frame size */ 779 NdisStatus = NDISCall(Adapter, 780 NdisRequestQueryInformation, 781 OID_GEN_MAXIMUM_FRAME_SIZE, 782 &Adapter->MTU, 783 sizeof(UINT)); 784 if (NdisStatus != NDIS_STATUS_SUCCESS) 785 return FALSE; 786 787 Interface->MTU = Adapter->MTU; 788 789 /* Get maximum packet size */ 790 NdisStatus = NDISCall(Adapter, 791 NdisRequestQueryInformation, 792 OID_GEN_MAXIMUM_TOTAL_SIZE, 793 &Adapter->MaxPacketSize, 794 sizeof(UINT)); 795 if (NdisStatus != NDIS_STATUS_SUCCESS) 796 return FALSE; 797 #endif 798 799 Adapter->State = Context->State; 800 801 return TRUE; 802 } 803 804 VOID ReconfigureAdapterWorker(PVOID Context) 805 { 806 PRECONFIGURE_CONTEXT ReconfigureContext = Context; 807 808 /* Complete the reconfiguration asynchronously */ 809 ReconfigureAdapter(ReconfigureContext); 810 811 /* Free the context */ 812 ExFreePool(ReconfigureContext); 813 } 814 815 VOID NTAPI ProtocolStatus( 816 NDIS_HANDLE BindingContext, 817 NDIS_STATUS GeneralStatus, 818 PVOID StatusBuffer, 819 UINT StatusBufferSize) 820 /* 821 * FUNCTION: Called by NDIS when the underlying driver has changed state 822 * ARGUMENTS: 823 * BindingContext = Pointer to a device context (LAN_ADAPTER) 824 * GeneralStatus = A general status code 825 * StatusBuffer = Pointer to a buffer with medium-specific data 826 * StatusBufferSize = Number of bytes in StatusBuffer 827 */ 828 { 829 PLAN_ADAPTER Adapter = BindingContext; 830 PRECONFIGURE_CONTEXT Context; 831 832 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 833 834 /* Ignore the status indication if we have no context yet. We'll get another later */ 835 if (!Adapter->Context) 836 return; 837 838 Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(RECONFIGURE_CONTEXT), CONTEXT_TAG); 839 if (!Context) 840 return; 841 842 Context->Adapter = Adapter; 843 844 switch(GeneralStatus) 845 { 846 case NDIS_STATUS_MEDIA_CONNECT: 847 DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n"); 848 849 if (Adapter->State == LAN_STATE_STARTED) 850 { 851 ExFreePoolWithTag(Context, CONTEXT_TAG); 852 return; 853 } 854 855 Context->State = LAN_STATE_STARTED; 856 break; 857 858 case NDIS_STATUS_MEDIA_DISCONNECT: 859 DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n"); 860 861 if (Adapter->State == LAN_STATE_STOPPED) 862 { 863 ExFreePoolWithTag(Context, CONTEXT_TAG); 864 return; 865 } 866 867 Context->State = LAN_STATE_STOPPED; 868 break; 869 870 case NDIS_STATUS_RESET_START: 871 Adapter->OldState = Adapter->State; 872 Adapter->State = LAN_STATE_RESETTING; 873 /* Nothing else to do here */ 874 ExFreePoolWithTag(Context, CONTEXT_TAG); 875 return; 876 877 case NDIS_STATUS_RESET_END: 878 Adapter->CompletingReset = TRUE; 879 Context->State = Adapter->OldState; 880 break; 881 882 default: 883 DbgPrint("Unhandled status: %x", GeneralStatus); 884 ExFreePoolWithTag(Context, CONTEXT_TAG); 885 return; 886 } 887 888 /* Queue the work item */ 889 if (!ChewCreate(ReconfigureAdapterWorker, Context)) 890 ExFreePoolWithTag(Context, CONTEXT_TAG); 891 } 892 893 VOID NTAPI ProtocolStatusComplete(NDIS_HANDLE NdisBindingContext) 894 /* 895 * FUNCTION: Called by NDIS when a status-change has occurred 896 * ARGUMENTS: 897 * BindingContext = Pointer to a device context (LAN_ADAPTER) 898 */ 899 { 900 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 901 } 902 903 NDIS_STATUS NTAPI 904 ProtocolPnPEvent( 905 NDIS_HANDLE NdisBindingContext, 906 PNET_PNP_EVENT PnPEvent) 907 { 908 switch(PnPEvent->NetEvent) 909 { 910 case NetEventSetPower: 911 DbgPrint("Device transitioned to power state %ld\n", PnPEvent->Buffer); 912 return NDIS_STATUS_SUCCESS; 913 914 case NetEventQueryPower: 915 DbgPrint("Device wants to go into power state %ld\n", PnPEvent->Buffer); 916 return NDIS_STATUS_SUCCESS; 917 918 case NetEventQueryRemoveDevice: 919 DbgPrint("Device is about to be removed\n"); 920 return NDIS_STATUS_SUCCESS; 921 922 case NetEventCancelRemoveDevice: 923 DbgPrint("Device removal cancelled\n"); 924 return NDIS_STATUS_SUCCESS; 925 926 default: 927 DbgPrint("Unhandled event type: %ld\n", PnPEvent->NetEvent); 928 return NDIS_STATUS_SUCCESS; 929 } 930 } 931 932 VOID NTAPI ProtocolBindAdapter( 933 OUT PNDIS_STATUS Status, 934 IN NDIS_HANDLE BindContext, 935 IN PNDIS_STRING DeviceName, 936 IN PVOID SystemSpecific1, 937 IN PVOID SystemSpecific2) 938 /* 939 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial 940 * bindings, and periodically thereafter as new adapters come online 941 * ARGUMENTS: 942 * Status: Return value to NDIS 943 * BindContext: Handle provided by NDIS to track pending binding operations 944 * DeviceName: Name of the miniport device to bind to 945 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information 946 * SystemSpecific2: Unused & must not be touched 947 */ 948 { 949 TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName)); 950 *Status = LANRegisterAdapter(DeviceName, SystemSpecific1); 951 } 952 953 954 VOID LANTransmit( 955 PVOID Context, 956 PNDIS_PACKET NdisPacket, 957 UINT Offset, 958 PVOID LinkAddress, 959 USHORT Type) 960 /* 961 * FUNCTION: Transmits a packet 962 * ARGUMENTS: 963 * Context = Pointer to context information (LAN_ADAPTER) 964 * NdisPacket = Pointer to NDIS packet to send 965 * Offset = Offset in packet where data starts 966 * LinkAddress = Pointer to link address of destination (NULL = broadcast) 967 * Type = LAN protocol type (LAN_PROTO_*) 968 */ 969 { 970 NDIS_STATUS NdisStatus; 971 PETH_HEADER EHeader; 972 PCHAR Data, OldData; 973 UINT Size, OldSize; 974 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context; 975 KIRQL OldIrql; 976 PNDIS_PACKET XmitPacket; 977 PIP_INTERFACE Interface = Adapter->Context; 978 979 TI_DbgPrint(DEBUG_DATALINK, 980 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n", 981 NdisPacket, Offset, Adapter)); 982 983 if (Adapter->State != LAN_STATE_STARTED) { 984 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_NOT_ACCEPTED); 985 return; 986 } 987 988 TI_DbgPrint(DEBUG_DATALINK, 989 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n", 990 Adapter->HWAddress[0] & 0xff, 991 Adapter->HWAddress[1] & 0xff, 992 Adapter->HWAddress[2] & 0xff, 993 Adapter->HWAddress[3] & 0xff, 994 Adapter->HWAddress[4] & 0xff, 995 Adapter->HWAddress[5] & 0xff)); 996 997 GetDataPtr( NdisPacket, 0, &OldData, &OldSize ); 998 999 NdisStatus = AllocatePacketWithBuffer(&XmitPacket, NULL, OldSize + Adapter->HeaderSize); 1000 if (NdisStatus != NDIS_STATUS_SUCCESS) { 1001 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_RESOURCES); 1002 return; 1003 } 1004 1005 GetDataPtr(XmitPacket, 0, &Data, &Size); 1006 1007 RtlCopyMemory(Data + Adapter->HeaderSize, OldData, OldSize); 1008 1009 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_SUCCESS); 1010 1011 switch (Adapter->Media) { 1012 case NdisMedium802_3: 1013 EHeader = (PETH_HEADER)Data; 1014 1015 if (LinkAddress) { 1016 /* Unicast address */ 1017 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH); 1018 } else { 1019 /* Broadcast address */ 1020 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF); 1021 } 1022 1023 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH); 1024 1025 switch (Type) { 1026 case LAN_PROTO_IPv4: 1027 EHeader->EType = ETYPE_IPv4; 1028 break; 1029 case LAN_PROTO_ARP: 1030 EHeader->EType = ETYPE_ARP; 1031 break; 1032 case LAN_PROTO_IPv6: 1033 EHeader->EType = ETYPE_IPv6; 1034 break; 1035 default: 1036 ASSERT(FALSE); 1037 return; 1038 } 1039 break; 1040 1041 default: 1042 /* FIXME: Support other medias */ 1043 break; 1044 } 1045 1046 TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress)); 1047 if( LinkAddress ) { 1048 TI_DbgPrint 1049 ( MID_TRACE, 1050 ("Link Address [%02x %02x %02x %02x %02x %02x]\n", 1051 ((PCHAR)LinkAddress)[0] & 0xff, 1052 ((PCHAR)LinkAddress)[1] & 0xff, 1053 ((PCHAR)LinkAddress)[2] & 0xff, 1054 ((PCHAR)LinkAddress)[3] & 0xff, 1055 ((PCHAR)LinkAddress)[4] & 0xff, 1056 ((PCHAR)LinkAddress)[5] & 0xff)); 1057 } 1058 1059 if (Adapter->MTU < Size) { 1060 /* This is NOT a pointer. MSDN explicitly says so. */ 1061 NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket, 1062 TcpLargeSendPacketInfo) = (PVOID)((ULONG_PTR)Adapter->MTU); 1063 } 1064 1065 /* Update interface stats */ 1066 Interface->Stats.OutBytes += Size; 1067 1068 TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql ); 1069 TI_DbgPrint(MID_TRACE, ("NdisSend\n")); 1070 NdisSend(&NdisStatus, Adapter->NdisHandle, XmitPacket); 1071 TI_DbgPrint(MID_TRACE, ("NdisSend %s\n", 1072 NdisStatus == NDIS_STATUS_PENDING ? 1073 "Pending" : "Complete")); 1074 TcpipReleaseSpinLock( &Adapter->Lock, OldIrql ); 1075 1076 /* I had a talk with vizzini: these really ought to be here. 1077 * we're supposed to see these completed by ndis *only* when 1078 * status_pending is returned. Note that this is different from 1079 * the situation with IRPs. */ 1080 if (NdisStatus != NDIS_STATUS_PENDING) 1081 ProtocolSendComplete((NDIS_HANDLE)Context, XmitPacket, NdisStatus); 1082 } 1083 1084 static NTSTATUS 1085 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) { 1086 OBJECT_ATTRIBUTES Attributes; 1087 NTSTATUS Status; 1088 1089 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0); 1090 Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes); 1091 return Status; 1092 } 1093 1094 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle, 1095 PWCHAR RegistryValue, 1096 PUNICODE_STRING String ) { 1097 UNICODE_STRING ValueName; 1098 UNICODE_STRING UnicodeString; 1099 NTSTATUS Status; 1100 ULONG ResultLength; 1101 UCHAR buf[1024]; 1102 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf; 1103 1104 RtlInitUnicodeString(&ValueName, RegistryValue); 1105 Status = 1106 ZwQueryValueKey(RegHandle, 1107 &ValueName, 1108 KeyValuePartialInformation, 1109 Information, 1110 sizeof(buf), 1111 &ResultLength); 1112 1113 if (!NT_SUCCESS(Status)) 1114 return Status; 1115 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */ 1116 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength)); 1117 1118 UnicodeString.Buffer = (PWCHAR)&Information->Data; 1119 UnicodeString.Length = Information->DataLength - sizeof(WCHAR); 1120 UnicodeString.MaximumLength = Information->DataLength; 1121 1122 String->Buffer = 1123 (PWCHAR)ExAllocatePoolWithTag( NonPagedPool, 1124 UnicodeString.MaximumLength + sizeof(WCHAR), REG_STR_TAG ); 1125 1126 if( !String->Buffer ) return STATUS_NO_MEMORY; 1127 1128 String->MaximumLength = UnicodeString.MaximumLength; 1129 RtlCopyUnicodeString( String, &UnicodeString ); 1130 1131 return STATUS_SUCCESS; 1132 } 1133 1134 /* 1135 * Utility to copy and append two unicode strings. 1136 * 1137 * IN OUT PUNICODE_STRING ResultFirst -> First string and result 1138 * IN PUNICODE_STRING Second -> Second string to append 1139 * IN BOOL Deallocate -> TRUE: Deallocate First string before 1140 * overwriting. 1141 * 1142 * Returns NTSTATUS. 1143 */ 1144 1145 NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst, 1146 PUNICODE_STRING Second, 1147 BOOLEAN Deallocate) { 1148 NTSTATUS Status; 1149 UNICODE_STRING Ustr = *ResultFirst; 1150 PWSTR new_string = ExAllocatePoolWithTag 1151 (PagedPool, 1152 (ResultFirst->Length + Second->Length + sizeof(WCHAR)), TEMP_STRING_TAG); 1153 if( !new_string ) { 1154 return STATUS_NO_MEMORY; 1155 } 1156 memcpy( new_string, ResultFirst->Buffer, ResultFirst->Length ); 1157 memcpy( new_string + ResultFirst->Length / sizeof(WCHAR), 1158 Second->Buffer, Second->Length ); 1159 if( Deallocate ) RtlFreeUnicodeString(ResultFirst); 1160 ResultFirst->Length = Ustr.Length + Second->Length; 1161 ResultFirst->MaximumLength = ResultFirst->Length; 1162 new_string[ResultFirst->Length / sizeof(WCHAR)] = 0; 1163 Status = RtlCreateUnicodeString(ResultFirst,new_string) ? 1164 STATUS_SUCCESS : STATUS_NO_MEMORY; 1165 ExFreePoolWithTag(new_string, TEMP_STRING_TAG); 1166 return Status; 1167 } 1168 1169 static NTSTATUS CheckForDeviceDesc( PUNICODE_STRING EnumKeyName, 1170 PUNICODE_STRING TargetKeyName, 1171 PUNICODE_STRING Name, 1172 PUNICODE_STRING DeviceDesc ) { 1173 UNICODE_STRING RootDevice = { 0, 0, NULL }, LinkageKeyName = { 0, 0, NULL }; 1174 UNICODE_STRING DescKeyName = { 0, 0, NULL }, Linkage = { 0, 0, NULL }; 1175 UNICODE_STRING BackSlash = { 0, 0, NULL }; 1176 HANDLE DescKey = NULL, LinkageKey = NULL; 1177 NTSTATUS Status; 1178 1179 TI_DbgPrint(DEBUG_DATALINK,("EnumKeyName %wZ\n", EnumKeyName)); 1180 1181 RtlInitUnicodeString(&BackSlash, L"\\"); 1182 RtlInitUnicodeString(&Linkage, L"\\Linkage"); 1183 1184 RtlInitUnicodeString(&DescKeyName, L""); 1185 AppendUnicodeString( &DescKeyName, EnumKeyName, FALSE ); 1186 AppendUnicodeString( &DescKeyName, &BackSlash, TRUE ); 1187 AppendUnicodeString( &DescKeyName, TargetKeyName, TRUE ); 1188 1189 RtlInitUnicodeString(&LinkageKeyName, L""); 1190 AppendUnicodeString( &LinkageKeyName, &DescKeyName, FALSE ); 1191 AppendUnicodeString( &LinkageKeyName, &Linkage, TRUE ); 1192 1193 Status = OpenRegistryKey( &LinkageKeyName, &LinkageKey ); 1194 if( !NT_SUCCESS(Status) ) goto cleanup; 1195 1196 Status = ReadStringFromRegistry( LinkageKey, L"RootDevice", &RootDevice ); 1197 if( !NT_SUCCESS(Status) ) goto cleanup; 1198 1199 if( RtlCompareUnicodeString( &RootDevice, Name, TRUE ) == 0 ) { 1200 Status = OpenRegistryKey( &DescKeyName, &DescKey ); 1201 if( !NT_SUCCESS(Status) ) goto cleanup; 1202 1203 Status = ReadStringFromRegistry( DescKey, L"DriverDesc", DeviceDesc ); 1204 if( !NT_SUCCESS(Status) ) goto cleanup; 1205 1206 TI_DbgPrint(DEBUG_DATALINK,("ADAPTER DESC: %wZ\n", DeviceDesc)); 1207 } else Status = STATUS_UNSUCCESSFUL; 1208 1209 cleanup: 1210 RtlFreeUnicodeString( &RootDevice ); 1211 RtlFreeUnicodeString( &LinkageKeyName ); 1212 RtlFreeUnicodeString( &DescKeyName ); 1213 if( LinkageKey ) ZwClose( LinkageKey ); 1214 if( DescKey ) ZwClose( DescKey ); 1215 1216 TI_DbgPrint(DEBUG_DATALINK,("Returning %x\n", Status)); 1217 1218 return Status; 1219 } 1220 1221 static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name, 1222 PUNICODE_STRING DeviceDesc ) { 1223 UNICODE_STRING EnumKeyName, TargetKeyName; 1224 HANDLE EnumKey; 1225 NTSTATUS Status; 1226 ULONG i; 1227 KEY_BASIC_INFORMATION *Kbio = 1228 ExAllocatePoolWithTag(NonPagedPool, sizeof(KEY_BASIC_INFORMATION), KBIO_TAG); 1229 ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength; 1230 1231 RtlInitUnicodeString( DeviceDesc, NULL ); 1232 1233 if( !Kbio ) return STATUS_INSUFFICIENT_RESOURCES; 1234 1235 RtlInitUnicodeString 1236 (&EnumKeyName, CCS_ROOT L"\\Control\\Class\\" TCPIP_GUID); 1237 1238 Status = OpenRegistryKey( &EnumKeyName, &EnumKey ); 1239 1240 if( !NT_SUCCESS(Status) ) { 1241 TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n", 1242 &EnumKeyName, Status)); 1243 ExFreePoolWithTag( Kbio, KBIO_TAG ); 1244 return Status; 1245 } 1246 1247 for( i = 0; NT_SUCCESS(Status); i++ ) { 1248 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation, 1249 Kbio, KbioLength, &ResultLength ); 1250 1251 if( Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW ) { 1252 ExFreePoolWithTag( Kbio, KBIO_TAG ); 1253 KbioLength = ResultLength; 1254 Kbio = ExAllocatePoolWithTag( NonPagedPool, KbioLength, KBIO_TAG ); 1255 if( !Kbio ) { 1256 TI_DbgPrint(DEBUG_DATALINK,("Failed to allocate memory\n")); 1257 ZwClose( EnumKey ); 1258 return STATUS_NO_MEMORY; 1259 } 1260 1261 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation, 1262 Kbio, KbioLength, &ResultLength ); 1263 1264 if( !NT_SUCCESS(Status) ) { 1265 TI_DbgPrint(DEBUG_DATALINK,("Couldn't enum key child %d\n", i)); 1266 ZwClose( EnumKey ); 1267 ExFreePoolWithTag( Kbio, KBIO_TAG ); 1268 return Status; 1269 } 1270 } 1271 1272 if( NT_SUCCESS(Status) ) { 1273 TargetKeyName.Length = TargetKeyName.MaximumLength = 1274 Kbio->NameLength; 1275 TargetKeyName.Buffer = Kbio->Name; 1276 1277 Status = CheckForDeviceDesc 1278 ( &EnumKeyName, &TargetKeyName, Name, DeviceDesc ); 1279 if( NT_SUCCESS(Status) ) { 1280 ZwClose( EnumKey ); 1281 ExFreePoolWithTag( Kbio, KBIO_TAG ); 1282 return Status; 1283 } else Status = STATUS_SUCCESS; 1284 } 1285 } 1286 1287 ZwClose( EnumKey ); 1288 ExFreePoolWithTag( Kbio, KBIO_TAG ); 1289 return STATUS_UNSUCCESSFUL; 1290 } 1291 1292 VOID GetName( PUNICODE_STRING RegistryKey, 1293 PUNICODE_STRING OutName ) { 1294 PWCHAR Ptr; 1295 UNICODE_STRING PartialRegistryKey; 1296 1297 PartialRegistryKey.Buffer = 1298 RegistryKey->Buffer + wcslen(CCS_ROOT L"\\Services\\"); 1299 Ptr = PartialRegistryKey.Buffer; 1300 1301 while( *Ptr != L'\\' && 1302 ((PCHAR)Ptr) < ((PCHAR)RegistryKey->Buffer) + RegistryKey->Length ) 1303 Ptr++; 1304 1305 PartialRegistryKey.Length = PartialRegistryKey.MaximumLength = 1306 (Ptr - PartialRegistryKey.Buffer) * sizeof(WCHAR); 1307 1308 RtlInitUnicodeString( OutName, L"" ); 1309 AppendUnicodeString( OutName, &PartialRegistryKey, FALSE ); 1310 } 1311 1312 BOOLEAN BindAdapter( 1313 PLAN_ADAPTER Adapter, 1314 PNDIS_STRING RegistryPath) 1315 /* 1316 * FUNCTION: Binds a LAN adapter to IP layer 1317 * ARGUMENTS: 1318 * Adapter = Pointer to LAN_ADAPTER structure 1319 * NOTES: 1320 * We set the lookahead buffer size, set the packet filter and 1321 * bind the adapter to IP layer 1322 */ 1323 { 1324 PIP_INTERFACE IF; 1325 NDIS_STATUS NdisStatus; 1326 LLIP_BIND_INFO BindInfo; 1327 ULONG Lookahead = LOOKAHEAD_SIZE; 1328 NTSTATUS Status; 1329 NDIS_MEDIA_STATE MediaState; 1330 1331 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1332 1333 Adapter->State = LAN_STATE_OPENING; 1334 1335 NdisStatus = NDISCall(Adapter, 1336 NdisRequestSetInformation, 1337 OID_GEN_CURRENT_LOOKAHEAD, 1338 &Lookahead, 1339 sizeof(ULONG)); 1340 if (NdisStatus != NDIS_STATUS_SUCCESS) { 1341 TI_DbgPrint(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus)); 1342 return FALSE; 1343 } 1344 1345 /* Bind the adapter to IP layer */ 1346 BindInfo.Context = Adapter; 1347 BindInfo.HeaderSize = Adapter->HeaderSize; 1348 BindInfo.MinFrameSize = Adapter->MinFrameSize; 1349 BindInfo.Address = (PUCHAR)&Adapter->HWAddress; 1350 BindInfo.AddressLength = Adapter->HWAddressLength; 1351 BindInfo.Transmit = LANTransmit; 1352 1353 IF = IPCreateInterface(&BindInfo); 1354 1355 if (!IF) { 1356 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); 1357 return FALSE; 1358 } 1359 1360 /* 1361 * Query per-adapter configuration from the registry 1362 * In case anyone is curious: there *is* an Ndis configuration api 1363 * for this sort of thing, but it doesn't really support things like 1364 * REG_MULTI_SZ very well, and there is a note in the DDK that says that 1365 * protocol drivers developed for win2k and above just use the native 1366 * services (ZwOpenKey, etc). 1367 */ 1368 1369 GetName( RegistryPath, &IF->Name ); 1370 1371 Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description ); 1372 if (!NT_SUCCESS(Status)) { 1373 TI_DbgPrint(MIN_TRACE, ("Failed to get device description.\n")); 1374 IPDestroyInterface(IF); 1375 return FALSE; 1376 } 1377 1378 TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n", 1379 &IF->Description)); 1380 1381 /* Get maximum link speed */ 1382 NdisStatus = NDISCall(Adapter, 1383 NdisRequestQueryInformation, 1384 OID_GEN_LINK_SPEED, 1385 &IF->Speed, 1386 sizeof(UINT)); 1387 1388 if (!NT_SUCCESS(NdisStatus)) 1389 IF->Speed = IP_DEFAULT_LINK_SPEED; 1390 1391 Adapter->Speed = IF->Speed * 100L; 1392 1393 /* Get maximum frame size */ 1394 NdisStatus = NDISCall(Adapter, 1395 NdisRequestQueryInformation, 1396 OID_GEN_MAXIMUM_FRAME_SIZE, 1397 &Adapter->MTU, 1398 sizeof(UINT)); 1399 if (NdisStatus != NDIS_STATUS_SUCCESS) 1400 return FALSE; 1401 1402 IF->MTU = Adapter->MTU; 1403 1404 /* Get maximum packet size */ 1405 NdisStatus = NDISCall(Adapter, 1406 NdisRequestQueryInformation, 1407 OID_GEN_MAXIMUM_TOTAL_SIZE, 1408 &Adapter->MaxPacketSize, 1409 sizeof(UINT)); 1410 if (NdisStatus != NDIS_STATUS_SUCCESS) 1411 return FALSE; 1412 1413 /* Register interface with IP layer */ 1414 IPRegisterInterface(IF); 1415 1416 /* Store adapter context */ 1417 Adapter->Context = IF; 1418 1419 /* Get the media state */ 1420 NdisStatus = NDISCall(Adapter, 1421 NdisRequestQueryInformation, 1422 OID_GEN_MEDIA_CONNECT_STATUS, 1423 &MediaState, 1424 sizeof(MediaState)); 1425 if (NdisStatus != NDIS_STATUS_SUCCESS) { 1426 TI_DbgPrint(DEBUG_DATALINK, ("Could not query media status (0x%X).\n", NdisStatus)); 1427 IPUnregisterInterface(IF); 1428 IPDestroyInterface(IF); 1429 return FALSE; 1430 } 1431 1432 /* Indicate the current media state */ 1433 ProtocolStatus(Adapter, 1434 (MediaState == NdisMediaStateConnected) ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT, 1435 NULL, 0); 1436 1437 /* Set packet filter so we can send and receive packets */ 1438 NdisStatus = NDISCall(Adapter, 1439 NdisRequestSetInformation, 1440 OID_GEN_CURRENT_PACKET_FILTER, 1441 &Adapter->PacketFilter, 1442 sizeof(UINT)); 1443 1444 if (NdisStatus != NDIS_STATUS_SUCCESS) { 1445 TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus)); 1446 IPUnregisterInterface(IF); 1447 IPDestroyInterface(IF); 1448 return FALSE; 1449 } 1450 1451 return TRUE; 1452 } 1453 1454 1455 VOID UnbindAdapter( 1456 PLAN_ADAPTER Adapter) 1457 /* 1458 * FUNCTION: Unbinds a LAN adapter from IP layer 1459 * ARGUMENTS: 1460 * Adapter = Pointer to LAN_ADAPTER structure 1461 */ 1462 { 1463 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1464 1465 if (Adapter->State == LAN_STATE_STARTED) { 1466 PIP_INTERFACE IF = Adapter->Context; 1467 1468 IPUnregisterInterface(IF); 1469 1470 IPDestroyInterface(IF); 1471 } 1472 } 1473 1474 1475 NDIS_STATUS LANRegisterAdapter( 1476 PNDIS_STRING AdapterName, 1477 PNDIS_STRING RegistryPath) 1478 /* 1479 * FUNCTION: Registers protocol with an NDIS adapter 1480 * ARGUMENTS: 1481 * AdapterName = Pointer to string with name of adapter to register 1482 * Adapter = Address of pointer to a LAN_ADAPTER structure 1483 * RETURNS: 1484 * Status of operation 1485 */ 1486 { 1487 PLAN_ADAPTER IF; 1488 NDIS_STATUS NdisStatus; 1489 NDIS_STATUS OpenStatus; 1490 UINT MediaIndex; 1491 NDIS_MEDIUM MediaArray[MAX_MEDIA]; 1492 UINT AddressOID; 1493 1494 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1495 1496 IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_ADAPTER), LAN_ADAPTER_TAG); 1497 if (!IF) { 1498 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); 1499 return NDIS_STATUS_RESOURCES; 1500 } 1501 1502 RtlZeroMemory(IF, sizeof(LAN_ADAPTER)); 1503 1504 /* Put adapter in stopped state */ 1505 IF->State = LAN_STATE_STOPPED; 1506 1507 /* Initialize protecting spin lock */ 1508 KeInitializeSpinLock(&IF->Lock); 1509 1510 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE); 1511 1512 /* Initialize array with media IDs we support */ 1513 MediaArray[MEDIA_ETH] = NdisMedium802_3; 1514 1515 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName)); 1516 /* Open the adapter. */ 1517 NdisOpenAdapter(&NdisStatus, 1518 &OpenStatus, 1519 &IF->NdisHandle, 1520 &MediaIndex, 1521 MediaArray, 1522 MAX_MEDIA, 1523 NdisProtocolHandle, 1524 IF, 1525 AdapterName, 1526 0, 1527 NULL); 1528 1529 /* Wait until the adapter is opened */ 1530 if (NdisStatus == NDIS_STATUS_PENDING) 1531 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL); 1532 else if (NdisStatus != NDIS_STATUS_SUCCESS) { 1533 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName)); 1534 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG); 1535 return NdisStatus; 1536 } 1537 1538 IF->Media = MediaArray[MediaIndex]; 1539 1540 /* Fill LAN_ADAPTER structure with some adapter specific information */ 1541 switch (IF->Media) { 1542 case NdisMedium802_3: 1543 IF->HWAddressLength = IEEE_802_ADDR_LENGTH; 1544 IF->BCastMask = BCAST_ETH_MASK; 1545 IF->BCastCheck = BCAST_ETH_CHECK; 1546 IF->BCastOffset = BCAST_ETH_OFFSET; 1547 IF->HeaderSize = sizeof(ETH_HEADER); 1548 IF->MinFrameSize = 60; 1549 AddressOID = OID_802_3_CURRENT_ADDRESS; 1550 IF->PacketFilter = 1551 NDIS_PACKET_TYPE_BROADCAST | 1552 NDIS_PACKET_TYPE_DIRECTED | 1553 NDIS_PACKET_TYPE_MULTICAST; 1554 break; 1555 1556 default: 1557 /* Unsupported media */ 1558 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n")); 1559 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG); 1560 return NDIS_STATUS_NOT_SUPPORTED; 1561 } 1562 1563 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */ 1564 NdisStatus = NDISCall(IF, 1565 NdisRequestQueryInformation, 1566 OID_GEN_MAXIMUM_SEND_PACKETS, 1567 &IF->MaxSendPackets, 1568 sizeof(UINT)); 1569 if (NdisStatus != NDIS_STATUS_SUCCESS) 1570 /* Legacy NIC drivers may not support this query, if it fails we 1571 assume it can send at least one packet per call to NdisSend(Packets) */ 1572 IF->MaxSendPackets = 1; 1573 1574 /* Get current hardware address */ 1575 NdisStatus = NDISCall(IF, 1576 NdisRequestQueryInformation, 1577 AddressOID, 1578 &IF->HWAddress, 1579 IF->HWAddressLength); 1580 if (NdisStatus != NDIS_STATUS_SUCCESS) { 1581 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n")); 1582 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG); 1583 return NdisStatus; 1584 } 1585 1586 /* Bind adapter to IP layer */ 1587 if( !BindAdapter(IF, RegistryPath) ) { 1588 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName)); 1589 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG); 1590 return NDIS_STATUS_NOT_ACCEPTED; 1591 } 1592 1593 /* Add adapter to the adapter list */ 1594 ExInterlockedInsertTailList(&AdapterListHead, 1595 &IF->ListEntry, 1596 &AdapterListLock); 1597 1598 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n")); 1599 1600 return NDIS_STATUS_SUCCESS; 1601 } 1602 1603 1604 NDIS_STATUS LANUnregisterAdapter( 1605 PLAN_ADAPTER Adapter) 1606 /* 1607 * FUNCTION: Unregisters protocol with NDIS adapter 1608 * ARGUMENTS: 1609 * Adapter = Pointer to a LAN_ADAPTER structure 1610 * RETURNS: 1611 * Status of operation 1612 */ 1613 { 1614 KIRQL OldIrql; 1615 NDIS_HANDLE NdisHandle; 1616 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; 1617 1618 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1619 1620 /* Unlink the adapter from the list */ 1621 RemoveEntryList(&Adapter->ListEntry); 1622 1623 /* Unbind adapter from IP layer */ 1624 UnbindAdapter(Adapter); 1625 1626 TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql); 1627 NdisHandle = Adapter->NdisHandle; 1628 if (NdisHandle) { 1629 Adapter->NdisHandle = NULL; 1630 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql); 1631 1632 NdisCloseAdapter(&NdisStatus, NdisHandle); 1633 if (NdisStatus == NDIS_STATUS_PENDING) { 1634 TcpipWaitForSingleObject(&Adapter->Event, 1635 UserRequest, 1636 KernelMode, 1637 FALSE, 1638 NULL); 1639 NdisStatus = Adapter->NdisStatus; 1640 } 1641 } else 1642 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql); 1643 1644 FreeAdapter(Adapter); 1645 1646 return NdisStatus; 1647 } 1648 1649 VOID 1650 NTAPI 1651 LANUnregisterProtocol(VOID) 1652 /* 1653 * FUNCTION: Unregisters this protocol driver with NDIS 1654 * NOTES: Does not care wether we are already registered 1655 */ 1656 { 1657 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1658 1659 if (ProtocolRegistered) { 1660 NDIS_STATUS NdisStatus; 1661 PLIST_ENTRY CurrentEntry; 1662 PLIST_ENTRY NextEntry; 1663 PLAN_ADAPTER Current; 1664 KIRQL OldIrql; 1665 1666 TcpipAcquireSpinLock(&AdapterListLock, &OldIrql); 1667 1668 /* Search the list and remove every adapter we find */ 1669 CurrentEntry = AdapterListHead.Flink; 1670 while (CurrentEntry != &AdapterListHead) { 1671 NextEntry = CurrentEntry->Flink; 1672 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry); 1673 /* Unregister it */ 1674 LANUnregisterAdapter(Current); 1675 CurrentEntry = NextEntry; 1676 } 1677 1678 TcpipReleaseSpinLock(&AdapterListLock, OldIrql); 1679 1680 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle); 1681 ProtocolRegistered = FALSE; 1682 } 1683 } 1684 1685 VOID 1686 NTAPI 1687 ProtocolUnbindAdapter( 1688 PNDIS_STATUS Status, 1689 NDIS_HANDLE ProtocolBindingContext, 1690 NDIS_HANDLE UnbindContext) 1691 { 1692 /* We don't pend any unbinding so we can just ignore UnbindContext */ 1693 *Status = LANUnregisterAdapter((PLAN_ADAPTER)ProtocolBindingContext); 1694 } 1695 1696 NTSTATUS LANRegisterProtocol( 1697 PNDIS_STRING Name) 1698 /* 1699 * FUNCTION: Registers this protocol driver with NDIS 1700 * ARGUMENTS: 1701 * Name = Name of this protocol driver 1702 * RETURNS: 1703 * Status of operation 1704 */ 1705 { 1706 NDIS_STATUS NdisStatus; 1707 NDIS_PROTOCOL_CHARACTERISTICS ProtChars; 1708 1709 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); 1710 1711 InitializeListHead(&AdapterListHead); 1712 KeInitializeSpinLock(&AdapterListLock); 1713 1714 /* Set up protocol characteristics */ 1715 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); 1716 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR; 1717 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR; 1718 ProtChars.Name.Length = Name->Length; 1719 ProtChars.Name.Buffer = Name->Buffer; 1720 ProtChars.Name.MaximumLength = Name->MaximumLength; 1721 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete; 1722 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete; 1723 ProtChars.ResetCompleteHandler = ProtocolResetComplete; 1724 ProtChars.RequestCompleteHandler = ProtocolRequestComplete; 1725 ProtChars.SendCompleteHandler = ProtocolSendComplete; 1726 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete; 1727 ProtChars.ReceivePacketHandler = ProtocolReceivePacket; 1728 ProtChars.ReceiveHandler = ProtocolReceive; 1729 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete; 1730 ProtChars.StatusHandler = ProtocolStatus; 1731 ProtChars.StatusCompleteHandler = ProtocolStatusComplete; 1732 ProtChars.BindAdapterHandler = ProtocolBindAdapter; 1733 ProtChars.PnPEventHandler = ProtocolPnPEvent; 1734 ProtChars.UnbindAdapterHandler = ProtocolUnbindAdapter; 1735 ProtChars.UnloadHandler = LANUnregisterProtocol; 1736 1737 /* Try to register protocol */ 1738 NdisRegisterProtocol(&NdisStatus, 1739 &NdisProtocolHandle, 1740 &ProtChars, 1741 sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); 1742 if (NdisStatus != NDIS_STATUS_SUCCESS) 1743 { 1744 TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus)); 1745 return (NTSTATUS)NdisStatus; 1746 } 1747 1748 ProtocolRegistered = TRUE; 1749 1750 return STATUS_SUCCESS; 1751 } 1752 1753 /* EOF */ 1754