blob: 45696b464e6f3053a912dc8efb242c4a11561260 [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;
861 // The |nlattr::nla_type| value for array elements in the provided data may
862 // start on any number and are allowed to be discontiguous. In order to
863 // skirt writing an iterator, this code replaces the |nla_type| with a
864 // contiguous |id|, starting at 1 (note that, while nested structure
865 // attributes may not have an |nlattr::nla_type| valued at zero, no such
866 // restriction exists for nested array attributes -- this code starts the id
Wade Guthrief1b36412013-04-11 14:51:31 -0700867 // at one in order to be consistent with nested structures).
Wade Guthrief162f8b2013-02-27 14:13:55 -0800868 //
869 // TODO(wdg): Determine whether any code depends on the value of
870 // |nlattr::nla_type| for nested array attributes.
871 int id = 1;
872 nla_for_each_nested_type_corrected(attr, attrs, remaining) {
Wade Guthrief1b36412013-04-11 14:51:31 -0700873 string attribute_name = StringPrintf(
874 "%s_%d", array_template.attribute_name.c_str(), id);
875 AddAttributeToNested(list, array_template.type, id, attribute_name, *attr,
876 array_template);
Wade Guthrief162f8b2013-02-27 14:13:55 -0800877 ++id;
878 }
879 return true;
880}
881
882// A nested structure provides a fixed set of child attributes (some of
Wade Guthrief1b36412013-04-11 14:51:31 -0700883// which may be optional).
Wade Guthrief162f8b2013-02-27 14:13:55 -0800884// static
885bool NetlinkNestedAttribute::ParseNestedStructure(
886 AttributeList *list,
Wade Guthrief1b36412013-04-11 14:51:31 -0700887 const NetlinkNestedAttribute::NestedData::NestedDataVector &templates,
Wade Guthrief162f8b2013-02-27 14:13:55 -0800888 const nlattr *const_data) {
889 if (!list) {
890 LOG(ERROR) << "NULL |list| parameter";
891 return false;
892 }
Wade Guthrief1b36412013-04-11 14:51:31 -0700893 if (templates.empty()) {
894 LOG(ERROR) << "|templates| size is zero";
Wade Guthrief162f8b2013-02-27 14:13:55 -0800895 return false;
896 }
897 if (!const_data) {
898 LOG(ERROR) << "Null |const_data| parameter";
899 return false;
900 }
901 // Casting away constness since |nla_parse_nested| doesn't mark its input as
902 // const even though it doesn't modify this input parameter.
903 nlattr *attr_data = const_cast<nlattr *>(const_data);
904
905 // |nla_parse_nested| requires an array of |nla_policy|. While an attribute id
906 // of zero is illegal, we still need to fill that spot in the policy
907 // array so the loop will start at zero.
Wade Guthrief1b36412013-04-11 14:51:31 -0700908 scoped_array<nla_policy> policy(new nla_policy[templates.size()]);
909 for (size_t id = 0; id < templates.size() ; ++id) {
910 memset(&policy[id], 0, sizeof(nla_policy));
911 policy[id].type = templates[id].type;
Wade Guthrief162f8b2013-02-27 14:13:55 -0800912 }
913
914 // |nla_parse_nested| builds an array of |nlattr| from the input message.
Wade Guthrief1b36412013-04-11 14:51:31 -0700915 scoped_array<nlattr *>attr(new nlattr *[templates.size()]);
916 if (nla_parse_nested(attr.get(), templates.size() - 1, attr_data,
Wade Guthrief162f8b2013-02-27 14:13:55 -0800917 policy.get())) {
918 LOG(ERROR) << "nla_parse_nested failed";
919 return false;
920 }
921
922 // Note that the attribute id of zero is illegal so we'll start with id=1.
Wade Guthrief1b36412013-04-11 14:51:31 -0700923 for (size_t id = 1; id < templates.size(); ++id) {
Wade Guthrief162f8b2013-02-27 14:13:55 -0800924 // Add |attr[id]| if it exists, otherwise, it's a legally omitted optional
925 // attribute.
926 if (attr[id]) {
927 AddAttributeToNested(list, policy[id].type, id,
Wade Guthrief1b36412013-04-11 14:51:31 -0700928 templates[id].attribute_name, *attr[id],
929 templates[id]);
Wade Guthrief162f8b2013-02-27 14:13:55 -0800930 }
931 }
932 return true;
933}
934
935// static
936void NetlinkNestedAttribute::AddAttributeToNested(
937 AttributeList *list, uint16_t type, size_t id, const string &attribute_name,
938 const nlattr &attr, const NestedData &nested_template) {
Wade Guthrief1b36412013-04-11 14:51:31 -0700939 CHECK(list);
940 if (!nested_template.parse_attribute.is_null()) {
941 if (!nested_template.parse_attribute.Run(
942 list, id, attribute_name,
943 ByteString(reinterpret_cast<const char *>(nla_data(&attr)),
944 nla_len(&attr)))) {
945 LOG(WARNING) << "Custom attribute parser returned |false| for "
946 << attribute_name << "(" << id << ").";
947 }
948 return;
949 }
Wade Guthrief162f8b2013-02-27 14:13:55 -0800950 switch (type) {
951 case NLA_UNSPEC:
952 list->CreateRawAttribute(id, attribute_name.c_str());
953 list->SetRawAttributeValue(id, ByteString(
954 reinterpret_cast<const char *>(nla_data(&attr)), nla_len(&attr)));
955 break;
956 case NLA_U8:
957 list->CreateU8Attribute(id, attribute_name.c_str());
958 list->SetU8AttributeValue(id, NlaGetU8(&attr));
959 break;
960 case NLA_U16:
961 list->CreateU16Attribute(id, attribute_name.c_str());
962 list->SetU16AttributeValue(id, NlaGetU16(&attr));
963 break;
964 case NLA_U32:
965 list->CreateU32Attribute(id, attribute_name.c_str());
966 list->SetU32AttributeValue(id, NlaGetU32(&attr));
967 break;
968 case NLA_U64:
969 list->CreateU64Attribute(id, attribute_name.c_str());
970 list->SetU64AttributeValue(id, NlaGetU64(&attr));
971 break;
972 case NLA_FLAG:
973 list->CreateFlagAttribute(id, attribute_name.c_str());
974 list->SetFlagAttributeValue(id, true);
975 break;
976 case NLA_STRING:
977 // Note that nested structure attributes are validated by |validate_nla|
978 // which requires a string attribute to have at least 1 character
979 // (presumably for the '\0') while the kernel can create an empty string
980 // for at least one nested string array attribute type
981 // (NL80211_ATTR_SCAN_SSIDS -- the emptyness of the string is exhibited
982 // by the value of |nlattr::nla_len|). This code handles both cases.
983 list->CreateStringAttribute(id, attribute_name.c_str());
984 if (nla_len(&attr) <= 0) {
985 list->SetStringAttributeValue(id, "");
986 } else {
987 list->SetStringAttributeValue(id, NlaGetString(&attr));
988 }
989 break;
990 case NLA_NESTED:
991 {
Wade Guthrief1b36412013-04-11 14:51:31 -0700992 if (nested_template.deeper_nesting.empty()) {
Wade Guthrief162f8b2013-02-27 14:13:55 -0800993 LOG(ERROR) << "No rules for nesting " << attribute_name
994 << ". Ignoring.";
995 break;
996 }
997 list->CreateNestedAttribute(id, attribute_name.c_str());
998
999 // Now, handle the nested data.
1000 AttributeListRefPtr nested_attribute;
1001 if (!list->GetNestedAttributeList(id, &nested_attribute) ||
1002 !nested_attribute) {
1003 LOG(FATAL) << "Couldn't get attribute " << attribute_name
1004 << " which we just created.";
1005 break;
1006 }
1007
1008 if (!InitNestedFromNlAttr(nested_attribute.get(),
1009 nested_template.deeper_nesting,
Wade Guthrief162f8b2013-02-27 14:13:55 -08001010 &attr)) {
1011 LOG(ERROR) << "Couldn't parse attribute " << attribute_name;
1012 break;
1013 }
1014 list->SetNestedAttributeHasAValue(id);
1015 }
1016 break;
1017 default:
1018 LOG(ERROR) << "Discarding " << attribute_name
1019 << ". Attribute has unhandled type " << type << ".";
1020 break;
1021 }
1022}
1023
Wade Guthrief1b36412013-04-11 14:51:31 -07001024NetlinkNestedAttribute::NestedData::NestedData()
1025 : type(NLA_UNSPEC), attribute_name("<UNKNOWN>"), is_array(false) {}
1026NetlinkNestedAttribute::NestedData::NestedData(
1027 uint16_t type_arg, string attribute_name_arg, bool is_array_arg)
1028 : type(type_arg), attribute_name(attribute_name_arg),
1029 is_array(is_array_arg) {}
1030
1031NetlinkNestedAttribute::NestedData::NestedData(
1032 uint16_t type_arg, string attribute_name_arg, bool is_array_arg,
1033 const AttributeParser &parse_attribute_arg)
1034 : type(type_arg), attribute_name(attribute_name_arg),
1035 is_array(is_array_arg), parse_attribute(parse_attribute_arg) {}
1036
Wade Guthrief162f8b2013-02-27 14:13:55 -08001037// NetlinkRawAttribute
1038
1039const char NetlinkRawAttribute::kMyTypeString[] = "<raw>";
1040const NetlinkAttribute::Type NetlinkRawAttribute::kType =
1041 NetlinkAttribute::kTypeRaw;
1042
1043bool NetlinkRawAttribute::InitFromNlAttr(const nlattr *input) {
1044 if (!input) {
1045 LOG(ERROR) << "Null |input| parameter";
1046 return false;
1047 }
1048
1049 if (!NetlinkAttribute::InitFromNlAttr(input)) {
1050 return false;
1051 }
1052 has_a_value_ = true;
1053 return true;
1054}
1055
1056bool NetlinkRawAttribute::GetRawValue(ByteString *output) const {
1057 if (!has_a_value_) {
1058 SLOG(WiFi, 7) << "Raw attribute " << id_string()
1059 << " hasn't been set to any value.";
1060 return false;
1061 }
1062 if (output) {
1063 *output = data_;
1064 }
1065 return true;
1066}
1067
1068bool NetlinkRawAttribute::SetRawValue(const ByteString new_value) {
1069 data_ = new_value;
1070 has_a_value_ = true;
1071 return true;
1072}
1073
1074bool NetlinkRawAttribute::ToString(string *output) const {
1075 if (!output) {
1076 LOG(ERROR) << "Null |output| parameter";
1077 return false;
1078 }
1079 if (!has_a_value_) {
1080 SLOG(WiFi, 7) << "Raw attribute " << id_string()
1081 << " hasn't been set to any value.";
1082 return false;
1083 }
1084 int total_bytes = data_.GetLength();
1085 const uint8_t *const_data = data_.GetConstData();
1086
1087 *output = StringPrintf("%d bytes:", total_bytes);
1088 for (int i = 0; i < total_bytes; ++i) {
1089 StringAppendF(output, " 0x%02x", const_data[i]);
1090 }
1091 return true;
1092}
1093
1094ByteString NetlinkRawAttribute::Encode() const {
1095 return NetlinkAttribute::EncodeGeneric(data_.GetConstData(),
1096 data_.GetLength());
1097}
1098
1099NetlinkAttributeGeneric::NetlinkAttributeGeneric(int id)
1100 : NetlinkRawAttribute(id, "unused-string") {
1101 StringAppendF(&id_string_, "<UNKNOWN ATTRIBUTE %d>", id);
1102}
1103
1104const char *NetlinkAttributeGeneric::id_string() const {
1105 return id_string_.c_str();
1106}
1107
1108} // namespace shill