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