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