📄 init.c
字号:
//
// We need to know whether the device has been assigned any resources
// by the bus driver because this enables has to decide whether to
// indicate the received packets at PASSIVE_LEVEL or DISPATCH_LEVEL.
// NDIS makes an assumption that any device that uses hardware resources
// will indicate packets from a DPC routine.
//
if (Status == NDIS_STATUS_SUCCESS) {
//
// There is possibility that we are enumerated by the toaster bus
// driver. The toaster bus driver just for illustration purpose
// assigns a port resource to every child it pops.
//
Adapter->IsHardwareDevice = TRUE;
} else {
//
// No hardware resources. So we will indicate the packets at
// PASSIVE_LEVEL.
//
Adapter->IsHardwareDevice = FALSE;
}
//
// Set our media state of disconnected unitl we are successfully connected
// to the target device. This flag will be cleared by the
//
MP_SET_FLAG(Adapter, fMP_DISCONNECTED);
#ifdef NDIS50_MINIPORT
//
// Register a shutdown handler for NDIS50 or earlier miniports
// For NDIS51 miniports, set AdapterShutdownHandler.
//
NdisMRegisterAdapterShutdownHandler(
Adapter->AdapterHandle,
(PVOID) Adapter,
(ADAPTER_SHUTDOWN_HANDLER) MPShutdown);
#endif
ntStatus = NICInitAdapterWorker(Adapter);
if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND){
//
// If the target device doesn't exist, we will register for ExCallback.
// Our callback routine will be called at PASSIVE_LEVEL when the
// target driver (NDISPROT) gets loaded and notifies the callback.
//
DEBUGP (MP_INFO, ( "Target device doesn't exist at this time %x\n", ntStatus ));
if(NICRegisterExCallback(Adapter)){
ntStatus = STATUS_SUCCESS;
}
}else if(ntStatus == STATUS_NO_MORE_ENTRIES){
ntStatus = STATUS_SUCCESS;
}
NT_STATUS_TO_NDIS_STATUS(ntStatus, &Status);
DEBUGP(MP_TRACE, ("<--- InitializeAdapter, Status=%x\n", Status));
return Status;
}
VOID
NICInitWorkItemCallback(
PNDIS_WORK_ITEM WorkItem,
PVOID Context)
/*++
Routine Description:
Workitme to retry our Initialization work as a result of notifiction
from the target driver.
Arguments:
WorkItem - Pointer to workitem
Dummy - Unused
Return Value:
--*/
{
PMP_ADAPTER Adapter = (PMP_ADAPTER)Context;
NTSTATUS ntStatus;
DEBUGP(MP_TRACE, ("--> NICInitWorkItemCallback\n"));
PAGED_CODE();
NdisFreeMemory(WorkItem, sizeof(NDIS_WORK_ITEM), 0);
ntStatus = NICInitAdapterWorker(Adapter);
if (NT_SUCCESS(ntStatus)){
//
// Let us indicate our media state to protocol drivers.
//
NdisMIndicateStatus(Adapter->AdapterHandle,
NDIS_STATUS_MEDIA_CONNECT,
(PVOID)0, 0);
NdisMIndicateStatusComplete(Adapter->AdapterHandle);
} else {
if(ntStatus == STATUS_OBJECT_NAME_NOT_FOUND){
//
// This could be a spurious notification as a result
// of another instance of our miniport registering
// the callaback.
//
DEBUGP (MP_ERROR, ( "NDISPROT is not ready yet\n"));
}else {
//
// I guess something irrecoverable happened. So let
// us remove our adapter instance by calling.
//
DEBUGP (MP_ERROR, ( "Removing miniport...\n"));
NdisMRemoveMiniport(Adapter->AdapterHandle);
}
}
MP_DEC_REF(Adapter);
DEBUGP(MP_TRACE, ("<-- NICInitWorkItemCallback\n"));
return;
}
NTSTATUS
NICInitAdapterWorker(
PMP_ADAPTER Adapter
)
/*++
Routine Description:
This is the worker routine for doing all the initialization work.
It opens the target device, allocates send & receive side resources
and spawns a worker thread to start receiving packets from the
target device.
Arguments:
Adapter Pointer to our adapter
Return Value:
NT Status code
--*/
{
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
NDIS_STATUS Status;
ULONG unUsed;
DEBUGP(MP_WARNING, ("--> NICInitAdapterWorker %p\n", Adapter));
PAGED_CODE();
//
// Let us make sure only one thread is executing this routine by
// waiting on this synchronization event.
//
DEBUGP(MP_WARNING, ("Waiting on the InitEvent...\n"));
NdisWaitEvent(&Adapter->InitEvent, 0);
do {
if(!MP_TEST_FLAG(Adapter, fMP_INIT_IN_PROGRESS)) {
//
// Adapter has been initialized successfully.
//
ntStatus = STATUS_SUCCESS;
break;
}
#ifdef INTERFACE_WITH_NDISPROT
ntStatus = NICOpenNdisProtocolInterface(Adapter);
if(!NT_SUCCESS(ntStatus)) {
break;
}
Adapter->TargetSupportsChainedMdls = FALSE;
#else
Adapter->TargetDeviceObject = Adapter->NextDeviceObject;
//
// Assuming this is driver attached to PCIDRV underneath. If you
// adapt this driver for someother stack, make sure the target
// supports chanined MDLs. For example, USB stack doesn't support
// chained MDLs.
//
Adapter->TargetSupportsChainedMdls = TRUE;
#endif
Status = NICAllocSendResources(Adapter);
if(Status != NDIS_STATUS_SUCCESS)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
DEBUGP(MP_ERROR, ("Failed to allocate send side resources\n"));
break;
}
Status = NICAllocRecvResources(Adapter);
if(Status != NDIS_STATUS_SUCCESS)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
DEBUGP(MP_ERROR, ("Failed to send side resources\n"));
break;
}
ntStatus = NICSendRequest(Adapter,
NdisRequestQueryInformation,
OID_GEN_LINK_SPEED,
&Adapter->ulLinkSpeed,
sizeof(ULONG),
&unUsed,
&unUsed
);
if(!NT_SUCCESS(ntStatus)){
DEBUGP(MP_ERROR, ("-->Unable to get link speed %x\n", ntStatus));
break;
}
//
// If the device property is set to promiscuous, we will set the
// target NIC to promiscuous mode and use a locally administered
// MAC address. Otherwise, we will assume the MAC address of the
// target NIC (We are assuming that user must have disabled the
// binding of TCP/IP with the target NIC).
//
if(Adapter->Promiscuous) {
ULONG PacketFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
DEBUGP(MP_TRACE, ("Set the physical NIC to promiscuous mode\n"));
ntStatus = NICSendRequest(Adapter,
NdisRequestSetInformation,
OID_GEN_CURRENT_PACKET_FILTER,
&PacketFilter,
sizeof(ULONG),
&unUsed,
&unUsed
);
if(!NT_SUCCESS(ntStatus)){
DEBUGP(MP_ERROR, ("-->Unable to set the NIC to promiscuous mode %x\n", ntStatus));
break;
}
} else {
//
// Then get the physical NICs MAC address and use that as our
// MAC address. Hoping that user must have disabled TCP/IP
// bindings with the physcial NIC.
//
ntStatus = NICSendRequest(Adapter,
NdisRequestQueryInformation,
OID_802_3_CURRENT_ADDRESS,
Adapter->PhyNicMacAddress,
ETH_LENGTH_OF_ADDRESS,
&unUsed,
&unUsed
);
if(!NT_SUCCESS(ntStatus)){
DEBUGP(MP_ERROR, ("-->Unable to get mac address %x\n", ntStatus));
break;
}
ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentAddress,
Adapter->PhyNicMacAddress);
DEBUGP(MP_WARNING, ("Current Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
Adapter->CurrentAddress[0],
Adapter->CurrentAddress[1],
Adapter->CurrentAddress[2],
Adapter->CurrentAddress[3],
Adapter->CurrentAddress[4],
Adapter->CurrentAddress[5]));
}
MP_CLEAR_FLAG(Adapter, fMP_INIT_IN_PROGRESS);
MP_CLEAR_FLAG(Adapter, fMP_DISCONNECTED);
MP_SET_FLAG(Adapter, fMP_POST_WRITES);
MP_SET_FLAG(Adapter, fMP_POST_READS);
//
// Finally schedule a workitme to start reading packets from
// the target device. Anytime, you post an asynchronous work
// make sure to take a reference on the Adapter to synchrnonize
// the halt handler with the workitem.
//
MP_INC_REF(Adapter);
NdisScheduleWorkItem(&Adapter->ReadWorkItem);
Adapter->StatusIndicationIrp =
IoAllocateIrp( Adapter->TargetDeviceObject->StackSize, FALSE );
if (NULL == Adapter->StatusIndicationIrp) {
DEBUGP(MP_ERROR, ("IoAllocateIrp failed\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
NICPostAsynchronousStatusIndicationIrp(Adapter);
}while(FALSE);
if(!NT_SUCCESS(ntStatus)){
NICFreeSendResources(Adapter);
NICFreeRecvResources(Adapter);
}
//
// Signal the event so another thread can proceed.
//
NdisSetEvent(&Adapter->InitEvent);
DEBUGP(MP_TRACE, ("<-- NICInitAdapterWorker %x\n", ntStatus));
return ntStatus;
}
NTSTATUS
NICMakeSynchronousIoctl(
IN PDEVICE_OBJECT TopOfDeviceStack,
IN PFILE_OBJECT FileObject,
IN ULONG IoctlControlCode,
IN OUT PVOID InputBuffer,
IN ULONG InputBufferLength,
IN OUT PVOID OutputBuffer,
IN ULONG OutputBufferLength,
OUT PULONG BytesReadOrWritten
)
/*++
Routine Description:
This routine sends a synchronous ioctl request. This has been customized
to handle only buffered IOCTLs. It also assumes that InputBuffer and
OutputBuffer pointers are non paged kernelmode bufferr addresses. This routine
can be called at IRQL <= DISPATCH_LEVEL.
Arguments:
TopOfDeviceStack - Pointer to the target deviceobject
IoctlControlCode - Value of the IOCTL request
InputBuffer - Buffer to be sent to the TopOfDeviceStack
InputBufferLength - Size of buffer to be sent to the TopOfDeviceStack
OutputBuffer - Buffer for received data from the TopOfDeviceStack
OutputBufferLength - Size of receive buffer from the TopOfDeviceStack
BytesReadOrWritten - Number of bytes read or written
Return Value:
NT status code
--*/
{
KEVENT event;
PIRP irp;
PIO_STACK_LOCATION irpSp;
NTSTATUS status;
ULONG length;
PVOID buffer = NULL;
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoAllocateIrp( TopOfDeviceStack->StackSize, FALSE );
if (NULL == irp) {
DEBUGP(MP_ERROR, ("IoAllocateIrp failed\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
irpSp->Parameters.DeviceIoControl.IoControlCode = IoctlControlCode;
irpSp->FileObject = FileObject;
irp->MdlAddress = NULL;
irp->AssociatedIrp.SystemBuffer = NULL;
//
// Make sure the IOCTL is a buffered IOCTL.
//
ASSERT((IoctlControlCode & 3) == METHOD_BUFFERED);
//
// Allocate a buffer that is large enough to contain
// both the input and the output buffers. Copy the input buffer
// to the allocated buffer and set the appropriate IRP fields.
//
if (InputBufferLength != 0 || OutputBufferLength != 0) {
length = InputBufferLength > OutputBufferLength ?
InputBufferLength : OutputBufferLength;
buffer = ExAllocatePoolWithTag( NonPagedPool, length, NIC_TAG);
if (buffer == NULL) {
IoFreeIrp( irp );
return STATUS_INSUFFICIENT_RESOURCES;
}
if (InputBuffer) {
RtlCopyMemory( buffer,
InputBuffer,
InputBufferLength );
}
}
irp->AssociatedIrp.SystemBuffer = buffer;
IoSetCompletionRoutine(irp,
NICMakeSynchronousIoCtlCompletion,
(PVOID)&event,
TRUE,
TRUE,
TRUE);
IoCallDriver(TopOfDeviceStack, irp);
//
// Wait for the event to be signalled by the completion
// routine.
//
KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE, // Not alertable
NULL);
//
// Copy the content of system buffer to output buffer.
//
if (OutputBuffer && buffer) {
RtlCopyMemory( OutputBuffer,
buffer,
OutputBufferLength );
}
status = irp->IoStatus.Status;
*BytesReadOrWritten = (ULONG)irp->IoStatus.Information;
if(buffer){
ExFreePoolWithTag(buffer, NIC_TAG);
}
IoFreeIrp(irp);
return status;
}
NTSTATUS
NICMakeSynchronousIoCtlCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -