blob: 771ffbd64819f873e660f4ad6b09e202b2bfed7a [file] [log] [blame]
// Copyright 2019 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 <lib/fit/defer.h>
#include <lib/fxl/logging.h>
#include "mock_netstack.h"
void MockNetstack::AddEthernetDevice(
std::string topological_path,
fuchsia::netstack::InterfaceConfig interfaceConfig,
fidl::InterfaceHandle<::fuchsia::hardware::ethernet::Device> device,
AddEthernetDeviceCallback callback) {
auto deferred =
fit::defer([callback = std::move(callback)]() { callback(0); });
eth_device_ = device.BindSync();
zx_status_t status;
std::unique_ptr<fuchsia::hardware::ethernet::Fifos> fifos;
eth_device_->GetFifos(&status, &fifos);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to get fifos: " << status;
return;
}
rx_ = std::move(fifos->rx);
tx_ = std::move(fifos->tx);
status = zx::vmo::create(kVmoSize, ZX_VMO_NON_RESIZABLE, &vmo_);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to create vmo: " << status;
return;
}
zx::vmo vmo_dup;
status =
vmo_.duplicate(ZX_RIGHTS_IO | ZX_RIGHT_MAP | ZX_RIGHT_TRANSFER, &vmo_dup);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to duplicate vmo: " << status;
return;
}
eth_device_->SetIOBuffer(std::move(vmo_dup), &status);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to set IO buffer: " << status;
return;
}
status = zx::vmar::root_self()->map(
0, vmo_, 0, kVmoSize,
ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_REQUIRE_NON_RESIZABLE,
&io_addr_);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to map vmo: " << status;
return;
}
fuchsia::hardware::ethernet::FifoEntry entry;
entry.offset = 0;
entry.length = 100;
entry.flags = 0;
entry.cookie = 0;
status = rx_.write(sizeof(fuchsia::hardware::ethernet::FifoEntry), &entry, 1,
nullptr);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to write to rx fifo: " << status;
return;
}
eth_device_->Start(&status);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "Failed to start ethernet device: " << status;
return;
}
}
zx_status_t MockNetstack::SendPacket(void* packet, size_t length) {
fuchsia::hardware::ethernet::FifoEntry entry;
entry.offset = 512;
entry.length = length;
entry.flags = 0;
entry.cookie = 0;
size_t count;
memcpy(reinterpret_cast<void*>(io_addr_ + entry.offset), packet, length);
zx_status_t status = tx_.write(sizeof(fuchsia::hardware::ethernet::FifoEntry),
&entry, 1, &count);
if (status != ZX_OK) {
return status;
}
if (count != 1) {
return ZX_ERR_INTERNAL;
}
zx_signals_t pending = 0;
status = tx_.wait_one(ZX_FIFO_READABLE | ZX_FIFO_PEER_CLOSED,
zx::deadline_after(kTestTimeout), &pending);
if (status != ZX_OK) {
return status;
} else if (pending & ZX_SOCKET_PEER_CLOSED) {
return ZX_ERR_PEER_CLOSED;
}
status = tx_.read(sizeof(fuchsia::hardware::ethernet::FifoEntry), &entry, 1,
nullptr);
if (status != ZX_OK) {
return status;
}
if (entry.flags != fuchsia::hardware::ethernet::FIFO_TX_OK) {
return ZX_ERR_IO;
}
return ZX_OK;
}
zx_status_t MockNetstack::ReceivePacket(void* packet, size_t length) {
fuchsia::hardware::ethernet::FifoEntry entry;
zx_signals_t pending = 0;
zx_status_t status = rx_.wait_one(ZX_FIFO_READABLE | ZX_FIFO_PEER_CLOSED,
zx::deadline_after(kTestTimeout), &pending);
if (status != ZX_OK) {
return status;
} else if (pending & ZX_SOCKET_PEER_CLOSED) {
return ZX_ERR_PEER_CLOSED;
}
status = rx_.read(sizeof(fuchsia::hardware::ethernet::FifoEntry), &entry, 1,
nullptr);
if (status != ZX_OK) {
return status;
}
if (entry.flags != fuchsia::hardware::ethernet::FIFO_RX_OK) {
return ZX_ERR_IO;
}
if (entry.length > length) {
return ZX_ERR_BUFFER_TOO_SMALL;
}
memcpy(packet, reinterpret_cast<void*>(io_addr_ + entry.offset), length);
return ZX_OK;
}