📄 lan.c
字号:
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 + -