//Copy the packet into a buffer
while (CurrentMdl && DataLength > 0)
{
NdisQueryMdl(CurrentMdl, &pSrc, &CurrLength, NormalPagePriority);
if (pSrc == NULL)
{
bytesCopied = 0;
break;
}
//
// Current buffer length is greater than the offset to the buffer
//
if (CurrLength > Offset)
{
pSrc += Offset;
CurrLength -= Offset;
if (CurrLength > DataLength)
{
CurrLength = DataLength;
}
DataLength -= CurrLength;
NdisMoveMemory(pDest, pSrc, CurrLength);
bytesCopied += CurrLength;
pDest += CurrLength;
Offset = 0;
}
else
{
Offset -= CurrLength;
}
NdisGetNextMdl(CurrentMdl, &CurrentMdl);
}
这段代码就是拷贝数据到缓冲区。其中CurrMDL,offset和dataLength来自Net_Buffer:
pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
//
// Try to get the 1p data from OOB data
//
if(NET_BUFFER_LIST_INFO(pNetBufferList, Ieee8021QNetBufferListInfo) != 0)
{
Ndis8021QInfo.Value = NET_BUFFER_LIST_INFO(pNetBufferList, Ieee8021QNetBufferListInfo);
UserPriority = (UCHAR)Ndis8021QInfo.TagHeader.UserPriority;
}
//copy the packet into a buffer
pDest = packetBuffer;
CurrentMdl = pNetBuffer->MdlChain;
Offset = pNetBuffer->DataOffset;
DataLength = pNetBuffer->DataLength;
其中NET_BUFFER_LIST_FIRST_NB返回的是第一个Net_Buffer. CurrentMDL指向MDL的list.现在来看看如何拷贝数据的。其中NdisQueryMdl返回MDL虚拟地址的基地址Psrc,和对应的缓冲区长度CurrLength
1、如果CurrLenght > offset,那么把Psrc+offset,指向used data.同样,CurrLength-offset,表示当前的MDL中有用的数据长度。然后执行NdisMoveMemory的拷贝操作.紧接着把,dataLength-CurrLength,因为已经拷贝好了一部分,然后再把offset置零,因为现在指针已经到了可用数据区。
2、当再次得到下一个MDL的Psrc,和CurrLength时,因为offset已经=0,所以CurrLength肯定大于0,所以即使执行PSrc+=offset, CurrLength-=offset.最后拷贝整个长度的空间(以图为例,不都是这样!!),dataLength-CurrLength.
3、最后第三次得到pSrc,和CurrLength,但是CurrLength,已经大于dataLength,所以只拷贝dataLength的长度数据。就完成了所有数据拷贝。
4、但是如果第一次的时候offset>CurrLength,那么就是比如图中第一个MDL为unused data区,执行offset-=CurrLength.如下图:
这样之后又回到了前面所说的CurrLength>offset了。
这就是拷贝数据到缓冲区的过程。不知有何疏漏,或者错误,见谅~