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 #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
     34 
     35 BaseNL80211Attr::BaseNL80211Attr(int id,
     36     const vector<uint8_t>& raw_buffer) {
     37   size_t size = raw_buffer.size();
     38   InitHeaderAndResize(id, size);
     39   memcpy(data_.data() + NLA_HDRLEN, raw_buffer.data(), raw_buffer.size());
     40 }
     41 
     42 void BaseNL80211Attr::InitHeaderAndResize(int attribute_id,
     43                                           int payload_length) {
     44   data_.resize(NLA_HDRLEN + NLA_ALIGN(payload_length), 0);
     45   nlattr* header = reinterpret_cast<nlattr*>(data_.data());
     46   header->nla_type = attribute_id;
     47   header->nla_len = NLA_HDRLEN + payload_length;
     48 }
     49 
     50 int BaseNL80211Attr::GetAttributeId() const {
     51   const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
     52   return header->nla_type;
     53 }
     54 
     55 bool BaseNL80211Attr::IsValid() const {
     56   if (data_.size() < NLA_HDRLEN) {
     57     return false;
     58   }
     59   const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
     60   return NLA_ALIGN(header->nla_len) == data_.size();
     61 }
     62 
     63 const vector<uint8_t>& BaseNL80211Attr::GetConstData() const {
     64   return data_;
     65 }
     66 
     67 bool BaseNL80211Attr::GetAttributeImpl(const uint8_t* buf,
     68                                        size_t len,
     69                                        int attr_id,
     70                                        uint8_t** attr_start,
     71                                        uint8_t** attr_end) {
     72   // Skip the top level attribute header.
     73   const uint8_t* ptr = buf;
     74   const uint8_t* end_ptr = buf + len;
     75   while (ptr + NLA_HDRLEN <= end_ptr) {
     76     const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
     77     if (header->nla_type == attr_id) {
     78       if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
     79         LOG(ERROR) << "Failed to get attribute: broken nl80211 atrribute.";
     80         return false;
     81       }
     82       if (attr_start != nullptr && attr_end != nullptr) {
     83         *attr_start = const_cast<uint8_t*>(ptr);
     84         *attr_end = const_cast<uint8_t*>(ptr + NLA_ALIGN(header->nla_len));
     85       }
     86       return true;
     87     }
     88     ptr += NLA_ALIGN(header->nla_len);
     89   }
     90   return false;
     91 }
     92 
     93 
     94 bool BaseNL80211Attr::Merge(const BaseNL80211Attr& other_attr) {
     95   if (!other_attr.IsValid()) {
     96     LOG(ERROR) << "Can not merge invalid attribute";
     97     return false;
     98   }
     99   if (GetAttributeId() != other_attr.GetAttributeId()) {
    100     LOG(ERROR) << "Can not merge attributes with different ids";
    101     return false;
    102   }
    103 
    104   auto our_header = reinterpret_cast<nlattr*>(data_.data());
    105   int our_len_without_padding = our_header->nla_len;
    106   auto other_header =
    107       reinterpret_cast<const nlattr*>(other_attr.GetConstData().data());
    108   int other_len_without_padding = other_header->nla_len;
    109   // Update the length to include the content of |other_attr|.
    110   int total_len_without_padding =
    111       our_len_without_padding + other_len_without_padding - NLA_HDRLEN;
    112   our_header->nla_len = total_len_without_padding;
    113 
    114   // Remove padding 0s.
    115   data_.resize(our_len_without_padding);
    116   // Insert content of |other_attr|.
    117   data_.insert(
    118       data_.end(),
    119       reinterpret_cast<const uint8_t*>(other_header) + NLA_HDRLEN,
    120       reinterpret_cast<const uint8_t*>(other_header) +
    121           other_len_without_padding);
    122   // Add padding 0s.
    123   data_.resize(NLA_ALIGN(total_len_without_padding), 0);
    124   return true;
    125 }
    126 
    127 // For NL80211Attr<std::vector<uint8_t>>
    128 NL80211Attr<vector<uint8_t>>::NL80211Attr(int id,
    129     const vector<uint8_t>& raw_buffer) : BaseNL80211Attr(id, raw_buffer) {
    130 }
    131 
    132 NL80211Attr<vector<uint8_t>>::NL80211Attr(
    133     const vector<uint8_t>& data) {
    134   data_ = data;
    135 }
    136 
    137 vector<uint8_t> NL80211Attr<vector<uint8_t>>::GetValue() const {
    138   const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
    139   return vector<uint8_t>(
    140       data_.data() + NLA_HDRLEN,
    141       data_.data() + header->nla_len);
    142 }
    143 
    144 // For NL80211Attr<std::string>
    145 NL80211Attr<string>::NL80211Attr(int id, const string& str) {
    146   size_t size = str.size();
    147   // This string is storaged as a null-terminated string.
    148   // Buffer is initialized with 0s so we only need to make a space for
    149   // the null terminator.
    150   InitHeaderAndResize(id, size + 1);
    151   char* storage = reinterpret_cast<char*>(data_.data() + NLA_HDRLEN);
    152   str.copy(storage, size);
    153 }
    154 
    155 NL80211Attr<string>::NL80211Attr(const vector<uint8_t>& data) {
    156   data_ = data;
    157 }
    158 
    159 string NL80211Attr<string>::GetValue() const {
    160   const nlattr* header = reinterpret_cast<const nlattr*>(data_.data());
    161   size_t str_length = header->nla_len - NLA_HDRLEN;
    162   // Remove trailing zeros.
    163   while (str_length > 0 &&
    164          *(data_.data() + NLA_HDRLEN + str_length - 1) == 0) {
    165     str_length--;
    166   }
    167   return string(reinterpret_cast<const char*>(data_.data() + NLA_HDRLEN),
    168                 str_length);
    169 }
    170 
    171 // For NL80211NestedAttr
    172 NL80211NestedAttr::NL80211NestedAttr(int id) {
    173   InitHeaderAndResize(id, 0);
    174 }
    175 
    176 NL80211NestedAttr::NL80211NestedAttr(const vector<uint8_t>& data) {
    177   data_ = data;
    178 }
    179 
    180 void NL80211NestedAttr::AddAttribute(const BaseNL80211Attr& attribute) {
    181   const vector<uint8_t>& append_data = attribute.GetConstData();
    182   // Append the data of |attribute| to |this|.
    183   data_.insert(data_.end(), append_data.begin(), append_data.end());
    184   nlattr* header = reinterpret_cast<nlattr*>(data_.data());
    185   // We don't need to worry about padding for nested attribute.
    186   // Because as long as all sub attributes have padding, the payload is aligned.
    187   header->nla_len += append_data.size();
    188 }
    189 
    190 void NL80211NestedAttr::AddFlagAttribute(int attribute_id) {
    191   // We only need to append a header for flag attribute.
    192   // Make space for the new attribute.
    193   data_.resize(data_.size() + NLA_HDRLEN, 0);
    194   nlattr* flag_header =
    195       reinterpret_cast<nlattr*>(data_.data() + data_.size() - NLA_HDRLEN);
    196   flag_header->nla_type = attribute_id;
    197   flag_header->nla_len = NLA_HDRLEN;
    198   nlattr* nl_header = reinterpret_cast<nlattr*>(data_.data());
    199   nl_header->nla_len += NLA_HDRLEN;
    200 }
    201 
    202 bool NL80211NestedAttr::HasAttribute(int id) const {
    203   return BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN,
    204                                            data_.size() - NLA_HDRLEN,
    205                                            id, nullptr, nullptr);
    206 }
    207 
    208 bool NL80211NestedAttr::GetAttribute(int id,
    209     NL80211NestedAttr* attribute) const {
    210   uint8_t* start = nullptr;
    211   uint8_t* end = nullptr;
    212   if (!BaseNL80211Attr::GetAttributeImpl(data_.data() + NLA_HDRLEN,
    213                                          data_.size() - NLA_HDRLEN,
    214                                          id, &start, &end) ||
    215       start == nullptr ||
    216       end == nullptr) {
    217     return false;
    218   }
    219   *attribute = NL80211NestedAttr(vector<uint8_t>(start, end));
    220   if (!attribute->IsValid()) {
    221     return false;
    222   }
    223   return true;
    224 }
    225 
    226 bool NL80211NestedAttr::GetListOfNestedAttributes(
    227     vector<NL80211NestedAttr>* value) const {
    228   const uint8_t* ptr = data_.data() + NLA_HDRLEN;
    229   const uint8_t* end_ptr = data_.data() + data_.size();
    230   vector<NL80211NestedAttr> nested_attr_list;
    231   while (ptr + NLA_HDRLEN <= end_ptr) {
    232     const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
    233     if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
    234       LOG(ERROR) << "Failed to get list of nested attributes: invalid nla_len.";
    235       return false;
    236     }
    237     nested_attr_list.emplace_back(
    238         NL80211NestedAttr(vector<uint8_t>(ptr,
    239                                           ptr + NLA_ALIGN(header->nla_len))));
    240     if (!nested_attr_list.back().IsValid()) {
    241       return false;
    242     }
    243     ptr += NLA_ALIGN(header->nla_len);
    244   }
    245   *value = std::move(nested_attr_list);
    246   return true;
    247 }
    248 
    249 
    250 void NL80211NestedAttr::DebugLog() const {
    251   const uint8_t* ptr = data_.data() + NLA_HDRLEN;
    252   const uint8_t* end_ptr = data_.data() + data_.size();
    253   while (ptr + NLA_HDRLEN <= end_ptr) {
    254     const nlattr* header = reinterpret_cast<const nlattr*>(ptr);
    255     if (ptr + NLA_ALIGN(header->nla_len) > end_ptr) {
    256       LOG(ERROR) << "broken nl80211 atrribute.";
    257       return;
    258     }
    259     LOG(INFO) << "Have attribute with nla_type=" << header->nla_type
    260               << " and nla_len=" << header->nla_len;
    261     if (header->nla_len == 0) {
    262       LOG(ERROR) << "0 is a bad nla_len";
    263       return;
    264     }
    265     ptr += NLA_ALIGN(header->nla_len);
    266   }
    267 }
    268 
    269 }  // namespace wificond
    270 }  // namespace android
    271