blob: 80bace7f8682a2e0cd2f87950abd9895b6c46583 [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 {
Wade Guthrie35cb4b92013-04-19 10:46:11 -0700296 ByteString result;
297 if (has_a_value_) {
298 nlattr header;
299 header.nla_type = id();
300 header.nla_len = nla_attr_size(num_bytes);
301 result = ByteString(reinterpret_cast<unsigned char *>(&header),
302 sizeof(header));
303 result.Resize(NLA_HDRLEN); // Add padding after the header.
304 if (data && (num_bytes != 0)) {
305 result.Append(ByteString(data, num_bytes));
306 }
307 result.Resize(nla_total_size(num_bytes)); // Add padding.
Wade Guthrief162f8b2013-02-27 14:13:55 -0800308 }
Wade Guthrief162f8b2013-02-27 14:13:55 -0800309 return result;
310}
311
312// NetlinkU8Attribute
313
314const char NetlinkU8Attribute::kMyTypeString[] = "uint8_t";
315const NetlinkAttribute::Type NetlinkU8Attribute::kType =
316 NetlinkAttribute::kTypeU8;
317
318bool NetlinkU8Attribute::InitFromNlAttr(const nlattr *input) {
319 if (!input) {
320 LOG(ERROR) << "Null |input| parameter";
321 return false;
322 }
323
324 uint8_t data = NlaGetU8(input);
325 SetU8Value(data);
326 return NetlinkAttribute::InitFromNlAttr(input);
327}
328
329bool NetlinkU8Attribute::GetU8Value(uint8_t *output) const {
330 if (!has_a_value_) {
331 SLOG(WiFi, 7) << "U8 attribute " << id_string()
332 << " hasn't been set to any value.";
333 return false;
334 }
335 if (output) {
336 *output = value_;
337 }
338 return true;
339}
340
341bool NetlinkU8Attribute::SetU8Value(uint8_t new_value) {
342 value_ = new_value;
343 has_a_value_ = true;
344 return true;
345}
346
347bool NetlinkU8Attribute::ToString(string *output) const {
348 if (!output) {
349 LOG(ERROR) << "Null |output| parameter";
350 return false;
351 }
352 uint8_t value;
353 if (!GetU8Value(&value))
354 return false;
355 *output = StringPrintf("%u", value);
356 return true;
357}
358
359ByteString NetlinkU8Attribute::Encode() const {
360 return NetlinkAttribute::EncodeGeneric(
361 reinterpret_cast<const unsigned char *>(&value_), sizeof(value_));
362}
363
364
365// NetlinkU16Attribute
366
367const char NetlinkU16Attribute::kMyTypeString[] = "uint16_t";
368const NetlinkAttribute::Type NetlinkU16Attribute::kType =
369 NetlinkAttribute::kTypeU16;
370
371bool NetlinkU16Attribute::InitFromNlAttr(const nlattr *input) {
372 if (!input) {
373 LOG(ERROR) << "Null |input| parameter";
374 return false;
375 }
376
377 uint16_t data = NlaGetU16(input);
378 SetU16Value(data);
379 return NetlinkAttribute::InitFromNlAttr(input);
380}
381
382bool NetlinkU16Attribute::GetU16Value(uint16_t *output) const {
383 if (!has_a_value_) {
384 SLOG(WiFi, 7) << "U16 attribute " << id_string()
385 << " hasn't been set to any value.";
386 return false;
387 }
388 if (output) {
389 *output = value_;
390 }
391 return true;
392}
393
394bool NetlinkU16Attribute::SetU16Value(uint16_t new_value) {
395 value_ = new_value;
396 has_a_value_ = true;
397 return true;
398}
399
400bool NetlinkU16Attribute::ToString(string *output) const {
401 if (!output) {
402 LOG(ERROR) << "Null |output| parameter";
403 return false;
404 }
405 uint16_t value;
406 if (!GetU16Value(&value))
407 return false;
408 *output = StringPrintf("%u", value);
409 return true;
410}
411
412ByteString NetlinkU16Attribute::Encode() const {
413 return NetlinkAttribute::EncodeGeneric(
414 reinterpret_cast<const unsigned char *>(&value_), sizeof(value_));
415}
416
417// NetlinkU32Attribute::
418
419const char NetlinkU32Attribute::kMyTypeString[] = "uint32_t";
420const NetlinkAttribute::Type NetlinkU32Attribute::kType =
421 NetlinkAttribute::kTypeU32;
422
423bool NetlinkU32Attribute::InitFromNlAttr(const nlattr *input) {
424 if (!input) {
425 LOG(ERROR) << "Null |input| parameter";
426 return false;
427 }
428
429 uint32_t data = NlaGetU32(input);
430 SetU32Value(data);
431 return NetlinkAttribute::InitFromNlAttr(input);
432}
433
434bool NetlinkU32Attribute::GetU32Value(uint32_t *output) const {
435 if (!has_a_value_) {
436 SLOG(WiFi, 7) << "U32 attribute " << id_string()
437 << " hasn't been set to any value.";
438 return false;
439 }
440 if (output) {
441 *output = value_;
442 }
443 return true;
444}
445
446bool NetlinkU32Attribute::SetU32Value(uint32_t new_value) {
447 value_ = new_value;
448 has_a_value_ = true;
449 return true;
450}
451
452bool NetlinkU32Attribute::ToString(string *output) const {
453 if (!output) {
454 LOG(ERROR) << "Null |output| parameter";
455 return false;
456 }
457 uint32_t value;
458 if (!GetU32Value(&value))
459 return false;
460 *output = StringPrintf("%" PRIu32, value);
461 return true;
462}
463
464ByteString NetlinkU32Attribute::Encode() const {
465 return NetlinkAttribute::EncodeGeneric(
466 reinterpret_cast<const unsigned char *>(&value_), sizeof(value_));
467}
468
469// NetlinkU64Attribute
470
471const char NetlinkU64Attribute::kMyTypeString[] = "uint64_t";
472const NetlinkAttribute::Type NetlinkU64Attribute::kType =
473 NetlinkAttribute::kTypeU64;
474
475bool NetlinkU64Attribute::InitFromNlAttr(const nlattr *input) {
476 if (!input) {
477 LOG(ERROR) << "Null |input| parameter";
478 return false;
479 }
480
481 uint64_t data = NlaGetU64(input);
482 SetU64Value(data);
483 return NetlinkAttribute::InitFromNlAttr(input);
484}
485
486bool NetlinkU64Attribute::GetU64Value(uint64_t *output) const {
487 if (!has_a_value_) {
488 SLOG(WiFi, 7) << "U64 attribute " << id_string()
489 << " hasn't been set to any value.";
490 return false;
491 }
492 if (output) {
493 *output = value_;
494 }
495 return true;
496}
497
498bool NetlinkU64Attribute::SetU64Value(uint64_t new_value) {
499 value_ = new_value;
500 has_a_value_ = true;
501 return true;
502}
503
504bool NetlinkU64Attribute::ToString(string *output) const {
505 if (!output) {
506 LOG(ERROR) << "Null |output| parameter";
507 return false;
508 }
509 uint64_t value;
510 if (!GetU64Value(&value))
511 return false;
512 *output = StringPrintf("%" PRIu64, value);
513 return true;
514}
515
516ByteString NetlinkU64Attribute::Encode() const {
517 return NetlinkAttribute::EncodeGeneric(
518 reinterpret_cast<const unsigned char *>(&value_), sizeof(value_));
519}
520
521// NetlinkFlagAttribute
522
523const char NetlinkFlagAttribute::kMyTypeString[] = "flag";
524const NetlinkAttribute::Type NetlinkFlagAttribute::kType =
525 NetlinkAttribute::kTypeFlag;
526
527bool NetlinkFlagAttribute::InitFromNlAttr(const nlattr *input) {
528 if (!input) {
529 LOG(ERROR) << "Null |input| parameter";
530 return false;
531 }
532
533 // The existence of the parameter means it's true
534 SetFlagValue(true);
535 return NetlinkAttribute::InitFromNlAttr(input);
536}
537
538
539bool NetlinkFlagAttribute::GetFlagValue(bool *output) const {
540 if (output) {
541 // The lack of the existence of the attribute implies 'false'.
542 *output = (has_a_value_) ? value_ : false;
543 }
544 return true;
545}
546
547bool NetlinkFlagAttribute::SetFlagValue(bool new_value) {
548 value_ = new_value;
549 has_a_value_ = true;
550 return true;
551}
552
553bool NetlinkFlagAttribute::ToString(string *output) const {
554 if (!output) {
555 LOG(ERROR) << "Null |output| parameter";
556 return false;
557 }
558 bool value;
559 if (!GetFlagValue(&value))
560 return false;
561 *output = StringPrintf("%s", value ? "true" : "false");
562 return true;
563}
564
565ByteString NetlinkFlagAttribute::Encode() const {
566 if (has_a_value_ && value_) {
567 return NetlinkAttribute::EncodeGeneric(NULL, 0);
568 }
569 return ByteString(); // Encoding of nothing implies 'false'.
570}
571
572// NetlinkStringAttribute
573
574const char NetlinkStringAttribute::kMyTypeString[] = "string";
575const NetlinkAttribute::Type NetlinkStringAttribute::kType =
576 NetlinkAttribute::kTypeString;
577
578bool NetlinkStringAttribute::InitFromNlAttr(const nlattr *input) {
579 if (!input) {
580 LOG(ERROR) << "Null |input| parameter";
581 return false;
582 }
583
584 SetStringValue(NlaGetString(input));
585 return NetlinkAttribute::InitFromNlAttr(input);
586}
587
588bool NetlinkStringAttribute::GetStringValue(string *output) const {
589 if (!has_a_value_) {
590 SLOG(WiFi, 7) << "String attribute " << id_string()
591 << " hasn't been set to any value.";
592 return false;
593 }
594 if (output) {
595 *output = value_;
596 }
597 return true;
598}
599
600bool NetlinkStringAttribute::SetStringValue(const string new_value) {
601 value_ = new_value;
602 has_a_value_ = true;
603 return true;
604}
605
606bool NetlinkStringAttribute::ToString(string *output) const {
607 if (!output) {
608 LOG(ERROR) << "Null |output| parameter";
609 return false;
610 }
611 string value;
612 if (!GetStringValue(&value))
613 return false;
614
615 *output = StringPrintf("'%s'", value.c_str());
616 return true;
617}
618
619ByteString NetlinkStringAttribute::Encode() const {
620 return NetlinkAttribute::EncodeGeneric(
621 reinterpret_cast<const unsigned char *>(value_.c_str()),
622 value_.size() + 1);
623}
624
625// NetlinkNestedAttribute
626
627const char NetlinkNestedAttribute::kMyTypeString[] = "nested";
628const NetlinkAttribute::Type NetlinkNestedAttribute::kType =
629 NetlinkAttribute::kTypeNested;
630
631NetlinkNestedAttribute::NetlinkNestedAttribute(int id,
632 const char *id_string) :
633 NetlinkAttribute(id, id_string, kType, kMyTypeString),
634 value_(new AttributeList) {}
635
636ByteString NetlinkNestedAttribute::Encode() const {
637 // Encode attribute header.
638 nlattr header;
639 header.nla_type = id();
640 header.nla_len = nla_attr_size(sizeof(header));
641 ByteString result(reinterpret_cast<unsigned char *>(&header), sizeof(header));
642 result.Resize(NLA_HDRLEN); // Add padding after the header.
643
644 // Encode all nested attributes.
645 std::map<int, AttributeList::AttributePointer>::const_iterator attribute;
646 for (attribute = value_->attributes_.begin();
647 attribute != value_->attributes_.end();
648 ++attribute) {
649 // Each attribute appends appropriate padding so it's not necessary to
650 // re-add padding.
651 result.Append(attribute->second->Encode());
652 }
653
654 // Go back and fill-in the size.
655 nlattr *new_header = reinterpret_cast<nlattr *>(result.GetData());
656 new_header->nla_len = result.GetLength();
657
658 return result;
659}
660
661void NetlinkNestedAttribute::Print(int log_level, int indent) const {
662 SLOG(WiFi, log_level) << HeaderToPrint(indent);
663 value_->Print(log_level, indent + 1);
664}
665
666bool NetlinkNestedAttribute::ToString(std::string *output) const {
667 if (!output) {
668 LOG(ERROR) << "Null |output| parameter";
669 return false;
670 }
671
672 // This should never be called (attribute->ToString is only called
673 // from attribute->Print but NetlinkNestedAttribute::Print doesn't call
674 // |ToString|. Still, we should print something in case we got here
675 // accidentally.
676 LOG(WARNING) << "It is unexpected for this method to be called.";
677 output->append("<Nested Attribute>");
678 return true;
679}
680
681bool NetlinkNestedAttribute::GetNestedAttributeList(
682 AttributeListRefPtr *output) {
683 // Not checking |has_a_value| since GetNestedAttributeList is called to get
684 // a newly created AttributeList in order to have something to which to add
685 // attributes.
686 if (output) {
687 *output = value_;
688 }
689 return true;
690}
691
692bool NetlinkNestedAttribute::ConstGetNestedAttributeList(
693 AttributeListConstRefPtr *output) const {
694 if (!has_a_value_) {
695 LOG(ERROR) << "Attribute does not exist.";
696 return false;
697 }
698 if (output) {
699 *output = value_;
700 }
701 return true;
702}
703
704bool NetlinkNestedAttribute::SetNestedHasAValue() {
705 has_a_value_ = true;
706 return true;
707}
708
709// static
710bool NetlinkNestedAttribute::InitNestedFromNlAttr(
711 AttributeList *list,
712 const NestedData *nested_template,
713 size_t nested_template_size,
714 const nlattr *const_data) {
715 if (!nested_template) {
716 LOG(ERROR) << "Null |nested_template| parameter";
717 return false;
718 }
719 if ((nested_template_size == 1) && (nested_template[0].is_array)) {
720 return ParseNestedArray(list, *nested_template, const_data);
721 } else {
722 return ParseNestedStructure(list, nested_template, nested_template_size,
723 const_data);
724 }
725 return true;
726}
727
728// A nested array provides an arbitrary number of children, all of the same
729// data type. Each array element may be a simple type or may be a structure.
730//
731// static
732bool NetlinkNestedAttribute::ParseNestedArray(
733 AttributeList *list,
734 const NestedData &array_template,
735 const nlattr *const_data) {
736 if (!list) {
737 LOG(ERROR) << "NULL |list| parameter";
738 return false;
739 }
740 if (!const_data) {
741 LOG(ERROR) << "Null |const_data| parameter";
742 return false;
743 }
744 // Casting away constness since |nla_parse_nested| doesn't mark its input as
745 // const even though it doesn't modify this input parameter.
746 nlattr *attrs = const_cast<nlattr *>(const_data);
747
748 struct nlattr *attr;
749 int remaining;
750 // The |nlattr::nla_type| value for array elements in the provided data may
751 // start on any number and are allowed to be discontiguous. In order to
752 // skirt writing an iterator, this code replaces the |nla_type| with a
753 // contiguous |id|, starting at 1 (note that, while nested structure
754 // attributes may not have an |nlattr::nla_type| valued at zero, no such
755 // restriction exists for nested array attributes -- this code starts the id
756 // at zero in order to be consistent with nested structures).
757 //
758 // TODO(wdg): Determine whether any code depends on the value of
759 // |nlattr::nla_type| for nested array attributes.
760 int id = 1;
761 nla_for_each_nested_type_corrected(attr, attrs, remaining) {
762 string attribute_name = StringPrintf("%s_%d",
763 array_template.attribute_name, id);
764 AddAttributeToNested(list, array_template.policy.type, id, attribute_name,
765 *attr, array_template);
766 ++id;
767 }
768 return true;
769}
770
771// A nested structure provides a fixed set of child attributes (some of
772// which may be optional). The caller provides the expectation of the members
773// and values of a nested structure in the supplied 'policy' template
774// (|struct_template|).
775//
776// static
777bool NetlinkNestedAttribute::ParseNestedStructure(
778 AttributeList *list,
779 const NestedData *struct_template,
780 size_t nested_template_size,
781 const nlattr *const_data) {
782 if (!list) {
783 LOG(ERROR) << "NULL |list| parameter";
784 return false;
785 }
786 if (!struct_template) {
787 LOG(ERROR) << "Null |struct_template| parameter";
788 return false;
789 }
790 if (nested_template_size == 0) {
791 LOG(ERROR) << "|nested_template_size| parameter is zero";
792 return false;
793 }
794 if (!const_data) {
795 LOG(ERROR) << "Null |const_data| parameter";
796 return false;
797 }
798 // Casting away constness since |nla_parse_nested| doesn't mark its input as
799 // const even though it doesn't modify this input parameter.
800 nlattr *attr_data = const_cast<nlattr *>(const_data);
801
802 // |nla_parse_nested| requires an array of |nla_policy|. While an attribute id
803 // of zero is illegal, we still need to fill that spot in the policy
804 // array so the loop will start at zero.
805 scoped_array<nla_policy> policy(new nla_policy[nested_template_size]);
806 for (size_t id = 0; id < nested_template_size ; ++id) {
807 memcpy(&policy[id], &struct_template[id].policy, sizeof(nla_policy));
808 }
809
810 // |nla_parse_nested| builds an array of |nlattr| from the input message.
811 scoped_array<nlattr *>attr(new nlattr *[nested_template_size]);
812 if (nla_parse_nested(attr.get(), nested_template_size-1, attr_data,
813 policy.get())) {
814 LOG(ERROR) << "nla_parse_nested failed";
815 return false;
816 }
817
818 // Note that the attribute id of zero is illegal so we'll start with id=1.
819 for (size_t id = 1; id < nested_template_size; ++id) {
820 // Add |attr[id]| if it exists, otherwise, it's a legally omitted optional
821 // attribute.
822 if (attr[id]) {
823 AddAttributeToNested(list, policy[id].type, id,
824 struct_template[id].attribute_name, *attr[id],
825 struct_template[id]);
826 }
827 }
828 return true;
829}
830
831// static
832void NetlinkNestedAttribute::AddAttributeToNested(
833 AttributeList *list, uint16_t type, size_t id, const string &attribute_name,
834 const nlattr &attr, const NestedData &nested_template) {
835 switch (type) {
836 case NLA_UNSPEC:
837 list->CreateRawAttribute(id, attribute_name.c_str());
838 list->SetRawAttributeValue(id, ByteString(
839 reinterpret_cast<const char *>(nla_data(&attr)), nla_len(&attr)));
840 break;
841 case NLA_U8:
842 list->CreateU8Attribute(id, attribute_name.c_str());
843 list->SetU8AttributeValue(id, NlaGetU8(&attr));
844 break;
845 case NLA_U16:
846 list->CreateU16Attribute(id, attribute_name.c_str());
847 list->SetU16AttributeValue(id, NlaGetU16(&attr));
848 break;
849 case NLA_U32:
850 list->CreateU32Attribute(id, attribute_name.c_str());
851 list->SetU32AttributeValue(id, NlaGetU32(&attr));
852 break;
853 case NLA_U64:
854 list->CreateU64Attribute(id, attribute_name.c_str());
855 list->SetU64AttributeValue(id, NlaGetU64(&attr));
856 break;
857 case NLA_FLAG:
858 list->CreateFlagAttribute(id, attribute_name.c_str());
859 list->SetFlagAttributeValue(id, true);
860 break;
861 case NLA_STRING:
862 // Note that nested structure attributes are validated by |validate_nla|
863 // which requires a string attribute to have at least 1 character
864 // (presumably for the '\0') while the kernel can create an empty string
865 // for at least one nested string array attribute type
866 // (NL80211_ATTR_SCAN_SSIDS -- the emptyness of the string is exhibited
867 // by the value of |nlattr::nla_len|). This code handles both cases.
868 list->CreateStringAttribute(id, attribute_name.c_str());
869 if (nla_len(&attr) <= 0) {
870 list->SetStringAttributeValue(id, "");
871 } else {
872 list->SetStringAttributeValue(id, NlaGetString(&attr));
873 }
874 break;
875 case NLA_NESTED:
876 {
877 if (!nested_template.deeper_nesting) {
878 LOG(ERROR) << "No rules for nesting " << attribute_name
879 << ". Ignoring.";
880 break;
881 }
882 list->CreateNestedAttribute(id, attribute_name.c_str());
883
884 // Now, handle the nested data.
885 AttributeListRefPtr nested_attribute;
886 if (!list->GetNestedAttributeList(id, &nested_attribute) ||
887 !nested_attribute) {
888 LOG(FATAL) << "Couldn't get attribute " << attribute_name
889 << " which we just created.";
890 break;
891 }
892
893 if (!InitNestedFromNlAttr(nested_attribute.get(),
894 nested_template.deeper_nesting,
895 nested_template.deeper_nesting_size,
896 &attr)) {
897 LOG(ERROR) << "Couldn't parse attribute " << attribute_name;
898 break;
899 }
900 list->SetNestedAttributeHasAValue(id);
901 }
902 break;
903 default:
904 LOG(ERROR) << "Discarding " << attribute_name
905 << ". Attribute has unhandled type " << type << ".";
906 break;
907 }
908}
909
910// NetlinkRawAttribute
911
912const char NetlinkRawAttribute::kMyTypeString[] = "<raw>";
913const NetlinkAttribute::Type NetlinkRawAttribute::kType =
914 NetlinkAttribute::kTypeRaw;
915
916bool NetlinkRawAttribute::InitFromNlAttr(const nlattr *input) {
917 if (!input) {
918 LOG(ERROR) << "Null |input| parameter";
919 return false;
920 }
921
922 if (!NetlinkAttribute::InitFromNlAttr(input)) {
923 return false;
924 }
925 has_a_value_ = true;
926 return true;
927}
928
929bool NetlinkRawAttribute::GetRawValue(ByteString *output) const {
930 if (!has_a_value_) {
931 SLOG(WiFi, 7) << "Raw attribute " << id_string()
932 << " hasn't been set to any value.";
933 return false;
934 }
935 if (output) {
936 *output = data_;
937 }
938 return true;
939}
940
941bool NetlinkRawAttribute::SetRawValue(const ByteString new_value) {
942 data_ = new_value;
943 has_a_value_ = true;
944 return true;
945}
946
947bool NetlinkRawAttribute::ToString(string *output) const {
948 if (!output) {
949 LOG(ERROR) << "Null |output| parameter";
950 return false;
951 }
952 if (!has_a_value_) {
953 SLOG(WiFi, 7) << "Raw attribute " << id_string()
954 << " hasn't been set to any value.";
955 return false;
956 }
957 int total_bytes = data_.GetLength();
958 const uint8_t *const_data = data_.GetConstData();
959
960 *output = StringPrintf("%d bytes:", total_bytes);
961 for (int i = 0; i < total_bytes; ++i) {
962 StringAppendF(output, " 0x%02x", const_data[i]);
963 }
964 return true;
965}
966
967ByteString NetlinkRawAttribute::Encode() const {
968 return NetlinkAttribute::EncodeGeneric(data_.GetConstData(),
969 data_.GetLength());
970}
971
972NetlinkAttributeGeneric::NetlinkAttributeGeneric(int id)
973 : NetlinkRawAttribute(id, "unused-string") {
974 StringAppendF(&id_string_, "<UNKNOWN ATTRIBUTE %d>", id);
975}
976
977const char *NetlinkAttributeGeneric::id_string() const {
978 return id_string_.c_str();
979}
980
981} // namespace shill