1 /*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "hci/address.h"
18
19 #include <packet_runtime.h>
20
21 #include <algorithm>
22 #include <array>
23 #include <cstdint>
24 #include <cstdio>
25 #include <cstdlib>
26 #include <initializer_list>
27 #include <iomanip>
28 #include <ios>
29 #include <iterator>
30 #include <optional>
31 #include <sstream>
32 #include <string>
33 #include <utility>
34
35 namespace bluetooth::hci {
36
37 const Address Address::kAny{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
38 const Address Address::kEmpty{0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
39
40 // Address cannot initialize member variables as it is a POD type
41 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
Address(std::array<uint8_t,kLength> const & address)42 constexpr Address::Address(std::array<uint8_t, kLength> const& address) : address(address) {}
43
Address(const uint8_t (& address)[kLength])44 Address::Address(const uint8_t (&address)[kLength]) {
45 std::copy(address, address + kLength, this->address.begin());
46 }
47
Address(std::initializer_list<uint8_t> l)48 Address::Address(std::initializer_list<uint8_t> l) {
49 std::copy(l.begin(), std::min(l.begin() + kLength, l.end()), data());
50 }
51
Parse(pdl::packet::slice & input,Address * output)52 bool Address::Parse(pdl::packet::slice& input, Address* output) {
53 if (input.size() < kLength) {
54 return false;
55 }
56
57 std::array<uint8_t, kLength> address{
58 input.read_le<uint8_t>(), input.read_le<uint8_t>(), input.read_le<uint8_t>(),
59 input.read_le<uint8_t>(), input.read_le<uint8_t>(), input.read_le<uint8_t>(),
60 };
61 *output = Address(address);
62 return true;
63 }
64
ToString() const65 std::string Address::ToString() const {
66 std::stringstream ss;
67 for (auto it = address.rbegin(); it != address.rend(); it++) {
68 ss << std::nouppercase << std::hex << std::setw(2) << std::setfill('0') << +*it;
69 if (std::next(it) != address.rend()) {
70 ss << ':';
71 }
72 }
73 return ss.str();
74 }
75
FromString(const std::string & from)76 std::optional<Address> Address::FromString(const std::string& from) {
77 if (from.length() != 17) {
78 return std::nullopt;
79 }
80
81 Address addr{};
82 std::istringstream stream(from);
83 std::string token;
84 int index = 0;
85 while (getline(stream, token, ':')) {
86 if (index >= 6) {
87 return std::nullopt;
88 }
89
90 if (token.length() != 2) {
91 return std::nullopt;
92 }
93
94 char* temp = nullptr;
95 addr.address.at(5 - index) = std::strtol(token.c_str(), &temp, 16);
96 if (temp == token.c_str()) {
97 // string token is empty or has wrong format
98 return std::nullopt;
99 }
100 if (temp != (token.c_str() + token.size())) {
101 // cannot parse whole string
102 return std::nullopt;
103 }
104
105 index++;
106 }
107
108 if (index != 6) {
109 return std::nullopt;
110 }
111
112 return addr;
113 }
114
FromString(const std::string & from,Address & to)115 bool Address::FromString(const std::string& from, Address& to) {
116 auto addr = FromString(from);
117 if (!addr) {
118 to = {};
119 return false;
120 }
121 to = std::move(*addr);
122 return true;
123 }
124
FromOctets(const uint8_t * from)125 size_t Address::FromOctets(const uint8_t* from) {
126 std::copy(from, from + kLength, data());
127 return kLength;
128 }
129
IsValidAddress(const std::string & address)130 bool Address::IsValidAddress(const std::string& address) {
131 return Address::FromString(address).has_value();
132 }
133
134 } // namespace bluetooth::hci
135