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
BaseNL80211Attr(int id,const vector<uint8_t> & raw_buffer)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
InitHeaderAndResize(int attribute_id,int payload_length)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
GetAttributeId() const50 int BaseNL80211Attr::GetAttributeId() const {
51 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
52 return header->nla_type;
53 }
54
IsValid() const55 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
GetConstData() const63 const vector<uint8_t>& BaseNL80211Attr::GetConstData() const {
64 return data_;
65 }
66
GetAttributeImpl(const uint8_t * buf,size_t len,int attr_id,uint8_t ** attr_start,uint8_t ** attr_end)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
Merge(const BaseNL80211Attr & other_attr)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>>
NL80211Attr(int id,const vector<uint8_t> & raw_buffer)128 NL80211Attr<vector<uint8_t>>::NL80211Attr(int id,
129 const vector<uint8_t>& raw_buffer) : BaseNL80211Attr(id, raw_buffer) {
130 }
131
NL80211Attr(const vector<uint8_t> & data)132 NL80211Attr<vector<uint8_t>>::NL80211Attr(
133 const vector<uint8_t>& data) {
134 data_ = data;
135 }
136
GetValue() const137 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>
NL80211Attr(int id,const string & str)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
NL80211Attr(const vector<uint8_t> & data)155 NL80211Attr<string>::NL80211Attr(const vector<uint8_t>& data) {
156 data_ = data;
157 }
158
GetValue() const159 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
NL80211NestedAttr(int id)172 NL80211NestedAttr::NL80211NestedAttr(int id) {
173 InitHeaderAndResize(id, 0);
174 }
175
NL80211NestedAttr(const vector<uint8_t> & data)176 NL80211NestedAttr::NL80211NestedAttr(const vector<uint8_t>& data) {
177 data_ = data;
178 }
179
AddAttribute(const BaseNL80211Attr & attribute)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
AddFlagAttribute(int attribute_id)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
HasAttribute(int id) const202 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
GetAttribute(int id,NL80211NestedAttr * attribute) const208 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
GetListOfNestedAttributes(vector<NL80211NestedAttr> * value) const226 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
DebugLog() const250 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