blob: ab4d40643ac42fe7a8b54eb0aac677a980a7a928 [file] [log] [blame]
Wade Guthrie0d438532012-05-18 14:18:50 -07001// 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// This code is derived from the 'iw' source code. The copyright and license
6// of that code is as follows:
7//
8// Copyright (c) 2007, 2008 Johannes Berg
9// Copyright (c) 2007 Andy Lutomirski
10// Copyright (c) 2007 Mike Kershaw
11// Copyright (c) 2008-2009 Luis R. Rodriguez
12//
13// Permission to use, copy, modify, and/or distribute this software for any
14// purpose with or without fee is hereby granted, provided that the above
15// copyright notice and this permission notice appear in all copies.
16//
17// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
18// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
19// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
20// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
22// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
23// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25#include "shill/user_bound_nlmessage.h"
26
27#include <ctype.h>
28#include <endian.h>
29#include <errno.h>
30
31#include <netinet/in.h>
32#include <linux/nl80211.h>
33#include <net/if.h>
34#include <netlink/attr.h>
35#include <netlink/genl/ctrl.h>
36#include <netlink/genl/family.h>
37#include <netlink/genl/genl.h>
38#include <netlink/msg.h>
39#include <netlink/netlink.h>
40
41#include <iomanip>
42#include <string>
43
44#include <base/format_macros.h>
45#include <base/stl_util.h>
46#include <base/stringprintf.h>
47
48#include "shill/ieee80211.h"
49#include "shill/logging.h"
50#include "shill/scope_logger.h"
51
52using base::LazyInstance;
53using base::StringAppendF;
54using base::StringPrintf;
55using std::map;
56using std::string;
57using std::vector;
58
59namespace shill {
60
61namespace {
62LazyInstance<UserBoundNlMessageDataCollector> g_datacollector =
63 LAZY_INSTANCE_INITIALIZER;
64} // namespace
65
66const uint8_t UserBoundNlMessage::kCommand = 0xff;
67const char UserBoundNlMessage::kCommandString[] = "<Unknown Message>";
68const char UserBoundNlMessage::kBogusMacAddress[]="XX:XX:XX:XX:XX:XX";
69
70const uint8_t Nl80211Frame::kMinimumFrameByteCount = 26;
71const uint8_t Nl80211Frame::kFrameTypeMask = 0xfc;
72
73const uint32_t UserBoundNlMessage::kIllegalMessage = 0xFFFFFFFF;
74const int UserBoundNlMessage::kEthernetAddressBytes = 6;
75map<uint16_t, string> *UserBoundNlMessage::connect_status_map_ = NULL;
76
77// The nl messages look like this:
78//
79// XXXXXXXXXXXXXXXXXXX-nlmsg_total_size-XXXXXXXXXXXXXXXXXXX
80// XXXXXXXXXXXXXXXXXXX-nlmsg_msg_size-XXXXXXXXXXXXXXXXXXX
81// +-- gnhl nlmsg_tail(hdr) --+
82// | nlmsg_next(hdr) --+
83// v XXXXXXXXXXXX-nlmsg_len-XXXXXXXXXXXXXX V
84// -----+-----+-+----------------------------------------------+-++----
85// ... | | | payload | ||
86// | | +------+-+--------+-+--------------------------+ ||
87// | nl | | | | | | attribs | ||
88// | msg |p| genl |p| family |p+------+-+-------+-+-------+p|| ...
89// | hdr |a| msg |a| header |a| nl |p| pay |p| |a||
90// | |d| hdr |d| |d| attr |a| load |a| ... |d||
91// | | | | | | | |d| |d| | ||
92// -----+-----+-+----------------------------------------------+-++----
93// ^ ^ ^ ^
94// | | | XXXXXXX <-- nla_len(nlattr)
95// | | | +-- nla_data(nlattr)
96// | | X-nla_total_size-X
97// | | XXXXX-nlmsg_attrlen-XXXXXX
98// | +-- nlmsg_data(hdr) +-- nlmsg_attrdata()
99// +-- msg = nlmsg_hdr(raw_message)
100
101//
102// UserBoundNlMessage
103//
104
105UserBoundNlMessage::~UserBoundNlMessage() {
106 map<enum nl80211_attrs, nlattr *>::iterator i;
107 for (i = attributes_.begin(); i != attributes_.end(); ++i) {
108 delete [] reinterpret_cast<uint8_t *>(i->second);
109 }
110}
111
112bool UserBoundNlMessage::Init(nlattr *tb[NL80211_ATTR_MAX + 1],
113 nlmsghdr *msg) {
114 if (!tb) {
115 LOG(ERROR) << "Null |tb| parameter";
116 return false;
117 }
118
119 message_ = msg;
120
121 SLOG(WiFi, 6) << "NL Message " << GetId() << " <===";
122
123 for (int i = 0; i < NL80211_ATTR_MAX + 1; ++i) {
124 if (tb[i]) {
125 AddAttribute(static_cast<enum nl80211_attrs>(i), tb[i]);
126 }
127 }
128
129 // Convert integer values provided by libnl (for example, from the
130 // NL80211_ATTR_STATUS_CODE or NL80211_ATTR_REASON_CODE attribute) into
131 // strings describing the status.
132 if (!connect_status_map_) {
133 connect_status_map_ = new map<uint16_t, string>;
Wade Guthrie64b4c142012-08-20 15:21:01 -0700134 (*connect_status_map_)[IEEE_80211::kConnectStatusSuccessful] = "Successful";
135 (*connect_status_map_)[IEEE_80211::kConnectStatusFailure] =
136 "Unspecified failure";
137 (*connect_status_map_)[IEEE_80211::kConnectStatusNoLongerValid] =
138 "Previous authentication no longer valid";
139 (*connect_status_map_)[IEEE_80211::kConnectStatusSenderHasLeft] =
140 "Deauthenticated because sending station is leaving (or has left) the "
141 "IBSS or ESS";
142 (*connect_status_map_)[IEEE_80211::kConnectStatusNonAuthenticated] =
143 "Class 3 frame received from non-authenticated station";
144 (*connect_status_map_)[
145 IEEE_80211::kConnectStatusAllCapabilitiesNotSupported] =
146 "Cannot support all requested capabilities in the capability "
147 "information field";
148 (*connect_status_map_)[IEEE_80211::kConnectStatusCantConfirmAssociation] =
149 "Reassociation denied due to inability to confirm that association "
150 "exists";
151 (*connect_status_map_)[IEEE_80211::kConnectStatusAssociationDenied] =
152 "Association denied due to reason outside the scope of this standard";
153 (*connect_status_map_)[
154 IEEE_80211::kConnectStatusAuthenticationUnsupported] =
155 "Responding station does not support the specified authentication "
156 "algorithm";
157 (*connect_status_map_)[IEEE_80211::kConnectStatusOutOfSequence] =
158 "Received an authentication frame with authentication transaction "
159 "sequence number out of expected sequence";
160 (*connect_status_map_)[IEEE_80211::kConnectStatusChallengeFailure] =
161 "Authentication rejected because of challenge failure";
162 (*connect_status_map_)[IEEE_80211::kConnectStatusFrameTimeout] =
163 "Authentication rejected due to timeout waiting for next frame in "
164 "sequence";
165 (*connect_status_map_)[IEEE_80211::kConnectStatusMaxSta] = "Association "
166 "denied because AP is unable to handle additional associated STA";
167 (*connect_status_map_)[IEEE_80211::kConnectStatusDataRateUnsupported] =
168 "Association denied due to requesting station not supporting all of "
169 "the data rates in the BSSBasicRateSet parameter";
170 (*connect_status_map_)[IEEE_80211::kConnectStatusShortPreambleUnsupported] =
171 "Association denied due to requesting station not supporting the "
172 "short preamble option";
173 (*connect_status_map_)[IEEE_80211::kConnectStatusPbccUnsupported] =
174 "Association denied due to requesting station not supporting the PBCC "
175 "modulation option";
176 (*connect_status_map_)[
177 IEEE_80211::kConnectStatusChannelAgilityUnsupported] =
178 "Association denied due to requesting station not supporting the "
179 "channel agility option";
180 (*connect_status_map_)[IEEE_80211::kConnectStatusNeedSpectrumManagement] =
181 "Association request rejected because Spectrum Management capability "
182 "is required";
183 (*connect_status_map_)[
184 IEEE_80211::kConnectStatusUnacceptablePowerCapability] =
185 "Association request rejected because the information in the Power "
186 "Capability element is unacceptable";
187 (*connect_status_map_)[
188 IEEE_80211::kConnectStatusUnacceptableSupportedChannelInfo] =
189 "Association request rejected because the information in the "
190 "Supported Channels element is unacceptable";
191 (*connect_status_map_)[IEEE_80211::kConnectStatusShortTimeSlotRequired] =
192 "Association request rejected due to requesting station not "
193 "supporting the short slot time option";
194 (*connect_status_map_)[IEEE_80211::kConnectStatusErPbccRequired] =
195 "Association request rejected due to requesting station not supporting "
196 "the ER-PBCC modulation option";
197 (*connect_status_map_)[IEEE_80211::kConnectStatusHtFeaturesRequired] =
198 "Association denied due to requesting STA not supporting HT features";
199 (*connect_status_map_)[IEEE_80211::kConnectStatusR0khUnreachable] = "R0KH "
200 "Unreachable";
201 (*connect_status_map_)[IEEE_80211::kConnectStatusPcoTransitionRequired] =
202 "Association denied because the requesting STA does not support the "
203 "PCO transition required by the AP";
204 (*connect_status_map_)[IEEE_80211::kConnectStatusRejectedTemporarily] =
205 "Association request rejected temporarily; try again later";
206 (*connect_status_map_)[IEEE_80211::kConnectStatusRobustPolicyViolated] =
207 "Robust Management frame policy violation";
208 (*connect_status_map_)[IEEE_80211::kConnectStatusQosFailure] =
209 "Unspecified, QoS related failure";
210 (*connect_status_map_)[
211 IEEE_80211::kConnectStatusInsufficientBandwithForQsta] =
212 "Association denied due to QAP having insufficient bandwidth to handle "
213 "another QSTA";
214 (*connect_status_map_)[IEEE_80211::kConnectStatusPoorConditions] =
215 "Association denied due to poor channel conditions";
216 (*connect_status_map_)[IEEE_80211::kConnectStatusQosNotSupported] =
217 "Association (with QBSS) denied due to requesting station not "
218 "supporting the QoS facility";
219 (*connect_status_map_)[IEEE_80211::kConnectStatusDeclined] = "The request "
220 "has been declined";
221 (*connect_status_map_)[IEEE_80211::kConnectStatusInvalidParameterValues] =
222 "The request has not been successful as one or more parameters have "
223 "invalid values";
224 (*connect_status_map_)[IEEE_80211::kConnectStatusCannotBeHonored] = "The "
225 "TS has not been created because the request cannot be honored. "
226 "However, a suggested Tspec is provided so that the initiating QSTA "
227 "may attempt to send another TS with the suggested changes to the "
228 "TSpec";
229 (*connect_status_map_)[IEEE_80211::kConnectStatusInvalidInfoElement] =
230 "Invalid Information Element";
231 (*connect_status_map_)[IEEE_80211::kConnectStatusGroupCipherInvalid] =
232 "Group Cipher is not valid";
233 (*connect_status_map_)[IEEE_80211::kConnectStatusPairwiseCipherInvalid] =
234 "Pairwise Cipher is not valid";
235 (*connect_status_map_)[IEEE_80211::kConnectStatusAkmpInvalid] = "AKMP is "
236 "not valid";
237 (*connect_status_map_)[IEEE_80211::kConnectStatusUnsupportedRsnIeVersion] =
238 "Unsupported RSN IE version";
239 (*connect_status_map_)[IEEE_80211::kConnectStatusInvalidRsnIeCaps] =
240 "Invalid RSN IE Capabilities";
241 (*connect_status_map_)[IEEE_80211::kConnectStatusCipherSuiteRejected] =
242 "Cipher suite is rejected per security policy";
243 (*connect_status_map_)[IEEE_80211::kConnectStatusTsDelayNotMet] = "The TS "
244 "has not been created. However, the HC may be capable of creating a "
245 "TS, in response to a request, after the time indicated in the TS "
246 "Delay element";
247 (*connect_status_map_)[IEEE_80211::kConnectStatusDirectLinkIllegal] =
248 "Direct link is not allowed in the BSS by policy";
249 (*connect_status_map_)[IEEE_80211::kConnectStatusStaNotInQbss] =
250 "Destination STA is not present within this QBSS";
251 (*connect_status_map_)[IEEE_80211::kConnectStatusStaNotInQsta] = "The "
252 "destination STA is not a QSTA";
253 (*connect_status_map_)[IEEE_80211::kConnectStatusExcessiveListenInterval] =
254 "Association denied because Listen Interval is too large";
255 (*connect_status_map_)[IEEE_80211::kConnectStatusInvalidFastBssFrameCount] =
256 "Invalid Fast BSS Transition Action Frame Count";
257 (*connect_status_map_)[IEEE_80211::kConnectStatusInvalidPmkid] =
258 "Invalid PMKID";
259 (*connect_status_map_)[IEEE_80211::kConnectStatusInvalidMdie] =
260 "Invalid MDIE";
261 (*connect_status_map_)[IEEE_80211::kConnectStatusInvalidFtie] =
262 "Invalid FTIE";
Wade Guthrie0d438532012-05-18 14:18:50 -0700263 }
264
265 return true;
266}
267
268UserBoundNlMessage::AttributeNameIterator*
269 UserBoundNlMessage::GetAttributeNameIterator() const {
270 UserBoundNlMessage::AttributeNameIterator *iter =
271 new UserBoundNlMessage::AttributeNameIterator(attributes_);
272 return iter;
273}
274
275// Return true if the attribute is in our map, regardless of the value of
276// the attribute, itself.
277bool UserBoundNlMessage::AttributeExists(enum nl80211_attrs name) const {
278 return ContainsKey(attributes_, name);
279}
280
281uint32_t UserBoundNlMessage::GetId() const {
282 if (!message_) {
283 return kIllegalMessage;
284 }
285 return message_->nlmsg_seq;
286}
287
288enum UserBoundNlMessage::Type
289 UserBoundNlMessage::GetAttributeType(enum nl80211_attrs name) const {
290 const nlattr *attr = GetAttribute(name);
291 if (!attr) {
292 return kTypeError;
293 }
294
295 switch (nla_type(attr)) {
296 case NLA_UNSPEC: return kTypeUnspecified;
297 case NLA_U8: return kTypeU8;
298 case NLA_U16: return kTypeU16;
299 case NLA_U32: return kTypeU32;
300 case NLA_U64: return kTypeU64;
301 case NLA_STRING: return kTypeString;
302 case NLA_FLAG: return kTypeFlag;
303 case NLA_MSECS: return kTypeMsecs;
304 case NLA_NESTED: return kTypeNested;
305 default: return kTypeError;
306 }
307
308 return kTypeError;
309}
310
311string UserBoundNlMessage::GetAttributeTypeString(enum nl80211_attrs name)
312 const {
313 switch (GetAttributeType(name)) {
314 case kTypeUnspecified: return "Unspecified Type"; break;
315 case kTypeU8: return "uint8_t"; break;
316 case kTypeU16: return "uint16_t"; break;
317 case kTypeU32: return "uint32_t"; break;
318 case kTypeU64: return "uint64_t"; break;
319 case kTypeString: return "String"; break;
320 case kTypeFlag: return "Flag"; break;
321 case kTypeMsecs: return "MSec Type"; break;
322 case kTypeNested: return "Nested Type"; break;
323 case kTypeError: return "ERROR TYPE"; break;
324 default: return "Funky Type"; break;
325 }
326}
327
328// Returns the raw attribute data but not the header.
329bool UserBoundNlMessage::GetRawAttributeData(enum nl80211_attrs name,
330 void **value,
331 int *length) const {
332 if (!value) {
333 LOG(ERROR) << "Null |value| parameter";
334 return false;
335 }
336
337 const nlattr *attr = GetAttribute(name);
338 if (!attr) {
339 *value = NULL;
340 return false;
341 }
342
343 if (length) {
344 *length = nla_len(attr);
345 }
346 *value = nla_data(attr);
347 return true;
348}
349
350bool UserBoundNlMessage::GetStringAttribute(enum nl80211_attrs name,
351 string *value) const {
352 if (!value) {
353 LOG(ERROR) << "Null |value| parameter";
354 return false;
355 }
356
357 const nlattr *attr = GetAttribute(name);
358 if (!attr) {
359 return false;
360 }
361
362 value->assign(nla_get_string(const_cast<nlattr *>(attr)));
363 return true;
364}
365
366bool UserBoundNlMessage::GetU8Attribute(enum nl80211_attrs name,
367 uint8_t *value) const {
368 if (!value) {
369 LOG(ERROR) << "Null |value| parameter";
370 return false;
371 }
372
373 const nlattr *attr = GetAttribute(name);
374 if (!attr) {
375 return false;
376 }
377
378 *value = nla_get_u8(const_cast<nlattr *>(attr));
379 return true;
380}
381
382bool UserBoundNlMessage::GetU16Attribute(enum nl80211_attrs name,
383 uint16_t *value) const {
384 if (!value) {
385 LOG(ERROR) << "Null |value| parameter";
386 return false;
387 }
388
389 const nlattr *attr = GetAttribute(name);
390 if (!attr) {
391 return false;
392 }
393
394 *value = nla_get_u16(const_cast<nlattr *>(attr));
395 return true;
396}
397
398bool UserBoundNlMessage::GetU32Attribute(enum nl80211_attrs name,
399 uint32_t *value) const {
400 if (!value) {
401 LOG(ERROR) << "Null |value| parameter";
402 return false;
403 }
404
405 const nlattr *attr = GetAttribute(name);
406 if (!attr) {
407 return false;
408 }
409
410 *value = nla_get_u32(const_cast<nlattr *>(attr));
411 return true;
412}
413
414bool UserBoundNlMessage::GetU64Attribute(enum nl80211_attrs name,
415 uint64_t *value) const {
416 if (!value) {
417 LOG(ERROR) << "Null |value| parameter";
418 return false;
419 }
420
421 const nlattr *attr = GetAttribute(name);
422 if (!attr) {
423 return false;
424 }
425
426 *value = nla_get_u64(const_cast<nlattr *>(attr));
427 return true;
428}
429
430// Helper function to provide a string for a MAC address.
431bool UserBoundNlMessage::GetMacAttributeString(enum nl80211_attrs name,
432 string *value) const {
433 if (!value) {
434 LOG(ERROR) << "Null |value| parameter";
435 return false;
436 }
437
438 void *rawdata_void = NULL;
439 if (!GetRawAttributeData(name, &rawdata_void, NULL)) {
440 value->assign(kBogusMacAddress);
441 return false;
442 }
443 const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(rawdata_void);
444 value->assign(StringFromMacAddress(rawdata));
445
446 return true;
447}
448
449// Helper function to provide a string for NL80211_ATTR_SCAN_FREQUENCIES.
450bool UserBoundNlMessage::GetScanFrequenciesAttribute(
451 enum nl80211_attrs name, vector<uint32_t> *value) const {
452 if (!value) {
453 LOG(ERROR) << "Null |value| parameter";
454 return false;
455 }
456
457 value->clear();
458 if (AttributeExists(name)) {
459 void *rawdata = NULL;
460 int len = 0;
461 if (GetRawAttributeData(name, &rawdata, &len) && rawdata) {
462 nlattr *nst = NULL;
463 nlattr *attr_data = reinterpret_cast<nlattr *>(rawdata);
464 int rem_nst;
465
466 nla_for_each_attr(nst, attr_data, len, rem_nst) {
467 value->push_back(nla_get_u32(nst));
468 }
469 }
470 return true;
471 }
472
473 return false;
474}
475
476// Helper function to provide a string for NL80211_ATTR_SCAN_SSIDS.
477bool UserBoundNlMessage::GetScanSsidsAttribute(
478 enum nl80211_attrs name, vector<string> *value) const {
479 if (!value) {
480 LOG(ERROR) << "Null |value| parameter";
481 return false;
482 }
483
484 if (AttributeExists(name)) {
485 void *rawdata = NULL;
486 int len = 0;
487 if (GetRawAttributeData(name, &rawdata, &len) && rawdata) {
488 nlattr *nst = NULL;
489 nlattr *data = reinterpret_cast<nlattr *>(rawdata);
490 int rem_nst;
491
492 nla_for_each_attr(nst, data, len, rem_nst) {
493 value->push_back(StringFromSsid(nla_len(nst),
494 reinterpret_cast<const uint8_t *>(
495 nla_data(nst))).c_str());
496 }
497 }
498 return true;
499 }
500
501 return false;
502}
503
504bool UserBoundNlMessage::GetAttributeString(nl80211_attrs name,
505 string *param) const {
506 if (!param) {
507 LOG(ERROR) << "Null |param| parameter";
508 return false;
509 }
510
511 switch (GetAttributeType(name)) {
512 case kTypeU8: {
513 uint8_t value;
514 if (!GetU8Attribute(name, &value))
515 return false;
516 *param = StringPrintf("%u", value);
517 break;
518 }
519 case kTypeU16: {
520 uint16_t value;
521 if (!GetU16Attribute(name, &value))
522 return false;
523 *param = StringPrintf("%u", value);
524 break;
525 }
526 case kTypeU32: {
527 uint32_t value;
528 if (!GetU32Attribute(name, &value))
529 return false;
530 *param = StringPrintf("%" PRIu32, value);
531 break;
532 }
533 case kTypeU64: {
534 uint64_t value;
535 if (!GetU64Attribute(name, &value))
536 return false;
537 *param = StringPrintf("%" PRIu64, value);
538 break;
539 }
540 case kTypeString:
541 if (!GetStringAttribute(name, param))
542 return false;
543 break;
544
545 default:
546 return false;
547 }
548 return true;
549}
550
551string UserBoundNlMessage::RawToString(enum nl80211_attrs name) const {
552 string output = " === RAW: ";
553
554 const nlattr *attr = GetAttribute(name);
555 if (!attr) {
556 output.append("<NULL> ===");
557 return output;
558 }
559
560 const char *typestring = NULL;
561 switch (nla_type(attr)) {
562 case NLA_UNSPEC: typestring = "NLA_UNSPEC"; break;
563 case NLA_U8: typestring = "NLA_U8"; break;
564 case NLA_U16: typestring = "NLA_U16"; break;
565 case NLA_U32: typestring = "NLA_U32"; break;
566 case NLA_U64: typestring = "NLA_U64"; break;
567 case NLA_STRING: typestring = "NLA_STRING"; break;
568 case NLA_FLAG: typestring = "NLA_FLAG"; break;
569 case NLA_MSECS: typestring = "NLA_MSECS"; break;
570 case NLA_NESTED: typestring = "NLA_NESTED"; break;
571 default: typestring = "<UNKNOWN>"; break;
572 }
573
574 uint16_t length = nla_len(attr);
575 uint16_t type = nla_type(attr);
576 StringAppendF(&output, "len=%u type=(%u)=%s", length, type, typestring);
577
578 const uint8_t *const_data
579 = reinterpret_cast<const uint8_t *>(nla_data(attr));
580
581 output.append(" DATA: ");
582 for (int i =0 ; i < length; ++i) {
583 StringAppendF(&output, "[%d]=%02x ",
584 i, *(reinterpret_cast<const uint8_t *>(const_data)+i));
585 }
586 output.append(" ==== ");
587 return output;
588}
589
590// static
591string UserBoundNlMessage::StringFromAttributeName(enum nl80211_attrs name) {
592 switch (name) {
593 case NL80211_ATTR_UNSPEC:
594 return "NL80211_ATTR_UNSPEC"; break;
595 case NL80211_ATTR_WIPHY:
596 return "NL80211_ATTR_WIPHY"; break;
597 case NL80211_ATTR_WIPHY_NAME:
598 return "NL80211_ATTR_WIPHY_NAME"; break;
599 case NL80211_ATTR_IFINDEX:
600 return "NL80211_ATTR_IFINDEX"; break;
601 case NL80211_ATTR_IFNAME:
602 return "NL80211_ATTR_IFNAME"; break;
603 case NL80211_ATTR_IFTYPE:
604 return "NL80211_ATTR_IFTYPE"; break;
605 case NL80211_ATTR_MAC:
606 return "NL80211_ATTR_MAC"; break;
607 case NL80211_ATTR_KEY_DATA:
608 return "NL80211_ATTR_KEY_DATA"; break;
609 case NL80211_ATTR_KEY_IDX:
610 return "NL80211_ATTR_KEY_IDX"; break;
611 case NL80211_ATTR_KEY_CIPHER:
612 return "NL80211_ATTR_KEY_CIPHER"; break;
613 case NL80211_ATTR_KEY_SEQ:
614 return "NL80211_ATTR_KEY_SEQ"; break;
615 case NL80211_ATTR_KEY_DEFAULT:
616 return "NL80211_ATTR_KEY_DEFAULT"; break;
617 case NL80211_ATTR_BEACON_INTERVAL:
618 return "NL80211_ATTR_BEACON_INTERVAL"; break;
619 case NL80211_ATTR_DTIM_PERIOD:
620 return "NL80211_ATTR_DTIM_PERIOD"; break;
621 case NL80211_ATTR_BEACON_HEAD:
622 return "NL80211_ATTR_BEACON_HEAD"; break;
623 case NL80211_ATTR_BEACON_TAIL:
624 return "NL80211_ATTR_BEACON_TAIL"; break;
625 case NL80211_ATTR_STA_AID:
626 return "NL80211_ATTR_STA_AID"; break;
627 case NL80211_ATTR_STA_FLAGS:
628 return "NL80211_ATTR_STA_FLAGS"; break;
629 case NL80211_ATTR_STA_LISTEN_INTERVAL:
630 return "NL80211_ATTR_STA_LISTEN_INTERVAL"; break;
631 case NL80211_ATTR_STA_SUPPORTED_RATES:
632 return "NL80211_ATTR_STA_SUPPORTED_RATES"; break;
633 case NL80211_ATTR_STA_VLAN:
634 return "NL80211_ATTR_STA_VLAN"; break;
635 case NL80211_ATTR_STA_INFO:
636 return "NL80211_ATTR_STA_INFO"; break;
637 case NL80211_ATTR_WIPHY_BANDS:
638 return "NL80211_ATTR_WIPHY_BANDS"; break;
639 case NL80211_ATTR_MNTR_FLAGS:
640 return "NL80211_ATTR_MNTR_FLAGS"; break;
641 case NL80211_ATTR_MESH_ID:
642 return "NL80211_ATTR_MESH_ID"; break;
643 case NL80211_ATTR_STA_PLINK_ACTION:
644 return "NL80211_ATTR_STA_PLINK_ACTION"; break;
645 case NL80211_ATTR_MPATH_NEXT_HOP:
646 return "NL80211_ATTR_MPATH_NEXT_HOP"; break;
647 case NL80211_ATTR_MPATH_INFO:
648 return "NL80211_ATTR_MPATH_INFO"; break;
649 case NL80211_ATTR_BSS_CTS_PROT:
650 return "NL80211_ATTR_BSS_CTS_PROT"; break;
651 case NL80211_ATTR_BSS_SHORT_PREAMBLE:
652 return "NL80211_ATTR_BSS_SHORT_PREAMBLE"; break;
653 case NL80211_ATTR_BSS_SHORT_SLOT_TIME:
654 return "NL80211_ATTR_BSS_SHORT_SLOT_TIME"; break;
655 case NL80211_ATTR_HT_CAPABILITY:
656 return "NL80211_ATTR_HT_CAPABILITY"; break;
657 case NL80211_ATTR_SUPPORTED_IFTYPES:
658 return "NL80211_ATTR_SUPPORTED_IFTYPES"; break;
659 case NL80211_ATTR_REG_ALPHA2:
660 return "NL80211_ATTR_REG_ALPHA2"; break;
661 case NL80211_ATTR_REG_RULES:
662 return "NL80211_ATTR_REG_RULES"; break;
663 case NL80211_ATTR_MESH_CONFIG:
664 return "NL80211_ATTR_MESH_CONFIG"; break;
665 case NL80211_ATTR_BSS_BASIC_RATES:
666 return "NL80211_ATTR_BSS_BASIC_RATES"; break;
667 case NL80211_ATTR_WIPHY_TXQ_PARAMS:
668 return "NL80211_ATTR_WIPHY_TXQ_PARAMS"; break;
669 case NL80211_ATTR_WIPHY_FREQ:
670 return "NL80211_ATTR_WIPHY_FREQ"; break;
671 case NL80211_ATTR_WIPHY_CHANNEL_TYPE:
672 return "NL80211_ATTR_WIPHY_CHANNEL_TYPE"; break;
673 case NL80211_ATTR_KEY_DEFAULT_MGMT:
674 return "NL80211_ATTR_KEY_DEFAULT_MGMT"; break;
675 case NL80211_ATTR_MGMT_SUBTYPE:
676 return "NL80211_ATTR_MGMT_SUBTYPE"; break;
677 case NL80211_ATTR_IE:
678 return "NL80211_ATTR_IE"; break;
679 case NL80211_ATTR_MAX_NUM_SCAN_SSIDS:
680 return "NL80211_ATTR_MAX_NUM_SCAN_SSIDS"; break;
681 case NL80211_ATTR_SCAN_FREQUENCIES:
682 return "NL80211_ATTR_SCAN_FREQUENCIES"; break;
683 case NL80211_ATTR_SCAN_SSIDS:
684 return "NL80211_ATTR_SCAN_SSIDS"; break;
685 case NL80211_ATTR_GENERATION:
686 return "NL80211_ATTR_GENERATION"; break;
687 case NL80211_ATTR_BSS:
688 return "NL80211_ATTR_BSS"; break;
689 case NL80211_ATTR_REG_INITIATOR:
690 return "NL80211_ATTR_REG_INITIATOR"; break;
691 case NL80211_ATTR_REG_TYPE:
692 return "NL80211_ATTR_REG_TYPE"; break;
693 case NL80211_ATTR_SUPPORTED_COMMANDS:
694 return "NL80211_ATTR_SUPPORTED_COMMANDS"; break;
695 case NL80211_ATTR_FRAME:
696 return "NL80211_ATTR_FRAME"; break;
697 case NL80211_ATTR_SSID:
698 return "NL80211_ATTR_SSID"; break;
699 case NL80211_ATTR_AUTH_TYPE:
700 return "NL80211_ATTR_AUTH_TYPE"; break;
701 case NL80211_ATTR_REASON_CODE:
702 return "NL80211_ATTR_REASON_CODE"; break;
703 case NL80211_ATTR_KEY_TYPE:
704 return "NL80211_ATTR_KEY_TYPE"; break;
705 case NL80211_ATTR_MAX_SCAN_IE_LEN:
706 return "NL80211_ATTR_MAX_SCAN_IE_LEN"; break;
707 case NL80211_ATTR_CIPHER_SUITES:
708 return "NL80211_ATTR_CIPHER_SUITES"; break;
709 case NL80211_ATTR_FREQ_BEFORE:
710 return "NL80211_ATTR_FREQ_BEFORE"; break;
711 case NL80211_ATTR_FREQ_AFTER:
712 return "NL80211_ATTR_FREQ_AFTER"; break;
713 case NL80211_ATTR_FREQ_FIXED:
714 return "NL80211_ATTR_FREQ_FIXED"; break;
715 case NL80211_ATTR_WIPHY_RETRY_SHORT:
716 return "NL80211_ATTR_WIPHY_RETRY_SHORT"; break;
717 case NL80211_ATTR_WIPHY_RETRY_LONG:
718 return "NL80211_ATTR_WIPHY_RETRY_LONG"; break;
719 case NL80211_ATTR_WIPHY_FRAG_THRESHOLD:
720 return "NL80211_ATTR_WIPHY_FRAG_THRESHOLD"; break;
721 case NL80211_ATTR_WIPHY_RTS_THRESHOLD:
722 return "NL80211_ATTR_WIPHY_RTS_THRESHOLD"; break;
723 case NL80211_ATTR_TIMED_OUT:
724 return "NL80211_ATTR_TIMED_OUT"; break;
725 case NL80211_ATTR_USE_MFP:
726 return "NL80211_ATTR_USE_MFP"; break;
727 case NL80211_ATTR_STA_FLAGS2:
728 return "NL80211_ATTR_STA_FLAGS2"; break;
729 case NL80211_ATTR_CONTROL_PORT:
730 return "NL80211_ATTR_CONTROL_PORT"; break;
731 case NL80211_ATTR_TESTDATA:
732 return "NL80211_ATTR_TESTDATA"; break;
733 case NL80211_ATTR_PRIVACY:
734 return "NL80211_ATTR_PRIVACY"; break;
735 case NL80211_ATTR_DISCONNECTED_BY_AP:
736 return "NL80211_ATTR_DISCONNECTED_BY_AP"; break;
737 case NL80211_ATTR_STATUS_CODE:
738 return "NL80211_ATTR_STATUS_CODE"; break;
739 case NL80211_ATTR_CIPHER_SUITES_PAIRWISE:
740 return "NL80211_ATTR_CIPHER_SUITES_PAIRWISE"; break;
741 case NL80211_ATTR_CIPHER_SUITE_GROUP:
742 return "NL80211_ATTR_CIPHER_SUITE_GROUP"; break;
743 case NL80211_ATTR_WPA_VERSIONS:
744 return "NL80211_ATTR_WPA_VERSIONS"; break;
745 case NL80211_ATTR_AKM_SUITES:
746 return "NL80211_ATTR_AKM_SUITES"; break;
747 case NL80211_ATTR_REQ_IE:
748 return "NL80211_ATTR_REQ_IE"; break;
749 case NL80211_ATTR_RESP_IE:
750 return "NL80211_ATTR_RESP_IE"; break;
751 case NL80211_ATTR_PREV_BSSID:
752 return "NL80211_ATTR_PREV_BSSID"; break;
753 case NL80211_ATTR_KEY:
754 return "NL80211_ATTR_KEY"; break;
755 case NL80211_ATTR_KEYS:
756 return "NL80211_ATTR_KEYS"; break;
757 case NL80211_ATTR_PID:
758 return "NL80211_ATTR_PID"; break;
759 case NL80211_ATTR_4ADDR:
760 return "NL80211_ATTR_4ADDR"; break;
761 case NL80211_ATTR_SURVEY_INFO:
762 return "NL80211_ATTR_SURVEY_INFO"; break;
763 case NL80211_ATTR_PMKID:
764 return "NL80211_ATTR_PMKID"; break;
765 case NL80211_ATTR_MAX_NUM_PMKIDS:
766 return "NL80211_ATTR_MAX_NUM_PMKIDS"; break;
767 case NL80211_ATTR_DURATION:
768 return "NL80211_ATTR_DURATION"; break;
769 case NL80211_ATTR_COOKIE:
770 return "NL80211_ATTR_COOKIE"; break;
771 case NL80211_ATTR_WIPHY_COVERAGE_CLASS:
772 return "NL80211_ATTR_WIPHY_COVERAGE_CLASS"; break;
773 case NL80211_ATTR_TX_RATES:
774 return "NL80211_ATTR_TX_RATES"; break;
775 case NL80211_ATTR_FRAME_MATCH:
776 return "NL80211_ATTR_FRAME_MATCH"; break;
777 case NL80211_ATTR_ACK:
778 return "NL80211_ATTR_ACK"; break;
779 case NL80211_ATTR_PS_STATE:
780 return "NL80211_ATTR_PS_STATE"; break;
781 case NL80211_ATTR_CQM:
782 return "NL80211_ATTR_CQM"; break;
783 case NL80211_ATTR_LOCAL_STATE_CHANGE:
784 return "NL80211_ATTR_LOCAL_STATE_CHANGE"; break;
785 case NL80211_ATTR_AP_ISOLATE:
786 return "NL80211_ATTR_AP_ISOLATE"; break;
787 case NL80211_ATTR_WIPHY_TX_POWER_SETTING:
788 return "NL80211_ATTR_WIPHY_TX_POWER_SETTING"; break;
789 case NL80211_ATTR_WIPHY_TX_POWER_LEVEL:
790 return "NL80211_ATTR_WIPHY_TX_POWER_LEVEL"; break;
791 case NL80211_ATTR_TX_FRAME_TYPES:
792 return "NL80211_ATTR_TX_FRAME_TYPES"; break;
793 case NL80211_ATTR_RX_FRAME_TYPES:
794 return "NL80211_ATTR_RX_FRAME_TYPES"; break;
795 case NL80211_ATTR_FRAME_TYPE:
796 return "NL80211_ATTR_FRAME_TYPE"; break;
797 case NL80211_ATTR_CONTROL_PORT_ETHERTYPE:
798 return "NL80211_ATTR_CONTROL_PORT_ETHERTYPE"; break;
799 case NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT:
800 return "NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT"; break;
801 case NL80211_ATTR_SUPPORT_IBSS_RSN:
802 return "NL80211_ATTR_SUPPORT_IBSS_RSN"; break;
803 case NL80211_ATTR_WIPHY_ANTENNA_TX:
804 return "NL80211_ATTR_WIPHY_ANTENNA_TX"; break;
805 case NL80211_ATTR_WIPHY_ANTENNA_RX:
806 return "NL80211_ATTR_WIPHY_ANTENNA_RX"; break;
807 case NL80211_ATTR_MCAST_RATE:
808 return "NL80211_ATTR_MCAST_RATE"; break;
809 case NL80211_ATTR_OFFCHANNEL_TX_OK:
810 return "NL80211_ATTR_OFFCHANNEL_TX_OK"; break;
811 case NL80211_ATTR_BSS_HT_OPMODE:
812 return "NL80211_ATTR_BSS_HT_OPMODE"; break;
813 case NL80211_ATTR_KEY_DEFAULT_TYPES:
814 return "NL80211_ATTR_KEY_DEFAULT_TYPES"; break;
815 case NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION:
816 return "NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION"; break;
817 case NL80211_ATTR_MESH_SETUP:
818 return "NL80211_ATTR_MESH_SETUP"; break;
819 case NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX:
820 return "NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX"; break;
821 case NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX:
822 return "NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX"; break;
823 case NL80211_ATTR_SUPPORT_MESH_AUTH:
824 return "NL80211_ATTR_SUPPORT_MESH_AUTH"; break;
825 case NL80211_ATTR_STA_PLINK_STATE:
826 return "NL80211_ATTR_STA_PLINK_STATE"; break;
827 case NL80211_ATTR_WOWLAN_TRIGGERS:
828 return "NL80211_ATTR_WOWLAN_TRIGGERS"; break;
829 case NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED:
830 return "NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED"; break;
831 case NL80211_ATTR_SCHED_SCAN_INTERVAL:
832 return "NL80211_ATTR_SCHED_SCAN_INTERVAL"; break;
833 case NL80211_ATTR_INTERFACE_COMBINATIONS:
834 return "NL80211_ATTR_INTERFACE_COMBINATIONS"; break;
835 case NL80211_ATTR_SOFTWARE_IFTYPES:
836 return "NL80211_ATTR_SOFTWARE_IFTYPES"; break;
837 case NL80211_ATTR_REKEY_DATA:
838 return "NL80211_ATTR_REKEY_DATA"; break;
839 case NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS:
840 return "NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS"; break;
841 case NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN:
842 return "NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN"; break;
843 case NL80211_ATTR_SCAN_SUPP_RATES:
844 return "NL80211_ATTR_SCAN_SUPP_RATES"; break;
845 case NL80211_ATTR_HIDDEN_SSID:
846 return "NL80211_ATTR_HIDDEN_SSID"; break;
847 case NL80211_ATTR_IE_PROBE_RESP:
848 return "NL80211_ATTR_IE_PROBE_RESP"; break;
849 case NL80211_ATTR_IE_ASSOC_RESP:
850 return "NL80211_ATTR_IE_ASSOC_RESP"; break;
851 case NL80211_ATTR_STA_WME:
852 return "NL80211_ATTR_STA_WME"; break;
853 case NL80211_ATTR_SUPPORT_AP_UAPSD:
854 return "NL80211_ATTR_SUPPORT_AP_UAPSD"; break;
855 case NL80211_ATTR_ROAM_SUPPORT:
856 return "NL80211_ATTR_ROAM_SUPPORT"; break;
857 case NL80211_ATTR_SCHED_SCAN_MATCH:
858 return "NL80211_ATTR_SCHED_SCAN_MATCH"; break;
859 case NL80211_ATTR_MAX_MATCH_SETS:
860 return "NL80211_ATTR_MAX_MATCH_SETS"; break;
861 case NL80211_ATTR_PMKSA_CANDIDATE:
862 return "NL80211_ATTR_PMKSA_CANDIDATE"; break;
863 case NL80211_ATTR_TX_NO_CCK_RATE:
864 return "NL80211_ATTR_TX_NO_CCK_RATE"; break;
865 case NL80211_ATTR_TDLS_ACTION:
866 return "NL80211_ATTR_TDLS_ACTION"; break;
867 case NL80211_ATTR_TDLS_DIALOG_TOKEN:
868 return "NL80211_ATTR_TDLS_DIALOG_TOKEN"; break;
869 case NL80211_ATTR_TDLS_OPERATION:
870 return "NL80211_ATTR_TDLS_OPERATION"; break;
871 case NL80211_ATTR_TDLS_SUPPORT:
872 return "NL80211_ATTR_TDLS_SUPPORT"; break;
873 case NL80211_ATTR_TDLS_EXTERNAL_SETUP:
874 return "NL80211_ATTR_TDLS_EXTERNAL_SETUP"; break;
875 case NL80211_ATTR_DEVICE_AP_SME:
876 return "NL80211_ATTR_DEVICE_AP_SME"; break;
877 case NL80211_ATTR_DONT_WAIT_FOR_ACK:
878 return "NL80211_ATTR_DONT_WAIT_FOR_ACK"; break;
879 case NL80211_ATTR_FEATURE_FLAGS:
880 return "NL80211_ATTR_FEATURE_FLAGS"; break;
881 case NL80211_ATTR_PROBE_RESP_OFFLOAD:
882 return "NL80211_ATTR_PROBE_RESP_OFFLOAD"; break;
883 case NL80211_ATTR_PROBE_RESP:
884 return "NL80211_ATTR_PROBE_RESP"; break;
885 case NL80211_ATTR_DFS_REGION:
886 return "NL80211_ATTR_DFS_REGION"; break;
887 case NL80211_ATTR_DISABLE_HT:
888 return "NL80211_ATTR_DISABLE_HT"; break;
889 case NL80211_ATTR_HT_CAPABILITY_MASK:
890 return "NL80211_ATTR_HT_CAPABILITY_MASK"; break;
891 case NL80211_ATTR_NOACK_MAP:
892 return "NL80211_ATTR_NOACK_MAP"; break;
893 case NL80211_ATTR_INACTIVITY_TIMEOUT:
894 return "NL80211_ATTR_INACTIVITY_TIMEOUT"; break;
895 case NL80211_ATTR_RX_SIGNAL_DBM:
896 return "NL80211_ATTR_RX_SIGNAL_DBM"; break;
897 case NL80211_ATTR_BG_SCAN_PERIOD:
898 return "NL80211_ATTR_BG_SCAN_PERIOD"; break;
899 default:
900 return "<UNKNOWN>"; break;
901 }
902}
903
904// Protected members.
905
906// Duplicate attribute data, store in map indexed on |name|.
907bool UserBoundNlMessage::AddAttribute(enum nl80211_attrs name,
908 nlattr *data) {
909 if (ContainsKey(attributes_, name)) {
910 LOG(ERROR) << "Already have attribute name " << name;
911 return false;
912 }
913
914 if ((!data) || (nla_total_size(nla_len(data)) == 0)) {
915 attributes_[name] = NULL;
916 } else {
917 nlattr *newdata = reinterpret_cast<nlattr *>(
918 new uint8_t[nla_total_size(nla_len(data))]);
919 memcpy(newdata, data, nla_total_size(nla_len(data)));
920 attributes_[name] = newdata;
921 }
922 return true;
923}
924
925const nlattr *UserBoundNlMessage::GetAttribute(enum nl80211_attrs name)
926 const {
927 map<enum nl80211_attrs, nlattr *>::const_iterator match;
928 match = attributes_.find(name);
929 // This method may be called to explore the existence of the attribute so
930 // we'll not emit an error if it's not found.
931 if (match == attributes_.end()) {
932 return NULL;
933 }
934 return match->second;
935}
936
937string UserBoundNlMessage::GetHeaderString() const {
938 char ifname[IF_NAMESIZE] = "";
939 uint32_t ifindex = UINT32_MAX;
940 bool ifindex_exists = GetU32Attribute(NL80211_ATTR_IFINDEX, &ifindex);
941
942 uint32_t wifi = UINT32_MAX;
943 bool wifi_exists = GetU32Attribute(NL80211_ATTR_WIPHY, &wifi);
944
945 string output;
946 if (ifindex_exists && wifi_exists) {
947 StringAppendF(&output, "%s (phy #%" PRIu32 "): ",
948 (if_indextoname(ifindex, ifname) ? ifname : "<unknown>"),
949 wifi);
950 } else if (ifindex_exists) {
951 StringAppendF(&output, "%s: ",
952 (if_indextoname(ifindex, ifname) ? ifname : "<unknown>"));
953 } else if (wifi_exists) {
954 StringAppendF(&output, "phy #%" PRIu32 "u: ", wifi);
955 }
956
957 return output;
958}
959
960string UserBoundNlMessage::StringFromFrame(enum nl80211_attrs attr_name) const {
961 string output;
962
963 void *rawdata = NULL;
964 int frame_byte_count = 0;
965 if (GetRawAttributeData(attr_name, &rawdata, &frame_byte_count) && rawdata) {
966 const uint8_t *frame_data = reinterpret_cast<const uint8_t *>(rawdata);
967
968 Nl80211Frame frame(frame_data, frame_byte_count);
969 frame.ToString(&output);
970 } else {
971 output.append(" [no frame]");
972 }
973
974 return output;
975}
976
977// static
978string UserBoundNlMessage::StringFromKeyType(nl80211_key_type key_type) {
979 switch (key_type) {
980 case NL80211_KEYTYPE_GROUP:
981 return "Group";
982 case NL80211_KEYTYPE_PAIRWISE:
983 return "Pairwise";
984 case NL80211_KEYTYPE_PEERKEY:
985 return "PeerKey";
986 default:
987 return "<Unknown Key Type>";
988 }
989}
990
991// static
992string UserBoundNlMessage::StringFromMacAddress(const uint8_t *arg) {
993 string output;
994
995 if (!arg) {
996 output = kBogusMacAddress;
997 LOG(ERROR) << "|arg| parameter is NULL.";
998 } else {
999 StringAppendF(&output, "%02x", arg[0]);
1000
1001 for (int i = 1; i < kEthernetAddressBytes ; ++i) {
1002 StringAppendF(&output, ":%02x", arg[i]);
1003 }
1004 }
1005 return output;
1006}
1007
1008// static
1009string UserBoundNlMessage::StringFromRegInitiator(__u8 initiator) {
1010 switch (initiator) {
1011 case NL80211_REGDOM_SET_BY_CORE:
1012 return "the wireless core upon initialization";
1013 case NL80211_REGDOM_SET_BY_USER:
1014 return "a user";
1015 case NL80211_REGDOM_SET_BY_DRIVER:
1016 return "a driver";
1017 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
1018 return "a country IE";
1019 default:
1020 return "<Unknown Reg Initiator>";
1021 }
1022}
1023
1024// static
1025string UserBoundNlMessage::StringFromSsid(const uint8_t len,
1026 const uint8_t *data) {
1027 string output;
1028 if (!data) {
1029 StringAppendF(&output, "<Error from %s, NULL parameter>", __func__);
1030 LOG(ERROR) << "|data| parameter is NULL.";
1031 return output;
1032 }
1033
1034 for (int i = 0; i < len; ++i) {
1035 if (data[i] == ' ')
1036 output.append(" ");
1037 else if (isprint(data[i]))
1038 StringAppendF(&output, "%c", static_cast<char>(data[i]));
1039 else
1040 StringAppendF(&output, "\\x%2x", data[i]);
1041 }
1042
1043 return output;
1044}
1045
1046// static
1047string UserBoundNlMessage::StringFromStatus(uint16_t status) {
1048 map<uint16_t, string>::const_iterator match;
1049 match = connect_status_map_->find(status);
1050 if (match == connect_status_map_->end()) {
1051 string output;
1052 StringAppendF(&output, "<Unknown Status:%u>", status);
1053 return output;
1054 }
1055 return match->second;
1056}
1057
1058Nl80211Frame::Nl80211Frame(const uint8_t *raw_frame, int frame_byte_count) :
1059 frame_type_(kIllegalFrameType), status_(0), frame_(0), byte_count_(0) {
1060 if (raw_frame == NULL)
1061 return;
1062
1063 frame_ = new uint8_t[frame_byte_count];
1064 memcpy(frame_, raw_frame, frame_byte_count);
1065 byte_count_ = frame_byte_count;
1066 const IEEE_80211::ieee80211_frame *frame =
1067 reinterpret_cast<const IEEE_80211::ieee80211_frame *>(frame_);
1068
1069 // Now, let's populate the other stuff.
1070 if (frame_byte_count >= kMinimumFrameByteCount) {
1071 mac_from_ =
1072 UserBoundNlMessage::StringFromMacAddress(&frame->destination_mac[0]);
1073 mac_to_ = UserBoundNlMessage::StringFromMacAddress(&frame->source_mac[0]);
1074 frame_type_ = frame->frame_control & kFrameTypeMask;
1075
1076 switch (frame_type_) {
1077 case kAssocResponseFrameType:
1078 case kReassocResponseFrameType:
1079 status_ = le16toh(frame->u.associate_response.status_code);
1080 break;
1081
1082 case kAuthFrameType:
1083 status_ = le16toh(frame->u.authentiate_message.status_code);
1084 break;
1085
1086 case kDisassocFrameType:
1087 case kDeauthFrameType:
1088 status_ = le16toh(frame->u.deauthentiate_message.reason_code);
1089 break;
1090
1091 default:
1092 break;
1093 }
1094 }
1095}
1096
1097Nl80211Frame::~Nl80211Frame() {
1098 delete [] frame_;
1099 frame_ = NULL;
1100}
1101
1102bool Nl80211Frame::ToString(string *output) {
1103 if (!output) {
1104 LOG(ERROR) << "NULL |output|";
1105 return false;
1106 }
1107
1108 if ((byte_count_ == 0) || (frame_ == reinterpret_cast<uint8_t *>(NULL))) {
1109 output->append(" [no frame]");
1110 return true;
1111 }
1112
1113 if (byte_count_ < kMinimumFrameByteCount) {
1114 output->append(" [invalid frame: ");
1115 } else {
1116 StringAppendF(output, " %s -> %s", mac_from_.c_str(), mac_to_.c_str());
1117
1118 switch (frame_[0] & kFrameTypeMask) {
1119 case kAssocResponseFrameType:
1120 StringAppendF(output, "; AssocResponse status: %u: %s",
1121 status_,
1122 UserBoundNlMessage::StringFromStatus(status_).c_str());
1123 break;
1124 case kReassocResponseFrameType:
1125 StringAppendF(output, "; ReassocResponse status: %u: %s",
1126 status_,
1127 UserBoundNlMessage::StringFromStatus(status_).c_str());
1128 break;
1129 case kAuthFrameType:
1130 StringAppendF(output, "; Auth status: %u: %s",
1131 status_,
1132 UserBoundNlMessage::StringFromStatus(status_).c_str());
1133 break;
1134
1135 case kDisassocFrameType:
1136 StringAppendF(output, "; Disassoc reason %u: %s",
1137 status_,
1138 UserBoundNlMessage::StringFromStatus(status_).c_str());
1139 break;
1140 case kDeauthFrameType:
1141 StringAppendF(output, "; Deauth reason %u: %s",
1142 status_,
1143 UserBoundNlMessage::StringFromStatus(status_).c_str());
1144 break;
1145
1146 default:
1147 break;
1148 }
1149 output->append(" [frame: ");
1150 }
1151
1152 for (int i = 0; i < byte_count_; ++i) {
1153 StringAppendF(output, "%02x, ", frame_[i]);
1154 }
1155 output->append("]");
1156
1157 return true;
1158}
1159
1160bool Nl80211Frame::IsEqual(const Nl80211Frame &other) {
1161 if (byte_count_ != other.byte_count_) {
1162 return false;
1163 }
1164
1165 for (int i = 0; i < byte_count_; ++i) {
1166 if (frame_[i] != other.frame_[i]) {
1167 return false;
1168 }
1169 }
1170
1171 return true;
1172}
1173
1174//
1175// Specific UserBoundNlMessage types.
1176//
1177
1178const uint8_t AssociateMessage::kCommand = NL80211_CMD_ASSOCIATE;
1179const char AssociateMessage::kCommandString[] = "NL80211_CMD_ASSOCIATE";
1180
1181string AssociateMessage::ToString() const {
1182 string output(GetHeaderString());
1183 output.append("assoc");
1184 if (AttributeExists(NL80211_ATTR_FRAME))
1185 output.append(StringFromFrame(NL80211_ATTR_FRAME));
1186 else if (AttributeExists(NL80211_ATTR_TIMED_OUT))
1187 output.append(": timed out");
1188 else
1189 output.append(": unknown event");
1190 return output;
1191}
1192
1193const uint8_t AuthenticateMessage::kCommand = NL80211_CMD_AUTHENTICATE;
1194const char AuthenticateMessage::kCommandString[] = "NL80211_CMD_AUTHENTICATE";
1195
1196string AuthenticateMessage::ToString() const {
1197 string output(GetHeaderString());
1198 output.append("auth");
1199 if (AttributeExists(NL80211_ATTR_FRAME)) {
1200 output.append(StringFromFrame(NL80211_ATTR_FRAME));
1201 } else {
1202 output.append(AttributeExists(NL80211_ATTR_TIMED_OUT) ?
1203 ": timed out" : ": unknown event");
1204 }
1205 return output;
1206}
1207
1208const uint8_t CancelRemainOnChannelMessage::kCommand =
1209 NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL;
1210const char CancelRemainOnChannelMessage::kCommandString[] =
1211 "NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL";
1212
1213string CancelRemainOnChannelMessage::ToString() const {
1214 string output(GetHeaderString());
1215 uint32_t freq;
1216 uint64_t cookie;
1217 StringAppendF(&output,
1218 "done with remain on freq %" PRIu32 " (cookie %" PRIx64 ")",
1219 (GetU32Attribute(NL80211_ATTR_WIPHY_FREQ, &freq) ? 0 : freq),
1220 (GetU64Attribute(NL80211_ATTR_COOKIE, &cookie) ? 0 : cookie));
1221 return output;
1222}
1223
1224const uint8_t ConnectMessage::kCommand = NL80211_CMD_CONNECT;
1225const char ConnectMessage::kCommandString[] = "NL80211_CMD_CONNECT";
1226
1227string ConnectMessage::ToString() const {
1228 string output(GetHeaderString());
1229
1230 uint16_t status = UINT16_MAX;
1231
1232 if (!GetU16Attribute(NL80211_ATTR_STATUS_CODE, &status)) {
1233 output.append("unknown connect status");
1234 } else if (status == 0) {
1235 output.append("connected");
1236 } else {
1237 output.append("failed to connect");
1238 }
1239
1240 if (AttributeExists(NL80211_ATTR_MAC)) {
1241 string mac;
1242 GetMacAttributeString(NL80211_ATTR_MAC, &mac);
1243 StringAppendF(&output, " to %s", mac.c_str());
1244 }
1245 if (status)
1246 StringAppendF(&output, ", status: %u: %s", status,
1247 StringFromStatus(status).c_str());
1248 return output;
1249}
1250
1251const uint8_t DeauthenticateMessage::kCommand = NL80211_CMD_DEAUTHENTICATE;
1252const char DeauthenticateMessage::kCommandString[] =
1253 "NL80211_CMD_DEAUTHENTICATE";
1254
1255string DeauthenticateMessage::ToString() const {
1256 string output(GetHeaderString());
1257 StringAppendF(&output, "deauth%s",
1258 StringFromFrame(NL80211_ATTR_FRAME).c_str());
1259 return output;
1260}
1261
1262const uint8_t DeleteStationMessage::kCommand = NL80211_CMD_DEL_STATION;
1263const char DeleteStationMessage::kCommandString[] = "NL80211_CMD_DEL_STATION";
1264
1265string DeleteStationMessage::ToString() const {
1266 string mac;
1267 GetMacAttributeString(NL80211_ATTR_MAC, &mac);
1268 string output(GetHeaderString());
1269 StringAppendF(&output, "del station %s", mac.c_str());
1270 return output;
1271}
1272
1273const uint8_t DisassociateMessage::kCommand = NL80211_CMD_DISASSOCIATE;
1274const char DisassociateMessage::kCommandString[] = "NL80211_CMD_DISASSOCIATE";
1275
1276string DisassociateMessage::ToString() const {
1277 string output(GetHeaderString());
1278 StringAppendF(&output, "disassoc%s",
1279 StringFromFrame(NL80211_ATTR_FRAME).c_str());
1280 return output;
1281}
1282
1283const uint8_t DisconnectMessage::kCommand = NL80211_CMD_DISCONNECT;
1284const char DisconnectMessage::kCommandString[] = "NL80211_CMD_DISCONNECT";
1285
1286string DisconnectMessage::ToString() const {
1287 string output(GetHeaderString());
1288 StringAppendF(&output, "disconnected %s",
1289 ((AttributeExists(NL80211_ATTR_DISCONNECTED_BY_AP)) ?
1290 "(by AP)" : "(local request)"));
1291
1292 uint16_t reason = UINT16_MAX;
1293 if (GetU16Attribute(NL80211_ATTR_REASON_CODE, &reason)) {
1294 StringAppendF(&output, " reason: %u: %s",
1295 reason, StringFromStatus(reason).c_str());
1296 }
1297 return output;
1298}
1299
1300const uint8_t FrameTxStatusMessage::kCommand = NL80211_CMD_FRAME_TX_STATUS;
1301const char FrameTxStatusMessage::kCommandString[] =
1302 "NL80211_CMD_FRAME_TX_STATUS";
1303
1304string FrameTxStatusMessage::ToString() const {
1305 string output(GetHeaderString());
1306 uint64_t cookie = UINT64_MAX;
1307 GetU64Attribute(NL80211_ATTR_COOKIE, &cookie);
1308
1309 StringAppendF(&output, "mgmt TX status (cookie %" PRIx64 "): %s",
1310 cookie,
1311 (AttributeExists(NL80211_ATTR_ACK) ? "acked" : "no ack"));
1312 return output;
1313}
1314
1315const uint8_t JoinIbssMessage::kCommand = NL80211_CMD_JOIN_IBSS;
1316const char JoinIbssMessage::kCommandString[] = "NL80211_CMD_JOIN_IBSS";
1317
1318string JoinIbssMessage::ToString() const {
1319 string mac;
1320 GetMacAttributeString(NL80211_ATTR_MAC, &mac);
1321 string output(GetHeaderString());
1322 StringAppendF(&output, "IBSS %s joined", mac.c_str());
1323 return output;
1324}
1325
1326const uint8_t MichaelMicFailureMessage::kCommand =
1327 NL80211_CMD_MICHAEL_MIC_FAILURE;
1328const char MichaelMicFailureMessage::kCommandString[] =
1329 "NL80211_CMD_MICHAEL_MIC_FAILURE";
1330
1331string MichaelMicFailureMessage::ToString() const {
1332 string output(GetHeaderString());
1333
1334 output.append("Michael MIC failure event:");
1335
1336 if (AttributeExists(NL80211_ATTR_MAC)) {
1337 string mac;
1338 GetMacAttributeString(NL80211_ATTR_MAC, &mac);
1339 StringAppendF(&output, " source MAC address %s", mac.c_str());
1340 }
1341
1342 if (AttributeExists(NL80211_ATTR_KEY_SEQ)) {
1343 void *rawdata = NULL;
1344 int length = 0;
1345 if (GetRawAttributeData(NL80211_ATTR_KEY_SEQ, &rawdata, &length) &&
1346 rawdata && length == 6) {
1347 const unsigned char *seq = reinterpret_cast<const unsigned char *>(
1348 rawdata);
1349 StringAppendF(&output, " seq=%02x%02x%02x%02x%02x%02x",
1350 seq[0], seq[1], seq[2], seq[3], seq[4], seq[5]);
1351 }
1352 }
1353 uint32_t key_type_val = UINT32_MAX;
1354 if (GetU32Attribute(NL80211_ATTR_KEY_TYPE, &key_type_val)) {
1355 enum nl80211_key_type key_type =
1356 static_cast<enum nl80211_key_type >(key_type_val);
1357 StringAppendF(&output, " Key Type %s", StringFromKeyType(key_type).c_str());
1358 }
1359
1360 uint8_t key_index = UINT8_MAX;
1361 if (GetU8Attribute(NL80211_ATTR_KEY_IDX, &key_index)) {
1362 StringAppendF(&output, " Key Id %u", key_index);
1363 }
1364
1365 return output;
1366}
1367
1368const uint8_t NewScanResultsMessage::kCommand = NL80211_CMD_NEW_SCAN_RESULTS;
1369const char NewScanResultsMessage::kCommandString[] =
1370 "NL80211_CMD_NEW_SCAN_RESULTS";
1371
1372string NewScanResultsMessage::ToString() const {
1373 string output(GetHeaderString());
1374 output.append("scan finished");
1375
1376 {
1377 output.append("; frequencies: ");
1378 vector<uint32_t> list;
1379 if (GetScanFrequenciesAttribute(NL80211_ATTR_SCAN_FREQUENCIES, &list)) {
1380 string str;
1381 for (vector<uint32_t>::const_iterator i = list.begin();
1382 i != list.end(); ++i) {
1383 StringAppendF(&str, " %" PRIu32 ", ", *i);
1384 }
1385 output.append(str);
1386 }
1387 }
1388
1389 {
1390 output.append("; SSIDs: ");
1391 vector<string> list;
1392 if (GetScanSsidsAttribute(NL80211_ATTR_SCAN_SSIDS, &list)) {
1393 string str;
1394 for (vector<string>::const_iterator i = list.begin();
1395 i != list.end(); ++i) {
1396 StringAppendF(&str, "\"%s\", ", i->c_str());
1397 }
1398 output.append(str);
1399 }
1400 }
1401
1402 return output;
1403}
1404
1405const uint8_t NewStationMessage::kCommand = NL80211_CMD_NEW_STATION;
1406const char NewStationMessage::kCommandString[] = "NL80211_CMD_NEW_STATION";
1407
1408string NewStationMessage::ToString() const {
1409 string mac;
1410 GetMacAttributeString(NL80211_ATTR_MAC, &mac);
1411 string output(GetHeaderString());
1412 StringAppendF(&output, "new station %s", mac.c_str());
1413
1414 return output;
1415}
1416
1417const uint8_t NewWifiMessage::kCommand = NL80211_CMD_NEW_WIPHY;
1418const char NewWifiMessage::kCommandString[] = "NL80211_CMD_NEW_WIPHY";
1419
1420string NewWifiMessage::ToString() const {
1421 string output(GetHeaderString());
1422 string wifi_name = "None";
1423 GetStringAttribute(NL80211_ATTR_WIPHY_NAME, &wifi_name);
1424 StringAppendF(&output, "renamed to %s", wifi_name.c_str());
1425 return output;
1426}
1427
1428const uint8_t NotifyCqmMessage::kCommand = NL80211_CMD_NOTIFY_CQM;
1429const char NotifyCqmMessage::kCommandString[] = "NL80211_CMD_NOTIFY_CQM";
1430
1431string NotifyCqmMessage::ToString() const {
1432 static const nla_policy kCqmPolicy[NL80211_ATTR_CQM_MAX + 1] = {
1433 { NLA_U32, 0, 0 }, // Who Knows?
1434 { NLA_U32, 0, 0 }, // [NL80211_ATTR_CQM_RSSI_THOLD]
1435 { NLA_U32, 0, 0 }, // [NL80211_ATTR_CQM_RSSI_HYST]
1436 { NLA_U32, 0, 0 }, // [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]
1437 };
1438
1439 string output(GetHeaderString());
1440 output.append("connection quality monitor event: ");
1441
1442 const nlattr *const_data = GetAttribute(NL80211_ATTR_CQM);
1443 nlattr *cqm_attr = const_cast<nlattr *>(const_data);
1444
1445 nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
1446 if (!AttributeExists(NL80211_ATTR_CQM) || !cqm_attr ||
1447 nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, cqm_attr,
1448 const_cast<nla_policy *>(kCqmPolicy))) {
1449 output.append("missing data!");
1450 return output;
1451 }
1452 if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) {
1453 enum nl80211_cqm_rssi_threshold_event rssi_event =
1454 static_cast<enum nl80211_cqm_rssi_threshold_event>(
1455 nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]));
1456 if (rssi_event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH)
1457 output.append("RSSI went above threshold");
1458 else
1459 output.append("RSSI went below threshold");
1460 } else if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT] &&
1461 AttributeExists(NL80211_ATTR_MAC)) {
1462 string mac;
1463 GetMacAttributeString(NL80211_ATTR_MAC, &mac);
1464 StringAppendF(&output, "peer %s didn't ACK %" PRIu32 " packets",
1465 mac.c_str(),
1466 nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]));
1467 } else {
1468 output.append("unknown event");
1469 }
1470
1471 return output;
1472}
1473
1474const uint8_t PmksaCandidateMessage::kCommand = NL80211_ATTR_PMKSA_CANDIDATE;
1475const char PmksaCandidateMessage::kCommandString[] =
1476 "NL80211_ATTR_PMKSA_CANDIDATE";
1477
1478string PmksaCandidateMessage::ToString() const {
1479 string output(GetHeaderString());
1480 output.append("PMKSA candidate found");
1481 return output;
1482}
1483
1484const uint8_t RegBeaconHintMessage::kCommand = NL80211_CMD_REG_BEACON_HINT;
1485const char RegBeaconHintMessage::kCommandString[] =
1486 "NL80211_CMD_REG_BEACON_HINT";
1487
1488string RegBeaconHintMessage::ToString() const {
1489 string output(GetHeaderString());
1490 uint32_t wiphy_idx = UINT32_MAX;
1491 GetU32Attribute(NL80211_ATTR_WIPHY, &wiphy_idx);
1492
1493 const nlattr *const_before = GetAttribute(NL80211_ATTR_FREQ_BEFORE);
1494 ieee80211_beacon_channel chan_before_beacon;
1495 memset(&chan_before_beacon, 0, sizeof(chan_before_beacon));
1496 if (ParseBeaconHintChan(const_before, &chan_before_beacon))
1497 return "";
1498
1499 const nlattr *const_after = GetAttribute(NL80211_ATTR_FREQ_AFTER);
1500 ieee80211_beacon_channel chan_after_beacon;
1501 memset(&chan_after_beacon, 0, sizeof(chan_after_beacon));
1502 if (ParseBeaconHintChan(const_after, &chan_after_beacon))
1503 return "";
1504
1505 if (chan_before_beacon.center_freq != chan_after_beacon.center_freq)
1506 return "";
1507
1508 /* A beacon hint is sent _only_ if something _did_ change */
1509 output.append("beacon hint:");
1510 StringAppendF(&output, "phy%" PRIu32 " %u MHz [%d]:",
1511 wiphy_idx, chan_before_beacon.center_freq,
1512 ChannelFromIeee80211Frequency(chan_before_beacon.center_freq));
1513
1514 if (chan_before_beacon.passive_scan && !chan_after_beacon.passive_scan)
1515 output.append("\to active scanning enabled");
1516 if (chan_before_beacon.no_ibss && !chan_after_beacon.no_ibss)
1517 output.append("\to beaconing enabled");
1518 return output;
1519}
1520
1521int RegBeaconHintMessage::ParseBeaconHintChan(const nlattr *tb,
1522 ieee80211_beacon_channel *chan)
1523 const {
1524 static const nla_policy kBeaconFreqPolicy[
1525 NL80211_FREQUENCY_ATTR_MAX + 1] = {
1526 {0, 0, 0},
1527 { NLA_U32, 0, 0 }, // [NL80211_FREQUENCY_ATTR_FREQ]
1528 {0, 0, 0},
1529 { NLA_FLAG, 0, 0 }, // [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]
1530 { NLA_FLAG, 0, 0 }, // [NL80211_FREQUENCY_ATTR_NO_IBSS]
1531 };
1532
1533 if (!tb) {
1534 LOG(ERROR) << "|tb| parameter is NULL.";
1535 return -EINVAL;
1536 }
1537
1538 if (!chan) {
1539 LOG(ERROR) << "|chan| parameter is NULL.";
1540 return -EINVAL;
1541 }
1542
1543 nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
1544
1545 if (nla_parse_nested(tb_freq,
1546 NL80211_FREQUENCY_ATTR_MAX,
1547 const_cast<nlattr *>(tb),
1548 const_cast<nla_policy *>(kBeaconFreqPolicy)))
1549 return -EINVAL;
1550
1551 chan->center_freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
1552
1553 if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
1554 chan->passive_scan = true;
1555 if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
1556 chan->no_ibss = true;
1557
1558 return 0;
1559}
1560
1561int RegBeaconHintMessage::ChannelFromIeee80211Frequency(int freq) {
1562 // TODO(wdg): get rid of these magic numbers.
1563 if (freq == 2484)
1564 return 14;
1565
1566 if (freq < 2484)
1567 return (freq - 2407) / 5;
1568
1569 /* FIXME: dot11ChannelStartingFactor (802.11-2007 17.3.8.3.2) */
1570 return freq/5 - 1000;
1571}
1572
1573const uint8_t RegChangeMessage::kCommand = NL80211_CMD_REG_CHANGE;
1574const char RegChangeMessage::kCommandString[] = "NL80211_CMD_REG_CHANGE";
1575
1576string RegChangeMessage::ToString() const {
1577 string output(GetHeaderString());
1578 output.append("regulatory domain change: ");
1579
1580 uint8_t reg_type = UINT8_MAX;
1581 GetU8Attribute(NL80211_ATTR_REG_TYPE, &reg_type);
1582
1583 uint32_t initiator = UINT32_MAX;
1584 GetU32Attribute(NL80211_ATTR_REG_INITIATOR, &initiator);
1585
1586 uint32_t wifi = UINT32_MAX;
1587 bool wifi_exists = GetU32Attribute(NL80211_ATTR_WIPHY, &wifi);
1588
1589 string alpha2 = "<None>";
1590 GetStringAttribute(NL80211_ATTR_REG_ALPHA2, &alpha2);
1591
1592 switch (reg_type) {
1593 case NL80211_REGDOM_TYPE_COUNTRY:
1594 StringAppendF(&output, "set to %s by %s request",
1595 alpha2.c_str(), StringFromRegInitiator(initiator).c_str());
1596 if (wifi_exists)
1597 StringAppendF(&output, " on phy%" PRIu32, wifi);
1598 break;
1599
1600 case NL80211_REGDOM_TYPE_WORLD:
1601 StringAppendF(&output, "set to world roaming by %s request",
1602 StringFromRegInitiator(initiator).c_str());
1603 break;
1604
1605 case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
1606 StringAppendF(&output,
1607 "custom world roaming rules in place on phy%" PRIu32
1608 " by %s request",
1609 wifi, StringFromRegInitiator(initiator).c_str());
1610 break;
1611
1612 case NL80211_REGDOM_TYPE_INTERSECTION:
1613 StringAppendF(&output, "intersection used due to a request made by %s",
1614 StringFromRegInitiator(initiator).c_str());
1615 if (wifi_exists)
1616 StringAppendF(&output, " on phy%" PRIu32, wifi);
1617 break;
1618
1619 default:
1620 output.append("unknown source");
1621 break;
1622 }
1623 return output;
1624}
1625
1626const uint8_t RemainOnChannelMessage::kCommand = NL80211_CMD_REMAIN_ON_CHANNEL;
1627const char RemainOnChannelMessage::kCommandString[] =
1628 "NL80211_CMD_REMAIN_ON_CHANNEL";
1629
1630string RemainOnChannelMessage::ToString() const {
1631 string output(GetHeaderString());
1632
1633 uint32_t wifi_freq = UINT32_MAX;
1634 GetU32Attribute(NL80211_ATTR_WIPHY_FREQ, &wifi_freq);
1635
1636 uint32_t duration = UINT32_MAX;
1637 GetU32Attribute(NL80211_ATTR_DURATION, &duration);
1638
1639 uint64_t cookie = UINT64_MAX;
1640 GetU64Attribute(NL80211_ATTR_COOKIE, &cookie);
1641
1642 StringAppendF(&output, "remain on freq %" PRIu32 " (%" PRIu32 "ms, cookie %"
1643 PRIx64 ")",
1644 wifi_freq, duration, cookie);
1645 return output;
1646}
1647
1648const uint8_t RoamMessage::kCommand = NL80211_CMD_ROAM;
1649const char RoamMessage::kCommandString[] = "NL80211_CMD_ROAM";
1650
1651string RoamMessage::ToString() const {
1652 string output(GetHeaderString());
1653 output.append("roamed");
1654
1655 if (AttributeExists(NL80211_ATTR_MAC)) {
1656 string mac;
1657 GetMacAttributeString(NL80211_ATTR_MAC, &mac);
1658 StringAppendF(&output, " to %s", mac.c_str());
1659 }
1660 return output;
1661}
1662
1663const uint8_t ScanAbortedMessage::kCommand = NL80211_CMD_SCAN_ABORTED;
1664const char ScanAbortedMessage::kCommandString[] = "NL80211_CMD_SCAN_ABORTED";
1665
1666string ScanAbortedMessage::ToString() const {
1667 string output(GetHeaderString());
1668 output.append("scan aborted");
1669
1670 {
1671 output.append("; frequencies: ");
1672 vector<uint32_t> list;
1673 if (GetScanFrequenciesAttribute(NL80211_ATTR_SCAN_FREQUENCIES, &list)) {
1674 string str;
1675 for (vector<uint32_t>::const_iterator i = list.begin();
1676 i != list.end(); ++i) {
1677 StringAppendF(&str, " %" PRIu32 ", ", *i);
1678 }
1679 output.append(str);
1680 }
1681 }
1682
1683 {
1684 output.append("; SSIDs: ");
1685 vector<string> list;
1686 if (GetScanSsidsAttribute(NL80211_ATTR_SCAN_SSIDS, &list)) {
1687 string str;
1688 for (vector<string>::const_iterator i = list.begin();
1689 i != list.end(); ++i) {
1690 StringAppendF(&str, "\"%s\", ", i->c_str());
1691 }
1692 output.append(str);
1693 }
1694 }
1695
1696 return output;
1697}
1698
1699const uint8_t TriggerScanMessage::kCommand = NL80211_CMD_TRIGGER_SCAN;
1700const char TriggerScanMessage::kCommandString[] = "NL80211_CMD_TRIGGER_SCAN";
1701
1702string TriggerScanMessage::ToString() const {
1703 string output(GetHeaderString());
1704 output.append("scan started");
1705
1706 {
1707 output.append("; frequencies: ");
1708 vector<uint32_t> list;
1709 if (GetScanFrequenciesAttribute(NL80211_ATTR_SCAN_FREQUENCIES, &list)) {
1710 string str;
1711 for (vector<uint32_t>::const_iterator i = list.begin();
1712 i != list.end(); ++i) {
1713 StringAppendF(&str, "%" PRIu32 ", ", *i);
1714 }
1715 output.append(str);
1716 }
1717 }
1718
1719 {
1720 output.append("; SSIDs: ");
1721 vector<string> list;
1722 if (GetScanSsidsAttribute(NL80211_ATTR_SCAN_SSIDS, &list)) {
1723 string str;
1724 for (vector<string>::const_iterator i = list.begin();
1725 i != list.end(); ++i) {
1726 StringAppendF(&str, "\"%s\", ", i->c_str());
1727 }
1728 output.append(str);
1729 }
1730 }
1731
1732 return output;
1733}
1734
1735const uint8_t UnknownMessage::kCommand = 0xff;
1736const char UnknownMessage::kCommandString[] = "<Unknown Message Type>";
1737
1738string UnknownMessage::ToString() const {
1739 string output(GetHeaderString());
1740 StringAppendF(&output, "unknown event %u", command_);
1741 return output;
1742}
1743
1744const uint8_t UnprotDeauthenticateMessage::kCommand =
1745 NL80211_CMD_UNPROT_DEAUTHENTICATE;
1746const char UnprotDeauthenticateMessage::kCommandString[] =
1747 "NL80211_CMD_UNPROT_DEAUTHENTICATE";
1748
1749string UnprotDeauthenticateMessage::ToString() const {
1750 string output(GetHeaderString());
1751 StringAppendF(&output, "unprotected deauth %s",
1752 StringFromFrame(NL80211_ATTR_FRAME).c_str());
1753 return output;
1754}
1755
1756const uint8_t UnprotDisassociateMessage::kCommand =
1757 NL80211_CMD_UNPROT_DISASSOCIATE;
1758const char UnprotDisassociateMessage::kCommandString[] =
1759 "NL80211_CMD_UNPROT_DISASSOCIATE";
1760
1761string UnprotDisassociateMessage::ToString() const {
1762 string output(GetHeaderString());
1763 StringAppendF(&output, "unprotected disassoc %s",
1764 StringFromFrame(NL80211_ATTR_FRAME).c_str());
1765 return output;
1766}
1767
1768//
1769// Factory class.
1770//
1771
1772UserBoundNlMessage *UserBoundNlMessageFactory::CreateMessage(nlmsghdr *msg) {
1773 if (!msg) {
1774 LOG(ERROR) << "NULL |msg| parameter";
1775 return NULL;
1776 }
1777
1778 scoped_ptr<UserBoundNlMessage> message;
1779 genlmsghdr *gnlh =
1780 reinterpret_cast<genlmsghdr *>(nlmsg_data(msg));
1781
1782 if (!gnlh) {
1783 LOG(ERROR) << "NULL gnlh";
1784 return NULL;
1785 }
1786
1787 switch (gnlh->cmd) {
1788 case AssociateMessage::kCommand:
1789 message.reset(new AssociateMessage()); break;
1790 case AuthenticateMessage::kCommand:
1791 message.reset(new AuthenticateMessage()); break;
1792 case CancelRemainOnChannelMessage::kCommand:
1793 message.reset(new CancelRemainOnChannelMessage()); break;
1794 case ConnectMessage::kCommand:
1795 message.reset(new ConnectMessage()); break;
1796 case DeauthenticateMessage::kCommand:
1797 message.reset(new DeauthenticateMessage()); break;
Wade Guthrie0d438532012-05-18 14:18:50 -07001798 case DeleteStationMessage::kCommand:
1799 message.reset(new DeleteStationMessage()); break;
Wade Guthrie0d438532012-05-18 14:18:50 -07001800 case DisassociateMessage::kCommand:
1801 message.reset(new DisassociateMessage()); break;
1802 case DisconnectMessage::kCommand:
1803 message.reset(new DisconnectMessage()); break;
1804 case FrameTxStatusMessage::kCommand:
1805 message.reset(new FrameTxStatusMessage()); break;
1806 case JoinIbssMessage::kCommand:
1807 message.reset(new JoinIbssMessage()); break;
1808 case MichaelMicFailureMessage::kCommand:
1809 message.reset(new MichaelMicFailureMessage()); break;
1810 case NewScanResultsMessage::kCommand:
1811 message.reset(new NewScanResultsMessage()); break;
1812 case NewStationMessage::kCommand:
1813 message.reset(new NewStationMessage()); break;
1814 case NewWifiMessage::kCommand:
1815 message.reset(new NewWifiMessage()); break;
1816 case NotifyCqmMessage::kCommand:
1817 message.reset(new NotifyCqmMessage()); break;
1818 case PmksaCandidateMessage::kCommand:
1819 message.reset(new PmksaCandidateMessage()); break;
1820 case RegBeaconHintMessage::kCommand:
1821 message.reset(new RegBeaconHintMessage()); break;
1822 case RegChangeMessage::kCommand:
1823 message.reset(new RegChangeMessage()); break;
1824 case RemainOnChannelMessage::kCommand:
1825 message.reset(new RemainOnChannelMessage()); break;
1826 case RoamMessage::kCommand:
1827 message.reset(new RoamMessage()); break;
1828 case ScanAbortedMessage::kCommand:
1829 message.reset(new ScanAbortedMessage()); break;
1830 case TriggerScanMessage::kCommand:
1831 message.reset(new TriggerScanMessage()); break;
1832 case UnprotDeauthenticateMessage::kCommand:
1833 message.reset(new UnprotDeauthenticateMessage()); break;
1834 case UnprotDisassociateMessage::kCommand:
1835 message.reset(new UnprotDisassociateMessage()); break;
1836
1837 default:
1838 message.reset(new UnknownMessage(gnlh->cmd)); break;
1839 break;
1840 }
1841
1842 nlattr *tb[NL80211_ATTR_MAX + 1];
1843
1844 // Parse the attributes from the nl message payload (which starts at the
1845 // header) into the 'tb' array.
1846 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
1847 genlmsg_attrlen(gnlh, 0), NULL);
1848
1849 if (!message->Init(tb, msg)) {
1850 LOG(ERROR) << "Message did not initialize properly";
1851 return NULL;
1852 }
1853
Wade Guthrie0d438532012-05-18 14:18:50 -07001854 return message.release();
1855}
1856
1857UserBoundNlMessageDataCollector *
1858 UserBoundNlMessageDataCollector::GetInstance() {
1859 return g_datacollector.Pointer();
1860}
1861
1862UserBoundNlMessageDataCollector::UserBoundNlMessageDataCollector() {
1863 need_to_print[NL80211_ATTR_PMKSA_CANDIDATE] = true;
1864 need_to_print[NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL] = true;
1865 need_to_print[NL80211_CMD_DEL_STATION] = true;
1866 need_to_print[NL80211_CMD_FRAME_TX_STATUS] = true;
1867 need_to_print[NL80211_CMD_JOIN_IBSS] = true;
1868 need_to_print[NL80211_CMD_MICHAEL_MIC_FAILURE] = true;
1869 need_to_print[NL80211_CMD_NEW_WIPHY] = true;
1870 need_to_print[NL80211_CMD_REG_BEACON_HINT] = true;
1871 need_to_print[NL80211_CMD_REG_CHANGE] = true;
1872 need_to_print[NL80211_CMD_REMAIN_ON_CHANNEL] = true;
1873 need_to_print[NL80211_CMD_ROAM] = true;
1874 need_to_print[NL80211_CMD_SCAN_ABORTED] = true;
1875 need_to_print[NL80211_CMD_UNPROT_DEAUTHENTICATE] = true;
1876 need_to_print[NL80211_CMD_UNPROT_DISASSOCIATE] = true;
1877}
1878
1879void UserBoundNlMessageDataCollector::CollectDebugData(
1880 const UserBoundNlMessage &message, nlmsghdr *msg)
1881{
1882 if (!msg) {
1883 LOG(ERROR) << "NULL |msg| parameter";
1884 return;
1885 }
1886
1887 bool doit = false;
1888
1889 map<uint8_t, bool>::const_iterator node;
1890 node = need_to_print.find(message.GetMessageType());
1891 if (node != need_to_print.end())
1892 doit = node->second;
1893
1894 if (doit) {
Wade Guthried6153612012-08-23 11:36:14 -07001895 LOG(INFO) << "@@const unsigned char "
Wade Guthrie0d438532012-05-18 14:18:50 -07001896 << "k" << message.GetMessageTypeString()
Wade Guthried6153612012-08-23 11:36:14 -07001897 << "[] = {";
Wade Guthrie0d438532012-05-18 14:18:50 -07001898
1899 int payload_bytes = nlmsg_len(msg);
1900
1901 size_t bytes = nlmsg_total_size(payload_bytes);
1902 unsigned char *rawdata = reinterpret_cast<unsigned char *>(msg);
1903 for (size_t i=0; i<bytes; ++i) {
Wade Guthried6153612012-08-23 11:36:14 -07001904 LOG(INFO) << " 0x"
Wade Guthrie0d438532012-05-18 14:18:50 -07001905 << std::hex << std::setfill('0') << std::setw(2)
1906 << + rawdata[i] << ",";
1907 }
Wade Guthried6153612012-08-23 11:36:14 -07001908 LOG(INFO) << "};";
Wade Guthrie0d438532012-05-18 14:18:50 -07001909 need_to_print[message.GetMessageType()] = false;
1910 }
1911}
1912
1913} // namespace shill.