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