阅读:2189回复:1
NDIS发包蓝屏问题
最近有一个需求,需要在以太网封包前发送自己的一个包,做一些类似准入控制的事情。
所以有下想法,修改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这个宏上。 请高手指点迷津。谢谢 |
|
沙发#
发布于:2010-02-06 12:41
错误太明显了,好好读读自己的代码,一眼就能看到了
|
|
|