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