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