NetworkingDriverKit - 如何访问数据包数据?
NetworkingDriverKit - How can I access packet data?
我一直在创建虚拟以太网接口。我已经打开了与控制应用程序的异步通信,每次有新数据包时,控制应用程序都会收到通知,然后请求数据包数据。数据包数据存储在一个简单的结构中,字节数为 uint8_t[1600]
,长度为 uint32_t
。每次数据包可用时,dext 都能够使用虚拟数据填充此结构,并且虚拟数据在控制应用程序上可见。但是,我正在努力用真实的数据包数据填充它。
IOUserNetworkPacket
提供有关数据包的元数据。它包含数据包时间戳、大小等,但它似乎不包含数据包的数据。 GetDataOffset()
和 GetMemorySegmentOffset()
方法似乎 return 字节偏移数据包数据在其内存缓冲区中的位置。我的直觉告诉我将这个偏移量添加到数据包数据存储位置的指针上。问题是我不知道数据包实际存储在哪里。
我知道它们由 IOUserNetworkPacketBufferPool
管理,但我不认为那是它们的记忆所在。 CopyMemoryDescriptor()
方法给出了其内容的 IOMemoryDescriptor
。我尝试使用描述符创建一个 IOMemoryMap
,用它来调用 GetAddress()
。指向所有提到的对象的指针导致垃圾数据。
我一定是完全错了。如果有人知道如何访问数据包数据或有任何想法,我将不胜感激。谢谢。
IOUserClient::ExternalMethod
中的代码片段:
case GetPacket:
{
IOUserNetworkPacket *packet =
ivars->m_provider->getPacket();
GetPacket_Output output;
output.packet_size = packet->getDataLength();
IOUserNetworkPacketBufferPool *pool;
packet->GetPacketBufferPool(&pool);
IOMemoryDescriptor *memory = nullptr;
pool->CopyMemoryDescriptor(&memory);
IOMemoryMap *map = nullptr;
memory->CreateMapping(0, 0, 0, 0, 0, &map);
uint64_t address = map->GetAddress()
+ packet->getMemorySegmentOffset();
memcpy(output.packet_data,
(void*)address, packet->getDataLength());
in_arguments->structureOutput = OSData::withBytes(
&output, sizeof(GetPacket_Output));
// free stuff
} break;
问题是由 IOUserNetworkPacketBufferPool
错误引起的。我的 bufferSize
设置为 1600,除了这个值被忽略并替换为 2048。IOUserNetworkPackets
表现得好像 bufferSize
是 1600,所以他们给出了一个无效的偏移量。
正在创建缓冲池并对其进行映射:
kern_return_t
IMPL(FooDriver, Start)
{
// ...
IOUserNetworkPacketBufferPool::Create(this, "FooBuffer",
32, 32, 2048, &ivars->packet_buffer));
packet_buffer->CopyMemoryDescriptor(ivars->packet_buffer_md);
ivars->packet_md->Map(0, 0, 0, IOVMPageSize,
&ivars->packet_buffer_addr, &ivars->packet_buffer_length));
// ...
}
正在获取数据包:
void FooDriver::getPacketData(
IOUserNetworkPacket *packet,
uint8_t *packet_data,
uint32_t *packet_size
) {
uint8_t packet_head;
uint64_t packet_offset;
packet->GetHeadroom(&packet_head);
packet->GetMemorySegmentOffset(&packet_offset);
uint8_t *buffer = (uint8_t*)(ivars->packet_buffer_addr
+ packet_offset + packet_head);
*packet_size = packet->getDataLength();
memcpy(packet_data, buffer, *packet_size);
}
我一直在创建虚拟以太网接口。我已经打开了与控制应用程序的异步通信,每次有新数据包时,控制应用程序都会收到通知,然后请求数据包数据。数据包数据存储在一个简单的结构中,字节数为 uint8_t[1600]
,长度为 uint32_t
。每次数据包可用时,dext 都能够使用虚拟数据填充此结构,并且虚拟数据在控制应用程序上可见。但是,我正在努力用真实的数据包数据填充它。
IOUserNetworkPacket
提供有关数据包的元数据。它包含数据包时间戳、大小等,但它似乎不包含数据包的数据。 GetDataOffset()
和 GetMemorySegmentOffset()
方法似乎 return 字节偏移数据包数据在其内存缓冲区中的位置。我的直觉告诉我将这个偏移量添加到数据包数据存储位置的指针上。问题是我不知道数据包实际存储在哪里。
我知道它们由 IOUserNetworkPacketBufferPool
管理,但我不认为那是它们的记忆所在。 CopyMemoryDescriptor()
方法给出了其内容的 IOMemoryDescriptor
。我尝试使用描述符创建一个 IOMemoryMap
,用它来调用 GetAddress()
。指向所有提到的对象的指针导致垃圾数据。
我一定是完全错了。如果有人知道如何访问数据包数据或有任何想法,我将不胜感激。谢谢。
IOUserClient::ExternalMethod
中的代码片段:
case GetPacket:
{
IOUserNetworkPacket *packet =
ivars->m_provider->getPacket();
GetPacket_Output output;
output.packet_size = packet->getDataLength();
IOUserNetworkPacketBufferPool *pool;
packet->GetPacketBufferPool(&pool);
IOMemoryDescriptor *memory = nullptr;
pool->CopyMemoryDescriptor(&memory);
IOMemoryMap *map = nullptr;
memory->CreateMapping(0, 0, 0, 0, 0, &map);
uint64_t address = map->GetAddress()
+ packet->getMemorySegmentOffset();
memcpy(output.packet_data,
(void*)address, packet->getDataLength());
in_arguments->structureOutput = OSData::withBytes(
&output, sizeof(GetPacket_Output));
// free stuff
} break;
问题是由 IOUserNetworkPacketBufferPool
错误引起的。我的 bufferSize
设置为 1600,除了这个值被忽略并替换为 2048。IOUserNetworkPackets
表现得好像 bufferSize
是 1600,所以他们给出了一个无效的偏移量。
正在创建缓冲池并对其进行映射:
kern_return_t
IMPL(FooDriver, Start)
{
// ...
IOUserNetworkPacketBufferPool::Create(this, "FooBuffer",
32, 32, 2048, &ivars->packet_buffer));
packet_buffer->CopyMemoryDescriptor(ivars->packet_buffer_md);
ivars->packet_md->Map(0, 0, 0, IOVMPageSize,
&ivars->packet_buffer_addr, &ivars->packet_buffer_length));
// ...
}
正在获取数据包:
void FooDriver::getPacketData(
IOUserNetworkPacket *packet,
uint8_t *packet_data,
uint32_t *packet_size
) {
uint8_t packet_head;
uint64_t packet_offset;
packet->GetHeadroom(&packet_head);
packet->GetMemorySegmentOffset(&packet_offset);
uint8_t *buffer = (uint8_t*)(ivars->packet_buffer_addr
+ packet_offset + packet_head);
*packet_size = packet->getDataLength();
memcpy(packet_data, buffer, *packet_size);
}