blob: 98a108993d79f9b85dcb6bcf0034e327066a0d15 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <wlan/mlme/packet.h>
#include <fbl/limits.h>
#include <zircon/assert.h>
#include <algorithm>
#include <utility>
namespace wlan {
fbl::unique_ptr<Packet> Packet::CreateWlanPacket(size_t frame_len) {
fbl::unique_ptr<Buffer> buffer = GetBuffer(frame_len);
if (buffer == nullptr) { return nullptr; }
auto packet = fbl::make_unique<Packet>(std::move(buffer), frame_len);
packet->set_peer(Packet::Peer::kWlan);
return packet;
}
Packet::Packet(fbl::unique_ptr<Buffer> buffer, size_t len) : buffer_(std::move(buffer)), len_(len) {
ZX_ASSERT(buffer_.get());
ZX_DEBUG_ASSERT(len <= buffer_->capacity());
}
zx_status_t Packet::CopyFrom(const void* src, size_t len, size_t offset) {
if (offset + len > buffer_->capacity()) { return ZX_ERR_BUFFER_TOO_SMALL; }
std::memcpy(buffer_->data() + offset, src, len);
len_ = std::max(len_, offset + len);
return ZX_OK;
}
zx_status_t Packet::AsWlanTxPacket(wlan_tx_packet_t* tx_pkt) {
ZX_DEBUG_ASSERT(len() <= fbl::numeric_limits<uint16_t>::max());
ethmac_netbuf_t netbuf = {
.data = mut_data(),
.len = static_cast<uint16_t>(len()),
};
*tx_pkt = {.packet_head = &netbuf};
if (has_ext_data()) {
tx_pkt->packet_tail = ext_data();
tx_pkt->tail_offset = ext_offset();
}
if (has_ctrl_data<wlan_tx_info_t>()) {
std::memcpy(&tx_pkt->info, ctrl_data<wlan_tx_info_t>(), sizeof(tx_pkt->info));
}
return ZX_OK;
}
fbl::unique_ptr<Buffer> GetBuffer(size_t len) {
fbl::unique_ptr<Buffer> buffer;
// TODO(tkilbourn): implement a better fallback system here
if (len > kLargeBufferSize) {
buffer = HugeBufferAllocator::New();
} else if (len > kSmallBufferSize) {
buffer = LargeBufferAllocator::New();
if (buffer == nullptr) {
// Fallback to huge buffers.
buffer = HugeBufferAllocator::New();
}
} else {
buffer = SmallBufferAllocator::New();
if (buffer == nullptr) {
// Fall back to the large buffers if we're out of small buffers.
buffer = LargeBufferAllocator::New();
if (buffer == nullptr) { buffer = HugeBufferAllocator::New(); }
}
}
return buffer;
}
} // namespace wlan
// Definition of static slab allocators.
// TODO(tkilbourn): tune how many slabs we are willing to grow up to. Reasonably large limits chosen
// for now.
DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(::wlan::HugeBufferTraits, 2, true);
DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(::wlan::LargeBufferTraits, 20, true);
DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(::wlan::SmallBufferTraits, 80, true);