Home | History | Annotate | Download | only in net
      1 //
      2 // Copyright (C) 2012 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 "shill/net/attribute_list.h"
     18 
     19 #include <ctype.h>
     20 #include <linux/nl80211.h>
     21 
     22 #include <iomanip>
     23 #include <map>
     24 #include <string>
     25 
     26 #include <base/logging.h>
     27 #include <base/stl_util.h>
     28 #include <base/strings/stringprintf.h>
     29 
     30 #include "shill/net/netlink_attribute.h"
     31 #include "shill/net/netlink_message.h"
     32 
     33 using base::StringAppendF;
     34 using base::WeakPtr;
     35 using std::map;
     36 using std::string;
     37 
     38 namespace shill {
     39 
     40 bool AttributeList::CreateAttribute(
     41     int id, AttributeList::NewFromIdMethod factory) {
     42   if (ContainsKey(attributes_, id)) {
     43     VLOG(7) << "Trying to re-add attribute " << id << ", not overwriting";
     44     return true;
     45   }
     46   attributes_[id] = AttributePointer(factory.Run(id));
     47   return true;
     48 }
     49 
     50 bool AttributeList::CreateControlAttribute(int id) {
     51   return CreateAttribute(
     52       id, base::Bind(&NetlinkAttribute::NewControlAttributeFromId));
     53 }
     54 
     55 bool AttributeList::CreateNl80211Attribute(
     56     int id, NetlinkMessage::MessageContext context) {
     57   return CreateAttribute(
     58       id, base::Bind(&NetlinkAttribute::NewNl80211AttributeFromId, context));
     59 }
     60 
     61 bool AttributeList::CreateAndInitAttribute(
     62     const AttributeList::NewFromIdMethod& factory,
     63     int id, const ByteString& value) {
     64   if (!CreateAttribute(id, factory)) {
     65     return false;
     66   }
     67   return InitAttributeFromValue(id, value);
     68 }
     69 
     70 bool AttributeList::InitAttributeFromValue(int id, const ByteString& value) {
     71   NetlinkAttribute* attribute = GetAttribute(id);
     72   if (!attribute)
     73     return false;
     74   return attribute->InitFromValue(value);
     75 }
     76 
     77 void AttributeList::Print(int log_level, int indent) const {
     78   map<int, AttributePointer>::const_iterator i;
     79 
     80   for (i = attributes_.begin(); i != attributes_.end(); ++i) {
     81     i->second->Print(log_level, indent);
     82   }
     83 }
     84 
     85 // static
     86 bool AttributeList::IterateAttributes(
     87     const ByteString& payload, size_t offset,
     88     const AttributeList::AttributeMethod& method) {
     89   const unsigned char* ptr = payload.GetConstData() + NLA_ALIGN(offset);
     90   const unsigned char* end = payload.GetConstData() + payload.GetLength();
     91   while (ptr + sizeof(nlattr) <= end) {
     92     const nlattr* attribute = reinterpret_cast<const nlattr*>(ptr);
     93     if (attribute->nla_len < sizeof(*attribute) ||
     94         ptr + attribute->nla_len > end) {
     95       LOG(ERROR) << "Malformed nla attribute indicates length "
     96                  << attribute->nla_len << ".  "
     97                  << (end - ptr - NLA_HDRLEN) << " bytes remain in buffer.  "
     98                  << "Error occurred at offset "
     99                  << (ptr - payload.GetConstData()) << ".";
    100       return false;
    101     }
    102     ByteString value;
    103     if (attribute->nla_len > NLA_HDRLEN) {
    104       value = ByteString(ptr + NLA_HDRLEN, attribute->nla_len - NLA_HDRLEN);
    105     }
    106     if (!method.Run(attribute->nla_type, value)) {
    107       return false;
    108     }
    109     ptr += NLA_ALIGN(attribute->nla_len);
    110   }
    111   if (ptr < end) {
    112     LOG(INFO) << "Decode left " << (end - ptr) << " unparsed bytes.";
    113   }
    114   return true;
    115 }
    116 
    117 bool AttributeList::Decode(const ByteString& payload,
    118                            size_t offset,
    119                            const AttributeList::NewFromIdMethod& factory) {
    120   return IterateAttributes(
    121       payload, offset, base::Bind(&AttributeList::CreateAndInitAttribute,
    122                                   base::Unretained(this), factory));
    123 }
    124 
    125 ByteString AttributeList::Encode() const {
    126   ByteString result;
    127   map<int, AttributePointer>::const_iterator i;
    128 
    129   for (i = attributes_.begin(); i != attributes_.end(); ++i) {
    130     result.Append(i->second->Encode());
    131   }
    132   return result;
    133 }
    134 
    135 // U8 Attribute.
    136 
    137 bool AttributeList::GetU8AttributeValue(int id, uint8_t* value) const {
    138   NetlinkAttribute* attribute = GetAttribute(id);
    139   if (!attribute)
    140     return false;
    141   return attribute->GetU8Value(value);
    142 }
    143 
    144 bool AttributeList::CreateU8Attribute(int id, const char* id_string) {
    145   if (ContainsKey(attributes_, id)) {
    146     LOG(ERROR) << "Trying to re-add attribute: " << id;
    147     return false;
    148   }
    149   attributes_[id] = AttributePointer(
    150       new NetlinkU8Attribute(id, id_string));
    151   return true;
    152 }
    153 
    154 bool AttributeList::SetU8AttributeValue(int id, uint8_t value) {
    155   NetlinkAttribute* attribute = GetAttribute(id);
    156   if (!attribute)
    157     return false;
    158   return attribute->SetU8Value(value);
    159 }
    160 
    161 
    162 // U16 Attribute.
    163 
    164 bool AttributeList::GetU16AttributeValue(int id, uint16_t* value) const {
    165   NetlinkAttribute* attribute = GetAttribute(id);
    166   if (!attribute)
    167     return false;
    168   return attribute->GetU16Value(value);
    169 }
    170 
    171 bool AttributeList::CreateU16Attribute(int id, const char* id_string) {
    172   if (ContainsKey(attributes_, id)) {
    173     LOG(ERROR) << "Trying to re-add attribute: " << id;
    174     return false;
    175   }
    176   attributes_[id] = AttributePointer(
    177       new NetlinkU16Attribute(id, id_string));
    178   return true;
    179 }
    180 
    181 bool AttributeList::SetU16AttributeValue(int id, uint16_t value) {
    182   NetlinkAttribute* attribute = GetAttribute(id);
    183   if (!attribute)
    184     return false;
    185   return attribute->SetU16Value(value);
    186 }
    187 
    188 // U32 Attribute.
    189 
    190 bool AttributeList::GetU32AttributeValue(int id, uint32_t* value) const {
    191   NetlinkAttribute* attribute = GetAttribute(id);
    192   if (!attribute)
    193     return false;
    194   return attribute->GetU32Value(value);
    195 }
    196 
    197 bool AttributeList::CreateU32Attribute(int id, const char* id_string) {
    198   if (ContainsKey(attributes_, id)) {
    199     LOG(ERROR) << "Trying to re-add attribute: " << id;
    200     return false;
    201   }
    202   attributes_[id] = AttributePointer(
    203       new NetlinkU32Attribute(id, id_string));
    204   return true;
    205 }
    206 
    207 bool AttributeList::SetU32AttributeValue(int id, uint32_t value) {
    208   NetlinkAttribute* attribute = GetAttribute(id);
    209   if (!attribute)
    210     return false;
    211   return attribute->SetU32Value(value);
    212 }
    213 
    214 // U64 Attribute.
    215 
    216 bool AttributeList::GetU64AttributeValue(int id, uint64_t* value) const {
    217   NetlinkAttribute* attribute = GetAttribute(id);
    218   if (!attribute)
    219     return false;
    220   return attribute->GetU64Value(value);
    221 }
    222 
    223 bool AttributeList::CreateU64Attribute(int id, const char* id_string) {
    224   if (ContainsKey(attributes_, id)) {
    225     LOG(ERROR) << "Trying to re-add attribute: " << id;
    226     return false;
    227   }
    228   attributes_[id] = AttributePointer(
    229       new NetlinkU64Attribute(id, id_string));
    230   return true;
    231 }
    232 
    233 bool AttributeList::SetU64AttributeValue(int id, uint64_t value) {
    234   NetlinkAttribute* attribute = GetAttribute(id);
    235   if (!attribute)
    236     return false;
    237   return attribute->SetU64Value(value);
    238 }
    239 
    240 // Flag Attribute.
    241 
    242 bool AttributeList::GetFlagAttributeValue(int id, bool* value) const {
    243   NetlinkAttribute* attribute = GetAttribute(id);
    244   if (!attribute)
    245     return false;
    246   return attribute->GetFlagValue(value);
    247 }
    248 
    249 bool AttributeList::CreateFlagAttribute(int id, const char* id_string) {
    250   if (ContainsKey(attributes_, id)) {
    251     LOG(ERROR) << "Trying to re-add attribute: " << id;
    252     return false;
    253   }
    254   attributes_[id] = AttributePointer(
    255       new NetlinkFlagAttribute(id, id_string));
    256   return true;
    257 }
    258 
    259 bool AttributeList::SetFlagAttributeValue(int id, bool value) {
    260   NetlinkAttribute* attribute = GetAttribute(id);
    261   if (!attribute)
    262     return false;
    263   return attribute->SetFlagValue(value);
    264 }
    265 
    266 bool AttributeList::IsFlagAttributeTrue(int id) const {
    267   bool flag;
    268   if (!GetFlagAttributeValue(id, &flag)) {
    269     return false;
    270   }
    271   return flag;
    272 }
    273 
    274 // String Attribute.
    275 
    276 bool AttributeList::GetStringAttributeValue(int id, string* value) const {
    277   NetlinkAttribute* attribute = GetAttribute(id);
    278   if (!attribute)
    279     return false;
    280   return attribute->GetStringValue(value);
    281 }
    282 
    283 bool AttributeList::CreateStringAttribute(int id, const char* id_string) {
    284   if (ContainsKey(attributes_, id)) {
    285     LOG(ERROR) << "Trying to re-add attribute: " << id;
    286     return false;
    287   }
    288   attributes_[id] = AttributePointer(
    289       new NetlinkStringAttribute(id, id_string));
    290   return true;
    291 }
    292 
    293 bool AttributeList::CreateSsidAttribute(int id, const char* id_string) {
    294   if (ContainsKey(attributes_, id)) {
    295     LOG(ERROR) << "Trying to re-add attribute: " << id;
    296     return false;
    297   }
    298   attributes_[id] = AttributePointer(
    299       new NetlinkSsidAttribute(id, id_string));
    300   return true;
    301 }
    302 
    303 bool AttributeList::SetStringAttributeValue(int id, string value) {
    304   NetlinkAttribute* attribute = GetAttribute(id);
    305   if (!attribute)
    306     return false;
    307   return attribute->SetStringValue(value);
    308 }
    309 
    310 // Nested Attribute.
    311 
    312 bool AttributeList::GetNestedAttributeList(int id,
    313                                            AttributeListRefPtr* value) {
    314   NetlinkAttribute* attribute = GetAttribute(id);
    315   if (!attribute)
    316     return false;
    317   return attribute->GetNestedAttributeList(value);
    318 }
    319 
    320 bool AttributeList::ConstGetNestedAttributeList(
    321     int id, AttributeListConstRefPtr* value) const {
    322   NetlinkAttribute* attribute = GetAttribute(id);
    323   if (!attribute)
    324     return false;
    325   return attribute->ConstGetNestedAttributeList(value);
    326 }
    327 
    328 bool AttributeList::SetNestedAttributeHasAValue(int id) {
    329   NetlinkAttribute* attribute = GetAttribute(id);
    330   if (!attribute)
    331     return false;
    332   return attribute->SetNestedHasAValue();
    333 }
    334 
    335 bool AttributeList::CreateNestedAttribute(int id, const char* id_string) {
    336   if (ContainsKey(attributes_, id)) {
    337     LOG(ERROR) << "Trying to re-add attribute: " << id;
    338     return false;
    339   }
    340   attributes_[id] = AttributePointer(
    341       new NetlinkNestedAttribute(id, id_string));
    342   return true;
    343 }
    344 
    345 // Raw Attribute.
    346 
    347 bool AttributeList::GetRawAttributeValue(int id,
    348                                          ByteString* output) const {
    349   NetlinkAttribute* attribute = GetAttribute(id);
    350   if (!attribute)
    351     return false;
    352 
    353   ByteString raw_value;
    354 
    355   if (!attribute->GetRawValue(&raw_value))
    356     return false;
    357 
    358   if (output) {
    359     *output = raw_value;
    360   }
    361   return true;
    362 }
    363 
    364 bool AttributeList::SetRawAttributeValue(int id, ByteString value) {
    365   NetlinkAttribute* attribute = GetAttribute(id);
    366   if (!attribute)
    367     return false;
    368   return attribute->SetRawValue(value);
    369 }
    370 
    371 bool AttributeList::CreateRawAttribute(int id, const char* id_string) {
    372   if (ContainsKey(attributes_, id)) {
    373     LOG(ERROR) << "Trying to re-add attribute: " << id;
    374     return false;
    375   }
    376   attributes_[id] = AttributePointer(new NetlinkRawAttribute(id, id_string));
    377   return true;
    378 }
    379 
    380 bool AttributeList::GetAttributeAsString(int id, std::string* value) const {
    381   NetlinkAttribute* attribute = GetAttribute(id);
    382   if (!attribute)
    383     return false;
    384 
    385   return attribute->ToString(value);
    386 }
    387 
    388 NetlinkAttribute* AttributeList::GetAttribute(int id) const {
    389   map<int, AttributePointer>::const_iterator i;
    390   i = attributes_.find(id);
    391   if (i == attributes_.end()) {
    392     return nullptr;
    393   }
    394   return i->second.get();
    395 }
    396 
    397 }  // namespace shill
    398