ndis6.0 NetBufferSend
2015-06-11 16:47
239 查看
FilterSendNetBufferListsComplete:
NDIS calls the FilterSendNetBufferListsComplete function to complete a send request that a filter driver started by calling the NdisFSendNetBufferLists function.
FilterSendNetBufferLists:
NDIS calls the FilterSendNetBufferLists function to allow a filterdriver to filter a linked list of NET_BUFFER_LISTstructures.
调用关系如下:
![](http://hi.csdn.net/attachment/201107/29/0_1311930764761r.gif)
ndis6.0中NET_BUFFER_LIST和NET_BUFFER是两个很重要的数据结构。
如何在FilterSendNetBufferLists函数中读取数据包的内容呢,步骤如下:
1.pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(CurrNbl)
2.pMdl = NET_BUFFER_CURRENT_MDL(pCurrentNetBuffer)
3.NdisQueryMdl(
pMdl,
&pEthHeader,
&ulBufferLength,
NormalPagePriority);可以获得Mdl的地址指针保存在pEthHeader中,同时返回MDL内存块的大小ulBufferLength。
4.pEthHeader = (struct ether_header *)((PUCHAR)pEthHeader + NET_BUFFER_CURRENT_MDL_OFFSET(pCurrentNetBuffer)),这样pEthHeader 即指向我们熟悉的数据帧了(包含以太头+TCP/IP层头部)。
在获取数据包的过程中需要注意的是:
1).一个NET_BUFFER_LIST结构指向的是一连串的NET_BUFFER,这些NET_BUFFER中保存的数据包内容属于同一个stream(the same src-ip,dst-ip,src-port,dst-port and protocol)。通过NET_BUFFER_NEXT_NB(pCurrentNetBuffer)可以获取下一个NET_BUFFER。
2).在NET_BUFFER中包含NET_BUFFER_DATA结构
typedef struct _NET_BUFFER_DATA {
PNET_BUFFER Next;
PMDL MdlChain;
ULONG DataLength;
ULONG DataOffset;
PMDL CurrentMdl;
ULONG CurrentMdlOffset;
} NET_BUFFER_DATA, *PNET_BUFFER_DATA;
数据包的内容保存在MDL中,在上面的步骤2和3中,可通过NET_BUFFER信息获取到保存数据包内容的地址。因为MDL指示的那一块内存会有一个MDL头部信息(我并不确定),所以需要用pEthHeader + NET_BUFFER_CURRENT_MDL_OFFSET(pCurrentNetBuffer),这时才指向真正意义上的数据包内容。
3).一个NET_BUFFER因为MDL指向的内存大小有限制(我的观察是100个字节左右),所以一个NET_BUFFER会含有多个MDL(如一个1000字节的数据包,可能就会分为10个MDL进行保存),用MdlChain表示(即一个Mdl链表)。
4).
4000
通常情况下,NET_BUFFER中MdlChain与NET_BUFFER_CURRENT_MDL(pCurrentNetBuffer)获取到的CurrentMdl相同,同样的NET_BUFFER_CURRENT_MDL_OFFSET(pCurrentNetBuffer)与NET_BUFFER中DataOffset相同。
5).NET_BUFFER中DataLength代表数据包的总长度。在上面的步骤3中,获取到的ulBufferLength - NET_BUFFER_CURRENT_MDL(pCurrentNetBuffer),若所得值小于DataLength,则说明NET_BUFFER中含有多个MDL,若想获取完整包的信息则通过pMdl.next获取下一个MDL指针,在进行相关操作。
下面是我改写filter中FilterSendNetBufferLists函数的代码:
VOID FilterSendNetBufferLists( IN NDIS_HANDLE FilterModuleContext, IN PNET_BUFFER_LIST NetBufferLists, IN NDIS_PORT_NUMBER PortNumber, IN ULONG SendFlags ) /*++ Routine Description: Send Net Buffer List handler This function is an optional function for filter drivers. If provided, NDIS will call this function to transmit a linked list of NetBuffers, described by a NetBuferList, over the network. If this handler is NULL, NDIS will skip calling this fitler when sending a NetBufferList and will call the next lower fitler in the stack with a non_NULL FilterSendNetBufferList handleror the miniport driver. A filter that doesn't provide a FilerSendNetBufferList handler can not initiate a send o its own. Arguments: FilterModuleContext: Pointer to our filter context area. NetBufferLists: Pointer to a List of NetBufferLists. PortNumber - Port Number to which this send is targetted SendFlags- Specifies if the call is at DISPATCH_LEVEL Return Value: NDIS_STATUS_SUCCESS: NDIS_STATUS_PENDING: NDIS_STATUS_INVALID_PACKET: NDIS_STATUS_RESOURCES: NDIS_STATUS_FAILURE: NOTE: The filter will act like a passthru filter. --*/ { PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext; BOOLEAN DispatchLevel; BOOLEAN bFalse = FALSE; PNET_BUFFER_LIST CurrNbl, NextNbl; PNET_BUFFER pCurrentNetBuffer; PMDL pMdl; ULONG ulOffset; struct ether_header *pEthHeader = NULL; ULONG ulBufferLength = 0; ULONG NBDO; ULONG NBDL; //DEBUGP(DL_TRACE, ("===>SendNetBufferList: NBL = %p.\n", NetBufferLists)); do { DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendFlags); #if DBG // // we should never get packets to send if we are not in running state // FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); // // If the filter is not in running state, fail the send // if (pFilter->State != FilterRunning) { DEBUGP(4, ("NOT SURE WHETHER IN THIS PATH.\n")); FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); CurrNbl = NetBufferLists; while (CurrNbl) { NET_BUFFER_LIST_STATUS(CurrNbl) = NDIS_STATUS_PAUSED; CurrNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); } NdisFSendNetBufferListsComplete(pFilter->FilterHandle, NetBufferLists, DispatchLevel ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0); break; } FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); #endif if (pFilter->TrackSends) { FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel); CurrNbl = NetBufferLists; while (CurrNbl) { pFilter->OutstandingSends++; FILTER_LOG_SEND_REF(1, pFilter, CurrNbl, pFilter->OutstandingSends); NextNbl = NET_BUFFER_LIST_NEXT_NBL(CurrNbl); DEBUGP(4, ("===>BufferList: NBL = %p, begin the NB process.\n", NetBufferLists)); for(pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(CurrNbl); pCurrentNetBuffer != NULL; pCurrentNetBuffer = NET_BUFFER_NEXT_NB(pCurrentNetBuffer)) { pMdl = NET_BUFFER_CURRENT_MDL(pCurrentNetBuffer); ulOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pCurrentNetBuffer); NBDL = NET_BUFFER_DATA_LENGTH(pCurrentNetBuffer); NBDO = NET_BUFFER_DATA_OFFSET(pCurrentNetBuffer); do { ASSERT(pMdl != NULL); if (pMdl) { NdisQueryMdl( pMdl, &pEthHeader, &ulBufferLength, NormalPagePriority); } if (NULL == pEthHeader) { // // The system is low on resources. Set up to handle failure // below. // ulBufferLength = 0; break; } if (0 == ulBufferLength) { break; } ASSERT(ulBufferLength > ulOffset); //if the ulBufferLength < NBDL, then there are some more MDLs. DbgPrint("NBDL IS %d, NBD0 IS %d, MDL_OFFSET IS %d, MDL NET BUFFER LENGTH IS %d\n", NBDL, NBDO, ulOffset, ulBufferLength); ulBufferLength -= ulOffset; pEthHeader = (struct ether_header *)((PUCHAR)pEthHeader + ulOffset); if (ulBufferLength < sizeof(struct ether_header)) { DEBUGP(DL_WARN, ("ReceiveNetBufferList: runt nbl %p, first buffer length %d\n", CurrNbl, ulBufferLength)); break; } DbgPrint("DstMAC: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",pEthHeader->ether_dhost[0],pEthHeader->ether_dhost[1],pEthHeader->ether_dhost[2],pEthHeader->ether_dhost[3],pEthHeader->ether_dhost[4],pEthHeader->ether_dhost[5]); DbgPrint("srcMAC: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",pEthHeader->ether_shost[0],pEthHeader->ether_shost[1],pEthHeader->ether_shost[2],pEthHeader->ether_shost[3],pEthHeader->ether_shost[4],pEthHeader->ether_shost[5]); }while (bFalse); DbgPrint("End one NB process!\n"); } //DbgPrint("IF NOT SHOW THIE, MAYBE SOME PROBLEM.\n"); CurrNbl= NextNbl; } FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel); } // // If necessary, queue the NetBufferList in a local structure for later processing // NdisFSendNetBufferLists(pFilter->FilterHandle, NetBufferLists, PortNumber, SendFlags); } while (bFalse); DEBUGP(4, ("<===SendNetBufferList. \n")); }
其中用到了一个新的数据类型,可以添加到filter.h头文件中:
#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ struct ether_header { UCHAR ether_dhost[ETHER_ADDR_LEN]; UCHAR ether_shost[ETHER_ADDR_LEN]; USHORT ether_type; };
相关文章推荐
- 【迁移学习】2010-A Survey on Transfer Learning
- TIKZ全局样式设置
- 对js闭包的学习
- html 字符串拼接
- JS常用代码备忘
- HTML5新特性展示利用history.replaceState()修改历史记录
- jquery sticky停靠在右下角的插件 ,jquery pushytip提示框显示插件
- iOS5 strong, weak, unsafe_unretained ARC
- 如何判断浏览器的类型?
- js 身份证号验证
- css中div高度自适应
- React.js 基础入门四--要点总结
- 【前端JS】input textarea 默认文字,点击消失
- 手动触发js事件
- JQuery中$.ajax()方法参数详解
- JQuery学习系列1
- js获取url的参数的正则方式
- 剑指offer-第三章高质量的代码(调整数组顺序使得奇数位于偶数的前面)
- 网页 css 样式 初始化
- A Few Words about my ProRes Encoder