NDIS驱动分为3层
协议层驱动
绑定再所有网卡上,所以能截获接收到的包,但无法截获发送的包
中间层驱动
(P部分)绑定在了所有小端口驱动上(M部分)也被所有的协议驱动绑定,收发都能拦截。所有中间层小端口部分负责处理发送的包,协议部分负责处理接受的包
小端口驱动
网卡驱动
NDIS驱动开始
NdisMInitializeWrapper初始化NDIS句柄,
NdisIMRegisterLayeredMiniport注册小端口特征并获得DriverHandle,提供一组回调函数,用来拦截发送数据包,进行分析解析。
NdisRegisterProtocol注册协议特征并获得ProtHandle,拦截接受数据包,进行能分析解析。
NdisIMAssociateMiniport。将DriverHandle与ProtHandle关联。
收发包处理(协议部分的PtReceive(),小端口部分的MpSend())
协议分析(接收,拒绝,修改)
代码部分
在DriverEntry做了小端口,协议部分初始化,创建设备对象符号链接。初始化各种协议头。
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*------------------------------------------------------------------------------
逐一设置protocolChar结构中的每一个域。这些域一些是驱动程序所必需的版本号、名字等信息,
另外一些是函数指针,它们指定了一些NDIS自动执行的函数的入口地址。
这里指定的每一个函数在程序中必须有它的具体实现。其中有些函数指针可以为NULL,
表示不指定这个函数。但是,NDIS要求一些函数是必须指定的,它们包括:
BindAdapterHandler、UnbindAdapterHandler、OpenAdapterCompleteHandler 、
CloseAdapterCompleteHandler、ReceiveHandler 、ReceiveCompleteHandler、
TransferCompleteHandler、SendCompleteHandler 、ResetCompleteHandler 、
RequestCompleteHandler StatusHandler 、StatusCompleteHandler 、PnPEventHandler
------------------------------------------------------------------------------*/
/*++
Routine Description:
First entry point to be called, when this driver is loaded.
Register with NDIS as an intermediate driver.
Arguments:
DriverObject - pointer to the system's driver object structure
for this driver
RegistryPath - system's registry path for this driver
Return Value:
STATUS_SUCCESS if all initialization is successful, STATUS_XXX
error code if not.
--*/
{
NDIS_STATUS Status;
NDIS_PROTOCOL_CHARACTERISTICS PChars;//协议部分回调函数
NDIS_MINIPORT_CHARACTERISTICS MChars;//小端口相关回调函数
PNDIS_CONFIGURATION_PARAMETER Param;
NDIS_STRING Name;
NDIS_HANDLE WrapperHandle;
// add by LornWolf
UNICODE_STRING nameString, linkString;
UINT FuncIndex;
PDEVICE_OBJECT MyDeviceObject;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
//end add
Status = NDIS_STATUS_SUCCESS;
NdisAllocateSpinLock(&GlobalLock);
NdisMInitializeWrapper(&NdisWrapperHandle, DriverObject, RegistryPath, NULL);
do//放在dowhilefalse为了出错直接退出。
{
//
// Register the miniport with NDIS. Note that it is the miniport
// which was started as a driver and not the protocol. Also the miniport
// must be registered prior to the protocol since the protocol's BindAdapter
// handler can be initiated anytime and when it is, it must be ready to
// start driver instances.
//
NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL);
NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));
MChars.MajorNdisVersion = PASSTHRU_MAJOR_NDIS_VERSION;
MChars.MinorNdisVersion = PASSTHRU_MINOR_NDIS_VERSION;
MChars.InitializeHandler = MPInitialize;
MChars.QueryInformationHandler = MPQueryInformation;
MChars.SetInformationHandler = MPSetInformation;
MChars.ResetHandler = MPReset;
MChars.TransferDataHandler = MPTransferData;
MChars.HaltHandler = MPHalt;
#ifdef NDIS51_MINIPORT
MChars.CancelSendPacketsHandler = MPCancelSendPackets;
MChars.PnPEventNotifyHandler = MPDevicePnPEvent;
MChars.AdapterShutdownHandler = MPAdapterShutdown;
#endif // NDIS51_MINIPORT
//
// We will disable the check for hang timeout so we do not
// need a check for hang handler!
//
MChars.CheckForHangHandler = NULL;
MChars.ReturnPacketHandler = MPReturnPacket;//这时候已经没有IRP这个概念了,不能直接找
//所属进程了。在tdi中维护端口和ip地址的一个表,在ndis中拿到端口去查那个表
//
// Either the Send or the SendPackets handler should be specified.
// If SendPackets handler is specified, SendHandler is ignored
//下面是用来拦截发包的函数,
MChars.SendHandler = NULL; // MPSend;
MChars.SendPacketsHandler = MPSendPackets;
Status = NdisIMRegisterLayeredMiniport(NdisWrapperHandle,
&MChars,
sizeof(MChars),
&DriverHandle);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
#ifndef WIN9X
NdisMRegisterUnloadHandler(NdisWrapperHandle, PtUnload);
#endif
//
// Now register the protocol.
//
NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
PChars.MajorNdisVersion = PASSTHRU_PROT_MAJOR_NDIS_VERSION;
PChars.MinorNdisVersion = PASSTHRU_PROT_MINOR_NDIS_VERSION;
//
// Make sure the protocol-name matches the service-name
// (from the INF) under which this protocol is installed.
// This is needed to ensure that NDIS can correctly determine
// the binding and call us to bind to miniports below.
//
NdisInitUnicodeString(&Name, L"Passthru"); // Protocol name
PChars.Name = Name;
PChars.OpenAdapterCompleteHandler = PtOpenAdapterComplete;
PChars.CloseAdapterCompleteHandler = PtCloseAdapterComplete;
PChars.SendCompleteHandler = PtSendComplete;
PChars.TransferDataCompleteHandler = PtTransferDataComplete;
PChars.ResetCompleteHandler = PtResetComplete;
PChars.RequestCompleteHandler = PtRequestComplete;
PChars.ReceiveHandler = PtReceive;
PChars.ReceiveCompleteHandler = PtReceiveComplete;
PChars.StatusHandler = PtStatus;
PChars.StatusCompleteHandler = PtStatusComplete;
PChars.BindAdapterHandler = PtBindAdapter;
PChars.UnbindAdapterHandler = PtUnbindAdapter;
PChars.UnloadHandler = PtUnloadProtocol;
PChars.ReceivePacketHandler = PtReceivePacket;
PChars.PnPEventHandler= PtPNPHandler;
NdisRegisterProtocol(&Status,
&ProtHandle,
&PChars,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
if (Status != NDIS_STATUS_SUCCESS)
{
NdisIMDeregisterLayeredMiniport(DriverHandle);
break;
}
NdisIMAssociateMiniport(DriverHandle, ProtHandle);
}
while (FALSE);
//----------------- 创建设备对象与符号连接----------------------------add by xiaoqiang
RtlInitUnicodeString(&nameString, L"\\Device\\MyPassthru" );
RtlInitUnicodeString(&linkString, L"\\??\\MyPassthru");
for(FuncIndex = 0; FuncIndex <=IRP_MJ_MAXIMUM_FUNCTION; FuncIndex++)
{
MajorFunction[FuncIndex] = NULL;
}
MajorFunction[IRP_MJ_CREATE] = MydrvDispatch;
MajorFunction[IRP_MJ_CLOSE] = MydrvDispatch;
MajorFunction[IRP_MJ_DEVICE_CONTROL] = MydrvDispatchIoctl;//下发规则
Status = NdisMRegisterDevice(
WrapperHandle,
&nameString,
&linkString,
MajorFunction,
&MyDeviceObject,
&NdisDeviceHandle
);
if(Status != STATUS_SUCCESS)
{
DbgPrint("NdisMRegisterDevice failed!\n");
}
// 初始化config规则
DbgPrint("初始化config规则!\n");
g_Rules.global.fw_status=FWS_ALLOWALL;//放行
g_Rules.global.log_disable=0;
g_Rules.global.fw_mode=RM_ALLOW;
g_Rules.tcp.disable=0;
g_Rules.udp.disable=0;
g_Rules.icmp.disable=0;
// 分配与应用程序共享的内存
SystemVirtualAddress = ExAllocatePool(NonPagedPool, 1024);
Mdl = IoAllocateMdl(SystemVirtualAddress, 1024, FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(Mdl);
if (Status != NDIS_STATUS_SUCCESS)
{
NdisTerminateWrapper(NdisWrapperHandle, NULL);
}
g_pIPHeader=&g_IPHeader;
g_pTCPHeader=&g_TCPHeader;
g_pUDPHeader=&g_UDPHeader;
g_pICMPHeader=&g_ICMPHeader;
g_pLog = &g_Log;
return(Status);
}
//-------------------------------------------------------------add by xiaoqiang
static NTSTATUS MydrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp)
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp;
// UNREFERENCED_PARAMETER(DeviceObject);
irpSp = IoGetCurrentIrpStackLocation(pIrp);
switch (irpSp->MajorFunction)
{
case IRP_MJ_CREATE:
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0L;
break;
case IRP_MJ_CLOSE:
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0L;
MmUnmapLockedPages(UserVirtualAddress, Mdl);
break;
}
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
关于规则定义如下,总体分为全局,TCP,UDP规则,其次每个里面又分为In或者out
/**************************************************************
规则结构
***************************************************************/
//#include "DDKLBLInc.h"
#pragma pack(1)
struct Fw_Global {
char fw_status; //防火墙状态
char log_disable; //是否允许记日志
char fw_mode; //除了禁止的都允许、除了允许的都禁止
};
struct Fw_Rule_Node {
u_long id; //Rule的号码
u_char protocol; //协议类型
u_long s_ip; //原IP
u_long s_mask; //掩码
u_short s_port; //原端口
u_long d_ip; //目的IP
u_long d_mask; //掩码
u_short d_port; //目的端口
u_char direct; //方向
u_char action; //是否拦截
char sMemo[100];//备注
struct Fw_Rule_Node *next; //指向下个节点的指针
};
struct Fw_Rule {
u_char disable; //是否允许协议
struct Fw_Rule_Node *pin, *pout; //指向下个in, out节点的指针
};
//总体结构:
struct Fw_Rules {
struct Fw_Global global;
struct Fw_Rule tcp;
struct Fw_Rule udp;
struct Fw_Rule icmp;
struct Fw_Rule ip;
};
#pragma pack()
发包部分代码
然后看一下send方面的监控,MPSendPackets
VOID
MPSendPackets(
IN NDIS_HANDLE MiniportAdapterContext,
IN PPNDIS_PACKET PacketArray,//存放包的数组
IN UINT NumberOfPackets//包的数量
)
/*++
Routine Description:
Send Packet Array handler. Either this or our SendPacket handler is called
based on which one is enabled in our Miniport Characteristics.
Arguments:
MiniportAdapterContext Pointer to our adapter
PacketArray Set of packets to send
NumberOfPackets Self-explanatory
Return Value:
None
--*/
{
PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
NDIS_STATUS Status;
UINT i;
PVOID MediaSpecificInfo = NULL;
UINT MediaSpecificInfoSize = 0;
//add by xiaoqiang
UINT OffsetSize;
PUCHAR pPacketContent;
UCHAR nMatch = ALLOW;
DbgPrint("==>MPSendPackets(...)\n");
for (i = 0; i < NumberOfPackets; i++)
{
PNDIS_PACKET Packet, MyPacket;
Packet = PacketArray[i];
//---------------------------------------------------------add by xiaoqiang Mar 12 2006
DbgPrint("==>自定义区域\n");
if(Packet!=NULL)
{
// 分配内存
DbgPrint(("Packet!=NULL"));
Status = NdisAllocateMemoryWithTag((PVOID *)&pPacketContent, BUFFER_SIZE, 'maDN');
if(Status != NDIS_STATUS_SUCCESS)
{
DbgPrint("MPSendPackets:NdisAllocateMemory Failed\n");
nMatch=DENY;
}
if(pPacketContent == NULL)
{
DbgPrint("MPSendPackets:pPacketContent==NULL\n");
nMatch=DENY;
}
NdisZeroMemory(pPacketContent, BUFFER_SIZE);
CopyPacket2Buffer(Packet,pPacketContent,&OffsetSize); //数据拷贝函数
if(OffsetSize!=0)
{
nMatch=UTIL_MatchRule(pPacketContent, DT_OUT);
}
DBGPRINT(("In MPSentPacket And Free Memory\n"));
NdisFreeMemory(pPacketContent, BUFFER_SIZE, 0);
}
else
{
DbgPrint(("Packet=NULL 无法截获数据包"));
}
if(nMatch==DENY)
{
// 释放资源并返回
NdisFreePacket(Packet);
return;
}
DbgPrint("<==自定义区域\n");
//---------------------------------------------------------add end
#ifdef NDIS51
//
// Use NDIS 5.1 packet stacking:
//
{
PNDIS_PACKET_STACK pStack;
BOOLEAN Remaining;
//
// Packet stacks: Check if we can use the same packet for sending down.
//
pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
if (Remaining)
{
//
// We can reuse "Packet".
//
// NOTE: if we needed to keep per-packet information in packets
// sent down, we can use pStack->IMReserved[].
//
ASSERT(pStack);
NdisSend(&Status,
pAdapt->BindingHandle,
Packet);
if (Status != NDIS_STATUS_PENDING)
{
NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
Packet,
Status);
}
DbgPrint("NdisMSendComplete and Will be continue\n");
continue;
}
}
#endif
NdisAllocatePacket(&Status,
&MyPacket,
pAdapt->SendPacketPoolHandle);
if (Status == NDIS_STATUS_SUCCESS)
{
PSEND_RSVD SendRsvd;
SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
SendRsvd->OriginalPkt = Packet;
MyPacket->Private.Flags = NdisGetPacketFlags(Packet);
MyPacket->Private.Head = Packet->Private.Head;
MyPacket->Private.Tail = Packet->Private.Tail;
#ifdef WIN9X
//
// Work around the fact that NDIS does not initialize this
// to FALSE on Win9x.
//
MyPacket->Private.ValidCounts = FALSE;
#endif // WIN9X
//
// Copy the OOB data from the original packet to the new
// packet.
//
NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
NDIS_OOB_DATA_FROM_PACKET(Packet),
sizeof(NDIS_PACKET_OOB_DATA));
//
// Copy relevant parts of the per packet info into the new packet
//
#ifndef WIN9X
NdisIMCopySendPerPacketInfo(MyPacket, Packet);
#endif
//
// Copy the Media specific information
//
NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
&MediaSpecificInfo,
&MediaSpecificInfoSize);
if (MediaSpecificInfo || MediaSpecificInfoSize)
{
NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
MediaSpecificInfo,
MediaSpecificInfoSize);
}
NdisSend(&Status,
pAdapt->BindingHandle,
MyPacket);
if (Status != NDIS_STATUS_PENDING)
{
#ifndef WIN9X
NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
#endif
NdisFreePacket(MyPacket);
}
}
if (Status != NDIS_STATUS_PENDING)
{
NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
Packet,
Status);
}
}
DbgPrint("<==MPSendPackets(...)\n");
}
中间用到的拷贝函数,从包中拷贝数据到缓冲区
//
// Purpose
// 从截获的包描述符里面取出数据到缓冲区
// add by xiaoqiang
void CopyPacket2Buffer(IN PNDIS_PACKET pPacket,IN OUT PUCHAR pBuff,IN OUT PUINT pLength)
{
PNDIS_BUFFER BuffDT; //定义一个buffer指示符
PUCHAR BuffVA; //指向一个PNDIS_PACKET结构里面的Buffer的虚拟地址
UINT BuffLen; //Buffer的长度
*pLength=0; //数据包内容的总长度,开始先置零
BuffLen=0;
NdisQueryPacket(pPacket,NULL,NULL,&BuffDT,NULL); //查询Packet的信息,这里查的是Packet的Buffer指示符链表的第一个Buffer
while(BuffDT!=(PNDIS_BUFFER)NULL)
{
NdisQueryBufferSafe(BuffDT,&BuffVA,&BuffLen,32); //得到BuffDT指向的那个Buffer的虚拟地BuffVA和长度BuffLen
NdisMoveMemory(pBuff,BuffVA,BuffLen); //将BuffVA其中的内容,移动到pBuff指向的那块区域
pBuff=pBuff+BuffLen; //pBuff指针后移,前BuffLen个字节已经填入数据
*pLength+=BuffLen; //计算pBuff中填入数据的总长度pLength
NdisGetNextBuffer(BuffDT,&BuffDT); //获得Buffer指示符链表中的下一个Buffer指示符
}
return;
}
UTIL_MatchRule解析包函数。
UCHAR UTIL_MatchRule(char *pPacketContent, char Direct)
{
UCHAR nProtocol;
USHORT nEtherType = 0, nIPhdrLen, nIPOffset;
UCHAR nAction;
ULONG datetime=0;
nAction = ALLOW;
DBGPRINT(("==>UTIL_MatchRule(...)"));
//如果防火墙状态为切断所有则返回
if(g_Rules.global.fw_status==FWS_DENYALL) return DENY;
if(g_Rules.global.fw_status==FWS_ALLOWALL) return ALLOW;
// Copy the data.
if(1)
{
// Copy the data.
// DBGPRINT(("判断是否以太网包"));
NdisMoveMemory(
(PUCHAR)&nEtherType,
(pPacketContent + MEtherType),//MEtherType=12
sizeof(USHORT)
);
nEtherType = UTIL_htons( nEtherType ); //将包类型转换为网络顺序
if( nEtherType == ETHERTYPE_IP ) //if 包类型是IP包
{
//read ip header
nAction = ALLOW;
NdisMoveMemory(
(PUCHAR )g_pIPHeader,
pPacketContent + MHdrSize,//MHdrSize=14
sizeof(*g_pIPHeader)
);
nIPOffset=UTIL_ntohs(g_pIPHeader->ip_off);
#pragma warning(disable:4554)
if((nIPOffset&IP_DF==0)&&(nIPOffset&0x1FFF!=0)) //分片非第一片允许通过
return ALLOW;
nIPhdrLen=g_pIPHeader->ip_hl*4;//计算IP头长度
nProtocol=g_pIPHeader->ip_p;
switch(nProtocol)
{
case IPPROTO_TCP:
NdisMoveMemory(
(PUCHAR)g_pTCPHeader,
//包首指针+帧头长度+IP头长度,就是TCP头指针
pPacketContent + MHdrSize + nIPhdrLen,
sizeof(*g_pTCPHeader)
);
DBGPRINT(("数据包类型:TCP包,方向:%d",Direct));
nAction=UTIL_MatchTcpRule(g_pIPHeader, g_pTCPHeader, Direct);
return nAction;
break;
case IPPROTO_UDP:
NdisMoveMemory(
(PUCHAR)g_pUDPHeader,
pPacketContent + MHdrSize + nIPhdrLen,
sizeof(*g_pUDPHeader)
);
DBGPRINT(("数据包类型:UDP包"));
nAction=UTIL_MatchUdpRule(g_pIPHeader, g_pUDPHeader, Direct);
return nAction;
break;
case IPPROTO_ICMP:
NdisMoveMemory(
(PUCHAR)g_pICMPHeader,
pPacketContent + MHdrSize + nIPhdrLen,
sizeof(*g_pICMPHeader)
);
DBGPRINT(("数据包类型:ICMP包"));
nAction=UTIL_MatchIcmpRule(g_pIPHeader, g_pICMPHeader, Direct);
return nAction;
break;
}
}
DBGPRINT(("<==UTIL_MatchRule(...)"));
if(g_Rules.global.fw_mode==RM_DENY)
return DENY;
else
return ALLOW;
}
}
然后匹配TCL函数如下
UCHAR UTIL_MatchTcpRule(struct ip *pIpHeader, struct tcphdr *pTcpHeader, char Direct)
{
UCHAR nAction=NOT_MATCH;
USHORT nSrcPort, nDstPort;
ULONG nSrcIP, nDstIP;
struct Fw_Rule *pTcpRule=NULL;
struct Fw_Rule_Node *ptr=NULL;
pTcpRule=&g_Rules.tcp;
if(pTcpRule->disable) return DENY; //不允许TCP协议通过
DBGPRINT(("==>UTIL_MatchTcpRule TCP包方向:%d",Direct));
if(Direct==DT_OUT)
{
nSrcIP=UTIL_ntohl(pIpHeader->ip_src.s_addr);
nDstIP=UTIL_ntohl(pIpHeader->ip_dst.s_addr);
nSrcPort=UTIL_ntohs(pTcpHeader->th_sport);
nDstPort=UTIL_ntohs(pTcpHeader->th_dport);
ptr=pTcpRule->pout;
}
else
{
nSrcIP=UTIL_ntohl(pIpHeader->ip_src.s_addr);
nDstIP=UTIL_ntohl(pIpHeader->ip_dst.s_addr);
nSrcPort=UTIL_ntohs(pTcpHeader->th_sport);
nDstPort=UTIL_ntohs(pTcpHeader->th_dport);
ptr=pTcpRule->pin;
}
/*
DBGPRINT(("Rule direct:%d",ptr->direct));
DBGPRINT(("Packet Server IP:%d",nSrcIP & ptr->s_mask));
DBGPRINT(("Rule Server IP:%d",ptr->s_ip));
DBGPRINT(("Packet Client IP:%d",nDstIP & ptr->d_mask));
DBGPRINT(("Rule Client IP:%d",ptr->d_ip));
DBGPRINT(("Packet Server Port:%d",nSrcPort));
DBGPRINT(("Rule Server Port:%d",ptr->s_port));
DBGPRINT(("Packet Client Port:%d",nDstPort));
DBGPRINT(("Rule Client Port:%d",ptr->d_port));
*/
for(; ptr!=NULL; ptr=ptr->next)
{
if(((nSrcPort==ptr->s_port)||(ptr->s_port==0)) &&
((nDstPort==ptr->d_port)||(ptr->d_port==0)) &&
((ptr->s_ip==(nSrcIP & ptr->s_mask))||(ptr->s_ip==0))&&
((ptr->d_ip==(nDstIP & ptr->d_mask))||(ptr->d_ip==0))&&
(Direct==ptr->direct))
{
nAction=ptr->action;
break;
}
}
UTIL_CountPacket(PT_TCP, Direct, nAction, (int)UTIL_ntohs(pIpHeader->ip_len));
if (nAction!=NOT_MATCH)
{
if (!g_Rules.global.log_disable)
UTIL_TcpWriteLog(ptr, pIpHeader,pTcpHeader,Direct);
}
return nAction;
}
收包部分代码
收包就是不同函数处理不同协议的情况了,
NDIS_STATUS
PtReceive(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize
)
/*++
Routine Description:
Handle receive data indicated up by the miniport below. We pass
it along to the protocol above us.
If the miniport below indicates packets, NDIS would more
likely call us at our ReceivePacket handler. However we
might be called here in certain situations even though
the miniport below has indicated a receive packet, e.g.
if the miniport had set packet status to NDIS_STATUS_RESOURCES.
Arguments:
<see DDK ref page for ProtocolReceive>
Return Value:
NDIS_STATUS_SUCCESS if we processed the receive successfully,
NDIS_STATUS_XXX error code if we discarded it.
--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
PNDIS_PACKET MyPacket, Packet, MyPacket1;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
//-----------------------------add by xiaoqiang
PNDIS_BUFFER pPacketBuffer, pBakBuffer;
PUCHAR pPacketContent, pBakContent;
UINT PacketLen;
UCHAR nMatch = ALLOW;
UINT OffsetSize;
UINT BytesTransferred;
PRECV_RSVD RecvRsvd = NULL;
PVOID MediaSpecificInfo = NULL;
ULONG MediaSpecificSize= 0;
DBGPRINT(("==>PtReceive(...)\n"));
if (!pAdapt->MiniportHandle)
{
Status = NDIS_STATUS_FAILURE;
}
else do
{
//* ---------------注释掉,不采用这种方法取得数据包。--------------------------
//
// Get at the packet, if any, indicated up by the miniport below.
//
Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext);
if (Packet != NULL)
{
DBGPRINT(("NdisGetReceivedPacket != NULL\n"));
//
// The miniport below did indicate up a packet. Use information
// from that packet to construct a new packet to indicate up.
//
#ifdef NDIS51
//
// NDIS 5.1 NOTE: Do not reuse the original packet in indicating
// up a receive, even if there is sufficient packet stack space.
// If we had to do so, we would have had to overwrite the
// status field in the original packet to NDIS_STATUS_RESOURCES,
// and it is not allowed for protocols to overwrite this field
// in received packets.
//
#endif // NDIS51
//
// Get a packet off the pool and indicate that up
//
NdisDprAllocatePacket(&Status,
&MyPacket,
pAdapt->RecvPacketPoolHandle);
if (Status == NDIS_STATUS_SUCCESS)
{
//
// Make our packet point to data from the original
// packet. NOTE: this works only because we are
// indicating a receive directly from the context of
// our receive indication. If we need to queue this
// packet and indicate it from another thread context,
// we will also have to allocate a new buffer and copy
// over the packet contents, OOB data and per-packet
// information. This is because the packet data
// is available only for the duration of this
// receive indication call.
//
MyPacket->Private.Head = Packet->Private.Head;
MyPacket->Private.Tail = Packet->Private.Tail;
//
// Get the original packet (it could be the same packet as the
// one received or a different one based on the number of layered
// miniports below) and set it on the indicated packet so the OOB
// data is visible correctly at protocols above.
//
NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);
//
// Copy packet flags.
//
NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
//
// Force protocols above to make a copy if they want to hang
// on to data in this packet. This is because we are in our
// Receive handler (not ReceivePacket) and we can't return a
// ref count from here.
//
NDIS_SET_PACKET_STATUS(MyPacket, NDIS_STATUS_RESOURCES);
//
// By setting NDIS_STATUS_RESOURCES, we also know that we can reclaim
// this packet as soon as the call to NdisMIndicateReceivePacket
// returns.
//
NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);
//
// Reclaim the indicated packet. Since we had set its status
// to NDIS_STATUS_RESOURCES, we are guaranteed that protocols
// above are done with it.
//
NdisDprFreePacket(MyPacket);
break;
}
}
else
{
//
// The miniport below us uses the old-style (not packet)
// receive indication. Fall through.
//
}
//
// Fall through if the miniport below us has either not
// indicated a packet or we could not allocate one
//
//-----------------------------------------------------------------------*/
//-------------------------------------------add by xiaoqiang Mar 16 2006
if(FALSE){}
else if(PacketSize <= LookAheadBufferSize) // 如果 LookAheadBuffer 中包含了全部数据
{
// 分配内存
Status = NdisAllocateMemoryWithTag((PVOID *)&pPacketContent, BUFFER_SIZE, 'maDN');
if(Status != NDIS_STATUS_SUCCESS)
{
DbgPrint("PTReceive:NdisAllocateMemory Failed\n");
return(NDIS_STATUS_NOT_ACCEPTED);
}
if(pPacketContent == NULL)
{
DbgPrint("PTReceive:pPacketContent==NULL\n");
return(NDIS_STATUS_NOT_ACCEPTED);
}
// 将包头和 LookAheadBuffer 复制到新分配的内存中
NdisZeroMemory(pPacketContent, BUFFER_SIZE);
NdisMoveMemory(pPacketContent, HeaderBuffer, HeaderBufferSize);
NdisMoveMemory(pPacketContent+ HeaderBufferSize, LookAheadBuffer, LookAheadBufferSize);
PacketLen = PacketSize+HeaderBufferSize;
nMatch=UTIL_MatchRule(pPacketContent, DT_IN);
if(nMatch==DENY)
{
return NDIS_STATUS_NOT_ACCEPTED;
}
// 在包池中分配包描述符
NdisDprAllocatePacket(&Status, &MyPacket, pAdapt->RecvPacketPoolHandle);
if(Status == NDIS_STATUS_SUCCESS)
{
// 在缓冲池中分配缓冲描述符,将包描述符与缓冲描述符关联。
NdisAllocateBuffer(&Status, &pPacketBuffer, pAdapt->RecvBufferPoolHandle, pPacketContent, PacketLen);
NdisChainBufferAtFront(MyPacket, pPacketBuffer);
MyPacket->Private.Head->Next = NULL;
MyPacket->Private.Tail = NULL;
RecvRsvd=(PRECV_RSVD)(MyPacket->MiniportReserved);
RecvRsvd->OriginalPkt = NULL;
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);
// 向上层协议驱动指示数据包,防真网卡行为。
NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);
if(NDIS_GET_PACKET_STATUS(MyPacket) != NDIS_STATUS_PENDING)
{
DBGPRINT(("In PtReceive And Free Memory\n"));
NdisFreeBuffer(pPacketBuffer);
NdisFreeMemory(pPacketContent, BUFFER_SIZE, 0);
NdisDprFreePacket(MyPacket);
}
}
break;
}
else // 如果 LookAheadBuffer 中没有包含全部数据
{
// 分配内存 pPacketContent,存放要传输的除 LookAheadBuffer 之外的数据。
Status = NdisAllocateMemoryWithTag((PVOID *)&pPacketContent, BUFFER_SIZE, 'maDN');
if(Status != NDIS_STATUS_SUCCESS)
{
DbgPrint("PtReceive:NdisAllocateMemory Failed.\n");
return(NDIS_STATUS_NOT_ACCEPTED);
}
if(pPacketContent==NULL)
{
DbgPrint("PTReceive:pPacketContent==NULL\n");
return(NDIS_STATUS_NOT_ACCEPTED);
}
NdisZeroMemory(pPacketContent,BUFFER_SIZE);
// 分配包描述符 MyPacket。
NdisDprAllocatePacket(&Status, &MyPacket, pAdapt->RecvPacketPoolHandle);
// 分配内存 pBakContent,存放HeaderBuffer + LookAheadBuffer。
Status = NdisAllocateMemoryWithTag((PVOID *)&pBakContent, BUFFER_SIZE, 'maDN');
if(Status != NDIS_STATUS_SUCCESS)
{
DbgPrint("PtReceive:NdisAllocateMemory Failed.\n");
return(NDIS_STATUS_NOT_ACCEPTED);
}
if(pBakContent == NULL)
{
DbgPrint("PTReceive:pPacketContent==NULL\n");
return(NDIS_STATUS_NOT_ACCEPTED);
}
// 将 HeaderBuffer + LookAheadBuffer 复制到 pBakContent 指向的内存中。
NdisZeroMemory(pBakContent, BUFFER_SIZE);
NdisMoveMemory(pBakContent, HeaderBuffer, HeaderBufferSize);
NdisMoveMemory(pBakContent+HeaderBufferSize, LookAheadBuffer, LookAheadBufferSize);
PacketLen = HeaderBufferSize + PacketSize;
// 为要传输的除 LookAheadBuffer 之外的数据分配缓冲描述符(该缓冲描述符与 pPacketContent 指向的内存关联)。
NdisAllocateBuffer(&Status, &pPacketBuffer, pAdapt->RecvBufferPoolHandle, pPacketContent, PacketSize-LookAheadBufferSize);
// 关联包描述符 MyPacket 与缓冲描述符 pPacketBuffer。
NdisChainBufferAtFront(MyPacket, pPacketBuffer);
MyPacket->Private.Head->Next=NULL;
MyPacket->Private.Tail=NULL;
OffsetSize = HeaderBufferSize + LookAheadBufferSize;
// 分配包描述符 MyPacket1。
NdisDprAllocatePacket(&Status, &MyPacket1, pAdapt->RecvPacketPoolHandle);
// 分配缓冲描述符 pBakBuffer,与 pBakContent 指向的内存关联。
NdisAllocateBuffer(&Status, &pBakBuffer, pAdapt->RecvBufferPoolHandle, pBakContent, OffsetSize);
// 关联包描述符 MyPacket1 与缓冲描述符 pBakBuffer。
NdisChainBufferAtFront(MyPacket1, pBakBuffer);
RecvRsvd = (PRECV_RSVD)(MyPacket->MiniportReserved);
RecvRsvd->OriginalPkt = (PNDIS_PACKET)MyPacket1;
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize); //为随后的接收指示设置一个与给定包描述符相连的OOB数据块中的HeaderSize值
// 取得 LookAheadBuffer 之后的数据
NdisTransferData(&Status,
pAdapt->BindingHandle,
MacReceiveContext,
LookAheadBufferSize, // 数据起始地址
PacketSize-LookAheadBufferSize, // 字节数
MyPacket,
&BytesTransferred);
if(Status != NDIS_STATUS_PENDING)
{
PtTransferDataComplete((NDIS_HANDLE)pAdapt, MyPacket, Status, BytesTransferred);
}
break;
}
//-----------------------------------------------------------end add
pAdapt->IndicateRcvComplete = TRUE;
switch (pAdapt->Medium)
{
case NdisMedium802_3:
case NdisMediumWan:
NdisMEthIndicateReceive(pAdapt->MiniportHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize);
break;
case NdisMedium802_5:
NdisMTrIndicateReceive(pAdapt->MiniportHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize);
break;
case NdisMediumFddi:
// NdisMFddiIndicateReceive(pAdapt->MiniportHandle,
// MacReceiveContext,
// HeaderBuffer,
// HeaderBufferSize,
// LookAheadBuffer,
// LookAheadBufferSize,
// PacketSize);
break;
default:
ASSERT(FALSE);
break;
}
} while(FALSE);
DBGPRINT(("<==PtReceive(...)\n"));
return Status;
}
VOID
PtReceiveComplete(
IN NDIS_HANDLE ProtocolBindingContext
)
/*++
Routine Description:
Called by the adapter below us when it is done indicating a batch of
received packets.
Arguments:
ProtocolBindingContext Pointer to our adapter structure.
Return Value:
None
--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
DBGPRINT(("==>PtReceiveComplete(...)\n"));
if ((pAdapt->MiniportHandle != NULL) && pAdapt->IndicateRcvComplete)
{
switch (pAdapt->Medium)
{
case NdisMedium802_3:
case NdisMediumWan:
NdisMEthIndicateReceiveComplete(pAdapt->MiniportHandle);
break;
case NdisMedium802_5:
NdisMTrIndicateReceiveComplete(pAdapt->MiniportHandle);
break;
case NdisMediumFddi:
//NdisMFddiIndicateReceiveComplete(pAdapt->MiniportHandle);
break;
default:
ASSERT(FALSE);
break;
}
}
DBGPRINT(("<==PtReceiveComplete(...)\n"));
pAdapt->IndicateRcvComplete = FALSE;
}
INT
PtReceivePacket(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
ReceivePacket handler. Called by NDIS if the miniport below supports
NDIS 4.0 style receives. Re-package the buffer chain in a new packet
and indicate the new packet to protocols above us. Any context for
packets indicated up must be kept in the MiniportReserved field.
NDIS 5.1 - packet stacking - if there is sufficient "stack space" in
the packet passed to us, we can use the same packet in a receive
indication.
Arguments:
ProtocolBindingContext - Pointer to our adapter structure.
Packet - Pointer to the packet
Return Value:
== 0 -> We are done with the packet
!= 0 -> We will keep the packet and call NdisReturnPackets() this
many times when done.
--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
NDIS_STATUS Status;
PNDIS_PACKET MyPacket;
BOOLEAN Remaining;
//add by xiaoqiang
UINT OffsetSize;
PUCHAR pPacketContent;
UCHAR nMatch = ALLOW;
DBGPRINT(("==>PtReceivePacket(...)\n"));
//
// Drop the packet silently if the upper miniport edge isn't initialized
//
if (!pAdapt->MiniportHandle)
{
return 0;
}
//-------------------------------------------------------------add by xiaoqiang Mar 12 2006
DbgPrint("==>自定义区域\n");
if(Packet!=NULL)
{
// 分配内存
DbgPrint(("Packet!=NULL"));
Status = NdisAllocateMemoryWithTag((PVOID *)&pPacketContent, BUFFER_SIZE, 'maDN');
if(Status != NDIS_STATUS_SUCCESS)
{
DbgPrint("PtReceivePacket:NdisAllocateMemory Failed\n");
return(NDIS_STATUS_NOT_ACCEPTED);
}
if(pPacketContent == NULL)
{
DbgPrint("PtReceivePacket:pPacketContent==NULL\n");
return(NDIS_STATUS_NOT_ACCEPTED);
}
NdisZeroMemory(pPacketContent, BUFFER_SIZE);
CopyPacket2Buffer(Packet,pPacketContent,&OffsetSize); //数据拷贝函数
if(OffsetSize!=0)
{
nMatch=UTIL_MatchRule(pPacketContent, DT_IN);
}
DBGPRINT(("In PtReceivePacket And Free Memory\n"));
NdisFreeMemory(pPacketContent, BUFFER_SIZE, 0);
}
else
{
DBGPRINT(("Packet=NULL"));
}
if(nMatch==DENY)
{
// 释放资源并返回
NdisFreePacket(Packet);
return NDIS_STATUS_NOT_ACCEPTED;
}
DbgPrint("<==自定义区域\n");
//---------------------------------------------------------add end
#ifdef NDIS51
//
// Check if we can reuse the same packet for indicating up.
// See also: PtReceive().
//
(VOID)NdisIMGetCurrentPacketStack(Packet, &Remaining);
if (Remaining)
{
//
// We can reuse "Packet". Indicate it up and be done with it.
//
Status = NDIS_GET_PACKET_STATUS(Packet);
NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &Packet, 1);
return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
}
#endif // NDIS51
//
// Get a packet off the pool and indicate that up
//
NdisDprAllocatePacket(&Status,
&MyPacket,
pAdapt->RecvPacketPoolHandle);
if (Status == NDIS_STATUS_SUCCESS)
{
PRECV_RSVD RecvRsvd;
RecvRsvd = (PRECV_RSVD)(MyPacket->MiniportReserved);
RecvRsvd->OriginalPkt = Packet;
MyPacket->Private.Head = Packet->Private.Head;
MyPacket->Private.Tail = Packet->Private.Tail;
//
// Get the original packet (it could be the same packet as the one
// received or a different one based on the number of layered miniports
// below) and set it on the indicated packet so the OOB data is visible
// correctly to protocols above us.
//
NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
//
// Set Packet Flags
//
NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
Status = NDIS_GET_PACKET_STATUS(Packet);
NDIS_SET_PACKET_STATUS(MyPacket, Status);
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, NDIS_GET_PACKET_HEADER_SIZE(Packet));
NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);
//
// Check if we had indicated up the packet with NDIS_STATUS_RESOURCES
// NOTE -- do not use NDIS_GET_PACKET_STATUS(MyPacket) for this since
// it might have changed! Use the value saved in the local variable.
//
if (Status == NDIS_STATUS_RESOURCES)
{
//
// Our ReturnPackets handler will not be called for this packet.
// We should reclaim it right here.
//
NdisDprFreePacket(MyPacket);
}
DBGPRINT(("<==PtReceivePacket(...)\n"));
return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
}
else
{
//
// We are out of packets. Silently drop it.
//
return(0);
}
}
VOID
PtTransferDataComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status,
IN UINT BytesTransferred
)
/*----------------------------------------------------------------------------------
在底层网卡驱动调用介质相关函数(NdisMXxxIndicateReceive)向上指示 数 据 包 时,如 果
LookAheadBuffer 中不包括全部数据,协议驱动会调用 NdisTransferData 来获得其余的数据,
如果 NdisTransferData 返回PENDING,则这个函数会在传输完成后自动被调用。
由于在 PtReceive 中没有采用介质相关函数(NdisMXxxIndicateReceive)向上指示数据包,而
是用 NdisMIndicateReceivePacket,所以上层协议(tcp/ip等)不会调用 NdisTransferData,
因此这个函数不会被自动调用。
----------------------------------------------------------------------------------*/
/*++
Routine Description:
Entry point called by NDIS to indicate completion of a call by us
to NdisTransferData.
See notes under SendComplete.
Arguments:
Return Value:
--*/
{
PADAPT pAdapt = (PADAPT)ProtocolBindingContext; //得到ProtocolBind的信息
PUCHAR pPacketContent; //指向 从Packet取出数据存放内存空间 的虚拟地址
PRECV_RSVD RecvRsvd; //Rsvd是供包的制造者用的,一般用来在开始时放入一些有用的数据供做回收处理。
//Rsvd的结构也是可以自己定义的,只有你制造的包,你才可以访问里边的东西
UINT OffsetSize, Result, PacketLen; //offsetSize=HeaderBufferSize + LookAheadBufferSize??,初始化定义大小是?????
PNDIS_BUFFER pPacketBuffer; //看下面说明 the head of the chain of buffer descriptors for a given packet
PNDIS_PACKET pBakPacket; //下面有解析
PNDIS_BUFFER pBakBuffer; //
PUCHAR pBakContent; //pPacketBuffer的虚拟地址
UINT BufferLen; //pPacketBuffer里面数据长度
UCHAR nMatch = ALLOW;
DbgPrint("==>PtTransferDataComplete(...)\n");
//
// Returning the Send on the Primary, will point to itself if there is no LBFO
//
// pAdapt = pAdapt->pPrimaryAdapt; //Pointer to the primary
RecvRsvd = (PRECV_RSVD)(Packet->MiniportReserved); //Rsvd未保留区
// pBakPacket 里是 HeaderBuffer + LookAheadBuffer 的内容。
pBakPacket = (PNDIS_PACKET)(RecvRsvd->OriginalPkt); //Rsvd->OriginalPkt是PtReceive中保留的包描述符
if(pAdapt->MiniportHandle) //是否有微端口绑定,没有话,那也就是不可能有数据上传了
{
if(pBakPacket == NULL) //是否有数据
NdisMTransferDataComplete(pAdapt->MiniportHandle, Packet, Status, BytesTransferred);
else
{
Status = NdisAllocateMemoryWithTag((PVOID *)&pPacketContent, BUFFER_SIZE, 'maDN'); //分配内存.xp不能用NdisAllocateMemory
CopyPacket2Buffer(pBakPacket, pPacketContent, &OffsetSize);
CopyPacket2Buffer(Packet, pPacketContent+OffsetSize, &PacketLen);
// if(Monitor_flag)
// {
nMatch=UTIL_MatchRule(pPacketContent, DT_IN);
// }
// else {}
PacketLen += OffsetSize;
// 释放包描述符pBakPacket、缓冲描述符pBakBuffer、内存pBakContent。
NdisUnchainBufferAtFront(pBakPacket, &pBakBuffer);
NdisQueryBufferSafe(pBakBuffer, &pBakContent, &BufferLen, 32);
NdisFreeBuffer(pBakBuffer);
NdisFreeMemory(pBakContent, BUFFER_SIZE, 0);
NdisFreePacket(pBakPacket);
//reserved为保留区,有两块,一个是ProtocolReserved,一个是MiniportReserved。顾名思意,一个是为协议层保留的,一个是为MINIPORT保留的。
memset(Packet->MiniportReserved, 0, sizeof(Packet->MiniportReserved));
//removes the buffer descriptor at the head of the chain of buffer descriptors for a given packet.
//so pPacketBuffer 应该是 the head of the chain of buffer descriptors for a given packet
NdisUnchainBufferAtFront(Packet, &pPacketBuffer);
NdisQueryBufferSafe(pPacketBuffer, &pBakContent, &BufferLen, 32); //32是Priority,看DDK说明
NdisFreeBuffer(pPacketBuffer);
NdisFreeMemory(pBakContent, BUFFER_SIZE, 0);
if(nMatch==DENY)
{
// 释放资源并返回
NdisFreePacket(Packet);
return;
}
//请求分配Buffer指示符
NdisAllocateBuffer(&Status, &pPacketBuffer, pAdapt->RecvBufferPoolHandle, pPacketContent, PacketLen);
NdisChainBufferAtFront(Packet, pPacketBuffer); //将它挂到Packet的Buffer指示符链表的最前端
//因为我们只一次性就分配一个足够大的MEMORY,然后分配一个BUFFER链到PACKET上,所以为空
Packet->Private.Head->Next=NULL;
Packet->Private.Tail=NULL;
NDIS_SET_PACKET_HEADER_SIZE(Packet,14); 设置包头14个字节
// 向上层协议驱动指示数据包,防真网卡行为。
NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &Packet, 1);
if(NDIS_GET_PACKET_STATUS(Packet)!=NDIS_STATUS_PENDING)
{
MPReturnPacket((NDIS_HANDLE)pAdapt, Packet);
}
}
}
DbgPrint("<==PtTransferDataComplete(...)\n");
return;
}
总结
就是在小端口拦截发包拿到发包,协议端拿到收包,解析包,读数据到缓存中,用TCPIP头解析数据。根据IP和端口匹配规则。
NDIS是个WDM驱动,需要创建添加设备对象(AddDevice)。
流程如下
加载
插入网卡
PNP Manger(找到中间层驱动),调用AddDevice()
PtBindAdapter
分配收发包池
-NdisOpenAdapter()
-NdisIMInitializeDeviceInstanceEx()
MpInitialize()
-NdisMSetAttributesEx设置上下文
NdisSend->MpSend/MpSendPackets
NdisXXXReceive等函数
NDIS怎么过滤的呢,没有IRP,没有创建过滤设备对象,如何实现过滤监控上层发下来的数据包的呢?
通过分层的函数调用关系实现,通过NdisSend-》MpSend-》NdisSend-》MpSend-》NdisSend-》MiniportSend,MpSend是自己注册地,用来过滤了信息。
receive也是类似。下层调用回调,上层就会被触发。实现分层过滤。
NDIS绑定
绑定实现:调用协议驱动中断PtBindAdapter,绑定,并获得Bindinghandle,以后都在这个handle发数据,具体说上层的协议驱动绑定到中间层的虚拟adapter上,中间层驱动绑定到下层小端口驱动上,每次绑定获得一个绑定句柄。
PNP管理器发现系统中可用的NIC设备-》找到注册过的中间层驱动-》调用中间层
AddDevice-》PtBingdAdapter-》NdisOpenAdapter-》NdisIMInitalizeDeviceInstanceEx-》MpInitialize-》注册适配器上下文NdisMSetAttributerEx