blob: e39c57b26d8cc4d3c633bbacf42b4b74b8a05a8b [file] [edit]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Internal utilities for Ethernet address manipulation.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_NETINET_ETHER_ETHER_UTILS_H
#define LLVM_LIBC_SRC_NETINET_ETHER_ETHER_UTILS_H
#include "hdr/stdint_proxy.h"
#include "hdr/types/size_t.h"
#include "hdr/types/struct_ether_addr.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/span.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
#include "src/__support/net/hex.h"
namespace LIBC_NAMESPACE_DECL {
namespace net {
/// Maximum length of an Ethernet address string "xx:xx:xx:xx:xx:xx\0".
inline constexpr size_t ETHER_ADDR_STR_LEN = 18;
/// Formats \p addr into \p buf (which must be at least ETHER_ADDR_STR_LEN
/// bytes) as a colon-separated lowercase hexadecimal string and returns
/// `buf.data()`.
LIBC_INLINE char *ether_ntoa_r(const struct ether_addr &addr,
cpp::span<char> buf) {
size_t pos = 0;
for (size_t i = 0; i < 6; ++i) {
uint8_t val = addr.ether_addr_octet[i];
if (val >= 0x10)
buf[pos++] = internal::int_to_b36_char(val >> 4);
buf[pos++] = internal::int_to_b36_char(val & 0xf);
buf[pos++] = i < 5 ? ':' : '\0';
}
return buf.data();
}
/// Parses \p str as an Ethernet address in the colon-separated hexadecimal
/// notation ("xx:xx:xx:xx:xx:xx"), where each octet consists of one or two
/// hexadecimal digits. Like musl (but unlike glibc), trailing characters are
/// not allowed. Returns nullopt if the string is not a valid address.
LIBC_INLINE cpp::optional<struct ether_addr> ether_aton(cpp::string_view str) {
struct ether_addr addr;
for (size_t i = 0; i < 6; ++i) {
if (i > 0) {
if (!str.starts_with(':'))
return cpp::nullopt;
str.remove_prefix(1);
}
cpp::optional<uint8_t> octet = consume_hex<uint8_t>(str);
if (!octet)
return cpp::nullopt;
addr.ether_addr_octet[i] = *octet;
}
if (!str.empty())
return cpp::nullopt;
return addr;
}
} // namespace net
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_NETINET_ETHER_ETHER_UTILS_H