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所标识。