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