📄 lan.c
字号:
* Adapter = Pointer to LAN_ADAPTER structure
* NOTES:
* We set the lookahead buffer size, set the packet filter and
* bind the adapter to IP layer
*/
{
PIP_INTERFACE IF;
NDIS_STATUS NdisStatus;
LLIP_BIND_INFO BindInfo;
IP_ADDRESS DefaultMask = { 0 };
ULONG Lookahead = LOOKAHEAD_SIZE;
NTSTATUS Status;
HANDLE RegHandle = 0;
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
Adapter->State = LAN_STATE_OPENING;
NdisStatus = NDISCall(Adapter,
NdisRequestSetInformation,
OID_GEN_CURRENT_LOOKAHEAD,
&Lookahead,
sizeof(ULONG));
if (NdisStatus != NDIS_STATUS_SUCCESS) {
TI_DbgPrint(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
return FALSE;
}
/* Bind the adapter to IP layer */
BindInfo.Context = Adapter;
BindInfo.HeaderSize = Adapter->HeaderSize;
BindInfo.MinFrameSize = Adapter->MinFrameSize;
BindInfo.MTU = Adapter->MTU;
BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
BindInfo.AddressLength = Adapter->HWAddressLength;
BindInfo.Transmit = LANTransmit;
IF = IPCreateInterface(&BindInfo);
if (!IF) {
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
return FALSE;
}
/*
* Query per-adapter configuration from the registry
* In case anyone is curious: there *is* an Ndis configuration api
* for this sort of thing, but it doesn't really support things like
* REG_MULTI_SZ very well, and there is a note in the DDK that says that
* protocol drivers developed for win2k and above just use the native
* services (ZwOpenKey, etc).
*/
GetName( RegistryPath, &IF->Name );
Status = OpenRegistryKey( RegistryPath, &RegHandle );
if(NT_SUCCESS(Status)) {
Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
&IF->Description));
} else {
IPDestroyInterface( IF );
return FALSE;
}
DefaultMask.Type = IP_ADDRESS_V4;
IF->Unicast = DefaultMask;
IF->Netmask = DefaultMask;
IF->Broadcast.Type = IP_ADDRESS_V4;
IF->Broadcast.Address.IPv4Address =
IF->Unicast.Address.IPv4Address |
~IF->Netmask.Address.IPv4Address;
TI_DbgPrint(DEBUG_DATALINK,("BCAST(IF) %s\n", A2S(&IF->Broadcast)));
/* Get maximum link speed */
NdisStatus = NDISCall(Adapter,
NdisRequestQueryInformation,
OID_GEN_LINK_SPEED,
&IF->Speed,
sizeof(UINT));
if( !NT_SUCCESS(NdisStatus) )
IF->Speed = IP_DEFAULT_LINK_SPEED;
/* Register interface with IP layer */
IPRegisterInterface(IF);
/* Set packet filter so we can send and receive packets */
NdisStatus = NDISCall(Adapter,
NdisRequestSetInformation,
OID_GEN_CURRENT_PACKET_FILTER,
&Adapter->PacketFilter,
sizeof(UINT));
if (NdisStatus != NDIS_STATUS_SUCCESS) {
TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
IPDestroyInterface(IF);
return FALSE;
}
Adapter->Context = IF;
Adapter->State = LAN_STATE_STARTED;
return TRUE;
}
VOID UnbindAdapter(
PLAN_ADAPTER Adapter)
/*
* FUNCTION: Unbinds a LAN adapter from IP layer
* ARGUMENTS:
* Adapter = Pointer to LAN_ADAPTER structure
*/
{
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
if (Adapter->State == LAN_STATE_STARTED) {
PIP_INTERFACE IF = Adapter->Context;
IPUnregisterInterface(IF);
IPDestroyInterface(IF);
}
}
NDIS_STATUS LANRegisterAdapter(
PNDIS_STRING AdapterName,
PNDIS_STRING RegistryPath)
/*
* FUNCTION: Registers protocol with an NDIS adapter
* ARGUMENTS:
* AdapterName = Pointer to string with name of adapter to register
* Adapter = Address of pointer to a LAN_ADAPTER structure
* RETURNS:
* Status of operation
*/
{
PLAN_ADAPTER IF;
NDIS_STATUS NdisStatus;
NDIS_STATUS OpenStatus;
UINT MediaIndex;
NDIS_MEDIUM MediaArray[MAX_MEDIA];
UINT AddressOID;
UINT Speed;
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
IF = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
if (!IF) {
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
return NDIS_STATUS_RESOURCES;
}
RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
/* Put adapter in stopped state */
IF->State = LAN_STATE_STOPPED;
/* Initialize protecting spin lock */
KeInitializeSpinLock(&IF->Lock);
KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
/* Initialize array with media IDs we support */
MediaArray[MEDIA_ETH] = NdisMedium802_3;
TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
/* Open the adapter. */
NdisOpenAdapter(&NdisStatus,
&OpenStatus,
&IF->NdisHandle,
&MediaIndex,
MediaArray,
MAX_MEDIA,
NdisProtocolHandle,
IF,
AdapterName,
0,
NULL);
/* Wait until the adapter is opened */
if (NdisStatus == NDIS_STATUS_PENDING)
KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
else if (NdisStatus != NDIS_STATUS_SUCCESS) {
TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName));
exFreePool(IF);
return NdisStatus;
}
IF->Media = MediaArray[MediaIndex];
/* Fill LAN_ADAPTER structure with some adapter specific information */
switch (IF->Media) {
case NdisMedium802_3:
IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
IF->BCastMask = BCAST_ETH_MASK;
IF->BCastCheck = BCAST_ETH_CHECK;
IF->BCastOffset = BCAST_ETH_OFFSET;
IF->HeaderSize = sizeof(ETH_HEADER);
IF->MinFrameSize = 60;
AddressOID = OID_802_3_CURRENT_ADDRESS;
IF->PacketFilter =
NDIS_PACKET_TYPE_BROADCAST |
NDIS_PACKET_TYPE_DIRECTED |
NDIS_PACKET_TYPE_MULTICAST;
break;
default:
/* Unsupported media */
TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
exFreePool(IF);
return NDIS_STATUS_NOT_SUPPORTED;
}
/* Get maximum frame size */
NdisStatus = NDISCall(IF,
NdisRequestQueryInformation,
OID_GEN_MAXIMUM_FRAME_SIZE,
&IF->MTU,
sizeof(UINT));
if (NdisStatus != NDIS_STATUS_SUCCESS) {
TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (NDISCall)\n", AdapterName));
exFreePool(IF);
return NdisStatus;
}
/* Get maximum packet size */
NdisStatus = NDISCall(IF,
NdisRequestQueryInformation,
OID_GEN_MAXIMUM_TOTAL_SIZE,
&IF->MaxPacketSize,
sizeof(UINT));
if (NdisStatus != NDIS_STATUS_SUCCESS) {
TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
exFreePool(IF);
return NdisStatus;
}
/* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
NdisStatus = NDISCall(IF,
NdisRequestQueryInformation,
OID_GEN_MAXIMUM_SEND_PACKETS,
&IF->MaxSendPackets,
sizeof(UINT));
if (NdisStatus != NDIS_STATUS_SUCCESS)
/* Legacy NIC drivers may not support this query, if it fails we
assume it can send at least one packet per call to NdisSend(Packets) */
IF->MaxSendPackets = 1;
/* Get current hardware address */
NdisStatus = NDISCall(IF,
NdisRequestQueryInformation,
AddressOID,
&IF->HWAddress,
IF->HWAddressLength);
if (NdisStatus != NDIS_STATUS_SUCCESS) {
TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
exFreePool(IF);
return NdisStatus;
}
/* Get maximum link speed */
NdisStatus = NDISCall(IF,
NdisRequestQueryInformation,
OID_GEN_LINK_SPEED,
&Speed,
sizeof(UINT));
if (NdisStatus != NDIS_STATUS_SUCCESS) {
TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
exFreePool(IF);
return NdisStatus;
}
/* Convert returned link speed to bps (it is in 100bps increments) */
IF->Speed = Speed * 100L;
/* Add adapter to the adapter list */
ExInterlockedInsertTailList(&AdapterListHead,
&IF->ListEntry,
&AdapterListLock);
/* Bind adapter to IP layer */
if( !BindAdapter(IF, RegistryPath) ) {
TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName));
exFreePool(IF);
return NDIS_STATUS_NOT_ACCEPTED;
}
TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS LANUnregisterAdapter(
PLAN_ADAPTER Adapter)
/*
* FUNCTION: Unregisters protocol with NDIS adapter
* ARGUMENTS:
* Adapter = Pointer to a LAN_ADAPTER structure
* RETURNS:
* Status of operation
*/
{
KIRQL OldIrql;
NDIS_HANDLE NdisHandle;
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
/* Unlink the adapter from the list */
RemoveEntryList(&Adapter->ListEntry);
/* Unbind adapter from IP layer */
UnbindAdapter(Adapter);
TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
NdisHandle = Adapter->NdisHandle;
if (NdisHandle) {
Adapter->NdisHandle = NULL;
TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
NdisCloseAdapter(&NdisStatus, NdisHandle);
if (NdisStatus == NDIS_STATUS_PENDING) {
TcpipWaitForSingleObject(&Adapter->Event,
UserRequest,
KernelMode,
FALSE,
NULL);
NdisStatus = Adapter->NdisStatus;
}
} else
TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
FreeAdapter(Adapter);
return NDIS_STATUS_SUCCESS;
}
NTSTATUS LANRegisterProtocol(
PNDIS_STRING Name)
/*
* FUNCTION: Registers this protocol driver with NDIS
* ARGUMENTS:
* Name = Name of this protocol driver
* RETURNS:
* Status of operation
*/
{
NDIS_STATUS NdisStatus;
NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
InitializeListHead(&AdapterListHead);
KeInitializeSpinLock(&AdapterListLock);
/* Set up protocol characteristics */
RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
ProtChars.Name.Length = Name->Length;
ProtChars.Name.Buffer = Name->Buffer;
ProtChars.Name.MaximumLength = Name->MaximumLength;
ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
ProtChars.ResetCompleteHandler = ProtocolResetComplete;
ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
ProtChars.SendCompleteHandler = ProtocolSendComplete;
ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
ProtChars.ReceiveHandler = ProtocolReceive;
ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
ProtChars.StatusHandler = ProtocolStatus;
ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
ProtChars.BindAdapterHandler = ProtocolBindAdapter;
/* Try to register protocol */
NdisRegisterProtocol(&NdisStatus,
&NdisProtocolHandle,
&ProtChars,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
return (NTSTATUS)NdisStatus;
}
ProtocolRegistered = TRUE;
return STATUS_SUCCESS;
}
VOID LANUnregisterProtocol(
VOID)
/*
* FUNCTION: Unregisters this protocol driver with NDIS
* NOTES: Does not care wether we are already registered
*/
{
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
if (ProtocolRegistered) {
NDIS_STATUS NdisStatus;
PLIST_ENTRY CurrentEntry;
PLIST_ENTRY NextEntry;
PLAN_ADAPTER Current;
KIRQL OldIrql;
TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
/* Search the list and remove every adapter we find */
CurrentEntry = AdapterListHead.Flink;
while (CurrentEntry != &AdapterListHead) {
NextEntry = CurrentEntry->Flink;
Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
/* Unregister it */
LANUnregisterAdapter(Current);
CurrentEntry = NextEntry;
}
TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
ProtocolRegistered = FALSE;
}
}
VOID LANStartup() {
InitializeListHead( &LanSendCompleteList );
KeInitializeSpinLock( &LanSendCompleteLock );
}
VOID LANShutdown() {
KIRQL OldIrql;
PLAN_WQ_ITEM WorkItem;
PLIST_ENTRY ListEntry;
KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
while( !IsListEmpty( &LanSendCompleteList ) ) {
ListEntry = RemoveHeadList( &LanSendCompleteList );
WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
FreeNdisPacket( WorkItem->Packet );
ExFreePool( WorkItem );
}
KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -