blob: a934074eed61facd305e40ce17d07b8d82b597c8 [file] [log] [blame]
Wade Guthrief162f8b2013-02-27 14:13:55 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/netlink_attribute.h"
6
7#include <netlink/attr.h>
8
9#include <string>
10
11#include <base/format_macros.h>
12#include <base/stringprintf.h>
13
14#include "shill/attribute_list.h"
15#include "shill/control_netlink_attribute.h"
16#include "shill/logging.h"
17#include "shill/nl80211_attribute.h"
Wade Guthrief54872f2013-04-11 15:11:50 -070018#include "shill/wifi.h"
Wade Guthrief162f8b2013-02-27 14:13:55 -080019
Wade Guthrief1b36412013-04-11 14:51:31 -070020using std::map;
Wade Guthrief162f8b2013-02-27 14:13:55 -080021using std::string;
22
23using base::StringAppendF;
24using base::StringPrintf;
25
26namespace shill {
27
28// This is a type-corrected copy of |nla_for_each_nested| from libnl.
29#define nla_for_each_nested_type_corrected(pos, nla, rem) \
30 for (pos = reinterpret_cast<struct nlattr *>(nla_data(nla)), \
31 rem = nla_len(nla); \
32 nla_ok(pos, rem); \
33 pos = nla_next(pos, &(rem)))
34
35NetlinkAttribute::NetlinkAttribute(int id,
36 const char *id_string,
37 Type datatype,
38 const char *datatype_string)
39 : has_a_value_(false), id_(id), id_string_(id_string), datatype_(datatype),
40 datatype_string_(datatype_string) {}
41
42// static
43NetlinkAttribute *NetlinkAttribute::NewNl80211AttributeFromId(int id) {
44 scoped_ptr<NetlinkAttribute> attr;
45 switch (id) {
Wade Guthrief54872f2013-04-11 15:11:50 -070046 case NL80211_ATTR_BSS:
47 attr.reset(new Nl80211AttributeBss());
48 break;
Wade Guthrief162f8b2013-02-27 14:13:55 -080049 case NL80211_ATTR_COOKIE:
50 attr.reset(new Nl80211AttributeCookie());
51 break;
52 case NL80211_ATTR_CQM:
53 attr.reset(new Nl80211AttributeCqm());
54 break;
55 case NL80211_ATTR_DISCONNECTED_BY_AP:
56 attr.reset(new Nl80211AttributeDisconnectedByAp());
57 break;
58 case NL80211_ATTR_DURATION:
59 attr.reset(new Nl80211AttributeDuration());
60 break;
61 case NL80211_ATTR_FRAME:
62 attr.reset(new Nl80211AttributeFrame());
63 break;
64 case NL80211_ATTR_GENERATION:
65 attr.reset(new Nl80211AttributeGeneration());
66 break;
67 case NL80211_ATTR_IFINDEX:
68 attr.reset(new Nl80211AttributeIfindex());
69 break;
Paul Stewart2ddf2c62013-04-16 09:47:34 -070070 case NL80211_ATTR_IFTYPE:
71 attr.reset(new Nl80211AttributeIftype());
72 break;
Wade Guthrief162f8b2013-02-27 14:13:55 -080073 case NL80211_ATTR_KEY_IDX:
74 attr.reset(new Nl80211AttributeKeyIdx());
75 break;
76 case NL80211_ATTR_KEY_SEQ:
77 attr.reset(new Nl80211AttributeKeySeq());
78 break;
79 case NL80211_ATTR_KEY_TYPE:
80 attr.reset(new Nl80211AttributeKeyType());
81 break;
82 case NL80211_ATTR_MAC:
83 attr.reset(new Nl80211AttributeMac());
84 break;
85 case NL80211_ATTR_REASON_CODE:
86 attr.reset(new Nl80211AttributeReasonCode());
87 break;
88 case NL80211_ATTR_REG_ALPHA2:
89 attr.reset(new Nl80211AttributeRegAlpha2());
90 break;
91 case NL80211_ATTR_REG_INITIATOR:
92 attr.reset(new Nl80211AttributeRegInitiator());
93 break;
94 case NL80211_ATTR_REG_TYPE:
95 attr.reset(new Nl80211AttributeRegType());
96 break;
97 case NL80211_ATTR_RESP_IE:
98 attr.reset(new Nl80211AttributeRespIe());
99 break;
100 case NL80211_ATTR_SCAN_FREQUENCIES:
101 attr.reset(new Nl80211AttributeScanFrequencies());
102 break;
103 case NL80211_ATTR_SCAN_SSIDS:
104 attr.reset(new Nl80211AttributeScanSsids());
105 break;
106 case NL80211_ATTR_STA_INFO:
107 attr.reset(new Nl80211AttributeStaInfo());
108 break;
109 case NL80211_ATTR_STATUS_CODE:
110 attr.reset(new Nl80211AttributeStatusCode());
111 break;
112 case NL80211_ATTR_SUPPORT_MESH_AUTH:
113 attr.reset(new Nl80211AttributeSupportMeshAuth());
114 break;
115 case NL80211_ATTR_TIMED_OUT:
116 attr.reset(new Nl80211AttributeTimedOut());
117 break;
118 case NL80211_ATTR_WIPHY_FREQ:
119 attr.reset(new Nl80211AttributeWiphyFreq());
120 break;
121 case NL80211_ATTR_WIPHY:
122 attr.reset(new Nl80211AttributeWiphy());
123 break;
124 case NL80211_ATTR_WIPHY_NAME:
125 attr.reset(new Nl80211AttributeWiphyName());
126 break;
127 default:
128 attr.reset(new NetlinkAttributeGeneric(id));
129 break;
130 }
131 return attr.release();
132}
133
134// static
135NetlinkAttribute *NetlinkAttribute::NewControlAttributeFromId(int id) {
136 scoped_ptr<NetlinkAttribute> attr;
137 switch (id) {
138 case CTRL_ATTR_FAMILY_ID:
139 attr.reset(new ControlAttributeFamilyId());
140 break;
141 case CTRL_ATTR_FAMILY_NAME:
142 attr.reset(new ControlAttributeFamilyName());
143 break;
144 case CTRL_ATTR_VERSION:
145 attr.reset(new ControlAttributeVersion());
146 break;
147 case CTRL_ATTR_HDRSIZE:
148 attr.reset(new ControlAttributeHdrSize());
149 break;
150 case CTRL_ATTR_MAXATTR:
151 attr.reset(new ControlAttributeMaxAttr());
152 break;
153 case CTRL_ATTR_OPS:
154 attr.reset(new ControlAttributeAttrOps());
155 break;
156 case CTRL_ATTR_MCAST_GROUPS:
157 attr.reset(new ControlAttributeMcastGroups());
158 break;
159 default:
160 attr.reset(new NetlinkAttributeGeneric(id));
161 break;
162 }
163 return attr.release();
164}
165
166// Duplicate attribute data, store in map indexed on |id|.
167bool NetlinkAttribute::InitFromNlAttr(const nlattr *other) {
168 if (!other) {
169 LOG(ERROR) << "NULL data";
170 return false;
171 }
172
173 data_ = ByteString(
174 reinterpret_cast<char *>(nla_data(const_cast<nlattr *>(other))),
175 nla_len(const_cast<nlattr *>(other)));
176 return true;
177}
178
179bool NetlinkAttribute::GetU8Value(uint8_t *value) const {
180 LOG(ERROR) << "Attribute is not of type 'U8'";
181 return false;
182}
183
184bool NetlinkAttribute::SetU8Value(uint8_t value) {
185 LOG(ERROR) << "Attribute is not of type 'U8'";
186 return false;
187}
188
189bool NetlinkAttribute::GetU16Value(uint16_t *value) const {
190 LOG(ERROR) << "Attribute is not of type 'U16'";
191 return false;
192}
193
194bool NetlinkAttribute::SetU16Value(uint16_t value) {
195 LOG(ERROR) << "Attribute is not of type 'U16'";
196 return false;
197}
198
199bool NetlinkAttribute::GetU32Value(uint32_t *value) const {
200 LOG(ERROR) << "Attribute is not of type 'U32'";
201 return false;
202}
203
204bool NetlinkAttribute::SetU32Value(uint32_t value) {
205 LOG(ERROR) << "Attribute is not of type 'U32'";
206 return false;
207}
208
209bool NetlinkAttribute::GetU64Value(uint64_t *value) const {
210 LOG(ERROR) << "Attribute is not of type 'U64'";
211 return false;
212}
213
214bool NetlinkAttribute::SetU64Value(uint64_t value) {
215 LOG(ERROR) << "Attribute is not of type 'U64'";
216 return false;
217}
218
219bool NetlinkAttribute::GetFlagValue(bool *value) const {
220 LOG(ERROR) << "Attribute is not of type 'Flag'";
221 return false;
222}
223
224bool NetlinkAttribute::SetFlagValue(bool value) {
225 LOG(ERROR) << "Attribute is not of type 'Flag'";
226 return false;
227}
228
229bool NetlinkAttribute::GetStringValue(string *value) const {
230 LOG(ERROR) << "Attribute is not of type 'String'";
231 return false;
232}
233
234bool NetlinkAttribute::SetStringValue(string value) {
235 LOG(ERROR) << "Attribute is not of type 'String'";
236 return false;
237}
238
239bool NetlinkAttribute::GetNestedAttributeList(AttributeListRefPtr *value) {
240 LOG(ERROR) << "Attribute is not of type 'Nested'";
241 return false;
242}
243
244bool NetlinkAttribute::ConstGetNestedAttributeList(
245 AttributeListConstRefPtr *value) const {
246 LOG(ERROR) << "Attribute is not of type 'Nested'";
247 return false;
248}
249
250bool NetlinkAttribute::SetNestedHasAValue() {
251 LOG(ERROR) << "Attribute is not of type 'Nested'";
252 return false;
253}
254
255bool NetlinkAttribute::GetRawValue(ByteString *value) const {
256 LOG(ERROR) << "Attribute is not of type 'Raw'";
257 return false;
258}
259
260bool NetlinkAttribute::SetRawValue(const ByteString new_value) {
261 LOG(ERROR) << "Attribute is not of type 'Raw'";
262 return false;
263}
264
265void NetlinkAttribute::Print(int log_level, int indent) const {
266 string attribute_value;
267 SLOG(WiFi, log_level) << HeaderToPrint(indent) << " "
268 << (ToString(&attribute_value) ? attribute_value :
269 "<DOES NOT EXIST>");
270}
271
272string NetlinkAttribute::RawToString() const {
273 string output = " === RAW: ";
274
275 if (!has_a_value_) {
276 StringAppendF(&output, "(empty)");
277 return output;
278 }
279
280 uint16_t length = data_.GetLength();
281 const uint8_t *const_data = data_.GetConstData();
282
283 StringAppendF(&output, "len=%u", length);
284 output.append(" DATA: ");
285 for (int i =0 ; i < length; ++i) {
286 StringAppendF(&output, "[%d]=%02x ", i, *(const_data)+i);
287 }
288 output.append(" ==== ");
289 return output;
290}
291
292string NetlinkAttribute::HeaderToPrint(int indent) const {
293 static const int kSpacesPerIndent = 2;
294 return StringPrintf("%*s%s(%d) %s %s=",
295 indent * kSpacesPerIndent, "",
296 id_string(),
297 id(),
298 datatype_string(),
299 ((has_a_value()) ? "": "UNINITIALIZED "));
300}
301
302ByteString NetlinkAttribute::EncodeGeneric(const unsigned char *data,
303 size_t num_bytes) const {
Wade Guthrie35cb4b92013-04-19 10:46:11 -0700304 ByteString result;
305 if (has_a_value_) {
306 nlattr header;
307 header.nla_type = id();
308 header.nla_len = nla_attr_size(num_bytes);
309 result = ByteString(reinterpret_cast<unsigned char *>(&header),
310 sizeof(header));
311 result.Resize(NLA_HDRLEN); // Add padding after the header.
312 if (data && (num_bytes != 0)) {
313 result.Append(ByteString(data, num_bytes));
314 }
315 result.Resize(nla_total_size(num_bytes)); // Add padding.
Wade Guthrief162f8b2013-02-27 14:13:55 -0800316 }
Wade Guthrief162f8b2013-02-27 14:13:55 -0800317 return result;
318}
319
320// NetlinkU8Attribute
321
322const char NetlinkU8Attribute::kMyTypeString[] = "uint8_t";
323const NetlinkAttribute::Type NetlinkU8Attribute::kType =
324 NetlinkAttribute::kTypeU8;
325
326bool NetlinkU8Attribute::InitFromNlAttr(const nlattr *input) {
327 if (!input) {
328 LOG(ERROR) << "Null |input| parameter";
329 return false;
330 }
331
332 uint8_t data = NlaGetU8(input);
333 SetU8Value(data);
334 return NetlinkAttribute::InitFromNlAttr(input);
335}
336
337bool NetlinkU8Attribute::GetU8Value(uint8_t *output) const {
338 if (!has_a_value_) {
339 SLOG(WiFi, 7) << "U8 attribute " << id_string()
340 << " hasn't been set to any value.";
341 return false;
342 }
343 if (output) {
344 *output = value_;
345 }
346 return true;
347}
348
349bool NetlinkU8Attribute::SetU8Value(uint8_t new_value) {
350 value_ = new_value;
351 has_a_value_ = true;
352 return true;
353}
354
355bool NetlinkU8Attribute::ToString(string *output) const {
356 if (!output) {
357 LOG(ERROR) << "Null |output| parameter";
358 return false;
359 }
360 uint8_t value;
361 if (!GetU8Value(&value))
362 return false;
363 *output = StringPrintf("%u", value);
364 return true;
365}
366
367ByteString NetlinkU8Attribute::Encode() const {
368 return NetlinkAttribute::EncodeGeneric(
369 reinterpret_cast<const unsigned char *>(&value_), sizeof(value_));
370}
371
372
373// NetlinkU16Attribute
374
375const char NetlinkU16Attribute::kMyTypeString[] = "uint16_t";
376const NetlinkAttribute::Type NetlinkU16Attribute::kType =
377 NetlinkAttribute::kTypeU16;
378
379bool NetlinkU16Attribute::InitFromNlAttr(const nlattr *input) {
380 if (!input) {
381 LOG(ERROR) << "Null |input| parameter";
382 return false;
383 }
384
385 uint16_t data = NlaGetU16(input);
386 SetU16Value(data);
387 return NetlinkAttribute::InitFromNlAttr(input);
388}
389
390bool NetlinkU16Attribute::GetU16Value(uint16_t *output) const {
391 if (!has_a_value_) {
392 SLOG(WiFi, 7) << "U16 attribute " << id_string()
393 << " hasn't been set to any value.";
394 return false;
395 }
396 if (output) {
397 *output = value_;
398 }
399 return true;
400}
401
402bool NetlinkU16Attribute::SetU16Value(uint16_t new_value) {
403 value_ = new_value;
404 has_a_value_ = true;
405 return true;
406}
407
408bool NetlinkU16Attribute::ToString(string *output) const {
409 if (!output) {
410 LOG(ERROR) << "Null |output| parameter";
411 return false;
412 }
413 uint16_t value;
414 if (!GetU16Value(&value))
415 return false;
416 *output = StringPrintf("%u", value);
417 return true;
418}
419
420ByteString NetlinkU16Attribute::Encode() const {
421 return NetlinkAttribute::EncodeGeneric(
422 reinterpret_cast<const unsigned char *>(&value_), sizeof(value_));
423}
424
425// NetlinkU32Attribute::
426
427const char NetlinkU32Attribute::kMyTypeString[] = "uint32_t";
428const NetlinkAttribute::Type NetlinkU32Attribute::kType =
429 NetlinkAttribute::kTypeU32;
430
431bool NetlinkU32Attribute::InitFromNlAttr(const nlattr *input) {
432 if (!input) {
433 LOG(ERROR) << "Null |input| parameter";
434 return false;
435 }
436
437 uint32_t data = NlaGetU32(input);
438 SetU32Value(data);
439 return NetlinkAttribute::InitFromNlAttr(input);
440}
441
442bool NetlinkU32Attribute::GetU32Value(uint32_t *output) const {
443 if (!has_a_value_) {
444 SLOG(WiFi, 7) << "U32 attribute " << id_string()
445 << " hasn't been set to any value.";
446 return false;
447 }
448 if (output) {
449 *output = value_;
450 }
451 return true;
452}
453
454bool NetlinkU32Attribute::SetU32Value(uint32_t new_value) {
455 value_ = new_value;
456 has_a_value_ = true;
457 return true;
458}
459
460bool NetlinkU32Attribute::ToString(string *output) const {
461 if (!output) {
462 LOG(ERROR) << "Null |output| parameter";
463 return false;
464 }
465 uint32_t value;
466 if (!GetU32Value(&value))
467 return false;
468 *output = StringPrintf("%" PRIu32, value);
469 return true;
470}
471
472ByteString NetlinkU32Attribute::Encode() const {
473 return NetlinkAttribute::EncodeGeneric(
474 reinterpret_cast<const unsigned char *>(&value_), sizeof(value_));
475}
476
477// NetlinkU64Attribute
478
479const char NetlinkU64Attribute::kMyTypeString[] = "uint64_t";
480const NetlinkAttribute::Type NetlinkU64Attribute::kType =
481 NetlinkAttribute::kTypeU64;
482
483bool NetlinkU64Attribute::InitFromNlAttr(const nlattr *input) {
484 if (!input) {
485 LOG(ERROR) << "Null |input| parameter";
486 return false;
487 }
488
489 uint64_t data = NlaGetU64(input);
490 SetU64Value(data);
491 return NetlinkAttribute::InitFromNlAttr(input);
492}
493
494bool NetlinkU64Attribute::GetU64Value(uint64_t *output) const {
495 if (!has_a_value_) {
496 SLOG(WiFi, 7) << "U64 attribute " << id_string()
497 << " hasn't been set to any value.";
498 return false;
499 }
500 if (output) {
501 *output = value_;
502 }
503 return true;
504}
505
506bool NetlinkU64Attribute::SetU64Value(uint64_t new_value) {
507 value_ = new_value;
508 has_a_value_ = true;
509 return true;
510}
511
512bool NetlinkU64Attribute::ToString(string *output) const {
513 if (!output) {
514 LOG(ERROR) << "Null |output| parameter";
515 return false;
516 }
517 uint64_t value;
518 if (!GetU64Value(&value))
519 return false;
520 *output = StringPrintf("%" PRIu64, value);
521 return true;
522}
523
524ByteString NetlinkU64Attribute::Encode() const {
525 return NetlinkAttribute::EncodeGeneric(
526 reinterpret_cast<const unsigned char *>(&value_), sizeof(value_));
527}
528
529// NetlinkFlagAttribute
530
531const char NetlinkFlagAttribute::kMyTypeString[] = "flag";
532const NetlinkAttribute::Type NetlinkFlagAttribute::kType =
533 NetlinkAttribute::kTypeFlag;
534
535bool NetlinkFlagAttribute::InitFromNlAttr(const nlattr *input) {
536 if (!input) {
537 LOG(ERROR) << "Null |input| parameter";
538 return false;
539 }
540
541 // The existence of the parameter means it's true
542 SetFlagValue(true);
543 return NetlinkAttribute::InitFromNlAttr(input);
544}
545
546
547bool NetlinkFlagAttribute::GetFlagValue(bool *output) const {
548 if (output) {
549 // The lack of the existence of the attribute implies 'false'.
550 *output = (has_a_value_) ? value_ : false;
551 }
552 return true;
553}
554
555bool NetlinkFlagAttribute::SetFlagValue(bool new_value) {
556 value_ = new_value;
557 has_a_value_ = true;
558 return true;
559}
560
561bool NetlinkFlagAttribute::ToString(string *output) const {
562 if (!output) {
563 LOG(ERROR) << "Null |output| parameter";
564 return false;
565 }
566 bool value;
567 if (!GetFlagValue(&value))
568 return false;
569 *output = StringPrintf("%s", value ? "true" : "false");
570 return true;
571}
572
573ByteString NetlinkFlagAttribute::Encode() const {
574 if (has_a_value_ && value_) {
575 return NetlinkAttribute::EncodeGeneric(NULL, 0);
576 }
577 return ByteString(); // Encoding of nothing implies 'false'.
578}
579
580// NetlinkStringAttribute
581
582const char NetlinkStringAttribute::kMyTypeString[] = "string";
583const NetlinkAttribute::Type NetlinkStringAttribute::kType =
584 NetlinkAttribute::kTypeString;
585
586bool NetlinkStringAttribute::InitFromNlAttr(const nlattr *input) {
587 if (!input) {
588 LOG(ERROR) << "Null |input| parameter";
589 return false;
590 }
591
592 SetStringValue(NlaGetString(input));
593 return NetlinkAttribute::InitFromNlAttr(input);
594}
595
596bool NetlinkStringAttribute::GetStringValue(string *output) const {
597 if (!has_a_value_) {
598 SLOG(WiFi, 7) << "String attribute " << id_string()
599 << " hasn't been set to any value.";
600 return false;
601 }
602 if (output) {
603 *output = value_;
604 }
605 return true;
606}
607
608bool NetlinkStringAttribute::SetStringValue(const string new_value) {
609 value_ = new_value;
610 has_a_value_ = true;
611 return true;
612}
613
614bool NetlinkStringAttribute::ToString(string *output) const {
615 if (!output) {
616 LOG(ERROR) << "Null |output| parameter";
617 return false;
618 }
619 string value;
620 if (!GetStringValue(&value))
621 return false;
622
623 *output = StringPrintf("'%s'", value.c_str());
624 return true;
625}
626
627ByteString NetlinkStringAttribute::Encode() const {
628 return NetlinkAttribute::EncodeGeneric(
629 reinterpret_cast<const unsigned char *>(value_.c_str()),
630 value_.size() + 1);
631}
632
Wade Guthrief54872f2013-04-11 15:11:50 -0700633// SSID attribute.
634
635bool NetlinkSsidAttribute::ToString(string *output) const {
636 if (!output) {
637 LOG(ERROR) << "Null |output| parameter";
638 return false;
639 }
640 string value;
641 if (!GetStringValue(&value))
642 return false;
643
644 *output = WiFi::LogSSID(value);
645 return true;
646}
647
Wade Guthrief162f8b2013-02-27 14:13:55 -0800648// NetlinkNestedAttribute
649
650const char NetlinkNestedAttribute::kMyTypeString[] = "nested";
651const NetlinkAttribute::Type NetlinkNestedAttribute::kType =
652 NetlinkAttribute::kTypeNested;
653
654NetlinkNestedAttribute::NetlinkNestedAttribute(int id,
655 const char *id_string) :
656 NetlinkAttribute(id, id_string, kType, kMyTypeString),
657 value_(new AttributeList) {}
658
659ByteString NetlinkNestedAttribute::Encode() const {
660 // Encode attribute header.
661 nlattr header;
662 header.nla_type = id();
663 header.nla_len = nla_attr_size(sizeof(header));
664 ByteString result(reinterpret_cast<unsigned char *>(&header), sizeof(header));
665 result.Resize(NLA_HDRLEN); // Add padding after the header.
666
667 // Encode all nested attributes.
Wade Guthrief1b36412013-04-11 14:51:31 -0700668 map<int, AttributeList::AttributePointer>::const_iterator attribute;
Wade Guthrief162f8b2013-02-27 14:13:55 -0800669 for (attribute = value_->attributes_.begin();
670 attribute != value_->attributes_.end();
671 ++attribute) {
672 // Each attribute appends appropriate padding so it's not necessary to
673 // re-add padding.
674 result.Append(attribute->second->Encode());
675 }
676
677 // Go back and fill-in the size.
678 nlattr *new_header = reinterpret_cast<nlattr *>(result.GetData());
679 new_header->nla_len = result.GetLength();
680
681 return result;
682}
683
684void NetlinkNestedAttribute::Print(int log_level, int indent) const {
685 SLOG(WiFi, log_level) << HeaderToPrint(indent);
686 value_->Print(log_level, indent + 1);
687}
688
Wade Guthrief1b36412013-04-11 14:51:31 -0700689bool NetlinkNestedAttribute::ToString(string *output) const {
Wade Guthrief162f8b2013-02-27 14:13:55 -0800690 if (!output) {
691 LOG(ERROR) << "Null |output| parameter";
692 return false;
693 }
694
695 // This should never be called (attribute->ToString is only called
696 // from attribute->Print but NetlinkNestedAttribute::Print doesn't call
697 // |ToString|. Still, we should print something in case we got here
698 // accidentally.
699 LOG(WARNING) << "It is unexpected for this method to be called.";
700 output->append("<Nested Attribute>");
701 return true;
702}
703
Wade Guthrief1b36412013-04-11 14:51:31 -0700704bool NetlinkNestedAttribute::InitFromNlAttr(const nlattr *const_data) {
705 if (!InitNestedFromNlAttr(value_.get(), nested_template_, const_data)) {
706 LOG(ERROR) << "InitNestedFromNlAttr() failed";
707 return false;
708 }
709 has_a_value_ = true;
710 return true;
711}
712
Wade Guthrief162f8b2013-02-27 14:13:55 -0800713bool NetlinkNestedAttribute::GetNestedAttributeList(
714 AttributeListRefPtr *output) {
715 // Not checking |has_a_value| since GetNestedAttributeList is called to get
716 // a newly created AttributeList in order to have something to which to add
717 // attributes.
718 if (output) {
719 *output = value_;
720 }
721 return true;
722}
723
724bool NetlinkNestedAttribute::ConstGetNestedAttributeList(
725 AttributeListConstRefPtr *output) const {
726 if (!has_a_value_) {
727 LOG(ERROR) << "Attribute does not exist.";
728 return false;
729 }
730 if (output) {
731 *output = value_;
732 }
733 return true;
734}
735
736bool NetlinkNestedAttribute::SetNestedHasAValue() {
737 has_a_value_ = true;
738 return true;
739}
740
Wade Guthrief162f8b2013-02-27 14:13:55 -0800741bool NetlinkNestedAttribute::InitNestedFromNlAttr(
742 AttributeList *list,
Wade Guthrief1b36412013-04-11 14:51:31 -0700743 const NetlinkNestedAttribute::NestedData::NestedDataVector &templates,
Wade Guthrief162f8b2013-02-27 14:13:55 -0800744 const nlattr *const_data) {
Wade Guthrief1b36412013-04-11 14:51:31 -0700745 if (templates.size() == 1 && templates[0].is_array) {
746 return ParseNestedArray(list, templates[0], const_data);
Wade Guthrief162f8b2013-02-27 14:13:55 -0800747 } else {
Wade Guthrief1b36412013-04-11 14:51:31 -0700748 return ParseNestedStructure(list, templates, const_data);
Wade Guthrief162f8b2013-02-27 14:13:55 -0800749 }
750 return true;
751}
752
753// A nested array provides an arbitrary number of children, all of the same
754// data type. Each array element may be a simple type or may be a structure.
755//
756// static
Wade Guthrief1b36412013-04-11 14:51:31 -0700757bool NetlinkNestedAttribute::ParseNestedArray(AttributeList *list,
758 const NestedData &array_template,
759 const nlattr *const_data) {
Wade Guthrief162f8b2013-02-27 14:13:55 -0800760 if (!list) {
761 LOG(ERROR) << "NULL |list| parameter";
762 return false;
763 }
764 if (!const_data) {
765 LOG(ERROR) << "Null |const_data| parameter";
766 return false;
767 }
768 // Casting away constness since |nla_parse_nested| doesn't mark its input as
769 // const even though it doesn't modify this input parameter.
770 nlattr *attrs = const_cast<nlattr *>(const_data);
771
772 struct nlattr *attr;
773 int remaining;
774 // The |nlattr::nla_type| value for array elements in the provided data may
775 // start on any number and are allowed to be discontiguous. In order to
776 // skirt writing an iterator, this code replaces the |nla_type| with a
777 // contiguous |id|, starting at 1 (note that, while nested structure
778 // attributes may not have an |nlattr::nla_type| valued at zero, no such
779 // restriction exists for nested array attributes -- this code starts the id
Wade Guthrief1b36412013-04-11 14:51:31 -0700780 // at one in order to be consistent with nested structures).
Wade Guthrief162f8b2013-02-27 14:13:55 -0800781 //
782 // TODO(wdg): Determine whether any code depends on the value of
783 // |nlattr::nla_type| for nested array attributes.
784 int id = 1;
785 nla_for_each_nested_type_corrected(attr, attrs, remaining) {
Wade Guthrief1b36412013-04-11 14:51:31 -0700786 string attribute_name = StringPrintf(
787 "%s_%d", array_template.attribute_name.c_str(), id);
788 AddAttributeToNested(list, array_template.type, id, attribute_name, *attr,
789 array_template);
Wade Guthrief162f8b2013-02-27 14:13:55 -0800790 ++id;
791 }
792 return true;
793}
794
795// A nested structure provides a fixed set of child attributes (some of
Wade Guthrief1b36412013-04-11 14:51:31 -0700796// which may be optional).
Wade Guthrief162f8b2013-02-27 14:13:55 -0800797// static
798bool NetlinkNestedAttribute::ParseNestedStructure(
799 AttributeList *list,
Wade Guthrief1b36412013-04-11 14:51:31 -0700800 const NetlinkNestedAttribute::NestedData::NestedDataVector &templates,
Wade Guthrief162f8b2013-02-27 14:13:55 -0800801 const nlattr *const_data) {
802 if (!list) {
803 LOG(ERROR) << "NULL |list| parameter";
804 return false;
805 }
Wade Guthrief1b36412013-04-11 14:51:31 -0700806 if (templates.empty()) {
807 LOG(ERROR) << "|templates| size is zero";
Wade Guthrief162f8b2013-02-27 14:13:55 -0800808 return false;
809 }
810 if (!const_data) {
811 LOG(ERROR) << "Null |const_data| parameter";
812 return false;
813 }
814 // Casting away constness since |nla_parse_nested| doesn't mark its input as
815 // const even though it doesn't modify this input parameter.
816 nlattr *attr_data = const_cast<nlattr *>(const_data);
817
818 // |nla_parse_nested| requires an array of |nla_policy|. While an attribute id
819 // of zero is illegal, we still need to fill that spot in the policy
820 // array so the loop will start at zero.
Wade Guthrief1b36412013-04-11 14:51:31 -0700821 scoped_array<nla_policy> policy(new nla_policy[templates.size()]);
822 for (size_t id = 0; id < templates.size() ; ++id) {
823 memset(&policy[id], 0, sizeof(nla_policy));
824 policy[id].type = templates[id].type;
Wade Guthrief162f8b2013-02-27 14:13:55 -0800825 }
826
827 // |nla_parse_nested| builds an array of |nlattr| from the input message.
Wade Guthrief1b36412013-04-11 14:51:31 -0700828 scoped_array<nlattr *>attr(new nlattr *[templates.size()]);
829 if (nla_parse_nested(attr.get(), templates.size() - 1, attr_data,
Wade Guthrief162f8b2013-02-27 14:13:55 -0800830 policy.get())) {
831 LOG(ERROR) << "nla_parse_nested failed";
832 return false;
833 }
834
835 // Note that the attribute id of zero is illegal so we'll start with id=1.
Wade Guthrief1b36412013-04-11 14:51:31 -0700836 for (size_t id = 1; id < templates.size(); ++id) {
Wade Guthrief162f8b2013-02-27 14:13:55 -0800837 // Add |attr[id]| if it exists, otherwise, it's a legally omitted optional
838 // attribute.
839 if (attr[id]) {
840 AddAttributeToNested(list, policy[id].type, id,
Wade Guthrief1b36412013-04-11 14:51:31 -0700841 templates[id].attribute_name, *attr[id],
842 templates[id]);
Wade Guthrief162f8b2013-02-27 14:13:55 -0800843 }
844 }
845 return true;
846}
847
848// static
849void NetlinkNestedAttribute::AddAttributeToNested(
850 AttributeList *list, uint16_t type, size_t id, const string &attribute_name,
851 const nlattr &attr, const NestedData &nested_template) {
Wade Guthrief1b36412013-04-11 14:51:31 -0700852 CHECK(list);
853 if (!nested_template.parse_attribute.is_null()) {
854 if (!nested_template.parse_attribute.Run(
855 list, id, attribute_name,
856 ByteString(reinterpret_cast<const char *>(nla_data(&attr)),
857 nla_len(&attr)))) {
858 LOG(WARNING) << "Custom attribute parser returned |false| for "
859 << attribute_name << "(" << id << ").";
860 }
861 return;
862 }
Wade Guthrief162f8b2013-02-27 14:13:55 -0800863 switch (type) {
864 case NLA_UNSPEC:
865 list->CreateRawAttribute(id, attribute_name.c_str());
866 list->SetRawAttributeValue(id, ByteString(
867 reinterpret_cast<const char *>(nla_data(&attr)), nla_len(&attr)));
868 break;
869 case NLA_U8:
870 list->CreateU8Attribute(id, attribute_name.c_str());
871 list->SetU8AttributeValue(id, NlaGetU8(&attr));
872 break;
873 case NLA_U16:
874 list->CreateU16Attribute(id, attribute_name.c_str());
875 list->SetU16AttributeValue(id, NlaGetU16(&attr));
876 break;
877 case NLA_U32:
878 list->CreateU32Attribute(id, attribute_name.c_str());
879 list->SetU32AttributeValue(id, NlaGetU32(&attr));
880 break;
881 case NLA_U64:
882 list->CreateU64Attribute(id, attribute_name.c_str());
883 list->SetU64AttributeValue(id, NlaGetU64(&attr));
884 break;
885 case NLA_FLAG:
886 list->CreateFlagAttribute(id, attribute_name.c_str());
887 list->SetFlagAttributeValue(id, true);
888 break;
889 case NLA_STRING:
890 // Note that nested structure attributes are validated by |validate_nla|
891 // which requires a string attribute to have at least 1 character
892 // (presumably for the '\0') while the kernel can create an empty string
893 // for at least one nested string array attribute type
894 // (NL80211_ATTR_SCAN_SSIDS -- the emptyness of the string is exhibited
895 // by the value of |nlattr::nla_len|). This code handles both cases.
896 list->CreateStringAttribute(id, attribute_name.c_str());
897 if (nla_len(&attr) <= 0) {
898 list->SetStringAttributeValue(id, "");
899 } else {
900 list->SetStringAttributeValue(id, NlaGetString(&attr));
901 }
902 break;
903 case NLA_NESTED:
904 {
Wade Guthrief1b36412013-04-11 14:51:31 -0700905 if (nested_template.deeper_nesting.empty()) {
Wade Guthrief162f8b2013-02-27 14:13:55 -0800906 LOG(ERROR) << "No rules for nesting " << attribute_name
907 << ". Ignoring.";
908 break;
909 }
910 list->CreateNestedAttribute(id, attribute_name.c_str());
911
912 // Now, handle the nested data.
913 AttributeListRefPtr nested_attribute;
914 if (!list->GetNestedAttributeList(id, &nested_attribute) ||
915 !nested_attribute) {
916 LOG(FATAL) << "Couldn't get attribute " << attribute_name
917 << " which we just created.";
918 break;
919 }
920
921 if (!InitNestedFromNlAttr(nested_attribute.get(),
922 nested_template.deeper_nesting,
Wade Guthrief162f8b2013-02-27 14:13:55 -0800923 &attr)) {
924 LOG(ERROR) << "Couldn't parse attribute " << attribute_name;
925 break;
926 }
927 list->SetNestedAttributeHasAValue(id);
928 }
929 break;
930 default:
931 LOG(ERROR) << "Discarding " << attribute_name
932 << ". Attribute has unhandled type " << type << ".";
933 break;
934 }
935}
936
Wade Guthrief1b36412013-04-11 14:51:31 -0700937NetlinkNestedAttribute::NestedData::NestedData()
938 : type(NLA_UNSPEC), attribute_name("<UNKNOWN>"), is_array(false) {}
939NetlinkNestedAttribute::NestedData::NestedData(
940 uint16_t type_arg, string attribute_name_arg, bool is_array_arg)
941 : type(type_arg), attribute_name(attribute_name_arg),
942 is_array(is_array_arg) {}
943
944NetlinkNestedAttribute::NestedData::NestedData(
945 uint16_t type_arg, string attribute_name_arg, bool is_array_arg,
946 const AttributeParser &parse_attribute_arg)
947 : type(type_arg), attribute_name(attribute_name_arg),
948 is_array(is_array_arg), parse_attribute(parse_attribute_arg) {}
949
Wade Guthrief162f8b2013-02-27 14:13:55 -0800950// NetlinkRawAttribute
951
952const char NetlinkRawAttribute::kMyTypeString[] = "<raw>";
953const NetlinkAttribute::Type NetlinkRawAttribute::kType =
954 NetlinkAttribute::kTypeRaw;
955
956bool NetlinkRawAttribute::InitFromNlAttr(const nlattr *input) {
957 if (!input) {
958 LOG(ERROR) << "Null |input| parameter";
959 return false;
960 }
961
962 if (!NetlinkAttribute::InitFromNlAttr(input)) {
963 return false;
964 }
965 has_a_value_ = true;
966 return true;
967}
968
969bool NetlinkRawAttribute::GetRawValue(ByteString *output) const {
970 if (!has_a_value_) {
971 SLOG(WiFi, 7) << "Raw attribute " << id_string()
972 << " hasn't been set to any value.";
973 return false;
974 }
975 if (output) {
976 *output = data_;
977 }
978 return true;
979}
980
981bool NetlinkRawAttribute::SetRawValue(const ByteString new_value) {
982 data_ = new_value;
983 has_a_value_ = true;
984 return true;
985}
986
987bool NetlinkRawAttribute::ToString(string *output) const {
988 if (!output) {
989 LOG(ERROR) << "Null |output| parameter";
990 return false;
991 }
992 if (!has_a_value_) {
993 SLOG(WiFi, 7) << "Raw attribute " << id_string()
994 << " hasn't been set to any value.";
995 return false;
996 }
997 int total_bytes = data_.GetLength();
998 const uint8_t *const_data = data_.GetConstData();
999
1000 *output = StringPrintf("%d bytes:", total_bytes);
1001 for (int i = 0; i < total_bytes; ++i) {
1002 StringAppendF(output, " 0x%02x", const_data[i]);
1003 }
1004 return true;
1005}
1006
1007ByteString NetlinkRawAttribute::Encode() const {
1008 return NetlinkAttribute::EncodeGeneric(data_.GetConstData(),
1009 data_.GetLength());
1010}
1011
1012NetlinkAttributeGeneric::NetlinkAttributeGeneric(int id)
1013 : NetlinkRawAttribute(id, "unused-string") {
1014 StringAppendF(&id_string_, "<UNKNOWN ATTRIBUTE %d>", id);
1015}
1016
1017const char *NetlinkAttributeGeneric::id_string() const {
1018 return id_string_.c_str();
1019}
1020
1021} // namespace shill