2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "wificond/net/nl80211_attribute.h"
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>;
33 // For BaseNL80211Attr
34 void BaseNL80211Attr::InitHeaderAndResize(int attribute_id,
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;
42 int BaseNL80211Attr::GetAttributeId() const {
43 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
44 return header->nla_type;
47 bool BaseNL80211Attr::IsValid() const {
48 if (data_.size() < NLA_HDRLEN) {
51 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
52 return NLA_ALIGN(header->nla_len) == data_.size();
55 const vector<uint8_t>& BaseNL80211Attr::GetConstData() const {
59 bool BaseNL80211Attr::GetAttributeImpl(const uint8_t* buf,
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.";
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));
80 ptr += NLA_ALIGN(header->nla_len);
86 // For NL80211Attr<std::vector<uint8_t>>
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());
94 NL80211Attr<vector<uint8_t>>::NL80211Attr(
95 const vector<uint8_t>& data) {
99 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);
106 // For NL80211Attr<std::string>
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);
117 NL80211Attr<string>::NL80211Attr(const vector<uint8_t>& data) {
121 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) {
129 return string(reinterpret_cast<const char*>(data_.data() + NLA_HDRLEN),
133 // For NL80211NestedAttr
134 NL80211NestedAttr::NL80211NestedAttr(int id) {
135 InitHeaderAndResize(id, 0);
138 NL80211NestedAttr::NL80211NestedAttr(const vector<uint8_t>& data) {
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();
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;
164 bool NL80211NestedAttr::HasAttribute(int id) const {
165 return BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN,
166 data_.size() - NLA_HDRLEN,
167 id, nullptr, nullptr);
170 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,
181 *attribute = NL80211NestedAttr(vector<uint8_t>(start, end));
182 if (!attribute->IsValid()) {
188 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.";
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()) {
205 ptr += NLA_ALIGN(header->nla_len);
207 *value = std::move(nested_attr_list);
212 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.";
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";
227 ptr += NLA_ALIGN(header->nla_len);
231 } // namespace wificond
232 } // namespace android