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