windows 驱动实例分析系列: NDIS 6.0的Filter 驱动改造(二)

news/2024/11/2 19:49:28/
缓冲区池

Filter驱动要发送数据,除了实现这两个回调之外,还需要分配一个NET_BUFFER_LIST池,用于从池中分配NET_BUFFER_LIST结构,注意内核代码必须仅从Pool中分配NET_BUFFER_LIST以及NET_BUFFER等缓冲区结构。

分配

 一般会使用下面的代码来分配缓冲区池:

NDIS_HANDLE AllocateListPool(NDIS_HANDLE NdisHandle)
{NET_BUFFER_LIST_POOL_PARAMETERS PoolParameters;NdisZeroMemory(&PoolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS));PoolParameters.Header.Type        = NDIS_OBJECT_TYPE_DEFAULT;PoolParameters.Header.Revision    = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;PoolParameters.Header.Size        = sizeof(PoolParameters);PoolParameters.ProtocolId         = NDIS_PROTOCOL_ID_DEFAULT ;PoolParameters.ContextSize        = sizeof(FILTER_SEND_NETBUFLIST_RSVD);PoolParameters.fAllocateNetBuffer = TRUE;PoolParameters.PoolTag            = FILTER_ALLOC_TAG;return NdisAllocateNetBufferListPool(NdisHandle, &PoolParameters);
}

后续可以用这个句柄分配一个NET_BUFFER_LIST结构,并且包含一个NET_BUFFER,这样的话就避免了调用NdisAllocateNetBufferPool分配NET_BUFFER的麻烦,但是NET_BUFFER_LIST可以挂接多个NET_BUFFER,这也是NdisAllocateNetBufferPool存在的意义。

释放

可以调用下面的代码释放分配的Pool:

// 释放NET_BUFFER_LIST池
void ReleasePool(NDIS_HANDLE  pNdisPoolHandle)
{if(NULL != pNdisPoolHandle){NdisFreeNetBufferListPool(pNdisPoolHandle);pNdisPoolHandle = NULL;}
}

在释放 NET_BUFFER_LIST 结构池之前,必须释放池中的所有NET_BUFFER_LIST结构,注意:释放结构池不等于释放池中的所有结构。 

数据包的接收

相比起发送,接收要简单很多,有两个例程和接受相关,分别是FilterReceiveNetBufferLists以及FilterReturnNetBufferLists函数,前者用于接受数据包,后者则是将数据包返回基础驱动程序。

如果 NDIS 传递给FilterReturnNetBufferLists中的 ReceiveFlags 中NDIS_RECEIVE_FLAGS_RESOURCES标志 指示的FilterReceiveNetBufferLists 函数未设置,Filter 驱动程序必须调用 NdisFReturnNetBufferLists 函数以返回 NET_BUFFER_LIST 结构和关联的数据。 在 Filter 驱动程序调用 NdisFReturnNetBufferLists 后,NDIS 将数据返回到基础驱动程序。:

VOID
FilterReceiveNetBufferLists(NDIS_HANDLE         FilterModuleContext,PNET_BUFFER_LIST    NetBufferLists,NDIS_PORT_NUMBER    PortNumber,ULONG               NumberOfNetBufferLists,ULONG               ReceiveFlags)
/*++Routine Description:FilerEReceiveNetBufferLists是Filter驱动程序的可选函数。如果提供,此功能处理接收底层发出的指示NIC或更低级别的Filter驱动程序。此函数也可以处理环回的结果。如果此处理程序为NULL,NDIS将跳过调用此处理程序在处理接收指示时的处理,并将调用在堆栈中下一个更高的指示驱动。一个不提供FilterReceiveNetBufferLists处理程序无法提供FilterReturnNetBufferLists处理程序,无法启动原始接收指示本身。Arguments:FilterModuleContext      - 上下文.NetBufferLists           - 数据包PortNumber               - 接收端口ReceiveFlags             -N.B.: 检查 NDIS_TEST_RECEIVE_CANNOT_PEND 中的 ReceiveFlags 非常重要。这控制接收指示是同步还是异步函数调用。--*/
{PMS_FILTER          pFilter = (PMS_FILTER)FilterModuleContext;BOOLEAN             DispatchLevel;ULONG               Ref;BOOLEAN             bFalse = FALSE;
#if DBGULONG               ReturnFlags;
#endifDEBUGP(DL_TRACE, "===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists);do{DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
#if DBGFILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);if (pFilter->State != FilterRunning){FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags)){ReturnFlags = 0;if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags)){NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);}NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);}break;}FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endifASSERT(NumberOfNetBufferLists >= 1);//// 如果您想丢弃接收到的数据包,则必须小心地// 修改 NBL 链,如下所示://// if NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags):// 对于每个未丢弃的 NBL,暂时将其从// 链接列表中断开,并使用// NdisFIndicateReceiveNetBufferLists 和// NDIS_RECEIVE_FLAGS_RESOURCES 标志集单独指示它。// 然后立即// 将 NBL 重新链接到链中。当所有 NBL 都已// 指示时,您可以从此函数返回。// // 否则(NDIS_TEST_RECEIVE_CANNOT_PEND 为 FALSE):// 将 NBL 的链接列表分为两个链:// 一个链包含要丢弃的数据包,另一个链中包含其他所有内容。// 使用 NdisFReturnNetBufferLists 返回第一个链,并使用 NdisFIndicateReceiveNetBufferLists 指示其余链。//// 注意:在以太网数据包的接收路径上,一个 NBL 将只有一个 NB。因此(假设您正在以太网上接收,或者连接到 Native WiFi 上方)您不必担心丢弃一个 NB,而是尝试指示同一 NBL 上的其余 NB。// 换句话说,如果第一个 NB 应该被丢弃,则丢弃整个 NBL。// 如果您想修改数据包,并且可以快速完成,您可以在此处进行修改。但是,请确保您保存了足够的信息以撤消 FilterReturnNetBufferLists 处理程序中的修改。// 如有必要,将 NetBufferLists 排队在本地结构中以供稍后处理。但是,不要将它们排队“太久”,否则系统的性能可能会下降。如果您需要无限期地保留 NBL,则分配内存,执行深度复制,然后返回原始 NBL。if (pFilter->TrackReceives){FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);pFilter->OutstandingRcvs += NumberOfNetBufferLists;Ref = pFilter->OutstandingRcvs;FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);}
#ifdef FILTER_TESTCopyNetBufferList(pFilter, NetBufferLists);
#endifNdisFIndicateReceiveNetBufferLists(pFilter->FilterHandle,NetBufferLists,PortNumber,NumberOfNetBufferLists,ReceiveFlags);if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) &&pFilter->TrackReceives){FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);pFilter->OutstandingRcvs -= NumberOfNetBufferLists;Ref = pFilter->OutstandingRcvs;FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);}} while (bFalse);DEBUGP(DL_TRACE, "<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags);}
数据包的访问

下面的代码用于将数据取出来,代码中并未处理缓冲区不足的情况,这只是一个案例演示:

NDIS_STATUS 
CopyNetBufferList(
IN PMS_FILTER pFilter, 
IN PNET_BUFFER_LIST NetBufferLists
)
{PUCHAR				pData = NULL;PNET_BUFFER_LIST	pCurrNbl = NetBufferLists;PNET_BUFFER			pCurrBuff = NULL;PNET_BUFFER         pNextBuff = NULL;PMDL				pMdl = NULL;ULONG				ulOffset = 0;int					nDataLen = 0;BOOLEAN             bFlags = !(KeGetCurrentIrql() == PASSIVE_LEVEL);// 1. 循环处理NET_BUFFER_LISTwhile (pCurrNbl){// 2. 获取一个NET_BUFFERpCurrBuff = NET_BUFFER_LIST_FIRST_NB(pCurrNbl);while (pCurrBuff){// 2.1 获取偏移量ulOffset = NET_BUFFER_DATA_OFFSET(pCurrBuff);// 2.2. 获取NMLpMdl = NET_BUFFER_FIRST_MDL(pCurrBuff);// 2.3. 获取长度nDataLen = NET_BUFFER_DATA_LENGTH(pCurrBuff);if (pMdl == NULL || nDataLen == 0) continue;// 从MDL中获取虚拟地址pData = (UCHAR*)MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);pNextBuff = NET_BUFFER_NEXT_NB(pCurrBuff);if (NULL == pNextBuff){// 获取真正的数据地址 pDatapData = pData + ulOffset;nDataLen = nDataLen - ulOffset;// 避免越界nDataLen = nDataLen > _DATA_SIZE ? _DATA_SIZE : nDataLen;// 由于上层随时可以读取数据,故需要增加自旋锁FILTER_ACQUIRE_LOCK(&pFilter->DataLock, bFlags);NdisZeroMemory(pFilter->Data, _DATA_SIZE);NdisMoveMemory(pFilter->Data, pData, nDataLen);FILTER_RELEASE_LOCK(&pFilter->DataLock, bFlags);}pCurrBuff = pNextBuff;}pCurrNbl = NET_BUFFER_LIST_NEXT_NBL(pCurrNbl);}return 0;
}

接收之后就是原始的数据缓冲区了。 


http://www.ppmy.cn/news/1543955.html

相关文章

Spring Boot实现的中小企业设备信息管理系统

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

千帆AppBuilder:让AI智能对话轻松融入您的网站,提升用户体验新高度!

​ 大模型场景实战培训&#xff0c;提示词效果调优&#xff0c;大模型应用定制开发&#xff0c;点击咨询 嘿&#xff0c;小伙伴们&#xff01;你们是不是也在寻找一种能够快速将AI智能对话融入业务网站的方法&#xff0c;让用户体验更上一层楼呢&#xff1f;如果是的话&#xf…

如何使用 NetBak PC Agent 备份和恢复 Windows 计算机或服务器?

创作立场:原创不易&#xff0c;拒绝搬运~ hello大家好&#xff0c;我是你们的老伙伴&#xff0c;稳重的大王~ 本期给大家介绍一款QNAP 发布的好用的备份软件&#xff0c;给大家分享一下使用经验&#xff0c;有需要的给个爱心鼓励一下&#xff0c;谢谢~ 开始正文 ----------…

加强版 第五节图像处理与视频分析

基本概念 图像轮廓 主要针对二值图像&#xff0c;轮廓是一系列点 vector<vector<Point>xxx用于存储多个点 vector<Vec4i>xxx包含四个整数&#xff0c;分别代表下一个轮廓的索引&#xff0c;上一个轮廓的索引&#xff0c;一个子轮廓的索引和父轮廓的索引 相…

G2 基于生成对抗网络(GAN)人脸图像生成

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 基于生成对抗网络&#xff08;GAN&#xff09;人脸图像生成 这周将构建并训练一个生成对抗网络&#xff08;GAN&#xff09;来生成人脸图像。 GAN 原理概述 …

解决Java接口接受附件入参失败的问题

接口的入参实体类存在 MultipartFile 类型属性&#xff0c;接口入参注解为RequestBody&#xff0c;会报错。需要把入参注解改为RequestPart&#xff0c;或者去掉注解。 RequestBody和RequestPart的异同&#xff1a; 相同点&#xff1a; 都可以用实体类接收传参 不同点&#xff…

分布式锁(redisson,看门狗,主从一致性)

目录 分布式锁一&#xff1a;基本原理和实现方式二&#xff1a;分布式锁的实现1&#xff1a;分布式锁的误删问题2&#xff1a;解决误删问题 三&#xff1a;lua脚本解决多条命令原子性问题调用lua脚本 四&#xff1a;Redisson1&#xff1a;redisson入门2&#xff1a;redisson可重…

.bixi勒索病毒来袭:如何防止文件加密与数据丢失?

导言 在网络威胁剧烈的今天&#xff0c;勒索病毒已成为企业和个人面临的重大安全挑战&#xff0c;其中虫洞勒索病毒习得高强度的加密手段和急剧传播的特性引起关注。一旦感染&#xff0c;就会加密关键数据并索要赎金&#xff0c;导致数据无法访问并带来巨大的财务损失。更为严…