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