深度剖析WinPcap之(八)――打开与关闭适配器(21)

1.6.3.2     NPF_GetDeviceMTU函数

函数获得最大传输单元(MTU),主要调用NdisRequest函数实现。对于各种错误情况,假设为以太网,假设为MTU1514个字节长度。
函数代码如下:
NTSTATUS
NPF_GetDeviceMTU(
               IN POPEN_INSTANCE pOpen,
               IN PIRP pIrp,
               OUT PUINT  pMtu)
{
    PLIST_ENTRY        RequestListEntry;
     PINTERNAL_REQUEST  MaxSizeReq;
     NDIS_STATUS        ReqStatus;
 
     ASSERT(pOpen != NULL);
     ASSERT(pIrp != NULL);
     ASSERT(pMtu != NULL);
 
/* 从双向链表中移出第一个元素*/
     RequestListEntry = ExInterlockedRemoveHeadList(
&pOpen->RequestList, &pOpen->RequestSpinLock);
 
     if (RequestListEntry == NULL)
     {
         // 错误,假设为以太网,设为1514个字节长度,函数返回
         *pMtu = 1514;
         return STATUS_SUCCESS;
     }
 
     MaxSizeReq = CONTAINING_RECORD(RequestListEntry, INTERNAL_REQUEST, ListElement);
     /* 设置Request成员的各参数*/
     MaxSizeReq->Request.RequestType = NdisRequestQueryInformation;
     MaxSizeReq->Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
 
     MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBuffer = pMtu;
     MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBufferLength =
sizeof (*pMtu);
 
     NdisResetEvent(&MaxSizeReq->InternalRequestCompletedEvent);
 
     /* 提交请求*/
     NdisRequest(
         &ReqStatus,
         pOpen->AdapterHandle,
         &MaxSizeReq->Request);
 
     if (ReqStatus == NDIS_STATUS_PENDING)
     {// 挂起,等待请求完成
         NdisWaitEvent(&MaxSizeReq->InternalRequestCompletedEvent, 0);
         ReqStatus = MaxSizeReq->RequestStatus;
     }
 
/* 在双向链表尾部原子插入一个元素,因为前面移出了该请求*/
     ExInterlockedInsertTailList(&pOpen->RequestList, &MaxSizeReq->ListElement, &pOpen->RequestSpinLock);
 
     if (ReqStatus == NDIS_STATUS_SUCCESS)
     {// 成功,返回
         return STATUS_SUCCESS;
     }
     else
     {
         // 错误,假设为以太网,设为1514个字节长度,函数返回
         *pMtu = 1514;
         return STATUS_SUCCESS;
     }
}
CONTAINING_RECORD 返回一个结构体实例的基地址,参数给定了该结构体类型、包含在该结构体中一个成员的地址与一个实例。宏原型如下:
PCHAR CONTAINING_RECORD(
IN PCHAR  Address,
IN TYPE  Type,
       IN PCHAR  Field
);
参数 Address 是指向 Type 类型结构体一个实例的一个成员指针。参数 Type 是需要返回结构体基地址的类型名。参数 Field 是被 Address 指向的成员名称,该成员被包含在 Type 类型中。
返回包含 Field 成员的结构体的基地址。
参看下面代码来理解该宏定义
PLIST_ENTRY         RequestListEntry;
PINTERNAL_REQUEST   MaxSizeReq;
 
/* 从双向链表中移出第一个元素*/
RequestListEntry = ExInterlockedRemoveHeadList(
&pOpen->RequestList, &pOpen->RequestSpinLock);
 
MaxSizeReq=CONTAINING_RECORD(
RequestListEntry, INTERNAL_REQUEST, ListElement);
 
typedef struct _INTERNAL_REQUEST {
LIST_ENTRY     ListElement;
NDIS_EVENT       InternalRequestCompletedEvent;
NDIS_REQUEST     Request;
NDIS_STATUS      RequestStatus;
} INTERNAL_REQUEST, *PINTERNAL_REQUEST;
也就是我们知道 结构体 INTERNAL_REQUEST 一个实例中的一个成员 ListElement 地址 RequestListEntry 需要获得包含 该成员实例的 INTERNAL_REQUEST 结构体的实例的地址MaxSizeReq
 

你可能感兴趣的:(职场,休闲,winpcap)