1

我一直在创建一个虚拟以太网接口。我已经与控制应用程序打开了异步通信,每次有新数据包时,都会通知控制应用程序,然后询问数据包数据。数据包数据存储在一个简单的结构中,uint8_t[1600]用于字节和uint32_t长度。每次数据包可用时,dext 都能够使用虚拟数据填充此结构,并且虚拟数据在控制应用程序上可见。但是,我正在努力用真实的数据包数据填充它。

IOUserNetworkPacket提供有关数据包的元数据。它包含数据包时间戳、大小等,但似乎不包含数据包的数据。有GetDataOffset()GetMemorySegmentOffset()方法似乎返回数据包数据在其内存缓冲区中的位置的字节偏移量。我的直觉告诉我将此偏移量添加到数据包数据存储位置的指针上。问题是我不知道数据包实际存储在哪里。

我知道他们是由 管理的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;
4

1 回答 1

0

该问题是由IOUserNetworkPacketBufferPool错误引起的。MybufferSize设置为 1600,但该值被忽略并替换为 2048。其IOUserNetworkPackets行为就像bufferSize1600 一样,因此它们给出了无效的偏移量。

创建缓冲池并映射它:

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);
}
于 2022-02-08T07:37:14.923 回答