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