blob: 51c920af45ca444c3607b09f6d832d891ef3fe9f [file] [log] [blame]
// Copyright 2020 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 "mac_adapter.h"
#include <lib/sync/completion.h>
#include <fbl/auto_lock.h>
namespace network {
namespace tun {
zx_status_t MacAdapter::Create(MacAdapterParent* parent, fuchsia::net::MacAddress mac,
bool promisc_only, std::unique_ptr<MacAdapter>* out) {
std::unique_ptr<MacAdapter> adapter(new MacAdapter(parent, mac, promisc_only));
mac_addr_impl_protocol_t proto = {&adapter->mac_addr_impl_protocol_ops_, adapter.get()};
zx_status_t status =
MacAddrDeviceInterface::Create(ddk::MacAddrImplProtocolClient(&proto), &adapter->device_);
if (status == ZX_OK) {
*out = std::move(adapter);
}
return status;
}
zx_status_t MacAdapter::Bind(async_dispatcher_t* dispatcher, zx::channel req) {
return device_->Bind(dispatcher, std::move(req));
}
void MacAdapter::Teardown(fit::callback<void()> callback) {
device_->Teardown(std::move(callback));
}
void MacAdapter::TeardownSync() {
sync_completion_t completion;
Teardown([&completion]() { sync_completion_signal(&completion); });
sync_completion_wait_deadline(&completion, ZX_TIME_INFINITE);
}
void MacAdapter::MacAddrImplGetAddress(uint8_t* out_mac) {
std::copy(mac_.octets.begin(), mac_.octets.end(), out_mac);
}
void MacAdapter::MacAddrImplGetFeatures(features_t* out_features) {
if (promisc_only_) {
out_features->multicast_filter_count = 0;
out_features->supported_modes = MODE_MULTICAST_PROMISCUOUS;
} else {
out_features->multicast_filter_count = fuchsia::net::tun::MAX_MULTICAST_FILTERS;
out_features->supported_modes =
MODE_PROMISCUOUS | MODE_MULTICAST_FILTER | MODE_MULTICAST_PROMISCUOUS;
}
}
void MacAdapter::MacAddrImplSetMode(mode_t mode, const uint8_t* multicast_macs_list,
size_t multicast_macs_count) {
fbl::AutoLock lock(&state_lock_);
fuchsia::hardware::network::MacFilterMode filter_mode{};
switch (mode) {
case MODE_PROMISCUOUS:
filter_mode = fuchsia::hardware::network::MacFilterMode::PROMISCUOUS;
break;
case MODE_MULTICAST_PROMISCUOUS:
filter_mode = fuchsia::hardware::network::MacFilterMode::MULTICAST_PROMISCUOUS;
break;
case MODE_MULTICAST_FILTER:
filter_mode = fuchsia::hardware::network::MacFilterMode::MULTICAST_FILTER;
break;
default:
ZX_ASSERT_MSG(false, "Unexpected filter mode %d", mode);
break;
}
mac_state_.set_mode(filter_mode);
std::vector<fuchsia::net::MacAddress> filters;
filters.reserve(multicast_macs_count);
while (multicast_macs_count--) {
auto& n = filters.emplace_back();
std::copy_n(multicast_macs_list, n.octets.size(), n.octets.begin());
multicast_macs_list += n.octets.size();
}
mac_state_.set_multicast_filters(std::move(filters));
parent_->OnMacStateChanged(this);
}
void MacAdapter::CloneMacState(fuchsia::net::tun::MacState* out) {
fbl::AutoLock lock(&state_lock_);
mac_state_.Clone(out);
}
} // namespace tun
} // namespace network