johnmacco
驱动牛犊
驱动牛犊
  • 注册日期2009-01-07
  • 最后登录2010-02-21
  • 粉丝0
  • 关注0
  • 积分4分
  • 威望31点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:2189回复:1

NDIS发包蓝屏问题

楼主#
更多 发布于:2010-02-06 01:00
最近有一个需求,需要在以太网封包前发送自己的一个包,做一些类似准入控制的事情。
所以有下想法,修改passthru使他发送包前加入一个自定义包,先发出去。代码如下:
在MPSendPackets里面的如下位置添加代码

PPPOE_PACKET* myPktBuf;
....
//
// 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);
}
myPktBuf=PacketAllocate(40);
NdisMoveMemory(myPktBuf->source,"123456", 6); //这里自己随便编一个mac地址应该没有关系,我用纯协议发包试过,没事情
NdisMoveMemory(myPktBuf->dest,"654321", 6);
NdisMoveMemory(myPktBuf->data,"archangel",9);
myPktBuf->proto=0x6388;
PppoeSendPacket(pAdapt,myPktBuf, 40); //自定义发包函数

NdisSend(&Status,
pAdapt->BindingHandle,
MyPacket);

if (Status != NDIS_STATUS_PENDING)
{
#ifndef WIN9X
NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
#endif
NdisFreePacket(MyPacket);
ADAPT_DECR_PENDING_SENDS(pAdapt);
}
.....

自定义函数如下:
//自定义的一个结构
typedef struct _PPPOE_PACKET {
// ethernet header
unsigned char dest[6];
unsigned char source[6];
unsigned short proto;
unsigned char data[1];
} PPPOE_PACKET;

NDIS_PHYSICAL_ADDRESS MaxAddress = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);

PDEVICE_OBJECT gDeviceObject;
//释放包缓存
void MyFreeNdisPacket(PNDIS_PACKET p) {
PNDIS_BUFFER b;
while(1) {
NdisUnchainBufferAtFront(p, &b);
if(b != NULL) {
NdisFreeBuffer(b);
} else {
break;
}
}
NdisFreePacket(p);
}
//释放徐内存
void PacketFree(PPPOE_PACKET *p, UINT len) {
DbgPrint("PacketFree");

if (len == 0) len = 1514;

DbgPrint("packet: 0x%x, size: %d\n", (UINT)p, len);

NdisFreeMemory(p, len, 0);

DbgPrint("PacketFree");
}
//分配包内存
PPPOE_PACKET *PacketAllocate(UINT len) {
NDIS_STATUS s;
PPPOE_PACKET *p;
PDEVICE_EXTENSION pDevExt;

DbgPrint("PacketAllocate");

if (len == 0) len = 1514;
s = NdisAllocateMemory(&p, len, 0, MaxAddress);
if (s != NDIS_STATUS_SUCCESS) {
DbgPrint("can not allocate packet, status: 0x%x\n", s);
p= NULL;
}
else DbgPrint("packet: 0x%x, size: %d\n", (UINT)pDevExt->pktBuf, len);

DbgPrint("PacketAllocate");
return (PPPOE_PACKET *)pDevExt->pktBuf;
}

//联合包描述和包缓存,发包
NDIS_STATUS PppoeSendPacket(PADAPT a, PVOID p, UINT plen) {
PSEND_RSVD pinfo;
PNDIS_BUFFER buffer;
PNDIS_PACKET packet;
NDIS_STATUS s;
UINT len,PacketSize,BufLength,i;
PUCHAR pPacketContent,pBuf;
MDL * pNext;
DbgPrint("PppoeSendPacket");
//分配包描述
NdisAllocatePacket(&s, &packet, a->SendPacketPoolHandle);
if (s != NDIS_STATUS_SUCCESS) {
DbgPrint("failed to allocate packet\n");
DbgPrint("sendPPPOEPacket");
return NDIS_STATUS_FAILURE;
}
//分配包缓冲
NdisAllocateBuffer(&s, &buffer, a->pppoeBufferPoolHandle, p, plen);
if (s != NDIS_STATUS_SUCCESS) {
DbgPrint("failed to allocate buffer\n");
DbgPrint("sendPPPOEPacket");
return NDIS_STATUS_FAILURE;
}
//链接包缓冲和包描述
NdisChainBufferAtFront(packet, buffer);

//这里为了看看包是否连接成功,查看一下pPacketContent里的内容,结果证明可以申请成功
NdisQueryPacket( packet,NULL,NULL,NULL,&PacketSize);
s= NdisAllocateMemory( &pPacketContent, 2000, 0,MaxAddress);
if (s!=NDIS_STATUS_SUCCESS )
return NDIS_STATUS_FAILURE;
NdisZeroMemory (pPacketContent, 2000);
NdisQueryBufferSafe(packet->Private.Head, &pBuf, &BufLength, 32 );
NdisMoveMemory(pPacketContent, pBuf, BufLength);
i = BufLength;
pNext = packet->Private.Head;
for(;;)
{
if(pNext == packet->Private.Tail)
break;
pNext = pNext->Next; //指针后移
if(pNext == NULL)
break;

NdisQueryBufferSafe(pNext,&pBuf,&BufLength,32);
NdisMoveMemory(pPacketContent+i,pBuf,BufLength);
i+=BufLength;
}

//设置内存描述符结尾,免得ndis再访问内存违例
packet->Private.Head->Next=NULL;
packet->Private.Tail=NULL;
NdisSetPacketFlags(packet, NDIS_FLAGS_DONT_LOOPBACK); //为了不叫包回环,这个地方有没有都会蓝屏,没关系

//为异步释放做准备
pinfo = (PSEND_RSVD)packet->ProtocolReserved;
pinfo->pppoeBuf = p;
pinfo->pppoeLen = plen;

//发送函数,就在这个地方蓝屏
NdisSend(&s, a->BindingHandle, packet);
if (s == NDIS_STATUS_PENDING) {
DbgPrint("Packet send pending\n");
}
else { //同步情况
DbgPrint("NdisSend status: 0x%x\n", s);

PacketFree(p, plen);
MyFreeNdisPacket(packet);
}

DbgPrint("sendPPPOEPacket");
return s;
}

修改地方还有

自定义发包里
NdisAllocateBuffer(&s, &buffer, a->pppoeBufferPoolHandle, p, plen);一句里的pppoeBufferPoolHandle是在PtBindAdapter的NdisOpenAdapter之前,
用如下代码申请的:
NdisAllocateBufferPool(&Status, &(pAdapt->pppoeBufferPoolHandle), 10);
if (Status != NDIS_STATUS_SUCCESS) {
DbgPrint("failed to allocate buffer pool");
pAdapt->pppoeBufferPoolHandle = NULL;
}

在passthru.h修改结构
typedef struct _SEND_RSVD
{
PNDIS_PACKET OriginalPkt;
PVOID pppoeBuf;
UINT pppoeLen;

} SEND_RSVD, *PSEND_RSVD;

在protocol.c里面修改PtSendComplete如下:
PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
PNDIS_PACKET Pkt;
NDIS_HANDLE PoolHandle;

#ifdef NDIS51
//
// Packet stacking:
//
// Determine if the packet we are completing is the one we allocated. If so, then
// get the original packet from the reserved area and completed it and free the
// allocated packet. If this is the packet that was sent down to us, then just
// complete it
//
PoolHandle = NdisGetPoolFromPacket(Packet);
if (PoolHandle != pAdapt->SendPacketPoolHandle)
{
//
// We had passed down a packet belonging to the protocol above us.
//
// DBGPRINT(("PtSendComp: Adapt %p, Stacked Packet %p\n", pAdapt, Packet));

NdisMSendComplete(pAdapt->MiniportHandle,
Packet,
Status);
}
else
#endif // NDIS51
{
PSEND_RSVD SendRsvd;

SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);//这里是我添加的
Pkt = SendRsvd->OriginalPkt;

if(Pkt==NULL)//自定义包没有这个,用来判断自定义包
{
PacketFree(SendRsvd->pppoeBuf, SendRsvd->pppoeLen);
MyFreeNdisPacket(Packet);//释放完成后直接退出
return;
}
#ifndef WIN9X
NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
#endif

NdisDprFreePacket(Packet);

NdisMSendComplete(pAdapt->MiniportHandle,
Pkt,
Status);
}
//
// Decrease the outstanding send count
//
ADAPT_DECR_PENDING_SENDS(pAdapt);

最后说一点,其实NdisAllocateBufferPool在NT也就是XP,2k后系统包池总是返回NULL。而PtSendComplete似乎永远调不到,错误总是发生在ndisSend这个宏上。

请高手指点迷津。谢谢
cyliu
论坛版主
论坛版主
  • 注册日期2003-06-13
  • 最后登录2014-04-11
  • 粉丝5
  • 关注0
  • 积分1238分
  • 威望2531点
  • 贡献值0点
  • 好评度577点
  • 原创分14分
  • 专家分10分
沙发#
发布于:2010-02-06 12:41
错误太明显了,好好读读自己的代码,一眼就能看到了
走走看看开源好 Solaris vs Linux
游客

返回顶部