1 /* 2 * Copyright (C) 2016 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 #ifndef WIFICOND_NET_NL80211_ATTRIBUTE_H_ 18 #define WIFICOND_NET_NL80211_ATTRIBUTE_H_ 19 20 #include <memory> 21 #include <string> 22 #include <type_traits> 23 #include <vector> 24 25 #include <linux/netlink.h> 26 27 #include <android-base/logging.h> 28 #include <android-base/macros.h> 29 30 namespace android { 31 namespace wificond { 32 33 class BaseNL80211Attr { 34 public: 35 BaseNL80211Attr(int id, const std::vector<uint8_t>& raw_buffer); 36 virtual ~BaseNL80211Attr() = default; 37 38 const std::vector<uint8_t>& GetConstData() const; 39 int GetAttributeId() const; 40 // This is used when we initialize a NL80211 attribute from an existing 41 // buffer. 42 virtual bool IsValid() const; 43 // A util helper function to find a specific sub attribute from a buffer. 44 // This buffer is supposed to be from a nested attribute or a nl80211 packet. 45 // |*start| and |*end| are the start and end pointers of buffer where 46 // |id| atrribute locates. 47 static bool GetAttributeImpl(const uint8_t* buf, 48 size_t len, 49 int attr_id, 50 uint8_t** attr_start, 51 uint8_t** attr_end); 52 // Merge the payload of |attr| to current attribute. 53 // This is only used for merging attribute from the response of split dump. 54 // Returns true on success. 55 bool Merge(const BaseNL80211Attr& attr); 56 57 protected: 58 BaseNL80211Attr() = default; 59 void InitHeaderAndResize(int attribute_id, int payload_length); 60 61 std::vector<uint8_t> data_; 62 }; 63 64 template <typename T> 65 class NL80211Attr : public BaseNL80211Attr { 66 public: 67 NL80211Attr(int id, T value) { 68 static_assert( 69 std::is_integral<T>::value, 70 "Failed to create NL80211Attr class with non-integral type"); 71 InitHeaderAndResize(id, sizeof(T)); 72 T* storage = reinterpret_cast<T*>(data_.data() + NLA_HDRLEN); 73 *storage = value; 74 } 75 // Caller is responsible for ensuring that |data| is: 76 // 1) Is at least NLA_HDRLEN long. 77 // 2) That *data when interpreted as a nlattr is internally consistent. 78 // (e.g. data.size() == NLA_ALIGN(nlattr.nla_len) 79 // and nla_len == NLA_HDRLEN + payload size 80 explicit NL80211Attr(const std::vector<uint8_t>& data) { 81 data_ = data; 82 } 83 84 ~NL80211Attr() override = default; 85 86 bool IsValid() const override { 87 if (!BaseNL80211Attr::IsValid()) { 88 return false; 89 } 90 // If BaseNL80211Attr::IsValid() == true, at least we have enough valid 91 // buffer for header. 92 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data()); 93 // Buffer size = header size + payload size + padding size 94 // nla_len = header size + payload size 95 if (NLA_ALIGN(sizeof(T)) + NLA_HDRLEN != data_.size() || 96 sizeof(T) + NLA_HDRLEN != header->nla_len ) { 97 return false; 98 } 99 return true; 100 } 101 102 T GetValue() const { 103 return *reinterpret_cast<const T*>(data_.data() + NLA_HDRLEN); 104 } 105 }; // class NL80211Attr for POD-types 106 107 template <> 108 class NL80211Attr<std::vector<uint8_t>> : public BaseNL80211Attr { 109 public: 110 NL80211Attr(int id, const std::vector<uint8_t>& raw_buffer); 111 explicit NL80211Attr(const std::vector<uint8_t>& data); 112 ~NL80211Attr() override = default; 113 std::vector<uint8_t> GetValue() const; 114 }; // class NL80211Attr for raw data 115 116 template <> 117 class NL80211Attr<std::string> : public BaseNL80211Attr { 118 public: 119 NL80211Attr(int id, const std::string& str); 120 // We parse string attribute buffer in the same way kernel does. 121 // All trailing zeros are trimmed when retrieving a std::string from 122 // byte array. 123 explicit NL80211Attr(const std::vector<uint8_t>& data); 124 ~NL80211Attr() override = default; 125 std::string GetValue() const; 126 }; // class NL80211Attr for string 127 128 // Force the compiler not to instantiate these templates because 129 // they will be instantiated in nl80211_attribute.cpp file. This helps 130 // reduce compile time as well as object file size. 131 extern template class NL80211Attr<uint8_t>; 132 extern template class NL80211Attr<uint16_t>; 133 extern template class NL80211Attr<uint32_t>; 134 extern template class NL80211Attr<uint64_t>; 135 extern template class NL80211Attr<std::vector<uint8_t>>; 136 extern template class NL80211Attr<std::string>; 137 138 class NL80211NestedAttr : public BaseNL80211Attr { 139 public: 140 explicit NL80211NestedAttr(int id); 141 explicit NL80211NestedAttr(const std::vector<uint8_t>& data); 142 ~NL80211NestedAttr() override = default; 143 144 void AddAttribute(const BaseNL80211Attr& attribute); 145 // For NLA_FLAG attribute 146 void AddFlagAttribute(int attribute_id); 147 bool HasAttribute(int id) const; 148 149 // Access an attribute nested within |this|. 150 // The result is returned by writing the attribute object to |*attribute|. 151 // Deeper nested attributes are not included. This means if A is nested within 152 // |this|, and B is nested within A, this function can't be used to access B. 153 // The reason is that we may have multiple attributes having the same 154 // attribute id, nested within different level of |this|. 155 bool GetAttribute(int id, NL80211NestedAttr* attribute) const; 156 157 template <typename T> 158 bool GetAttributeValue(int id, T* value) const { 159 std::vector<uint8_t> empty_vec; 160 // All data in |attribute| created here will be overwritten by 161 // GetAttribute(). So we use an empty vector to initialize it, 162 // regardless of the fact that an empty buffer is not qualified 163 // for creating a valid attribute. 164 NL80211Attr<T> attribute(empty_vec); 165 if (!GetAttribute(id, &attribute)) { 166 return false; 167 } 168 *value = attribute.GetValue(); 169 return true; 170 } 171 172 // Some of the nested attribute contains a list of same type sub-attributes. 173 // This function retrieves a vector of attribute values from a nested 174 // attribute. 175 // 176 // This is for both correctness and performance reasons: Refer to 177 // GetListOfAttributes(). 178 // 179 // Returns true on success. 180 template <typename T> 181 bool GetListOfAttributeValues(std::vector<T>* value) const { 182 const uint8_t* ptr = data_.data() + NLA_HDRLEN; 183 const uint8_t* end_ptr = data_.data() + data_.size(); 184 std::vector<T> attr_list; 185 while (ptr + NLA_HDRLEN <= end_ptr) { 186 const nlattr* header = reinterpret_cast<const nlattr*>(ptr); 187 if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) { 188 LOG(ERROR) << "Failed to get list of attributes: invalid nla_len."; 189 return false; 190 } 191 NL80211Attr<T> attribute(std::vector<uint8_t>( 192 ptr, 193 ptr + NLA_ALIGN(header->nla_len))); 194 if (!attribute.IsValid()) { 195 return false; 196 } 197 attr_list.emplace_back(attribute.GetValue()); 198 ptr += NLA_ALIGN(header->nla_len); 199 } 200 *value = std::move(attr_list); 201 return true; 202 } 203 204 // Some of the nested attribute contains a list of same type sub-attributes. 205 // This function retrieves a vector of attributes from a nested 206 // attribute. 207 // 208 // This is for both correctness and performance reasons: 209 // Correctness reason: 210 // These sub-attributes have attribute id from '0 to n' or '1 to n'. 211 // There is no document defining what the start index should be. 212 // 213 // Performance reson: 214 // Calling GetAttribute() from '0 to n' results a n^2 time complexity. 215 // This function get a list of attributes in one pass. 216 // 217 // Returns true on success. 218 template <typename T> 219 bool GetListOfAttributes(std::vector<NL80211Attr<T>>* value) const { 220 const uint8_t* ptr = data_.data() + NLA_HDRLEN; 221 const uint8_t* end_ptr = data_.data() + data_.size(); 222 std::vector<NL80211Attr<T>> attr_list; 223 while (ptr + NLA_HDRLEN <= end_ptr) { 224 const nlattr* header = reinterpret_cast<const nlattr*>(ptr); 225 if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) { 226 LOG(ERROR) << "Failed to get list of attributes: invalid nla_len."; 227 return false; 228 } 229 NL80211Attr<T> attribute(std::vector<uint8_t>( 230 ptr, 231 ptr + NLA_ALIGN(header->nla_len))); 232 if (!attribute.IsValid()) { 233 return false; 234 } 235 attr_list.emplace_back(attribute); 236 ptr += NLA_ALIGN(header->nla_len); 237 } 238 *value = std::move(attr_list); 239 return true; 240 } 241 242 // This is similar to |GetListOfAttributeValues|, but for the cases where all 243 // the sub-attributes are nested attributes. 244 bool GetListOfNestedAttributes(std::vector<NL80211NestedAttr>* value) const; 245 246 template <typename T> 247 bool GetAttribute(int id, NL80211Attr<T>* attribute) const { 248 uint8_t* start = nullptr; 249 uint8_t* end = nullptr; 250 if (!BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN, 251 data_.size() - NLA_HDRLEN, 252 id, &start, &end) || 253 start == nullptr || 254 end == nullptr) { 255 return false; 256 } 257 *attribute = NL80211Attr<T>(std::vector<uint8_t>(start, end)); 258 if (!attribute->IsValid()) { 259 return false; 260 } 261 return true; 262 } 263 264 void DebugLog() const; 265 266 }; 267 268 } // namespace wificond 269 } // namespace android 270 271 #endif // WIFICOND_NET_NL80211_ATTRIBUTE_H_ 272