6.2.3 内核空间中获得网络适配器列表的实现

在NPF中会由NPF_IoControl函数对IOCTL命令码BIOCSETOID与BIOCQUERYOID进行处理,其中BIOCSETOID与BIOCQUERYOID的具体定义与作用如下。

用来设置一个OID(object identifier,对象标识)值的IOCTL命令码的代码如下:


defne BIOCSETOID 0x80000000


用来获取一个OID值的IOCTL命令码的代码如下:


defne BIOCQUERYOID 0x80000004


NPF_IoControl函数中处理这两个IOCTL命令的代码如下:


case BIOCSETOID:

case BIOCQUERYOID:

/获得Ndis句柄/

if(NPF_StartUsingBinding(Open)==FALSE)

{

//失败

SET_FAILURE_INVALID_REQUEST();

break;

}

/从列表中获得一个请求/

RequestListEntry=ExInterlockedRemoveHeadList(

&Open->RequestList,&Open->RequestSpinLock);

if(RequestListEntry==NULL)

{

//释放Ndis句柄

NPF_StopUsingBinding(Open);

SET_FAILURE_NOMEM();

break;

}

pRequest=CONTAINING_RECORD(RequestListEntry,INTERNAL_REQUEST,ListElement);

/判断是否为一个Ndis请求/

OidData=Irp->AssociatedIrp.SystemBuffer;

if(

(IrpSp->Parameters.DeviceIoControl.InputBufferLength==

IrpSp->Parameters.DeviceIoControl.OutputBufferLength)

&&(IrpSp->Parameters.DeviceIoControl.InputBufferLength>=

sizeof(PACKET_OID_DATA))

&&(IrpSp->Parameters.DeviceIoControl.InputBufferLength>=

sizeof(PACKET_OID_DATA)-1+OidData->Length))

{

//内存有效

if(FunctionCode==BIOCSETOID)

{//设置参数

pRequest->Request.RequestType=NdisRequestSetInformation;

pRequest->Request.DATA.SET_INFORMATION.Oid=OidData->Oid;

pRequest->Request.DATA.SET_INFORMATION.InformationBuffer=

OidData->Data;

pRequest->Request.DATA.SET_INFORMATION.InformationBufferLength=

OidData->Length;

}

else

{//获取参数

pRequest->Request.RequestType=NdisRequestQueryInformation;

pRequest->Request.DATA.QUERY_INFORMATION.Oid=OidData->Oid;

pRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer=

OidData->Data;

pRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength=

OidData->Length;

}

//复位请求的完成事件

NdisResetEvent(&pRequest->InternalRequestCompletedEvent);

//提交该请求

NdisRequest(&Status,Open->AdapterHandle,&pRequest->Request);

}

else

{

//释放Ndis句柄的所有权

NPF_StopUsingBinding(Open);

//缓冲区太小

SET_FAILURE_BUFFER_SMALL();

break;

}

if(Status==NDIS_STATUS_PENDING)

{//等待请求的完成事件

NdisWaitEvent(&pRequest->InternalRequestCompletedEvent,0);

Status=pRequest->RequestStatus;

}

//释放Ndis句柄的所有权

NPF_StopUsingBinding(Open);

//完成该请求

if(FunctionCode==BIOCSETOID)

{//BIOCSETOID完成

OidData->Length=pRequest->Request.DATA.SET_INFORMATION.BytesRead;

}

else

{

if(FunctionCode==BIOCQUERYOID)

{//BIOCQUERYOID完成,写入OidData->Length长度的字节内容

OidData->Length=

pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten;

if(Status==NDIS_STATUS_SUCCESS)

{

if(pRequest->Request.DATA.QUERY_INFORMATION.BytesWritten>pRequest->Request.

DATA.QUERY_INFORMATION.InformationBufferLength)

{

Status=NDIS_STATUS_INVALID_DATA;

}

}

}

}

ExInterlockedInsertTailList(

&Open->RequestList,&pRequest->ListElement,&Open->RequestSpinLock);

if(Status==NDIS_STATUS_SUCCESS)

{

SET_RESULT_SUCCESS(sizeof(PACKET_OID_DATA)-1+OidData->Length);

}

else

{

SET_FAILURE_INVALID_REQUEST();

}


上述函数中,主要调用NdisRequest系统函数来向底层驱动发送请求,以完成设置/获取一个OID值。NdisRequest函数的原型如下:


VOID NdisRequest(

OUT PNDIS_STATUS Status,

IN NDIS_HANDLE NdisBindingHandle,

IN PNDIS_REQUEST NdisRequest

);


上述函数中,参数Status指向函数调用者提供的变量,用来返回状态值,底层驱动程序决定对应的NDIS_STATUS_XXX的返回状态;参数NdisBindingHandle描述由系统函数NdisOpenAdapter返回的句柄,它用于标识下一层驱动程序的目标NIC或者虚拟适配器;参数NdisRequest指向一个结构体,描述了带有一个给定OID_XXX编码的操作请求。OID是系统定义的,每种信息类型都被一个OID所标识。