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);
}