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 #include "wificond/net/nl80211_attribute.h" 18 19 using std::string; 20 using std::vector; 21 22 namespace android { 23 namespace wificond { 24 25 // Explicit instantiation 26 template class NL80211Attr<uint8_t>; 27 template class NL80211Attr<uint16_t>; 28 template class NL80211Attr<uint32_t>; 29 template class NL80211Attr<uint64_t>; 30 template class NL80211Attr<vector<uint8_t>>; 31 template class NL80211Attr<string>; 32 33 // For BaseNL80211Attr 34 35 BaseNL80211Attr::BaseNL80211Attr(int id, 36 const vector<uint8_t>& raw_buffer) { 37 size_t size = raw_buffer.size(); 38 InitHeaderAndResize(id, size); 39 memcpy(data_.data() + NLA_HDRLEN, raw_buffer.data(), raw_buffer.size()); 40 } 41 42 void BaseNL80211Attr::InitHeaderAndResize(int attribute_id, 43 int payload_length) { 44 data_.resize(NLA_HDRLEN + NLA_ALIGN(payload_length), 0); 45 nlattr* header = reinterpret_cast<nlattr*>(data_.data()); 46 header->nla_type = attribute_id; 47 header->nla_len = NLA_HDRLEN + payload_length; 48 } 49 50 int BaseNL80211Attr::GetAttributeId() const { 51 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data()); 52 return header->nla_type; 53 } 54 55 bool BaseNL80211Attr::IsValid() const { 56 if (data_.size() < NLA_HDRLEN) { 57 return false; 58 } 59 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data()); 60 return NLA_ALIGN(header->nla_len) == data_.size(); 61 } 62 63 const vector<uint8_t>& BaseNL80211Attr::GetConstData() const { 64 return data_; 65 } 66 67 bool BaseNL80211Attr::GetAttributeImpl(const uint8_t* buf, 68 size_t len, 69 int attr_id, 70 uint8_t** attr_start, 71 uint8_t** attr_end) { 72 // Skip the top level attribute header. 73 const uint8_t* ptr = buf; 74 const uint8_t* end_ptr = buf + len; 75 while (ptr + NLA_HDRLEN <= end_ptr) { 76 const nlattr* header = reinterpret_cast<const nlattr*>(ptr); 77 if (header->nla_type == attr_id) { 78 if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) { 79 LOG(ERROR) << "Failed to get attribute: broken nl80211 atrribute."; 80 return false; 81 } 82 if (attr_start != nullptr && attr_end != nullptr) { 83 *attr_start = const_cast<uint8_t*>(ptr); 84 *attr_end = const_cast<uint8_t*>(ptr + NLA_ALIGN(header->nla_len)); 85 } 86 return true; 87 } 88 ptr += NLA_ALIGN(header->nla_len); 89 } 90 return false; 91 } 92 93 94 bool BaseNL80211Attr::Merge(const BaseNL80211Attr& other_attr) { 95 if (!other_attr.IsValid()) { 96 LOG(ERROR) << "Can not merge invalid attribute"; 97 return false; 98 } 99 if (GetAttributeId() != other_attr.GetAttributeId()) { 100 LOG(ERROR) << "Can not merge attributes with different ids"; 101 return false; 102 } 103 104 auto our_header = reinterpret_cast<nlattr*>(data_.data()); 105 int our_len_without_padding = our_header->nla_len; 106 auto other_header = 107 reinterpret_cast<const nlattr*>(other_attr.GetConstData().data()); 108 int other_len_without_padding = other_header->nla_len; 109 // Update the length to include the content of |other_attr|. 110 int total_len_without_padding = 111 our_len_without_padding + other_len_without_padding - NLA_HDRLEN; 112 our_header->nla_len = total_len_without_padding; 113 114 // Remove padding 0s. 115 data_.resize(our_len_without_padding); 116 // Insert content of |other_attr|. 117 data_.insert( 118 data_.end(), 119 reinterpret_cast<const uint8_t*>(other_header) + NLA_HDRLEN, 120 reinterpret_cast<const uint8_t*>(other_header) + 121 other_len_without_padding); 122 // Add padding 0s. 123 data_.resize(NLA_ALIGN(total_len_without_padding), 0); 124 return true; 125 } 126 127 // For NL80211Attr<std::vector<uint8_t>> 128 NL80211Attr<vector<uint8_t>>::NL80211Attr(int id, 129 const vector<uint8_t>& raw_buffer) : BaseNL80211Attr(id, raw_buffer) { 130 } 131 132 NL80211Attr<vector<uint8_t>>::NL80211Attr( 133 const vector<uint8_t>& data) { 134 data_ = data; 135 } 136 137 vector<uint8_t> NL80211Attr<vector<uint8_t>>::GetValue() const { 138 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data()); 139 return vector<uint8_t>( 140 data_.data() + NLA_HDRLEN, 141 data_.data() + header->nla_len); 142 } 143 144 // For NL80211Attr<std::string> 145 NL80211Attr<string>::NL80211Attr(int id, const string& str) { 146 size_t size = str.size(); 147 // This string is storaged as a null-terminated string. 148 // Buffer is initialized with 0s so we only need to make a space for 149 // the null terminator. 150 InitHeaderAndResize(id, size + 1); 151 char* storage = reinterpret_cast<char*>(data_.data() + NLA_HDRLEN); 152 str.copy(storage, size); 153 } 154 155 NL80211Attr<string>::NL80211Attr(const vector<uint8_t>& data) { 156 data_ = data; 157 } 158 159 string NL80211Attr<string>::GetValue() const { 160 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data()); 161 size_t str_length = header->nla_len - NLA_HDRLEN; 162 // Remove trailing zeros. 163 while (str_length > 0 && 164 *(data_.data() + NLA_HDRLEN + str_length - 1) == 0) { 165 str_length--; 166 } 167 return string(reinterpret_cast<const char*>(data_.data() + NLA_HDRLEN), 168 str_length); 169 } 170 171 // For NL80211NestedAttr 172 NL80211NestedAttr::NL80211NestedAttr(int id) { 173 InitHeaderAndResize(id, 0); 174 } 175 176 NL80211NestedAttr::NL80211NestedAttr(const vector<uint8_t>& data) { 177 data_ = data; 178 } 179 180 void NL80211NestedAttr::AddAttribute(const BaseNL80211Attr& attribute) { 181 const vector<uint8_t>& append_data = attribute.GetConstData(); 182 // Append the data of |attribute| to |this|. 183 data_.insert(data_.end(), append_data.begin(), append_data.end()); 184 nlattr* header = reinterpret_cast<nlattr*>(data_.data()); 185 // We don't need to worry about padding for nested attribute. 186 // Because as long as all sub attributes have padding, the payload is aligned. 187 header->nla_len += append_data.size(); 188 } 189 190 void NL80211NestedAttr::AddFlagAttribute(int attribute_id) { 191 // We only need to append a header for flag attribute. 192 // Make space for the new attribute. 193 data_.resize(data_.size() + NLA_HDRLEN, 0); 194 nlattr* flag_header = 195 reinterpret_cast<nlattr*>(data_.data() + data_.size() - NLA_HDRLEN); 196 flag_header->nla_type = attribute_id; 197 flag_header->nla_len = NLA_HDRLEN; 198 nlattr* nl_header = reinterpret_cast<nlattr*>(data_.data()); 199 nl_header->nla_len += NLA_HDRLEN; 200 } 201 202 bool NL80211NestedAttr::HasAttribute(int id) const { 203 return BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN, 204 data_.size() - NLA_HDRLEN, 205 id, nullptr, nullptr); 206 } 207 208 bool NL80211NestedAttr::GetAttribute(int id, 209 NL80211NestedAttr* attribute) const { 210 uint8_t* start = nullptr; 211 uint8_t* end = nullptr; 212 if (!BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN, 213 data_.size() - NLA_HDRLEN, 214 id, &start, &end) || 215 start == nullptr || 216 end == nullptr) { 217 return false; 218 } 219 *attribute = NL80211NestedAttr(vector<uint8_t>(start, end)); 220 if (!attribute->IsValid()) { 221 return false; 222 } 223 return true; 224 } 225 226 bool NL80211NestedAttr::GetListOfNestedAttributes( 227 vector<NL80211NestedAttr>* value) const { 228 const uint8_t* ptr = data_.data() + NLA_HDRLEN; 229 const uint8_t* end_ptr = data_.data() + data_.size(); 230 vector<NL80211NestedAttr> nested_attr_list; 231 while (ptr + NLA_HDRLEN <= end_ptr) { 232 const nlattr* header = reinterpret_cast<const nlattr*>(ptr); 233 if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) { 234 LOG(ERROR) << "Failed to get list of nested attributes: invalid nla_len."; 235 return false; 236 } 237 nested_attr_list.emplace_back( 238 NL80211NestedAttr(vector<uint8_t>(ptr, 239 ptr + NLA_ALIGN(header->nla_len)))); 240 if (!nested_attr_list.back().IsValid()) { 241 return false; 242 } 243 ptr += NLA_ALIGN(header->nla_len); 244 } 245 *value = std::move(nested_attr_list); 246 return true; 247 } 248 249 250 void NL80211NestedAttr::DebugLog() const { 251 const uint8_t* ptr = data_.data() + NLA_HDRLEN; 252 const uint8_t* end_ptr = data_.data() + data_.size(); 253 while (ptr + NLA_HDRLEN <= end_ptr) { 254 const nlattr* header = reinterpret_cast<const nlattr*>(ptr); 255 if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) { 256 LOG(ERROR) << "broken nl80211 atrribute."; 257 return; 258 } 259 LOG(INFO) << "Have attribute with nla_type=" << header->nla_type 260 << " and nla_len=" << header->nla_len; 261 if (header->nla_len == 0) { 262 LOG(ERROR) << "0 is a bad nla_len"; 263 return; 264 } 265 ptr += NLA_ALIGN(header->nla_len); 266 } 267 } 268 269 } // namespace wificond 270 } // namespace android 271