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