阅读:6004回复:20
packet chain的问题
我看到各位大虾在作ndis im的程序中经常使用
NdisQueryBuffer和NdisGetNextBuffer。我现在 有一件事很迷惑,就是我们使用NdisQueryBuffer 得到一个packet链的第一个packet。 1。我的第一个问题就是,这第一个packet是不是就是一个完整的 ip包,如果是, 2。那么第二个问题: NdisGetNextBuffer得到的下一个包是什么呢?是不是 本机接收的或者发送的第二个包,这个包和前一个不一定 有相同的目的地址和源地址,是这样的马? 3。我的第三个问题:请问ptreceive调用一次是不是要接受 很多个ip包,所以我们要不断的用NdisQueryBuffer和NdisGetNextBuffer把所有的包都找出来? 同理,mpsend是不是也是一次发送多个ip包呢? mpsendpacket和ptreceivepacket呢? 请各位大虾多多指点,非常感谢 |
|
最新喜欢:lsq77
|
沙发#
发布于:2001-09-03 17:24
第一:
每个PACKET DESCREPTOR 里就是一个完整的IP包,无论里面有多少个BUFFER DESCREPTOR , 第二: 在下层的DRIVER,它是这样处理PACKET DESCREPTOR中的BUFFER DECREPTOR 的: *首先,从PACKET DESCREPTOR中取出第一个BUFFER DESCREPTOR,其实这个包就要包括MAC , IP 等头的数据, *然后,再取出剩余的BUFFER DESCREPTOR,而这些包只要是数据就行了, *最后,底层DRIEVER把头和数据拷到它的一个连续的内存里,就进行发送了。 不知这样你明白吗?呵呵 |
|
|
板凳#
发布于:2001-09-03 20:52
那么在上层的协议里头呢,它是不是也是这样干的呢?
*********************************************** 在下层的DRIVER,它是这样处理PACKET DESCREPTOR中的BUFFER DECREPTOR 的: *首先,从PACKET DESCREPTOR中取出第一个BUFFER DESCREPTOR,其实这个包就要包括MAC , IP 等头的数据, *然后,再取出剩余的BUFFER DESCREPTOR,而这些包只要是数据就行了, *最后,底层DRIEVER把头和数据拷到它的一个连续的内存里,就进行发送了。 ********************************************* |
|
|
地板#
发布于:2001-09-04 11:48
是的,你要是在你的驱动程序上获得IP包,你也应该这样作。
|
|
|
地下室#
发布于:2001-09-06 09:48
那么你能告诉我在im层获得的ip包的结构马?
我现在用passthru来抓包。我翻看了tcp/ip的 协议,说的是ip包的前20个字节是包头。其中 后8个是源和目的地址。可是我看前面一些人的 文章想“过滤icmp源码“中提到第12、13字节 是协议内容,这两者好像不一样呀????? 还有,我现在在passthru的基础上变成,我想得到 发送出去的包的ip地址,我在mpsend中抓包。 我跟踪过,我的网卡走的是mpsend。可是,现在我的 抓包程序一放上去,我的所有的数据包就不能发送 到网上(连ping都平不通了)。可是为什么呢? 用soft_ice跟踪,发现:NdisQueryPacket(MyPacket, NULL, NULL, &firstBuffer, &totalLength); 中firstbuffer为NULL,请多多指点,谢谢!!!! 我的源程序如下: NdisAllocatePacket(&Status,&MyPacket,pAdapt->SendPacketPoolHandle); if (Status == NDIS_STATUS_SUCCESS) { PNDIS_PACKET_EXTENSION Old, New; //////////////////new adding if(MyPacket!= NULL) { NdisQueryPacket(MyPacket, NULL, NULL, &firstBuffer, &totalLength); if( firstBuffer != NULL) { NdisQueryBuffer(firstBuffer, &virtualAddress, &totalLength); if(!virtualAddress) { } else { RtlCopyMemory(m_Packet[m_buffercount],virtualAddress,READLEN); DBGPRINT ("==>Passthru MPSend and Ready for filter!\n"); memcpy(Packet_data,virtualAddress,totalLength); } } } ///////////////////////new adding Rsvd = (PRSVD)(MyPacket->ProtocolReserved); Rsvd->OriginalPkt = Packet; MyPacket->Private.Flags = Flags; MyPacket->Private.Head = Packet->Private.Head; MyPacket->Private.Tail = Packet->Private.Tail; NdisSetPacketFlags(MyPacket, NDIS_FLAGS_DONT_LOOPBACK); NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket), NDIS_OOB_DATA_FROM_PACKET(Packet), sizeof(NDIS_PACKET_OOB_DATA)); NdisIMCopySendPerPacketInfo(MyPacket, Packet); |
|
|
5楼#
发布于:2001-09-06 10:28
你提到的12,13字节应该是拟太包的头结构中的第13和14字节,是协议类型,与IP头结构没有关系。至于IP头结构的定义,DDK中有,在Filter-Hook Driver中有讲,定义如下:
typedef struct IPHeader { UCHAR iph_verlen; // Version and length UCHAR iph_tos; // Type of service USHORT iph_length; // Total datagram length USHORT iph_id; // Identification USHORT iph_offset; // Flags, fragment offset UCHAR iph_ttl; // Time to live UCHAR iph_protocol; // Protocol USHORT iph_xsum; // Header checksum ULONG iph_src; // Source address ULONG iph_dest; // Destination address } IPHeader; |
|
|
6楼#
发布于:2001-09-06 10:47
那么你说的以太网的包头是在那一层上?网络层还是传输层?
我能不能从这个一太网的包头截获ip地址呢? 我现在有点糊涂了。因为我的想法是,应用层数据到网络数据 应该是这样的,先是tcp或者udp的包头封装这个数据,然后 用ip包头封装。然后在发送。那么你说的这个一太网的数据 是不是在这个过程中呢?还是我的理解就不对呢? windows ndis是这样吧应用层的数据一层一层的形成网络包呢? 我觉得ndis的protocal层已经把数据封装为ip包了,到了 im的mpsend,我得到的是一个封装好了的ip包不过数据分在 不同的buffer中?是这样的马? |
|
|
7楼#
发布于:2001-09-06 10:53
我个人认为你最好先用ndisquerypackets问一下这个packet 有多少个buffer descropters,如果返回不是0个buffer descripters,然后再去取firstbuffer,这样就安全,因为很可能有些包是没有buffer descripters.
|
|
|
8楼#
发布于:2001-09-06 10:57
确实是先封装TCP,UDP头,再封装IP头,到了IM时,已经把拟太头也封装到IP包的外面了。IM收到的数据就是一个完整的拟太帧,有14字节的拟太头,20字节的IP头,然后是IP层以上的应用。IP地址在IP头结构中就有,拟太头中的是你的网络设备的MAC地址。
|
|
|
9楼#
发布于:2001-09-06 14:47
感谢Dino大侠,解释的非常清楚,我现在对这个问题明白了。
我的程序的问题是因为我抓包的位置不对.现在就剩下第一个 问题了. |
|
|
10楼#
发布于:2001-09-06 16:08
第一:
每个PACKET DESCREPTOR 里就是一个完整的IP包,无论里面有多少个BUFFER DESCREPTOR , 第二: 在下层的DRIVER,它是这样处理PACKET DESCREPTOR中的BUFFER DECREPTOR 的: *首先,从PACKET DESCREPTOR中取出第一个BUFFER DESCREPTOR,其实这个包就要包括MAC , IP 等头的数据, *然后,再取出剩余的BUFFER DESCREPTOR,而这些包只要是数据就行了, *最后,底层DRIEVER把头和数据拷到它的一个连续的内存里,就进行发送了。 就是说,一个packet中的所有buffers就组成一个完整的IP包!!! |
|
|
11楼#
发布于:2001-09-07 11:03
大家的谈话对我也很有帮助,其实我也曾经遇到过同样的问题,现在我的数据包的发送问题已经解决了,我这里有一个问题,我的网卡收数据是一段连续的数据,我是否需要把它们做成数据包的格式?如果是,那需要分成几个buffer呢?我现在分了两个buffer,一个包含了14字节的包头,即源和目的的mac地址和两字节的数据类型。其他的数据我用一个buffer可以吗?我在初始化的时候调用了ndisAllocatePacketPool分配包池,用NdisAllocateBufferPool分配了buffer池,用NdisAllocatePacket从包池中分配了包,用NdisAllocateBuffer从buffer池中分配了两个buffer,然后将数据拷到buffer中,然后用NdisChainBufferAtBack把buffer连接到包中,然后用NdisMIndicateReceivePacket指示,这一过程对吗?什么时候把这些东西Free掉呢?因为我的网卡在接收时总是死机。
|
|
12楼#
发布于:2001-09-07 11:36
我的操作和你基本一样,但我只用了一个Buffer,然后用NdisMIndicateReceivePacket通知上乘的应用。调用完后就检查packet的状态,如果不是pending的话,就可以马上释放资源,如果是pending的话,就在miniportreturnpacket函数里面释放资源。
|
|
|
13楼#
发布于:2001-09-07 14:46
谢谢,DINO大虾的帮助,请问您说的释放资源是不是几个free函数,如果是的话,那就要再下一次接收数据的时候再次分配PacketPool\Packet\BufferPool\Buffer这些资源了,那不是太麻烦了吗?会不会影响网卡的速度呢?
|
|
14楼#
发布于:2001-09-07 15:05
我不是大峡,我只是小虾米而已。packetpool and bufferpool可以在初始化的时候分配好,以后就只用allocate packet and buffer了。如果你是用的packet数组的话,用完了可以调用NdisReinitializePacket,在吊之前要先把chain在她上面的buffer先unchain下来,这样packet就不用再分配了。
|
|
|
15楼#
发布于:2001-09-08 14:30
请问以上几位大虾,在将buffer 连接上packet中还要设置其他信息吗?我的网卡收数据是一段连续的数据,我只用了一个Buffer,然后用NdisMIndicateReceivePacket通知上乘的应用。在绑定tcp/ip后却总是ping 不通,不知为什么?请大虾指点。
|
|
16楼#
发布于:2001-09-08 15:56
Dino大虾请指教:
我在初始化时分配PacketPool和BufferPool,代码如下: NdisAllocatePacketPool(&Status,&m_PoolHandle,BTNET_MAX_SEND_PACKETS,16); if( NT_SUCCESS( Status ) ) { TRACE("%s","NDIS PacketPool allocate Success\n"); } else { TRACE("%s","NDIS Packet allocatePool failure\n"); return Status; } NdisAllocateBufferPool (&Status,&m_BufPoolHandle,BTNET_MAX_SEND_PACKETS); if( NT_SUCCESS( Status ) ) { TRACE("%s","NDIS BufferPool allocate Success\n"); } else { TRACE("%s","NDIS Buffer allocatePool failure\n"); return Status; } 我是通过IOCTL得到一个Buffer,代码如下: ioBuffer = pIrp->AssociatedIrp.SystemBuffer; inputBufferLength = irpStack-Parameters.DeviceIoControl.InputBufferLength; case IOCTL_WRITE_BTDEV: TRACE("%s","IOCTL_WRITE_BTDEV"); NdisMoveMemory(m_pRecvBuffer,ioBuffer,inputBufferLength);); NdisAllocatePacket((PNDIS_STATUS) &Status, &m_OurPacket, m_PoolHandle); if ( !NT_SUCCESS( Status )) { Status=STATUS_INSUFFICIENT_RESOURCES; break; } else NdisAllocateBuffer((PNDIS_STATUS)&Status,&m_OurBuffer, m_BufPoolHandle,m_pRecvBuffer,inputBufferLength); if ( !NT_SUCCESS( Status )) { Status=STATUS_INSUFFICIENT_RESOURCES; break; } else NdisChainBufferAtFront(m_OurPacket, m_OurBuffer ); NDIS_SET_PACKET_HEADER_SIZE(m_OurPacket,BTNET_HEADER_SIZE); NDIS_SET_PACKET_STATUS(m_OurPacket,NDIS_STATUS_RESOURCES); NdisMIndicateReceivePacket(g_AdapterHandle,&m_OurPacket,1); status=NDIS_GET_PACKET_STATUS(m_OurPacket); if(status==NDIS_STATUS_SUCCESS) { NdisUnchainBufferAtFront(m_OurPacket,&m_OurBuffer); if(m_OurBuffer) NdisFreeBuffer(m_OurBuffer); NdisFreePacket(m_OurPacket); } else if(status==NDIS_STATUS_PENDING) { TRACE("status=%s","NDIS_STATUS_PENDING"); } else TRACE("status=%s","NDIS_STATUS_RESOURCES"); Status=STATUS_SUCCESS; pIrp->IoStatus.Status = Status; TRACE("%s","*****************************"); pIrp->IoStatus.Information = inputBufferLength; TRACE("%s","*****************************"); break; ReturnPacket的代码为: NDIS_STATUS status=NDIS_GET_PACKET_STATUS(Packet); if(status==NDIS_STATUS_SUCCESS) { TRACE("status=%s","NDIS_STATUS_SUCCESS"); } else if(status==NDIS_STATUS_PENDING) { TRACE("status=%s","NDIS_STATUS_PENDING"); NdisUnchainBufferAtFront(Packet,&ndisBuffer); if(ndisBuffer) NdisFreeBuffer(ndisBuffer); NdisReinitializePacket(Packet); } else TRACE("status=%s","NDIS_STATUS_RESOURCES"); NdisUnchainBufferAtFront(m_OurPacket,&m_OurBuffer); if(m_OurBuffer) NdisFreeBuffer(m_OurBuffer); NdisFreePacket(m_OurPacket); } 我的驱动装好后,能得到对方的硬件地址和IP地址,但PING不通,怀疑是包给的不对,不知上面代码是否还有什么参数没设置,望指点. 小弟不胜感激!!! |
|
17楼#
发布于:2001-09-08 18:50
各位有没有抓过13、14字节是8、0的包(也就是ip)包。
但是第26-33字节不是源和目的地址(具体点,就是抓 udp或者ping 包的时候,13、14字节显示为ip包,但是 从26--29不是源地址好像28-31是,而目的地址酒不知道 是在那里了)。 还有,请问udp协议在以太网头的24字节是17还是16。 有前面的文章说是17,怎么我抓到的udp包都是16呢? |
|
|
18楼#
发布于:2003-11-27 14:57
我提交函数的时候,把Status设置成NDIS_STATUS_SUCCESS;
PNDIS_PACKET_OOB_DATA pOOBDATA = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)m_MyPktList[m_count]); pOOBDATA->Status = NDIS_STATUS_SUCCESS ; 然后就Indicate以后,NdisMIndicateReceivePacket 函数就可以重新使用原来的NDIS_PACKET了。 照我理解。 设置成NDIS_STATUS_RESOURCES,NDIS不会调用MiniportReturnPacket函数了/需要自己在Indicate以后,主动调用自己的处理资源函数。 请指教 |
|
19楼#
发布于:2003-11-27 18:16
第一个buffer到底是什么?!?!
不明白你们的意思, 一个ndispacket的长度不会超过1500字节,以太网为例子,依次的顺序是14个字节的以太帧头数据,20个字节的ip头信息,然后就是tcp或者udp的包头,然后一般才是数据,最后还有4个字节的以太网帧循环冗余校验。 太悲惨了,我需要得到整个帧数据后写入一个连续的缓冲才能够方便的统一处理他们。谁能教我方便的法儿???? |
|
|
上一页
下一页