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 33using base::StringAppendF; 34using base::WeakPtr; 35using std::map; 36using std::string; 37 38namespace shill { 39 40bool 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 50bool AttributeList::CreateControlAttribute(int id) { 51 return CreateAttribute( 52 id, base::Bind(&NetlinkAttribute::NewControlAttributeFromId)); 53} 54 55bool AttributeList::CreateNl80211Attribute( 56 int id, NetlinkMessage::MessageContext context) { 57 return CreateAttribute( 58 id, base::Bind(&NetlinkAttribute::NewNl80211AttributeFromId, context)); 59} 60 61bool 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 70bool 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 77void 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 86bool 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 117bool 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 125ByteString 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 137bool 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 144bool 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 154bool 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 164bool 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 171bool 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 181bool 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 190bool 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 197bool 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 207bool 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 216bool 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 223bool 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 233bool 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 242bool 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 249bool 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 259bool AttributeList::SetFlagAttributeValue(int id, bool value) { 260 NetlinkAttribute* attribute = GetAttribute(id); 261 if (!attribute) 262 return false; 263 return attribute->SetFlagValue(value); 264} 265 266bool 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 276bool 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 283bool 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 293bool 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 303bool 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 312bool 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 320bool 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 328bool AttributeList::SetNestedAttributeHasAValue(int id) { 329 NetlinkAttribute* attribute = GetAttribute(id); 330 if (!attribute) 331 return false; 332 return attribute->SetNestedHasAValue(); 333} 334 335bool 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 347bool 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 364bool AttributeList::SetRawAttributeValue(int id, ByteString value) { 365 NetlinkAttribute* attribute = GetAttribute(id); 366 if (!attribute) 367 return false; 368 return attribute->SetRawValue(value); 369} 370 371bool 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 380bool 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 388NetlinkAttribute* 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