⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lan.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
    TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
				 Adapter, Adapter->MTU));

    NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
                                           PacketSize + HeaderBufferSize );
    if( NdisStatus != NDIS_STATUS_SUCCESS ) {
	return NDIS_STATUS_NOT_ACCEPTED;
    }

    PC(NdisPacket)->PacketType = PacketType;

    TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));

    GetDataPtr( NdisPacket, 0, &BufferData, &temp );

    IPPacket.NdisPacket = NdisPacket;
    IPPacket.Position = 0;

    TransferDataCalled++;

    if (LookaheadBufferSize == PacketSize)
    {
        /* Optimized code path for packets that are fully contained in
         * the lookahead buffer. */
        NdisCopyLookaheadData(BufferData,
                              LookaheadBuffer,
                              LookaheadBufferSize,
                              Adapter->MacOptions);
    }
    else
    {
	if (NdisStatus == NDIS_STATUS_SUCCESS)
        {		  
            NdisTransferData(&NdisStatus, Adapter->NdisHandle,
                             MacReceiveContext, 0, PacketSize,
			     NdisPacket, &BytesTransferred);
        }
        else
        {
            BytesTransferred = 0;
        }
    }
    TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));

    if (NdisStatus != NDIS_STATUS_PENDING)
	ProtocolTransferDataComplete(BindingContext,
				     NdisPacket,
				     NdisStatus,
				     PacketSize);

    TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));

    return NDIS_STATUS_SUCCESS;
}


VOID STDCALL ProtocolReceiveComplete(
    NDIS_HANDLE BindingContext)
/*
 * FUNCTION: Called by NDIS when we're done receiving data
 * ARGUMENTS:
 *     BindingContext = Pointer to a device context (LAN_ADAPTER)
 */
{
    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
}


VOID STDCALL ProtocolStatus(
    NDIS_HANDLE BindingContext,
    NDIS_STATUS GenerelStatus,
    PVOID StatusBuffer,
    UINT StatusBufferSize)
/*
 * FUNCTION: Called by NDIS when the underlying driver has changed state
 * ARGUMENTS:
 *     BindingContext   = Pointer to a device context (LAN_ADAPTER)
 *     GenerelStatus    = A generel status code
 *     StatusBuffer     = Pointer to a buffer with medium-specific data
 *     StatusBufferSize = Number of bytes in StatusBuffer
 */
{
    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
}


VOID STDCALL ProtocolStatusComplete(
    NDIS_HANDLE NdisBindingContext)
/*
 * FUNCTION: Called by NDIS when a status-change has occurred
 * ARGUMENTS:
 *     BindingContext = Pointer to a device context (LAN_ADAPTER)
 */
{
    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
}

VOID STDCALL ProtocolBindAdapter(
    OUT PNDIS_STATUS   Status,
    IN  NDIS_HANDLE    BindContext,
    IN  PNDIS_STRING   DeviceName,
    IN  PVOID          SystemSpecific1,
    IN  PVOID          SystemSpecific2)
/*
 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
 *           bindings, and periodically thereafer as new adapters come online
 * ARGUMENTS:
 *     Status: Return value to NDIS
 *     BindContext: Handle provided by NDIS to track pending binding operations
 *     DeviceName: Name of the miniport device to bind to
 *     SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
 *     SystemSpecific2: Unused & must not be touched
 */
{
    /* XXX confirm that this is still true, or re-word the following comment */
    /* we get to ignore BindContext because we will never pend an operation with NDIS */
    TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
    *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
}


VOID LANTransmit(
    PVOID Context,
    PNDIS_PACKET NdisPacket,
    UINT Offset,
    PVOID LinkAddress,
    USHORT Type)
/*
 * FUNCTION: Transmits a packet
 * ARGUMENTS:
 *     Context     = Pointer to context information (LAN_ADAPTER)
 *     NdisPacket  = Pointer to NDIS packet to send
 *     Offset      = Offset in packet where data starts
 *     LinkAddress = Pointer to link address of destination (NULL = broadcast)
 *     Type        = LAN protocol type (LAN_PROTO_*)
 */
{
    NDIS_STATUS NdisStatus;
    PETH_HEADER EHeader;
    PCHAR Data;
    UINT Size;
    KIRQL OldIrql;
    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;

    TI_DbgPrint(DEBUG_DATALINK,
		("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
		 NdisPacket, Offset, Adapter));

    TI_DbgPrint(DEBUG_DATALINK,
		("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
		 Adapter->HWAddress[0] & 0xff,
		 Adapter->HWAddress[1] & 0xff,
		 Adapter->HWAddress[2] & 0xff,
		 Adapter->HWAddress[3] & 0xff,
		 Adapter->HWAddress[4] & 0xff,
		 Adapter->HWAddress[5] & 0xff));

    /* XXX arty -- Handled adjustment in a saner way than before ...
     * not needed immediately */
    GetDataPtr( NdisPacket, 0, &Data, &Size );

    LanChainCompletion( Adapter, NdisPacket );

    if (Adapter->State == LAN_STATE_STARTED) {
        switch (Adapter->Media) {
        case NdisMedium802_3:
            EHeader = (PETH_HEADER)Data;

            if (LinkAddress) {
                /* Unicast address */
                RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
            } else {
                /* Broadcast address */
                RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
            }

            RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);

            switch (Type) {
            case LAN_PROTO_IPv4:
                EHeader->EType = ETYPE_IPv4;
                break;
            case LAN_PROTO_ARP:
                EHeader->EType = ETYPE_ARP;
                break;
            case LAN_PROTO_IPv6:
                EHeader->EType = ETYPE_IPv6;
                break;
            default:
#ifdef DBG
                /* Should not happen */
                TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));

                ProtocolSendComplete((NDIS_HANDLE)Context,
                                     NdisPacket,
                                     NDIS_STATUS_FAILURE);
#endif
                return;
            }
            break;

        default:
            /* FIXME: Support other medias */
            break;
        }

	TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
	if( LinkAddress ) {
	    TI_DbgPrint
		( MID_TRACE,
		  ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
		   ((PCHAR)LinkAddress)[0] & 0xff,
		   ((PCHAR)LinkAddress)[1] & 0xff,
		   ((PCHAR)LinkAddress)[2] & 0xff,
		   ((PCHAR)LinkAddress)[3] & 0xff,
		   ((PCHAR)LinkAddress)[4] & 0xff,
		   ((PCHAR)LinkAddress)[5] & 0xff));
	}

	TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
	TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
        NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
	TI_DbgPrint(MID_TRACE, ("NdisSend %s\n",
				NdisStatus == NDIS_STATUS_PENDING ?
				"Pending" : "Complete"));
	TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );

	/* I had a talk with vizzini: these really ought to be here.
	 * we're supposed to see these completed by ndis *only* when
	 * status_pending is returned.  Note that this is different from
	 * the situation with IRPs. */
        if (NdisStatus != NDIS_STATUS_PENDING)
            ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
    } else {
        ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
    }
}

static NTSTATUS
OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
    OBJECT_ATTRIBUTES Attributes;
    NTSTATUS Status;

    InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
    Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes);
    return Status;
}

static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
					PWCHAR RegistryValue,
					PUNICODE_STRING String ) {
    UNICODE_STRING ValueName;
    UNICODE_STRING UnicodeString;
    NTSTATUS Status;
    ULONG ResultLength;
    UCHAR buf[1024];
    PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;

    RtlInitUnicodeString(&ValueName, RegistryValue);
    Status =
	ZwQueryValueKey(RegHandle,
			&ValueName,
			KeyValuePartialInformation,
			Information,
			sizeof(buf),
			&ResultLength);

    if (!NT_SUCCESS(Status))
	return Status;
    /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
    TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));

    UnicodeString.Buffer = (PWCHAR)&Information->Data;
    UnicodeString.Length = Information->DataLength - sizeof(WCHAR);
    UnicodeString.MaximumLength = Information->DataLength;

    String->Buffer =
	(PWCHAR)exAllocatePool( NonPagedPool,
				UnicodeString.MaximumLength + sizeof(WCHAR) );

    if( !String->Buffer ) return STATUS_NO_MEMORY;

    String->MaximumLength = UnicodeString.MaximumLength;
    RtlCopyUnicodeString( String, &UnicodeString );

    return STATUS_SUCCESS;
}

/*
 * Utility to copy and append two unicode strings.
 *
 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
 * IN     PUNICODE_STRING Second      -> Second string to append
 * IN     BOOL            Deallocate  -> TRUE: Deallocate First string before
 *                                       overwriting.
 *
 * Returns NTSTATUS.
 */

NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst,
				   PUNICODE_STRING Second,
				   BOOL Deallocate) {
    NTSTATUS Status;
    UNICODE_STRING Ustr = *ResultFirst;
    PWSTR new_string = ExAllocatePoolWithTag
        (PagedPool,
         (ResultFirst->Length + Second->Length + sizeof(WCHAR)), TAG_STRING);
    if( !new_string ) {
	return STATUS_NO_MEMORY;
    }
    memcpy( new_string, ResultFirst->Buffer, ResultFirst->Length );
    memcpy( new_string + ResultFirst->Length / sizeof(WCHAR),
	    Second->Buffer, Second->Length );
    if( Deallocate ) RtlFreeUnicodeString(ResultFirst);
    ResultFirst->Length = Ustr.Length + Second->Length;
    ResultFirst->MaximumLength = ResultFirst->Length;
    new_string[ResultFirst->Length / sizeof(WCHAR)] = 0;
    Status = RtlCreateUnicodeString(ResultFirst,new_string) ?
	STATUS_SUCCESS : STATUS_NO_MEMORY;
    ExFreePool(new_string);
    return Status;
}

static NTSTATUS CheckForDeviceDesc( PUNICODE_STRING EnumKeyName,
                                    PUNICODE_STRING TargetKeyName,
                                    PUNICODE_STRING Name,
                                    PUNICODE_STRING DeviceDesc ) {
    UNICODE_STRING RootDevice = { 0 }, LinkageKeyName = { 0 };
    UNICODE_STRING DescKeyName = { 0 }, Linkage = { 0 };
    UNICODE_STRING BackSlash = { 0 };
    HANDLE DescKey = NULL, LinkageKey = NULL;
    NTSTATUS Status;

    TI_DbgPrint(DEBUG_DATALINK,("EnumKeyName %wZ\n", EnumKeyName));

    RtlInitUnicodeString(&BackSlash, L"\\");
    RtlInitUnicodeString(&Linkage, L"\\Linkage");

    RtlInitUnicodeString(&DescKeyName, L"");
    AppendUnicodeString( &DescKeyName, EnumKeyName, FALSE );
    AppendUnicodeString( &DescKeyName, &BackSlash, TRUE );
    AppendUnicodeString( &DescKeyName, TargetKeyName, TRUE );

    RtlInitUnicodeString(&LinkageKeyName, L"");
    AppendUnicodeString( &LinkageKeyName, &DescKeyName, FALSE );
    AppendUnicodeString( &LinkageKeyName, &Linkage, TRUE );

    Status = OpenRegistryKey( &LinkageKeyName, &LinkageKey );
    if( !NT_SUCCESS(Status) ) goto cleanup;

    Status = ReadStringFromRegistry( LinkageKey, L"RootDevice", &RootDevice );
    if( !NT_SUCCESS(Status) ) goto cleanup;

    if( RtlCompareUnicodeString( &RootDevice, Name, TRUE ) == 0 ) {
        Status = OpenRegistryKey( &DescKeyName, &DescKey );
        if( !NT_SUCCESS(Status) ) goto cleanup;

        Status = ReadStringFromRegistry( DescKey, L"DriverDesc", DeviceDesc );
        if( !NT_SUCCESS(Status) ) goto cleanup;

        TI_DbgPrint(DEBUG_DATALINK,("ADAPTER DESC: %wZ\n", DeviceDesc));
    } else Status = STATUS_UNSUCCESSFUL;

cleanup:
    RtlFreeUnicodeString( &RootDevice );
    RtlFreeUnicodeString( &LinkageKeyName );
    RtlFreeUnicodeString( &DescKeyName );
    if( LinkageKey ) NtClose( LinkageKey );
    if( DescKey ) NtClose( DescKey );

    TI_DbgPrint(DEBUG_DATALINK,("Returning %x\n", Status));

    return Status;
}

static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name,
                                          PUNICODE_STRING DeviceDesc ) {
    UNICODE_STRING EnumKeyName, TargetKeyName;
    HANDLE EnumKey;
    NTSTATUS Status;
    ULONG i;
    KEY_BASIC_INFORMATION *Kbio =
        ExAllocatePool(NonPagedPool, sizeof(KEY_BASIC_INFORMATION));
    ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength;

    RtlInitUnicodeString
        (&EnumKeyName, CCS_ROOT L"\\Control\\Class\\" TCPIP_GUID);

    Status = OpenRegistryKey( &EnumKeyName, &EnumKey );

    if( !NT_SUCCESS(Status) )
        TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n",
                                    &EnumKeyName, Status));

    for( i = 0; NT_SUCCESS(Status); i++ ) {
        Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
                                 Kbio, KbioLength, &ResultLength );

        if( Status == STATUS_BUFFER_TOO_SMALL ) {
            ExFreePool( Kbio );
            KbioLength = ResultLength;
            Kbio = ExAllocatePool( NonPagedPool, KbioLength );

            Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
                                     Kbio, KbioLength, &ResultLength );

            TI_DbgPrint(DEBUG_DATALINK,("Couldn't enum key child %d\n", i));
            return Status;
        }

        if( NT_SUCCESS(Status) ) {
            TargetKeyName.Length = TargetKeyName.MaximumLength =
                Kbio->NameLength;
            TargetKeyName.Buffer = Kbio->Name;

            Status = CheckForDeviceDesc
                ( &EnumKeyName, &TargetKeyName, Name, DeviceDesc );
            if( NT_SUCCESS(Status) ) {
                NtClose( EnumKey );
                return Status;
            } else Status = STATUS_SUCCESS;
        }
    }

    RtlInitUnicodeString( DeviceDesc, L"" );
    AppendUnicodeString( DeviceDesc, &TargetKeyName, FALSE );
    NtClose( EnumKey );
    return STATUS_UNSUCCESSFUL;
}

VOID GetName( PUNICODE_STRING RegistryKey,
              PUNICODE_STRING OutName ) {
    PWCHAR Ptr;
    UNICODE_STRING PartialRegistryKey;

    PartialRegistryKey.Buffer =
        RegistryKey->Buffer + wcslen(CCS_ROOT L"\\Services\\");
    Ptr = PartialRegistryKey.Buffer;

    while( *Ptr != L'\\' &&
           ((PCHAR)Ptr) < ((PCHAR)RegistryKey->Buffer) + RegistryKey->Length )
        Ptr++;

    PartialRegistryKey.Length = PartialRegistryKey.MaximumLength =
        (Ptr - PartialRegistryKey.Buffer) * sizeof(WCHAR);

    RtlInitUnicodeString( OutName, L"" );
    AppendUnicodeString( OutName, &PartialRegistryKey, FALSE );
}

BOOLEAN BindAdapter(
    PLAN_ADAPTER Adapter,
    PNDIS_STRING RegistryPath)
/*
 * FUNCTION: Binds a LAN adapter to IP layer
 * ARGUMENTS:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -