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
InitHeaderAndResize(int attribute_id,int payload_length)34 void BaseNL80211Attr::InitHeaderAndResize(int attribute_id,
35 int payload_length) {
36 data_.resize(NLA_HDRLEN + NLA_ALIGN(payload_length), 0);
37 nlattr* header = reinterpret_cast<nlattr*>(data_.data());
38 header->nla_type = attribute_id;
39 header->nla_len = NLA_HDRLEN + payload_length;
40 }
41
GetAttributeId() const42 int BaseNL80211Attr::GetAttributeId() const {
43 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
44 return header->nla_type;
45 }
46
IsValid() const47 bool BaseNL80211Attr::IsValid() const {
48 if (data_.size() < NLA_HDRLEN) {
49 return false;
50 }
51 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
52 return NLA_ALIGN(header->nla_len) == data_.size();
53 }
54
GetConstData() const55 const vector<uint8_t>& BaseNL80211Attr::GetConstData() const {
56 return data_;
57 }
58
GetAttributeImpl(const uint8_t * buf,size_t len,int attr_id,uint8_t ** attr_start,uint8_t ** attr_end)59 bool BaseNL80211Attr::GetAttributeImpl(const uint8_t* buf,
60 size_t len,
61 int attr_id,
62 uint8_t** attr_start,
63 uint8_t** attr_end) {
64 // Skip the top level attribute header.
65 const uint8_t* ptr = buf;
66 const uint8_t* end_ptr = buf + len;
67 while (ptr + NLA_HDRLEN <= end_ptr) {
68 const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
69 if (header->nla_type == attr_id) {
70 if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
71 LOG(ERROR) << "Failed to get attribute: broken nl80211 atrribute.";
72 return false;
73 }
74 if (attr_start != nullptr && attr_end != nullptr) {
75 *attr_start = const_cast<uint8_t*>(ptr);
76 *attr_end = const_cast<uint8_t*>(ptr + NLA_ALIGN(header->nla_len));
77 }
78 return true;
79 }
80 ptr += NLA_ALIGN(header->nla_len);
81 }
82 return false;
83 }
84
85
86 // For NL80211Attr<std::vector<uint8_t>>
NL80211Attr(int id,const vector<uint8_t> & raw_buffer)87 NL80211Attr<vector<uint8_t>>::NL80211Attr(int id,
88 const vector<uint8_t>& raw_buffer) {
89 size_t size = raw_buffer.size();
90 InitHeaderAndResize(id, size);
91 memcpy(data_.data() + NLA_HDRLEN, raw_buffer.data(), raw_buffer.size());
92 }
93
NL80211Attr(const vector<uint8_t> & data)94 NL80211Attr<vector<uint8_t>>::NL80211Attr(
95 const vector<uint8_t>& data) {
96 data_ = data;
97 }
98
GetValue() const99 vector<uint8_t> NL80211Attr<vector<uint8_t>>::GetValue() const {
100 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
101 return vector<uint8_t>(
102 data_.data() + NLA_HDRLEN,
103 data_.data() + header->nla_len);
104 }
105
106 // For NL80211Attr<std::string>
NL80211Attr(int id,const string & str)107 NL80211Attr<string>::NL80211Attr(int id, const string& str) {
108 size_t size = str.size();
109 // This string is storaged as a null-terminated string.
110 // Buffer is initialized with 0s so we only need to make a space for
111 // the null terminator.
112 InitHeaderAndResize(id, size + 1);
113 char* storage = reinterpret_cast<char*>(data_.data() + NLA_HDRLEN);
114 str.copy(storage, size);
115 }
116
NL80211Attr(const vector<uint8_t> & data)117 NL80211Attr<string>::NL80211Attr(const vector<uint8_t>& data) {
118 data_ = data;
119 }
120
GetValue() const121 string NL80211Attr<string>::GetValue() const {
122 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
123 size_t str_length = header->nla_len - NLA_HDRLEN;
124 // Remove trailing zeros.
125 while (str_length > 0 &&
126 *(data_.data() + NLA_HDRLEN + str_length - 1) == 0) {
127 str_length--;
128 }
129 return string(reinterpret_cast<const char*>(data_.data() + NLA_HDRLEN),
130 str_length);
131 }
132
133 // For NL80211NestedAttr
NL80211NestedAttr(int id)134 NL80211NestedAttr::NL80211NestedAttr(int id) {
135 InitHeaderAndResize(id, 0);
136 }
137
NL80211NestedAttr(const vector<uint8_t> & data)138 NL80211NestedAttr::NL80211NestedAttr(const vector<uint8_t>& data) {
139 data_ = data;
140 }
141
AddAttribute(const BaseNL80211Attr & attribute)142 void NL80211NestedAttr::AddAttribute(const BaseNL80211Attr& attribute) {
143 const vector<uint8_t>& append_data = attribute.GetConstData();
144 // Append the data of |attribute| to |this|.
145 data_.insert(data_.end(), append_data.begin(), append_data.end());
146 nlattr* header = reinterpret_cast<nlattr*>(data_.data());
147 // We don't need to worry about padding for nested attribute.
148 // Because as long as all sub attributes have padding, the payload is aligned.
149 header->nla_len += append_data.size();
150 }
151
AddFlagAttribute(int attribute_id)152 void NL80211NestedAttr::AddFlagAttribute(int attribute_id) {
153 // We only need to append a header for flag attribute.
154 // Make space for the new attribute.
155 data_.resize(data_.size() + NLA_HDRLEN, 0);
156 nlattr* flag_header =
157 reinterpret_cast<nlattr*>(data_.data() + data_.size() - NLA_HDRLEN);
158 flag_header->nla_type = attribute_id;
159 flag_header->nla_len = NLA_HDRLEN;
160 nlattr* nl_header = reinterpret_cast<nlattr*>(data_.data());
161 nl_header->nla_len += NLA_HDRLEN;
162 }
163
HasAttribute(int id) const164 bool NL80211NestedAttr::HasAttribute(int id) const {
165 return BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN,
166 data_.size() - NLA_HDRLEN,
167 id, nullptr, nullptr);
168 }
169
GetAttribute(int id,NL80211NestedAttr * attribute) const170 bool NL80211NestedAttr::GetAttribute(int id,
171 NL80211NestedAttr* attribute) const {
172 uint8_t* start = nullptr;
173 uint8_t* end = nullptr;
174 if (!BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN,
175 data_.size() - NLA_HDRLEN,
176 id, &start, &end) ||
177 start == nullptr ||
178 end == nullptr) {
179 return false;
180 }
181 *attribute = NL80211NestedAttr(vector<uint8_t>(start, end));
182 if (!attribute->IsValid()) {
183 return false;
184 }
185 return true;
186 }
187
GetListOfNestedAttributes(vector<NL80211NestedAttr> * value) const188 bool NL80211NestedAttr::GetListOfNestedAttributes(
189 vector<NL80211NestedAttr>* value) const {
190 const uint8_t* ptr = data_.data() + NLA_HDRLEN;
191 const uint8_t* end_ptr = data_.data() + data_.size();
192 vector<NL80211NestedAttr> nested_attr_list;
193 while (ptr + NLA_HDRLEN <= end_ptr) {
194 const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
195 if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
196 LOG(ERROR) << "Failed to get list of nested attributes: invalid nla_len.";
197 return false;
198 }
199 nested_attr_list.emplace_back(
200 NL80211NestedAttr(vector<uint8_t>(ptr,
201 ptr + NLA_ALIGN(header->nla_len))));
202 if (!nested_attr_list.back().IsValid()) {
203 return false;
204 }
205 ptr += NLA_ALIGN(header->nla_len);
206 }
207 *value = std::move(nested_attr_list);
208 return true;
209 }
210
211
DebugLog() const212 void NL80211NestedAttr::DebugLog() const {
213 const uint8_t* ptr = data_.data() + NLA_HDRLEN;
214 const uint8_t* end_ptr = data_.data() + data_.size();
215 while (ptr + NLA_HDRLEN <= end_ptr) {
216 const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
217 if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
218 LOG(ERROR) << "broken nl80211 atrribute.";
219 return;
220 }
221 LOG(INFO) << "Have attribute with nla_type=" << header->nla_type
222 << " and nla_len=" << header->nla_len;
223 if (header->nla_len == 0) {
224 LOG(ERROR) << "0 is a bad nla_len";
225 return;
226 }
227 ptr += NLA_ALIGN(header->nla_len);
228 }
229 }
230
231 } // namespace wificond
232 } // namespace android
233