blob: 47bf933909dbde6e8d9e290683883ee3e5c6231d [file] [log] [blame]
// Copyright 2018 The Chromium OS 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 "arc/network/subnet.h"
#include <arpa/inet.h>
#include <utility>
#include <base/bind.h>
#include <base/logging.h>
namespace arc_networkd {
SubnetAddress::SubnetAddress(uint32_t addr, base::Closure release_cb)
: addr_(addr), release_cb_(std::move(release_cb)) {}
SubnetAddress::~SubnetAddress() {
release_cb_.Run();
}
uint32_t SubnetAddress::Address() const {
return htonl(addr_);
}
Subnet::Subnet(uint32_t network_id, size_t prefix, base::Closure release_cb)
: network_id_(network_id),
prefix_(prefix),
release_cb_(std::move(release_cb)),
weak_factory_(this) {
CHECK_LT(prefix, 32);
addrs_.resize(1ull << (32 - prefix), false);
// Mark the network id and broadcast address as allocated.
addrs_.front() = true;
addrs_.back() = true;
}
Subnet::~Subnet() {
release_cb_.Run();
}
std::unique_ptr<SubnetAddress> Subnet::Allocate(uint32_t addr) {
if (addr <= network_id_ || addr >= network_id_ + addrs_.size() - 1) {
// Address is out of bounds.
return nullptr;
}
uint32_t offset = addr - network_id_;
if (addrs_[offset]) {
// Address is already allocated.
return nullptr;
}
addrs_[offset] = true;
return std::make_unique<SubnetAddress>(
addr, base::Bind(&Subnet::Free, weak_factory_.GetWeakPtr(), offset));
}
uint32_t Subnet::AddressAtOffset(uint32_t offset) const {
if (offset >= AvailableCount())
return INADDR_ANY;
// The first usable IP is after the network id.
return htonl(network_id_ + 1 + offset);
}
size_t Subnet::AvailableCount() const {
// The available IP count is all IPs in a subnet, minus the network ID
// and the broadcast address.
return addrs_.size() - 2;
}
uint32_t Subnet::Netmask() const {
return htonl((0xffffffffull << (32 - prefix_)) & 0xffffffff);
}
size_t Subnet::Prefix() const {
return prefix_;
}
void Subnet::Free(uint32_t offset) {
DCHECK_NE(offset, 0);
DCHECK_LT(offset, addrs_.size() - 1);
addrs_[offset] = false;
}
} // namespace arc_networkd