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)
43 : address(address) {}
44
Address(const uint8_t (& address)[kLength])45 Address::Address(const uint8_t (&address)[kLength]) {
46 std::copy(address, address + kLength, this->address.begin());
47 }
48
Address(std::initializer_list<uint8_t> l)49 Address::Address(std::initializer_list<uint8_t> l) {
50 std::copy(l.begin(), std::min(l.begin() + kLength, l.end()), data());
51 }
52
Parse(pdl::packet::slice & input,Address * output)53 bool Address::Parse(pdl::packet::slice& input, Address* output) {
54 if (input.size() < kLength) {
55 return false;
56 }
57
58 std::array<uint8_t, kLength> address{
59 input.read_le<uint8_t>(), input.read_le<uint8_t>(),
60 input.read_le<uint8_t>(), input.read_le<uint8_t>(),
61 input.read_le<uint8_t>(), input.read_le<uint8_t>(),
62 };
63 *output = Address(address);
64 return true;
65 }
66
ToString() const67 std::string Address::ToString() const {
68 std::stringstream ss;
69 for (auto it = address.rbegin(); it != address.rend(); it++) {
70 ss << std::nouppercase << std::hex << std::setw(2) << std::setfill('0')
71 << +*it;
72 if (std::next(it) != address.rend()) {
73 ss << ':';
74 }
75 }
76 return ss.str();
77 }
78
FromString(const std::string & from)79 std::optional<Address> Address::FromString(const std::string& from) {
80 if (from.length() != 17) {
81 return std::nullopt;
82 }
83
84 Address addr{};
85 std::istringstream stream(from);
86 std::string token;
87 int index = 0;
88 while (getline(stream, token, ':')) {
89 if (index >= 6) {
90 return std::nullopt;
91 }
92
93 if (token.length() != 2) {
94 return std::nullopt;
95 }
96
97 char* temp = nullptr;
98 addr.address.at(5 - index) = std::strtol(token.c_str(), &temp, 16);
99 if (temp == token.c_str()) {
100 // string token is empty or has wrong format
101 return std::nullopt;
102 }
103 if (temp != (token.c_str() + token.size())) {
104 // cannot parse whole string
105 return std::nullopt;
106 }
107
108 index++;
109 }
110
111 if (index != 6) {
112 return std::nullopt;
113 }
114
115 return addr;
116 }
117
FromString(const std::string & from,Address & to)118 bool Address::FromString(const std::string& from, Address& to) {
119 auto addr = FromString(from);
120 if (!addr) {
121 to = {};
122 return false;
123 }
124 to = std::move(*addr);
125 return true;
126 }
127
FromOctets(const uint8_t * from)128 size_t Address::FromOctets(const uint8_t* from) {
129 std::copy(from, from + kLength, data());
130 return kLength;
131 }
132
IsValidAddress(const std::string & address)133 bool Address::IsValidAddress(const std::string& address) {
134 return Address::FromString(address).has_value();
135 }
136
137 } // namespace bluetooth::hci
138