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 #ifndef WIFICOND_NET_NL80211_ATTRIBUTE_H_
18 #define WIFICOND_NET_NL80211_ATTRIBUTE_H_
19 
20 #include <memory>
21 #include <string>
22 #include <type_traits>
23 #include <vector>
24 
25 #include <linux/netlink.h>
26 
27 #include <android-base/logging.h>
28 #include <android-base/macros.h>
29 
30 namespace android {
31 namespace wificond {
32 
33 class BaseNL80211Attr {
34  public:
35   BaseNL80211Attr(int id, const std::vector<uint8_t>& raw_buffer);
36   virtual ~BaseNL80211Attr() = default;
37 
38   const std::vector<uint8_t>& GetConstData() const;
39   int GetAttributeId() const;
40   // This is used when we initialize a NL80211 attribute from an existing
41   // buffer.
42   virtual bool IsValid() const;
43   // A util helper function to find a specific sub attribute from a buffer.
44   // This buffer is supposed to be from a nested attribute or a nl80211 packet.
45   // |*start| and |*end| are the start and end pointers of buffer where
46   // |id| atrribute locates.
47   static bool GetAttributeImpl(const uint8_t* buf,
48                               size_t len,
49                               int attr_id,
50                               uint8_t** attr_start,
51                               uint8_t** attr_end);
52   // Merge the payload of |attr| to current attribute.
53   // This is only used for merging attribute from the response of split dump.
54   // Returns true on success.
55   bool Merge(const BaseNL80211Attr& attr);
56 
57  protected:
58   BaseNL80211Attr() = default;
59   void InitHeaderAndResize(int attribute_id, int payload_length);
60 
61   std::vector<uint8_t> data_;
62 };
63 
64 template <typename T>
65 class NL80211Attr : public BaseNL80211Attr {
66  public:
NL80211Attr(int id,T value)67   NL80211Attr(int id, T value) {
68     static_assert(
69         std::is_integral<T>::value,
70         "Failed to create NL80211Attr class with non-integral type");
71     InitHeaderAndResize(id, sizeof(T));
72     T* storage = reinterpret_cast<T*>(data_.data() + NLA_HDRLEN);
73     *storage = value;
74   }
75   // Caller is responsible for ensuring that |data| is:
76   //   1) Is at least NLA_HDRLEN long.
77   //   2) That *data when interpreted as a nlattr is internally consistent.
78   // (e.g. data.size() == NLA_ALIGN(nlattr.nla_len)
79   // and nla_len == NLA_HDRLEN + payload size
NL80211Attr(const std::vector<uint8_t> & data)80   explicit NL80211Attr(const std::vector<uint8_t>& data) {
81     data_ = data;
82   }
83 
84   ~NL80211Attr() override = default;
85 
IsValid()86   bool IsValid() const override {
87     if (!BaseNL80211Attr::IsValid()) {
88       return false;
89     }
90     // If BaseNL80211Attr::IsValid() == true, at least we have enough valid
91     // buffer for header.
92     const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
93     // Buffer size = header size +  payload size + padding size
94     // nla_len  =  header size + payload size
95     if (NLA_ALIGN(sizeof(T)) + NLA_HDRLEN != data_.size() ||
96         sizeof(T) + NLA_HDRLEN != header->nla_len ) {
97       return false;
98     }
99     return true;
100   }
101 
GetValue()102   T GetValue() const {
103     return *reinterpret_cast<const T*>(data_.data() + NLA_HDRLEN);
104   }
105 };  // class NL80211Attr for POD-types
106 
107 template <>
108 class NL80211Attr<std::vector<uint8_t>> : public BaseNL80211Attr {
109  public:
110   NL80211Attr(int id, const std::vector<uint8_t>& raw_buffer);
111   explicit NL80211Attr(const std::vector<uint8_t>& data);
112   ~NL80211Attr() override = default;
113   std::vector<uint8_t> GetValue() const;
114 }; // class NL80211Attr for raw data
115 
116 template <size_t N>
117 class NL80211Attr<std::array<uint8_t, N>> : public BaseNL80211Attr {
118  public:
NL80211Attr(int id,const std::array<uint8_t,N> & raw_buffer)119   NL80211Attr(int id, const std::array<uint8_t, N>& raw_buffer)
120       : BaseNL80211Attr(
121           id, std::vector<uint8_t>(raw_buffer.begin(), raw_buffer.end())) {}
NL80211Attr(const std::vector<uint8_t> & data)122   explicit NL80211Attr(const std::vector<uint8_t>& data) {
123     data_ = data;
124   }
125   ~NL80211Attr() override = default;
GetValue()126   std::array<uint8_t, N> GetValue() const {
127     std::array<uint8_t, N> arr;
128     std::copy_n(data_.data() + NLA_HDRLEN, N, arr.begin());
129     return arr;
130   }
131 }; // class NL80211Attr for fixed size array
132 
133 template <>
134 class NL80211Attr<std::string> : public BaseNL80211Attr {
135  public:
136   NL80211Attr(int id, const std::string& str);
137   // We parse string attribute buffer in the same way kernel does.
138   // All trailing zeros are trimmed when retrieving a std::string from
139   // byte array.
140   explicit NL80211Attr(const std::vector<uint8_t>& data);
141   ~NL80211Attr() override = default;
142   std::string GetValue() const;
143 };  // class NL80211Attr for string
144 
145 // Force the compiler not to instantiate these templates because
146 // they will be instantiated in nl80211_attribute.cpp file. This helps
147 // reduce compile time as well as object file size.
148 extern template class NL80211Attr<uint8_t>;
149 extern template class NL80211Attr<uint16_t>;
150 extern template class NL80211Attr<uint32_t>;
151 extern template class NL80211Attr<uint64_t>;
152 extern template class NL80211Attr<std::vector<uint8_t>>;
153 extern template class NL80211Attr<std::string>;
154 
155 class NL80211NestedAttr : public BaseNL80211Attr {
156  public:
157   explicit NL80211NestedAttr(int id);
158   explicit NL80211NestedAttr(const std::vector<uint8_t>& data);
159   ~NL80211NestedAttr() override = default;
160 
161   void AddAttribute(const BaseNL80211Attr& attribute);
162   // For NLA_FLAG attribute
163   void AddFlagAttribute(int attribute_id);
164   bool HasAttribute(int id) const;
165 
166   // Access an attribute nested within |this|.
167   // The result is returned by writing the attribute object to |*attribute|.
168   // Deeper nested attributes are not included. This means if A is nested within
169   // |this|, and B is nested within A, this function can't be used to access B.
170   // The reason is that we may have multiple attributes having the same
171   // attribute id, nested within different level of |this|.
172   bool GetAttribute(int id, NL80211NestedAttr* attribute) const;
173 
174   template <typename T>
GetAttributeValue(int id,T * value)175   bool GetAttributeValue(int id, T* value) const {
176     std::vector<uint8_t> empty_vec;
177     // All data in |attribute| created here will be overwritten by
178     // GetAttribute(). So we use an empty vector to initialize it,
179     // regardless of the fact that an empty buffer is not qualified
180     // for creating a valid attribute.
181     NL80211Attr<T> attribute(empty_vec);
182     if (!GetAttribute(id, &attribute)) {
183       return false;
184     }
185     *value = attribute.GetValue();
186     return true;
187   }
188 
189   // Some of the nested attribute contains a list of same type sub-attributes.
190   // This function retrieves a vector of attribute values from a nested
191   // attribute.
192   //
193   // This is for both correctness and performance reasons: Refer to
194   // GetListOfAttributes().
195   //
196   // Returns true on success.
197   template <typename T>
GetListOfAttributeValues(std::vector<T> * value)198   bool GetListOfAttributeValues(std::vector<T>* value) const {
199     const uint8_t* ptr = data_.data() + NLA_HDRLEN;
200     const uint8_t* end_ptr = data_.data() + data_.size();
201     std::vector<T> attr_list;
202     while (ptr + NLA_HDRLEN <= end_ptr) {
203       const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
204       if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
205         LOG(ERROR) << "Failed to get list of attributes: invalid nla_len.";
206         return false;
207       }
208       NL80211Attr<T> attribute(std::vector<uint8_t>(
209           ptr,
210           ptr + NLA_ALIGN(header->nla_len)));
211       if (!attribute.IsValid()) {
212         return false;
213       }
214       attr_list.emplace_back(attribute.GetValue());
215       ptr += NLA_ALIGN(header->nla_len);
216     }
217     *value = std::move(attr_list);
218     return true;
219   }
220 
221   // Some of the nested attribute contains a list of same type sub-attributes.
222   // This function retrieves a vector of attributes from a nested
223   // attribute.
224   //
225   // This is for both correctness and performance reasons:
226   // Correctness reason:
227   // These sub-attributes have attribute id from '0 to n' or '1 to n'.
228   // There is no document defining what the start index should be.
229   //
230   // Performance reson:
231   // Calling GetAttribute() from '0 to n' results a n^2 time complexity.
232   // This function get a list of attributes in one pass.
233   //
234   // Returns true on success.
235   template <typename T>
GetListOfAttributes(std::vector<NL80211Attr<T>> * value)236   bool GetListOfAttributes(std::vector<NL80211Attr<T>>* value) const {
237     const uint8_t* ptr = data_.data() + NLA_HDRLEN;
238     const uint8_t* end_ptr = data_.data() + data_.size();
239     std::vector<NL80211Attr<T>> attr_list;
240     while (ptr + NLA_HDRLEN <= end_ptr) {
241       const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
242       if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
243         LOG(ERROR) << "Failed to get list of attributes: invalid nla_len.";
244         return false;
245       }
246       NL80211Attr<T> attribute(std::vector<uint8_t>(
247           ptr,
248           ptr + NLA_ALIGN(header->nla_len)));
249       if (!attribute.IsValid()) {
250         return false;
251       }
252       attr_list.emplace_back(attribute);
253       ptr += NLA_ALIGN(header->nla_len);
254     }
255     *value = std::move(attr_list);
256     return true;
257   }
258 
259   // This is similar to |GetListOfAttributeValues|, but for the cases where all
260   // the sub-attributes are nested attributes.
261   bool GetListOfNestedAttributes(std::vector<NL80211NestedAttr>* value) const;
262 
263   template <typename T>
GetAttribute(int id,NL80211Attr<T> * attribute)264   bool GetAttribute(int id, NL80211Attr<T>* attribute) const {
265     uint8_t* start = nullptr;
266     uint8_t* end = nullptr;
267     if (!BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN,
268                                            data_.size() - NLA_HDRLEN,
269                                            id, &start, &end) ||
270         start == nullptr ||
271         end == nullptr) {
272       return false;
273     }
274     *attribute = NL80211Attr<T>(std::vector<uint8_t>(start, end));
275     if (!attribute->IsValid()) {
276       return false;
277     }
278     return true;
279   }
280 
281   void DebugLog() const;
282 
283 };
284 
285 }  // namespace wificond
286 }  // namespace android
287 
288 #endif  // WIFICOND_NET_NL80211_ATTRIBUTE_H_
289