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