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