Home | History | Annotate | Download | only in net
      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:
     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
     80   explicit NL80211Attr(const std::vector<uint8_t>& data) {
     81     data_ = data;
     82   }
     83 
     84   ~NL80211Attr() override = default;
     85 
     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 
    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 <>
    117 class NL80211Attr<std::string> : public BaseNL80211Attr {
    118  public:
    119   NL80211Attr(int id, const std::string& str);
    120   // We parse string attribute buffer in the same way kernel does.
    121   // All trailing zeros are trimmed when retrieving a std::string from
    122   // byte array.
    123   explicit NL80211Attr(const std::vector<uint8_t>& data);
    124   ~NL80211Attr() override = default;
    125   std::string GetValue() const;
    126 };  // class NL80211Attr for string
    127 
    128 // Force the compiler not to instantiate these templates because
    129 // they will be instantiated in nl80211_attribute.cpp file. This helps
    130 // reduce compile time as well as object file size.
    131 extern template class NL80211Attr<uint8_t>;
    132 extern template class NL80211Attr<uint16_t>;
    133 extern template class NL80211Attr<uint32_t>;
    134 extern template class NL80211Attr<uint64_t>;
    135 extern template class NL80211Attr<std::vector<uint8_t>>;
    136 extern template class NL80211Attr<std::string>;
    137 
    138 class NL80211NestedAttr : public BaseNL80211Attr {
    139  public:
    140   explicit NL80211NestedAttr(int id);
    141   explicit NL80211NestedAttr(const std::vector<uint8_t>& data);
    142   ~NL80211NestedAttr() override = default;
    143 
    144   void AddAttribute(const BaseNL80211Attr& attribute);
    145   // For NLA_FLAG attribute
    146   void AddFlagAttribute(int attribute_id);
    147   bool HasAttribute(int id) const;
    148 
    149   // Access an attribute nested within |this|.
    150   // The result is returned by writing the attribute object to |*attribute|.
    151   // Deeper nested attributes are not included. This means if A is nested within
    152   // |this|, and B is nested within A, this function can't be used to access B.
    153   // The reason is that we may have multiple attributes having the same
    154   // attribute id, nested within different level of |this|.
    155   bool GetAttribute(int id, NL80211NestedAttr* attribute) const;
    156 
    157   template <typename T>
    158   bool GetAttributeValue(int id, T* value) const {
    159     std::vector<uint8_t> empty_vec;
    160     // All data in |attribute| created here will be overwritten by
    161     // GetAttribute(). So we use an empty vector to initialize it,
    162     // regardless of the fact that an empty buffer is not qualified
    163     // for creating a valid attribute.
    164     NL80211Attr<T> attribute(empty_vec);
    165     if (!GetAttribute(id, &attribute)) {
    166       return false;
    167     }
    168     *value = attribute.GetValue();
    169     return true;
    170   }
    171 
    172   // Some of the nested attribute contains a list of same type sub-attributes.
    173   // This function retrieves a vector of attribute values from a nested
    174   // attribute.
    175   //
    176   // This is for both correctness and performance reasons: Refer to
    177   // GetListOfAttributes().
    178   //
    179   // Returns true on success.
    180   template <typename T>
    181   bool GetListOfAttributeValues(std::vector<T>* value) const {
    182     const uint8_t* ptr = data_.data() + NLA_HDRLEN;
    183     const uint8_t* end_ptr = data_.data() + data_.size();
    184     std::vector<T> attr_list;
    185     while (ptr + NLA_HDRLEN <= end_ptr) {
    186       const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
    187       if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
    188         LOG(ERROR) << "Failed to get list of attributes: invalid nla_len.";
    189         return false;
    190       }
    191       NL80211Attr<T> attribute(std::vector<uint8_t>(
    192           ptr,
    193           ptr + NLA_ALIGN(header->nla_len)));
    194       if (!attribute.IsValid()) {
    195         return false;
    196       }
    197       attr_list.emplace_back(attribute.GetValue());
    198       ptr += NLA_ALIGN(header->nla_len);
    199     }
    200     *value = std::move(attr_list);
    201     return true;
    202   }
    203 
    204   // Some of the nested attribute contains a list of same type sub-attributes.
    205   // This function retrieves a vector of attributes from a nested
    206   // attribute.
    207   //
    208   // This is for both correctness and performance reasons:
    209   // Correctness reason:
    210   // These sub-attributes have attribute id from '0 to n' or '1 to n'.
    211   // There is no document defining what the start index should be.
    212   //
    213   // Performance reson:
    214   // Calling GetAttribute() from '0 to n' results a n^2 time complexity.
    215   // This function get a list of attributes in one pass.
    216   //
    217   // Returns true on success.
    218   template <typename T>
    219   bool GetListOfAttributes(std::vector<NL80211Attr<T>>* value) const {
    220     const uint8_t* ptr = data_.data() + NLA_HDRLEN;
    221     const uint8_t* end_ptr = data_.data() + data_.size();
    222     std::vector<NL80211Attr<T>> attr_list;
    223     while (ptr + NLA_HDRLEN <= end_ptr) {
    224       const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
    225       if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
    226         LOG(ERROR) << "Failed to get list of attributes: invalid nla_len.";
    227         return false;
    228       }
    229       NL80211Attr<T> attribute(std::vector<uint8_t>(
    230           ptr,
    231           ptr + NLA_ALIGN(header->nla_len)));
    232       if (!attribute.IsValid()) {
    233         return false;
    234       }
    235       attr_list.emplace_back(attribute);
    236       ptr += NLA_ALIGN(header->nla_len);
    237     }
    238     *value = std::move(attr_list);
    239     return true;
    240   }
    241 
    242   // This is similar to |GetListOfAttributeValues|, but for the cases where all
    243   // the sub-attributes are nested attributes.
    244   bool GetListOfNestedAttributes(std::vector<NL80211NestedAttr>* value) const;
    245 
    246   template <typename T>
    247   bool GetAttribute(int id, NL80211Attr<T>* attribute) const {
    248     uint8_t* start = nullptr;
    249     uint8_t* end = nullptr;
    250     if (!BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN,
    251                                            data_.size() - NLA_HDRLEN,
    252                                            id, &start, &end) ||
    253         start == nullptr ||
    254         end == nullptr) {
    255       return false;
    256     }
    257     *attribute = NL80211Attr<T>(std::vector<uint8_t>(start, end));
    258     if (!attribute->IsValid()) {
    259       return false;
    260     }
    261     return true;
    262   }
    263 
    264   void DebugLog() const;
    265 
    266 };
    267 
    268 }  // namespace wificond
    269 }  // namespace android
    270 
    271 #endif  // WIFICOND_NET_NL80211_ATTRIBUTE_H_
    272