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 #ifndef WIFICOND_NET_NL80211_ATTRIBUTE_H_
18 #define WIFICOND_NET_NL80211_ATTRIBUTE_H_
22 #include <type_traits>
25 #include <linux/netlink.h>
27 #include <android-base/logging.h>
28 #include <android-base/macros.h>
33 class BaseNL80211Attr {
35 virtual ~BaseNL80211Attr() = default;
37 const std::vector<uint8_t>& GetConstData() const;
38 int GetAttributeId() const;
39 // This is used when we initialize a NL80211 attribute from an existing
41 virtual bool IsValid() const;
42 // A util helper function to find a specific sub attribute from a buffer.
43 // This buffer is supposed to be from a nested attribute or a nl80211 packet.
44 // |*start| and |*end| are the start and end pointers of buffer where
45 // |id| atrribute locates.
46 static bool GetAttributeImpl(const uint8_t* buf,
53 BaseNL80211Attr() = default;
54 void InitHeaderAndResize(int attribute_id, int payload_length);
56 std::vector<uint8_t> data_;
60 class NL80211Attr : public BaseNL80211Attr {
62 NL80211Attr(int id, T value) {
64 std::is_integral<T>::value,
65 "Failed to create NL80211Attr class with non-integral type");
66 InitHeaderAndResize(id, sizeof(T));
67 T* storage = reinterpret_cast<T*>(data_.data() + NLA_HDRLEN);
70 // Caller is responsible for ensuring that |data| is:
71 // 1) Is at least NLA_HDRLEN long.
72 // 2) That *data when interpreted as a nlattr is internally consistent.
73 // (e.g. data.size() == NLA_ALIGN(nlattr.nla_len)
74 // and nla_len == NLA_HDRLEN + payload size
75 explicit NL80211Attr(const std::vector<uint8_t>& data) {
79 ~NL80211Attr() override = default;
81 bool IsValid() const override {
82 if (!BaseNL80211Attr::IsValid()) {
85 // If BaseNL80211Attr::IsValid() == true, at least we have enough valid
87 const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
88 // Buffer size = header size + payload size + padding size
89 // nla_len = header size + payload size
90 if (NLA_ALIGN(sizeof(T)) + NLA_HDRLEN != data_.size() ||
91 sizeof(T) + NLA_HDRLEN != header->nla_len ) {
98 return *reinterpret_cast<const T*>(data_.data() + NLA_HDRLEN);
100 }; // class NL80211Attr for POD-types
103 class NL80211Attr<std::vector<uint8_t>> : public BaseNL80211Attr {
105 NL80211Attr(int id, const std::vector<uint8_t>& raw_buffer);
106 explicit NL80211Attr(const std::vector<uint8_t>& data);
107 ~NL80211Attr() override = default;
108 std::vector<uint8_t> GetValue() const;
109 }; // class NL80211Attr for raw data
112 class NL80211Attr<std::string> : public BaseNL80211Attr {
114 NL80211Attr(int id, const std::string& str);
115 // We parse string attribute buffer in the same way kernel does.
116 // All trailing zeros are trimmed when retrieving a std::string from
118 explicit NL80211Attr(const std::vector<uint8_t>& data);
119 ~NL80211Attr() override = default;
120 std::string GetValue() const;
121 }; // class NL80211Attr for string
123 // Force the compiler not to instantiate these templates because
124 // they will be instantiated in nl80211_attribute.cpp file. This helps
125 // reduce compile time as well as object file size.
126 extern template class NL80211Attr<uint8_t>;
127 extern template class NL80211Attr<uint16_t>;
128 extern template class NL80211Attr<uint32_t>;
129 extern template class NL80211Attr<uint64_t>;
130 extern template class NL80211Attr<std::vector<uint8_t>>;
131 extern template class NL80211Attr<std::string>;
133 class NL80211NestedAttr : public BaseNL80211Attr {
135 explicit NL80211NestedAttr(int id);
136 explicit NL80211NestedAttr(const std::vector<uint8_t>& data);
137 ~NL80211NestedAttr() override = default;
139 void AddAttribute(const BaseNL80211Attr& attribute);
140 // For NLA_FLAG attribute
141 void AddFlagAttribute(int attribute_id);
142 bool HasAttribute(int id) const;
144 // Access an attribute nested within |this|.
145 // The result is returned by writing the attribute object to |*attribute|.
146 // Deeper nested attributes are not included. This means if A is nested within
147 // |this|, and B is nested within A, this function can't be used to access B.
148 // The reason is that we may have multiple attributes having the same
149 // attribute id, nested within different level of |this|.
150 bool GetAttribute(int id, NL80211NestedAttr* attribute) const;
152 template <typename T>
153 bool GetAttributeValue(int id, T* value) const {
154 std::vector<uint8_t> empty_vec;
155 // All data in |attribute| created here will be overwritten by
156 // GetAttribute(). So we use an empty vector to initialize it,
157 // regardless of the fact that an empty buffer is not qualified
158 // for creating a valid attribute.
159 NL80211Attr<T> attribute(empty_vec);
160 if (!GetAttribute(id, &attribute)) {
163 *value = attribute.GetValue();
167 // Some of the nested attribute contains a list of same type sub-attributes.
168 // This function retrieves a vector of attribute value from a nested
170 // This is for both correctness and performance reasons:
172 // Correctness reason:
173 // These sub-attributes have attribute id from '0 to n' or '1 to n'.
174 // There is no document defining what the start index should be.
175 // This function ignore all these fake attribute ids.
177 // Performance reson:
178 // Calling GetAttributeValue() from '0 to n' results a n^2 time complexity.
179 // This function get a list of attribute values in one pass.
181 // Returns true on success.
182 template <typename T>
183 bool GetListOfAttributeValues(std::vector<T>* value) const {
184 const uint8_t* ptr = data_.data() + NLA_HDRLEN;
185 const uint8_t* end_ptr = data_.data() + data_.size();
186 std::vector<T> attr_list;
187 while (ptr + NLA_HDRLEN <= end_ptr) {
188 const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
189 if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
190 LOG(ERROR) << "Failed to get list of attributes: invalid nla_len.";
193 NL80211Attr<T> attribute(std::vector<uint8_t>(
195 ptr + NLA_ALIGN(header->nla_len)));
196 if (!attribute.IsValid()) {
199 attr_list.emplace_back(attribute.GetValue());
200 ptr += NLA_ALIGN(header->nla_len);
202 *value = std::move(attr_list);
206 // This is similar to |GetListOfAttributeValues|, but for the cases where all
207 // the sub-attributes are nested attributes.
208 bool GetListOfNestedAttributes(std::vector<NL80211NestedAttr>* value) const;
210 template <typename T>
211 bool GetAttribute(int id, NL80211Attr<T>* attribute) const {
212 uint8_t* start = nullptr;
213 uint8_t* end = nullptr;
214 if (!BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN,
215 data_.size() - NLA_HDRLEN,
221 *attribute = NL80211Attr<T>(std::vector<uint8_t>(start, end));
222 if (!attribute->IsValid()) {
228 void DebugLog() const;
232 } // namespace wificond
233 } // namespace android
235 #endif // WIFICOND_NET_NL80211_ATTRIBUTE_H_