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 
CreateAttribute(int id,AttributeList::NewFromIdMethod factory)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 
CreateControlAttribute(int id)50 bool AttributeList::CreateControlAttribute(int id) {
51   return CreateAttribute(
52       id, base::Bind(&NetlinkAttribute::NewControlAttributeFromId));
53 }
54 
CreateNl80211Attribute(int id,NetlinkMessage::MessageContext context)55 bool AttributeList::CreateNl80211Attribute(
56     int id, NetlinkMessage::MessageContext context) {
57   return CreateAttribute(
58       id, base::Bind(&NetlinkAttribute::NewNl80211AttributeFromId, context));
59 }
60 
CreateAndInitAttribute(const AttributeList::NewFromIdMethod & factory,int id,const ByteString & value)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 
InitAttributeFromValue(int id,const ByteString & value)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 
Print(int log_level,int indent) const77 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
IterateAttributes(const ByteString & payload,size_t offset,const AttributeList::AttributeMethod & method)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 
Decode(const ByteString & payload,size_t offset,const AttributeList::NewFromIdMethod & factory)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 
Encode() const125 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 
GetU8AttributeValue(int id,uint8_t * value) const137 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 
CreateU8Attribute(int id,const char * id_string)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 
SetU8AttributeValue(int id,uint8_t value)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 
GetU16AttributeValue(int id,uint16_t * value) const164 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 
CreateU16Attribute(int id,const char * id_string)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 
SetU16AttributeValue(int id,uint16_t value)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 
GetU32AttributeValue(int id,uint32_t * value) const190 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 
CreateU32Attribute(int id,const char * id_string)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 
SetU32AttributeValue(int id,uint32_t value)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 
GetU64AttributeValue(int id,uint64_t * value) const216 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 
CreateU64Attribute(int id,const char * id_string)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 
SetU64AttributeValue(int id,uint64_t value)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 
GetFlagAttributeValue(int id,bool * value) const242 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 
CreateFlagAttribute(int id,const char * id_string)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 
SetFlagAttributeValue(int id,bool value)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 
IsFlagAttributeTrue(int id) const266 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 
GetStringAttributeValue(int id,string * value) const276 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 
CreateStringAttribute(int id,const char * id_string)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 
CreateSsidAttribute(int id,const char * id_string)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 
SetStringAttributeValue(int id,string value)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 
GetNestedAttributeList(int id,AttributeListRefPtr * value)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 
ConstGetNestedAttributeList(int id,AttributeListConstRefPtr * value) const320 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 
SetNestedAttributeHasAValue(int id)328 bool AttributeList::SetNestedAttributeHasAValue(int id) {
329   NetlinkAttribute* attribute = GetAttribute(id);
330   if (!attribute)
331     return false;
332   return attribute->SetNestedHasAValue();
333 }
334 
CreateNestedAttribute(int id,const char * id_string)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 
GetRawAttributeValue(int id,ByteString * output) const347 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 
SetRawAttributeValue(int id,ByteString value)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 
CreateRawAttribute(int id,const char * id_string)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 
GetAttributeAsString(int id,std::string * value) const380 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 
GetAttribute(int id) const388 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