blob: c0c24009412889d2a7bc947501d88209943cb4f4 [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
repo syncdc085c82012-12-28 08:54:41 -080025#include "shill/nl80211_message.h"
Wade Guthrie0d438532012-05-18 14:18:50 -070026
Wade Guthriebdcdaa72013-03-04 12:47:12 -080027#include <limits.h>
Wade Guthrie0d438532012-05-18 14:18:50 -070028#include <netlink/attr.h>
Wade Guthrie0d438532012-05-18 14:18:50 -070029#include <netlink/msg.h>
30#include <netlink/netlink.h>
31
Wade Guthrie8e278612013-02-26 10:32:34 -080032#include <algorithm>
Wade Guthrie89e6cb32013-03-07 08:03:45 -080033#include <map>
Wade Guthrie0d438532012-05-18 14:18:50 -070034#include <string>
Wade Guthrie89e6cb32013-03-07 08:03:45 -080035#include <vector>
Wade Guthrie0d438532012-05-18 14:18:50 -070036
Wade Guthrie68da97c2013-02-26 13:09:35 -080037#include <base/bind.h>
Wade Guthrie0d438532012-05-18 14:18:50 -070038#include <base/format_macros.h>
Wade Guthrie12f113a2013-03-12 17:15:46 -070039#include <base/stl_util.h>
Wade Guthrie0d438532012-05-18 14:18:50 -070040#include <base/stringprintf.h>
41
repo sync90ee0fa2012-12-18 10:08:08 -080042#include "shill/attribute_list.h"
Wade Guthrie0d438532012-05-18 14:18:50 -070043#include "shill/ieee80211.h"
44#include "shill/logging.h"
Wade Guthrief162f8b2013-02-27 14:13:55 -080045#include "shill/netlink_attribute.h"
Wade Guthrie89e6cb32013-03-07 08:03:45 -080046#include "shill/refptr_types.h"
Wade Guthrie0d438532012-05-18 14:18:50 -070047
Wade Guthrie68da97c2013-02-26 13:09:35 -080048using base::Bind;
Wade Guthrie0d438532012-05-18 14:18:50 -070049using base::LazyInstance;
50using base::StringAppendF;
51using base::StringPrintf;
52using std::map;
Wade Guthrie8e278612013-02-26 10:32:34 -080053using std::min;
Wade Guthrie0d438532012-05-18 14:18:50 -070054using std::string;
55using std::vector;
56
57namespace shill {
58
59namespace {
repo syncdc085c82012-12-28 08:54:41 -080060LazyInstance<Nl80211MessageDataCollector> g_datacollector =
Wade Guthrie0d438532012-05-18 14:18:50 -070061 LAZY_INSTANCE_INITIALIZER;
62} // namespace
63
Wade Guthrie0d438532012-05-18 14:18:50 -070064const uint8_t Nl80211Frame::kMinimumFrameByteCount = 26;
65const uint8_t Nl80211Frame::kFrameTypeMask = 0xfc;
66
Wade Guthrief48a1952013-03-04 17:33:47 -080067const uint32_t NetlinkMessage::kBroadcastSequenceNumber = 0;
68const uint16_t NetlinkMessage::kIllegalMessageType = UINT16_MAX;
Wade Guthriebdcdaa72013-03-04 12:47:12 -080069
70const char Nl80211Message::kBogusMacAddress[] = "XX:XX:XX:XX:XX:XX";
repo syncdc085c82012-12-28 08:54:41 -080071const unsigned int Nl80211Message::kEthernetAddressBytes = 6;
Wade Guthriebee87c22013-03-06 11:00:46 -080072const char Nl80211Message::kMessageTypeString[] = "nl80211";
repo syncdc085c82012-12-28 08:54:41 -080073map<uint16_t, string> *Nl80211Message::reason_code_string_ = NULL;
74map<uint16_t, string> *Nl80211Message::status_code_string_ = NULL;
Wade Guthriebdcdaa72013-03-04 12:47:12 -080075uint16_t Nl80211Message::nl80211_message_type_ = kIllegalMessageType;
76
Wade Guthrief48a1952013-03-04 17:33:47 -080077// NetlinkMessage
Wade Guthrie0d438532012-05-18 14:18:50 -070078
Wade Guthriebee87c22013-03-06 11:00:46 -080079ByteString NetlinkMessage::EncodeHeader(uint32_t sequence_number) {
Wade Guthrief48a1952013-03-04 17:33:47 -080080 ByteString result;
Wade Guthriebee87c22013-03-06 11:00:46 -080081 if (message_type_ == kIllegalMessageType) {
82 LOG(ERROR) << "Message type not set";
83 return result;
84 }
Wade Guthrief48a1952013-03-04 17:33:47 -080085 sequence_number_ = sequence_number;
86 if (sequence_number_ == kBroadcastSequenceNumber) {
87 LOG(ERROR) << "Couldn't get a legal sequence number";
88 return result;
89 }
Wade Guthrie0d438532012-05-18 14:18:50 -070090
Wade Guthrief48a1952013-03-04 17:33:47 -080091 // Build netlink header.
92 nlmsghdr header;
93 size_t nlmsghdr_with_pad = NLMSG_ALIGN(sizeof(header));
94 header.nlmsg_len = nlmsghdr_with_pad;
Wade Guthriebee87c22013-03-06 11:00:46 -080095 header.nlmsg_type = message_type_;
Wade Guthrief48a1952013-03-04 17:33:47 -080096 header.nlmsg_flags = NLM_F_REQUEST | flags_;
97 header.nlmsg_seq = sequence_number_;
98 header.nlmsg_pid = getpid();
Wade Guthrie0d438532012-05-18 14:18:50 -070099
Wade Guthrief48a1952013-03-04 17:33:47 -0800100 // Netlink header + pad.
101 result.Append(ByteString(reinterpret_cast<unsigned char *>(&header),
102 sizeof(header)));
103 result.Resize(nlmsghdr_with_pad); // Zero-fill pad space (if any).
104 return result;
105}
106
107bool NetlinkMessage::InitAndStripHeader(ByteString *input) {
Wade Guthriebdcdaa72013-03-04 12:47:12 -0800108 if (!input) {
109 LOG(ERROR) << "NULL input";
110 return false;
111 }
Wade Guthrief48a1952013-03-04 17:33:47 -0800112 if (input->GetLength() < sizeof(nlmsghdr)) {
113 LOG(ERROR) << "Insufficient input to extract nlmsghdr";
114 return false;
115 }
116
Wade Guthriebdcdaa72013-03-04 12:47:12 -0800117 // Read the nlmsghdr.
118 nlmsghdr *header = reinterpret_cast<nlmsghdr *>(input->GetData());
119 message_type_ = header->nlmsg_type;
120 flags_ = header->nlmsg_flags;
121 sequence_number_ = header->nlmsg_seq;
122
123 // Strip the nlmsghdr.
124 input->RemovePrefix(NLMSG_ALIGN(sizeof(struct nlmsghdr)));
Wade Guthrief48a1952013-03-04 17:33:47 -0800125 return true;
126}
127
128bool NetlinkMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
129 if (!const_msg) {
130 LOG(ERROR) << "Null |const_msg| parameter";
131 return false;
132 }
133 ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
134 const_msg->nlmsg_len);
135 if (!InitAndStripHeader(&message)) {
136 return false;
137 }
138 return true;
139}
140
141// static
142void NetlinkMessage::PrintBytes(int log_level, const unsigned char *buf,
143 size_t num_bytes) {
144 SLOG(WiFi, log_level) << "Netlink Message -- Examining Bytes";
145 if (!buf) {
146 SLOG(WiFi, log_level) << "<NULL Buffer>";
147 return;
148 }
149
150 if (num_bytes >= sizeof(nlmsghdr)) {
151 const nlmsghdr *header = reinterpret_cast<const nlmsghdr *>(buf);
152 SLOG(WiFi, log_level) << StringPrintf(
153 "len: %02x %02x %02x %02x = %u bytes",
154 buf[0], buf[1], buf[2], buf[3], header->nlmsg_len);
155
156 SLOG(WiFi, log_level) << StringPrintf(
157 "type | flags: %02x %02x %02x %02x - type:%u flags:%s%s%s%s%s",
158 buf[4], buf[5], buf[6], buf[7], header->nlmsg_type,
159 ((header->nlmsg_flags & NLM_F_REQUEST) ? " REQUEST" : ""),
160 ((header->nlmsg_flags & NLM_F_MULTI) ? " MULTI" : ""),
161 ((header->nlmsg_flags & NLM_F_ACK) ? " ACK" : ""),
162 ((header->nlmsg_flags & NLM_F_ECHO) ? " ECHO" : ""),
163 ((header->nlmsg_flags & NLM_F_DUMP_INTR) ? " BAD-SEQ" : ""));
164
165 SLOG(WiFi, log_level) << StringPrintf(
166 "sequence: %02x %02x %02x %02x = %u",
167 buf[8], buf[9], buf[10], buf[11], header->nlmsg_seq);
168 SLOG(WiFi, log_level) << StringPrintf(
169 "pid: %02x %02x %02x %02x = %u",
170 buf[12], buf[13], buf[14], buf[15], header->nlmsg_pid);
171 buf += sizeof(nlmsghdr);
172 num_bytes -= sizeof(nlmsghdr);
173 } else {
174 SLOG(WiFi, log_level) << "Not enough bytes (" << num_bytes
175 << ") for a complete nlmsghdr (requires "
176 << sizeof(nlmsghdr) << ").";
177 }
178
179 while (num_bytes) {
180 string output;
181 size_t bytes_this_row = min(num_bytes, static_cast<size_t>(32));
182 for (size_t i = 0; i < bytes_this_row; ++i) {
183 StringAppendF(&output, " %02x", *buf++);
184 }
185 SLOG(WiFi, log_level) << output;
186 num_bytes -= bytes_this_row;
187 }
188}
189
Wade Guthrie12f113a2013-03-12 17:15:46 -0700190// ErrorAckMessage.
191
Wade Guthrie71872472013-03-05 10:33:38 -0800192const uint16_t ErrorAckMessage::kMessageType = NLMSG_ERROR;
193
194bool ErrorAckMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
195 if (!const_msg) {
196 LOG(ERROR) << "Null |const_msg| parameter";
197 return false;
198 }
199 ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
200 const_msg->nlmsg_len);
201 if (!InitAndStripHeader(&message)) {
202 return false;
203 }
204
205 // Get the error code from the payload.
206 error_ = *(reinterpret_cast<const uint32_t *>(message.GetConstData()));
207 return true;
208}
209
Wade Guthriebee87c22013-03-06 11:00:46 -0800210ByteString ErrorAckMessage::Encode(uint32_t sequence_number) {
Wade Guthrie71872472013-03-05 10:33:38 -0800211 LOG(ERROR) << "We're not supposed to send errors or Acks to the kernel";
212 return ByteString();
213}
214
215string ErrorAckMessage::ToString() const {
216 string output;
217 if (error()) {
218 StringAppendF(&output, "NL80211_ERROR 0x%" PRIx32 ": %s",
219 -error_, strerror(-error_));
220 } else {
221 StringAppendF(&output, "ACK");
222 }
223 return output;
224}
225
226void ErrorAckMessage::Print(int log_level) const {
227 SLOG(WiFi, log_level) << ToString();
228}
229
Wade Guthrie12f113a2013-03-12 17:15:46 -0700230// NoopMessage.
231
Wade Guthrie71872472013-03-05 10:33:38 -0800232const uint16_t NoopMessage::kMessageType = NLMSG_NOOP;
233
Wade Guthriebee87c22013-03-06 11:00:46 -0800234ByteString NoopMessage::Encode(uint32_t sequence_number) {
Wade Guthrie71872472013-03-05 10:33:38 -0800235 LOG(ERROR) << "We're not supposed to send NOOP to the kernel";
236 return ByteString();
237}
238
239void NoopMessage::Print(int log_level) const {
240 SLOG(WiFi, log_level) << ToString();
241}
242
Wade Guthrie12f113a2013-03-12 17:15:46 -0700243// DoneMessage.
244
Wade Guthrie71872472013-03-05 10:33:38 -0800245const uint16_t DoneMessage::kMessageType = NLMSG_DONE;
246
Wade Guthriebee87c22013-03-06 11:00:46 -0800247ByteString DoneMessage::Encode(uint32_t sequence_number) {
Wade Guthrie71872472013-03-05 10:33:38 -0800248 LOG(ERROR)
249 << "We're not supposed to send Done messages (are we?) to the kernel";
250 return ByteString();
251}
252
253void DoneMessage::Print(int log_level) const {
254 SLOG(WiFi, log_level) << ToString();
255}
256
Wade Guthrie12f113a2013-03-12 17:15:46 -0700257// OverrunMessage.
258
Wade Guthrie71872472013-03-05 10:33:38 -0800259const uint16_t OverrunMessage::kMessageType = NLMSG_OVERRUN;
260
Wade Guthriebee87c22013-03-06 11:00:46 -0800261ByteString OverrunMessage::Encode(uint32_t sequence_number) {
Wade Guthrie71872472013-03-05 10:33:38 -0800262 LOG(ERROR) << "We're not supposed to send Overruns to the kernel";
263 return ByteString();
264}
265
266void OverrunMessage::Print(int log_level) const {
267 SLOG(WiFi, log_level) << ToString();
268}
269
Wade Guthrie12f113a2013-03-12 17:15:46 -0700270// UnknownMessage.
271
272ByteString UnknownMessage::Encode(uint32_t sequence_number) {
273 LOG(ERROR) << "We're not supposed to send UNKNOWN messages to the kernel";
274 return ByteString();
275}
276
277void UnknownMessage::Print(int log_level) const {
278 int total_bytes = message_body_.GetLength();
279 const uint8_t *const_data = message_body_.GetConstData();
280
281 string output = StringPrintf("%d bytes:", total_bytes);
282 for (int i = 0; i < total_bytes; ++i) {
283 StringAppendF(&output, " 0x%02x", const_data[i]);
284 }
285 SLOG(WiFi, log_level) << output;
286}
287
Wade Guthrief48a1952013-03-04 17:33:47 -0800288// GenericNetlinkMessage
289
Wade Guthriebee87c22013-03-06 11:00:46 -0800290ByteString GenericNetlinkMessage::EncodeHeader(uint32_t sequence_number) {
Wade Guthrief48a1952013-03-04 17:33:47 -0800291 // Build nlmsghdr.
Wade Guthriebee87c22013-03-06 11:00:46 -0800292 ByteString result(NetlinkMessage::EncodeHeader(sequence_number));
Wade Guthrief48a1952013-03-04 17:33:47 -0800293 if (result.GetLength() == 0) {
294 LOG(ERROR) << "Couldn't encode message header.";
295 return result;
296 }
297
298 // Build and append the genl message header.
299 genlmsghdr genl_header;
300 genl_header.cmd = command();
301 genl_header.version = 1;
302 genl_header.reserved = 0;
303
304 ByteString genl_header_string(
305 reinterpret_cast<unsigned char *>(&genl_header), sizeof(genl_header));
306 size_t genlmsghdr_with_pad = NLMSG_ALIGN(sizeof(genl_header));
307 genl_header_string.Resize(genlmsghdr_with_pad); // Zero-fill.
308
309 nlmsghdr *pheader = reinterpret_cast<nlmsghdr *>(result.GetData());
310 pheader->nlmsg_len += genlmsghdr_with_pad;
311 result.Append(genl_header_string);
312 return result;
313}
314
Wade Guthriebee87c22013-03-06 11:00:46 -0800315ByteString GenericNetlinkMessage::Encode(uint32_t sequence_number) {
316 ByteString result(EncodeHeader(sequence_number));
Wade Guthrief48a1952013-03-04 17:33:47 -0800317 if (result.GetLength() == 0) {
318 LOG(ERROR) << "Couldn't encode message header.";
319 return result;
320 }
321
322 // Build and append attributes (padding is included by
323 // AttributeList::Encode).
324 ByteString attribute_string = attributes_->Encode();
325
326 // Need to re-calculate |header| since |Append|, above, moves the data.
327 nlmsghdr *pheader = reinterpret_cast<nlmsghdr *>(result.GetData());
328 pheader->nlmsg_len += attribute_string.GetLength();
329 result.Append(attribute_string);
330
331 return result;
332}
333
334bool GenericNetlinkMessage::InitAndStripHeader(ByteString *input) {
335 if (!input) {
336 LOG(ERROR) << "NULL input";
337 return false;
338 }
339 if (!NetlinkMessage::InitAndStripHeader(input)) {
340 return false;
341 }
Wade Guthriebdcdaa72013-03-04 12:47:12 -0800342
343 // Read the genlmsghdr.
344 genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(input->GetData());
345 if (command_ != gnlh->cmd) {
346 LOG(WARNING) << "This object thinks it's a " << command_
347 << " but the message thinks it's a " << gnlh->cmd;
348 }
349
350 // Strip the genlmsghdr.
351 input->RemovePrefix(NLMSG_ALIGN(sizeof(struct genlmsghdr)));
352 return true;
Wade Guthrie8e278612013-02-26 10:32:34 -0800353}
354
Wade Guthrief48a1952013-03-04 17:33:47 -0800355void GenericNetlinkMessage::Print(int log_level) const {
356 SLOG(WiFi, log_level) << StringPrintf("Message %s (%d)",
357 command_string(),
358 command());
359 attributes_->Print(log_level, 1);
360}
361
362// Nl80211Message
363
Wade Guthriebee87c22013-03-06 11:00:46 -0800364// static
365void Nl80211Message::SetMessageType(uint16_t message_type) {
366 if (message_type == NetlinkMessage::kIllegalMessageType) {
367 LOG(FATAL) << "Absolutely need a legal message type for Nl80211 messages.";
368 }
369 nl80211_message_type_ = message_type;
370}
371
repo sync0efa9f02012-12-28 13:40:20 -0800372bool Nl80211Message::InitFromNlmsg(const nlmsghdr *const_msg) {
373 if (!const_msg) {
374 LOG(ERROR) << "Null |msg| parameter";
Wade Guthrie0d438532012-05-18 14:18:50 -0700375 return false;
376 }
Wade Guthriebdcdaa72013-03-04 12:47:12 -0800377 ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
378 const_msg->nlmsg_len);
Wade Guthrie0d438532012-05-18 14:18:50 -0700379
Wade Guthriebdcdaa72013-03-04 12:47:12 -0800380 if (!InitAndStripHeader(&message)) {
381 return false;
382 }
repo sync0efa9f02012-12-28 13:40:20 -0800383
384 // Attributes.
385 // Parse the attributes from the nl message payload into the 'tb' array.
386 nlattr *tb[NL80211_ATTR_MAX + 1];
Wade Guthriebdcdaa72013-03-04 12:47:12 -0800387 nla_parse(tb, NL80211_ATTR_MAX,
388 reinterpret_cast<nlattr *>(message.GetData()), message.GetLength(),
389 NULL);
repo sync0efa9f02012-12-28 13:40:20 -0800390
Wade Guthrie0d438532012-05-18 14:18:50 -0700391 for (int i = 0; i < NL80211_ATTR_MAX + 1; ++i) {
392 if (tb[i]) {
repo sync0efa9f02012-12-28 13:40:20 -0800393 // TODO(wdg): When Nl80211Messages instantiate their own attributes,
394 // this call should, instead, call |SetAttributeFromNlAttr|.
Wade Guthrieefe1f0c2013-02-26 17:42:01 -0800395 attributes_->CreateAndInitAttribute(
Wade Guthrie68da97c2013-02-26 13:09:35 -0800396 i, tb[i], Bind(&NetlinkAttribute::NewNl80211AttributeFromId));
Wade Guthrie0d438532012-05-18 14:18:50 -0700397 }
398 }
399
400 // Convert integer values provided by libnl (for example, from the
401 // NL80211_ATTR_STATUS_CODE or NL80211_ATTR_REASON_CODE attribute) into
402 // strings describing the status.
Wade Guthried4977f22012-08-22 12:37:54 -0700403 if (!reason_code_string_) {
404 reason_code_string_ = new map<uint16_t, string>;
405 (*reason_code_string_)[IEEE_80211::kReasonCodeUnspecified] =
406 "Unspecified reason";
407 (*reason_code_string_)[
408 IEEE_80211::kReasonCodePreviousAuthenticationInvalid] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700409 "Previous authentication no longer valid";
Wade Guthried4977f22012-08-22 12:37:54 -0700410 (*reason_code_string_)[IEEE_80211::kReasonCodeSenderHasLeft] =
411 "Deauthentcated because sending STA is leaving (or has left) IBSS or "
412 "ESS";
413 (*reason_code_string_)[IEEE_80211::kReasonCodeInactivity] =
414 "Disassociated due to inactivity";
415 (*reason_code_string_)[IEEE_80211::kReasonCodeTooManySTAs] =
416 "Disassociated because AP is unable to handle all currently associated "
417 "STAs";
418 (*reason_code_string_)[IEEE_80211::kReasonCodeNonAuthenticated] =
419 "Class 2 frame received from nonauthenticated STA";
420 (*reason_code_string_)[IEEE_80211::kReasonCodeNonAssociated] =
421 "Class 3 frame received from nonassociated STA";
422 (*reason_code_string_)[IEEE_80211::kReasonCodeDisassociatedHasLeft] =
423 "Disassociated because sending STA is leaving (or has left) BSS";
424 (*reason_code_string_)[
425 IEEE_80211::kReasonCodeReassociationNotAuthenticated] =
426 "STA requesting (re)association is not authenticated with responding "
427 "STA";
428 (*reason_code_string_)[IEEE_80211::kReasonCodeUnacceptablePowerCapability] =
429 "Disassociated because the information in the Power Capability "
430 "element is unacceptable";
431 (*reason_code_string_)[
432 IEEE_80211::kReasonCodeUnacceptableSupportedChannelInfo] =
433 "Disassociated because the information in the Supported Channels "
434 "element is unacceptable";
435 (*reason_code_string_)[IEEE_80211::kReasonCodeInvalidInfoElement] =
436 "Invalid information element, i.e., an information element defined in "
437 "this standard for which the content does not meet the specifications "
438 "in Clause 7";
439 (*reason_code_string_)[IEEE_80211::kReasonCodeMICFailure] =
440 "Message integrity code (MIC) failure";
441 (*reason_code_string_)[IEEE_80211::kReasonCode4WayTimeout] =
442 "4-Way Handshake timeout";
443 (*reason_code_string_)[IEEE_80211::kReasonCodeGroupKeyHandshakeTimeout] =
444 "Group Key Handshake timeout";
445 (*reason_code_string_)[IEEE_80211::kReasonCodeDifferenIE] =
446 "Information element in 4-Way Handshake different from "
447 "(Re)Association Request/Probe Response/Beacon frame";
448 (*reason_code_string_)[IEEE_80211::kReasonCodeGroupCipherInvalid] =
449 "Invalid group cipher";
450 (*reason_code_string_)[IEEE_80211::kReasonCodePairwiseCipherInvalid] =
451 "Invalid pairwise cipher";
452 (*reason_code_string_)[IEEE_80211::kReasonCodeAkmpInvalid] =
453 "Invalid AKMP";
454 (*reason_code_string_)[IEEE_80211::kReasonCodeUnsupportedRsnIeVersion] =
455 "Unsupported RSN information element version";
456 (*reason_code_string_)[IEEE_80211::kReasonCodeInvalidRsnIeCaps] =
457 "Invalid RSN information element capabilities";
458 (*reason_code_string_)[IEEE_80211::kReasonCode8021XAuth] =
459 "IEEE 802.1X authentication failed";
460 (*reason_code_string_)[IEEE_80211::kReasonCodeCipherSuiteRejected] =
461 "Cipher suite rejected because of the security policy";
462 (*reason_code_string_)[IEEE_80211::kReasonCodeUnspecifiedQoS] =
463 "Disassociated for unspecified, QoS-related reason";
464 (*reason_code_string_)[IEEE_80211::kReasonCodeQoSBandwidth] =
465 "Disassociated because QoS AP lacks sufficient bandwidth for this "
466 "QoS STA";
467 (*reason_code_string_)[IEEE_80211::kReasonCodeiPoorConditions] =
468 "Disassociated because excessive number of frames need to be "
469 "acknowledged, but are not acknowledged due to AP transmissions "
470 "and/or poor channel conditions";
471 (*reason_code_string_)[IEEE_80211::kReasonCodeOutsideTxop] =
472 "Disassociated because STA is transmitting outside the limits of its "
473 "TXOPs";
474 (*reason_code_string_)[IEEE_80211::kReasonCodeStaLeaving] =
475 "Requested from peer STA as the STA is leaving the BSS (or resetting)";
476 (*reason_code_string_)[IEEE_80211::kReasonCodeUnacceptableMechanism] =
477 "Requested from peer STA as it does not want to use the mechanism";
478 (*reason_code_string_)[IEEE_80211::kReasonCodeSetupRequired] =
479 "Requested from peer STA as the STA received frames using the "
480 "mechanism for which a setup is required";
481 (*reason_code_string_)[IEEE_80211::kReasonCodeTimeout] =
482 "Requested from peer STA due to timeout";
483 (*reason_code_string_)[IEEE_80211::kReasonCodeCipherSuiteNotSupported] =
484 "Peer STA does not support the requested cipher suite";
485 (*reason_code_string_)[IEEE_80211::kReasonCodeInvalid] = "<INVALID REASON>";
486 }
487
488 if (!status_code_string_) {
489 status_code_string_ = new map<uint16_t, string>;
490 (*status_code_string_)[IEEE_80211::kStatusCodeSuccessful] = "Successful";
491 (*status_code_string_)[IEEE_80211::kStatusCodeFailure] =
492 "Unspecified failure";
493 (*status_code_string_)[IEEE_80211::kStatusCodeAllCapabilitiesNotSupported] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700494 "Cannot support all requested capabilities in the capability "
495 "information field";
Wade Guthried4977f22012-08-22 12:37:54 -0700496 (*status_code_string_)[IEEE_80211::kStatusCodeCantConfirmAssociation] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700497 "Reassociation denied due to inability to confirm that association "
498 "exists";
Wade Guthried4977f22012-08-22 12:37:54 -0700499 (*status_code_string_)[IEEE_80211::kStatusCodeAssociationDenied] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700500 "Association denied due to reason outside the scope of this standard";
Wade Guthried4977f22012-08-22 12:37:54 -0700501 (*status_code_string_)[
502 IEEE_80211::kStatusCodeAuthenticationUnsupported] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700503 "Responding station does not support the specified authentication "
504 "algorithm";
Wade Guthried4977f22012-08-22 12:37:54 -0700505 (*status_code_string_)[IEEE_80211::kStatusCodeOutOfSequence] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700506 "Received an authentication frame with authentication transaction "
507 "sequence number out of expected sequence";
Wade Guthried4977f22012-08-22 12:37:54 -0700508 (*status_code_string_)[IEEE_80211::kStatusCodeChallengeFailure] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700509 "Authentication rejected because of challenge failure";
Wade Guthried4977f22012-08-22 12:37:54 -0700510 (*status_code_string_)[IEEE_80211::kStatusCodeFrameTimeout] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700511 "Authentication rejected due to timeout waiting for next frame in "
512 "sequence";
Wade Guthried4977f22012-08-22 12:37:54 -0700513 (*status_code_string_)[IEEE_80211::kStatusCodeMaxSta] =
514 "Association denied because AP is unable to handle additional "
515 "associated STA";
516 (*status_code_string_)[IEEE_80211::kStatusCodeDataRateUnsupported] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700517 "Association denied due to requesting station not supporting all of "
518 "the data rates in the BSSBasicRateSet parameter";
Wade Guthried4977f22012-08-22 12:37:54 -0700519 (*status_code_string_)[IEEE_80211::kStatusCodeShortPreambleUnsupported] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700520 "Association denied due to requesting station not supporting the "
521 "short preamble option";
Wade Guthried4977f22012-08-22 12:37:54 -0700522 (*status_code_string_)[IEEE_80211::kStatusCodePbccUnsupported] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700523 "Association denied due to requesting station not supporting the PBCC "
524 "modulation option";
Wade Guthried4977f22012-08-22 12:37:54 -0700525 (*status_code_string_)[
526 IEEE_80211::kStatusCodeChannelAgilityUnsupported] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700527 "Association denied due to requesting station not supporting the "
528 "channel agility option";
Wade Guthried4977f22012-08-22 12:37:54 -0700529 (*status_code_string_)[IEEE_80211::kStatusCodeNeedSpectrumManagement] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700530 "Association request rejected because Spectrum Management capability "
531 "is required";
Wade Guthried4977f22012-08-22 12:37:54 -0700532 (*status_code_string_)[
533 IEEE_80211::kStatusCodeUnacceptablePowerCapability] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700534 "Association request rejected because the information in the Power "
535 "Capability element is unacceptable";
Wade Guthried4977f22012-08-22 12:37:54 -0700536 (*status_code_string_)[
537 IEEE_80211::kStatusCodeUnacceptableSupportedChannelInfo] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700538 "Association request rejected because the information in the "
539 "Supported Channels element is unacceptable";
Wade Guthried4977f22012-08-22 12:37:54 -0700540 (*status_code_string_)[IEEE_80211::kStatusCodeShortTimeSlotRequired] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700541 "Association request rejected due to requesting station not "
Wade Guthried4977f22012-08-22 12:37:54 -0700542 "supporting the Short Slot Time option";
543 (*status_code_string_)[IEEE_80211::kStatusCodeDssOfdmRequired] =
544 "Association request rejected due to requesting station not "
545 "supporting the DSSS-OFDM option";
546 (*status_code_string_)[IEEE_80211::kStatusCodeQosFailure] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700547 "Unspecified, QoS related failure";
Wade Guthried4977f22012-08-22 12:37:54 -0700548 (*status_code_string_)[
549 IEEE_80211::kStatusCodeInsufficientBandwithForQsta] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700550 "Association denied due to QAP having insufficient bandwidth to handle "
551 "another QSTA";
Wade Guthried4977f22012-08-22 12:37:54 -0700552 (*status_code_string_)[IEEE_80211::kStatusCodePoorConditions] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700553 "Association denied due to poor channel conditions";
Wade Guthried4977f22012-08-22 12:37:54 -0700554 (*status_code_string_)[IEEE_80211::kStatusCodeQosNotSupported] =
555 "Association (with QoS BSS) denied due to requesting station not "
Wade Guthrie64b4c142012-08-20 15:21:01 -0700556 "supporting the QoS facility";
Wade Guthried4977f22012-08-22 12:37:54 -0700557 (*status_code_string_)[IEEE_80211::kStatusCodeDeclined] =
558 "The request has been declined";
559 (*status_code_string_)[IEEE_80211::kStatusCodeInvalidParameterValues] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700560 "The request has not been successful as one or more parameters have "
561 "invalid values";
Wade Guthried4977f22012-08-22 12:37:54 -0700562 (*status_code_string_)[IEEE_80211::kStatusCodeCannotBeHonored] =
563 "The TS has not been created because the request cannot be honored. "
Wade Guthrie64b4c142012-08-20 15:21:01 -0700564 "However, a suggested Tspec is provided so that the initiating QSTA "
565 "may attempt to send another TS with the suggested changes to the "
566 "TSpec";
Wade Guthried4977f22012-08-22 12:37:54 -0700567 (*status_code_string_)[IEEE_80211::kStatusCodeInvalidInfoElement] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700568 "Invalid Information Element";
Wade Guthried4977f22012-08-22 12:37:54 -0700569 (*status_code_string_)[IEEE_80211::kStatusCodeGroupCipherInvalid] =
570 "Invalid Group Cipher";
571 (*status_code_string_)[IEEE_80211::kStatusCodePairwiseCipherInvalid] =
572 "Invalid Pairwise Cipher";
573 (*status_code_string_)[IEEE_80211::kStatusCodeAkmpInvalid] = "Invalid AKMP";
574 (*status_code_string_)[IEEE_80211::kStatusCodeUnsupportedRsnIeVersion] =
575 "Unsupported RSN Information Element version";
576 (*status_code_string_)[IEEE_80211::kStatusCodeInvalidRsnIeCaps] =
577 "Invalid RSN Information Element Capabilities";
578 (*status_code_string_)[IEEE_80211::kStatusCodeCipherSuiteRejected] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700579 "Cipher suite is rejected per security policy";
Wade Guthried4977f22012-08-22 12:37:54 -0700580 (*status_code_string_)[IEEE_80211::kStatusCodeTsDelayNotMet] =
581 "The TS has not been created. However, the HC may be capable of "
582 "creating a TS, in response to a request, after the time indicated in "
583 "the TS Delay element";
584 (*status_code_string_)[IEEE_80211::kStatusCodeDirectLinkIllegal] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700585 "Direct link is not allowed in the BSS by policy";
Wade Guthried4977f22012-08-22 12:37:54 -0700586 (*status_code_string_)[IEEE_80211::kStatusCodeStaNotInBss] =
587 "Destination STA is not present within this BSS";
588 (*status_code_string_)[IEEE_80211::kStatusCodeStaNotInQsta] =
589 "The destination STA is not a QoS STA";
590 (*status_code_string_)[IEEE_80211::kStatusCodeExcessiveListenInterval] =
Wade Guthrie64b4c142012-08-20 15:21:01 -0700591 "Association denied because Listen Interval is too large";
Wade Guthried4977f22012-08-22 12:37:54 -0700592 (*status_code_string_)[IEEE_80211::kStatusCodeInvalid] = "<INVALID STATUS>";
Wade Guthrie0d438532012-05-18 14:18:50 -0700593 }
594
595 return true;
596}
597
Wade Guthrie0d438532012-05-18 14:18:50 -0700598// Helper function to provide a string for a MAC address.
Wade Guthrie68da97c2013-02-26 13:09:35 -0800599bool Nl80211Message::GetMacAttributeString(int id, string *value) const {
Wade Guthrie0d438532012-05-18 14:18:50 -0700600 if (!value) {
601 LOG(ERROR) << "Null |value| parameter";
602 return false;
603 }
604
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800605 ByteString data;
Wade Guthrieefe1f0c2013-02-26 17:42:01 -0800606 if (!const_attributes()->GetRawAttributeValue(id, &data)) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700607 value->assign(kBogusMacAddress);
608 return false;
609 }
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800610 value->assign(StringFromMacAddress(data.GetConstData()));
Wade Guthrie0d438532012-05-18 14:18:50 -0700611
612 return true;
613}
614
615// Helper function to provide a string for NL80211_ATTR_SCAN_FREQUENCIES.
repo syncdc085c82012-12-28 08:54:41 -0800616bool Nl80211Message::GetScanFrequenciesAttribute(
Wade Guthrie68da97c2013-02-26 13:09:35 -0800617 int id, vector<uint32_t> *value) const {
Wade Guthrie0d438532012-05-18 14:18:50 -0700618 if (!value) {
619 LOG(ERROR) << "Null |value| parameter";
620 return false;
621 }
622
623 value->clear();
Wade Guthried3dfd6c2013-02-28 17:40:36 -0800624
625 AttributeListConstRefPtr frequency_list;
626 if (!const_attributes()->ConstGetNestedAttributeList(
627 NL80211_ATTR_SCAN_FREQUENCIES, &frequency_list) || !frequency_list) {
628 LOG(ERROR) << "Couldn't get NL80211_ATTR_SCAN_FREQUENCIES attribute";
repo syncd316eb72012-12-10 15:48:47 -0800629 return false;
Wade Guthried3dfd6c2013-02-28 17:40:36 -0800630 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700631
Wade Guthried3dfd6c2013-02-28 17:40:36 -0800632 // Assume IDs for the nested attribute array are linear starting from 1.
633 // Currently, that is enforced in the input to the nested attribute.
634 uint32_t freq;
635 int i = 1;
636 while (frequency_list->GetU32AttributeValue(i, &freq)) {
637 value->push_back(freq);
638 ++i;
Wade Guthrie0d438532012-05-18 14:18:50 -0700639 }
repo syncd316eb72012-12-10 15:48:47 -0800640 return true;
Wade Guthrie0d438532012-05-18 14:18:50 -0700641}
642
643// Helper function to provide a string for NL80211_ATTR_SCAN_SSIDS.
repo syncdc085c82012-12-28 08:54:41 -0800644bool Nl80211Message::GetScanSsidsAttribute(
Wade Guthrie68da97c2013-02-26 13:09:35 -0800645 int id, vector<string> *value) const {
Wade Guthrie0d438532012-05-18 14:18:50 -0700646 if (!value) {
647 LOG(ERROR) << "Null |value| parameter";
648 return false;
649 }
650
Wade Guthried3dfd6c2013-02-28 17:40:36 -0800651 AttributeListConstRefPtr ssid_list;
652 if (!const_attributes()->ConstGetNestedAttributeList(
653 NL80211_ATTR_SCAN_SSIDS, &ssid_list) || !ssid_list) {
654 LOG(ERROR) << "Couldn't get NL80211_ATTR_SCAN_SSIDS attribute";
repo sync90ee0fa2012-12-18 10:08:08 -0800655 return false;
Wade Guthried3dfd6c2013-02-28 17:40:36 -0800656 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700657
Wade Guthried3dfd6c2013-02-28 17:40:36 -0800658 // Assume IDs for the nested attribute array are linear starting from 1.
659 // Currently, that is enforced in the input to the nested attribute.
660 string ssid;
661 int i = 1;
662 while (ssid_list->GetStringAttributeValue(i, &ssid)) {
663 value->push_back(ssid);
664 ++i;
Wade Guthrie0d438532012-05-18 14:18:50 -0700665 }
repo sync90ee0fa2012-12-18 10:08:08 -0800666 return true;
Wade Guthrie0d438532012-05-18 14:18:50 -0700667}
668
Wade Guthrie0d438532012-05-18 14:18:50 -0700669// static
repo syncdc085c82012-12-28 08:54:41 -0800670string Nl80211Message::StringFromMacAddress(const uint8_t *arg) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700671 string output;
672
673 if (!arg) {
674 output = kBogusMacAddress;
675 LOG(ERROR) << "|arg| parameter is NULL.";
676 } else {
677 StringAppendF(&output, "%02x", arg[0]);
678
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800679 for (unsigned int i = 1; i < kEthernetAddressBytes ; ++i) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700680 StringAppendF(&output, ":%02x", arg[i]);
681 }
682 }
683 return output;
684}
685
686// static
repo syncdc085c82012-12-28 08:54:41 -0800687string Nl80211Message::StringFromReason(uint16_t status) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700688 map<uint16_t, string>::const_iterator match;
Wade Guthried4977f22012-08-22 12:37:54 -0700689 match = reason_code_string_->find(status);
690 if (match == reason_code_string_->end()) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700691 string output;
Wade Guthried4977f22012-08-22 12:37:54 -0700692 if (status < IEEE_80211::kReasonCodeMax) {
693 StringAppendF(&output, "<Reserved Reason:%u>", status);
694 } else {
695 StringAppendF(&output, "<Unknown Reason:%u>", status);
696 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700697 return output;
698 }
699 return match->second;
700}
701
Wade Guthried4977f22012-08-22 12:37:54 -0700702// static
repo syncdc085c82012-12-28 08:54:41 -0800703string Nl80211Message::StringFromStatus(uint16_t status) {
Wade Guthried4977f22012-08-22 12:37:54 -0700704 map<uint16_t, string>::const_iterator match;
705 match = status_code_string_->find(status);
706 if (match == status_code_string_->end()) {
707 string output;
708 if (status < IEEE_80211::kStatusCodeMax) {
709 StringAppendF(&output, "<Reserved Status:%u>", status);
710 } else {
711 StringAppendF(&output, "<Unknown Status:%u>", status);
712 }
713 return output;
714 }
715 return match->second;
716}
717
repo syncdc085c82012-12-28 08:54:41 -0800718
Wade Guthrie71872472013-03-05 10:33:38 -0800719// Control Message
720
721const uint16_t ControlNetlinkMessage::kMessageType = GENL_ID_CTRL;
722
723bool ControlNetlinkMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
724 if (!const_msg) {
725 LOG(ERROR) << "Null |msg| parameter";
726 return false;
727 }
728 ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
729 const_msg->nlmsg_len);
730
731 if (!InitAndStripHeader(&message)) {
732 return false;
733 }
734
735 // Attributes.
736 // Parse the attributes from the nl message payload into the 'tb' array.
737 nlattr *tb[CTRL_ATTR_MAX + 1];
738 nla_parse(tb, CTRL_ATTR_MAX,
739 reinterpret_cast<nlattr *>(message.GetData()), message.GetLength(),
740 NULL);
741
742 for (int i = 0; i < CTRL_ATTR_MAX + 1; ++i) {
743 if (tb[i]) {
744 // TODO(wdg): When Nl80211Messages instantiate their own attributes,
745 // this call should, instead, call |SetAttributeFromNlAttr|.
746 attributes_->CreateAndInitAttribute(
747 i, tb[i], Bind(&NetlinkAttribute::NewControlAttributeFromId));
748 }
749 }
750 return true;
751}
752
753// Specific Control types.
754
755const uint8_t NewFamilyMessage::kCommand = CTRL_CMD_NEWFAMILY;
756const char NewFamilyMessage::kCommandString[] = "CTRL_CMD_NEWFAMILY";
757
758const uint8_t GetFamilyMessage::kCommand = CTRL_CMD_GETFAMILY;
759const char GetFamilyMessage::kCommandString[] = "CTRL_CMD_GETFAMILY";
760
Wade Guthrie12f113a2013-03-12 17:15:46 -0700761// static
762NetlinkMessage *ControlNetlinkMessage::CreateMessage(
763 const nlmsghdr *const_msg) {
764 if (!const_msg) {
765 LOG(ERROR) << "NULL |const_msg| parameter";
766 return NULL;
767 }
768 // Casting away constness since, while nlmsg_data doesn't change its
769 // parameter, it also doesn't declare its paramenter as const.
770 nlmsghdr *msg = const_cast<nlmsghdr *>(const_msg);
771 void *payload = nlmsg_data(msg);
772 genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(payload);
773
774 switch (gnlh->cmd) {
775 case NewFamilyMessage::kCommand:
776 return new NewFamilyMessage();
777 case GetFamilyMessage::kCommand:
778 return new GetFamilyMessage();
779 default:
780 LOG(WARNING) << "Unknown/unhandled netlink control message " << gnlh->cmd;
781 break;
782 }
783 return NULL;
784}
785
Wade Guthrie71872472013-03-05 10:33:38 -0800786// Nl80211Frame
787
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800788Nl80211Frame::Nl80211Frame(const ByteString &raw_frame)
Wade Guthried4977f22012-08-22 12:37:54 -0700789 : frame_type_(kIllegalFrameType), reason_(UINT16_MAX), status_(UINT16_MAX),
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800790 frame_(raw_frame) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700791 const IEEE_80211::ieee80211_frame *frame =
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800792 reinterpret_cast<const IEEE_80211::ieee80211_frame *>(
793 frame_.GetConstData());
Wade Guthrie0d438532012-05-18 14:18:50 -0700794
795 // Now, let's populate the other stuff.
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800796 if (frame_.GetLength() >= kMinimumFrameByteCount) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700797 mac_from_ =
repo syncdc085c82012-12-28 08:54:41 -0800798 Nl80211Message::StringFromMacAddress(&frame->destination_mac[0]);
799 mac_to_ = Nl80211Message::StringFromMacAddress(&frame->source_mac[0]);
Wade Guthrie0d438532012-05-18 14:18:50 -0700800 frame_type_ = frame->frame_control & kFrameTypeMask;
801
802 switch (frame_type_) {
803 case kAssocResponseFrameType:
804 case kReassocResponseFrameType:
805 status_ = le16toh(frame->u.associate_response.status_code);
806 break;
807
808 case kAuthFrameType:
809 status_ = le16toh(frame->u.authentiate_message.status_code);
810 break;
811
812 case kDisassocFrameType:
813 case kDeauthFrameType:
Wade Guthried4977f22012-08-22 12:37:54 -0700814 reason_ = le16toh(frame->u.deauthentiate_message.reason_code);
Wade Guthrie0d438532012-05-18 14:18:50 -0700815 break;
816
817 default:
818 break;
819 }
820 }
821}
822
Wade Guthried4977f22012-08-22 12:37:54 -0700823bool Nl80211Frame::ToString(string *output) const {
Wade Guthrie0d438532012-05-18 14:18:50 -0700824 if (!output) {
825 LOG(ERROR) << "NULL |output|";
826 return false;
827 }
828
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800829 if (frame_.IsEmpty()) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700830 output->append(" [no frame]");
831 return true;
832 }
833
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800834 if (frame_.GetLength() < kMinimumFrameByteCount) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700835 output->append(" [invalid frame: ");
836 } else {
837 StringAppendF(output, " %s -> %s", mac_from_.c_str(), mac_to_.c_str());
838
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800839 switch (frame_.GetConstData()[0] & kFrameTypeMask) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700840 case kAssocResponseFrameType:
841 StringAppendF(output, "; AssocResponse status: %u: %s",
842 status_,
repo syncdc085c82012-12-28 08:54:41 -0800843 Nl80211Message::StringFromStatus(status_).c_str());
Wade Guthrie0d438532012-05-18 14:18:50 -0700844 break;
845 case kReassocResponseFrameType:
846 StringAppendF(output, "; ReassocResponse status: %u: %s",
847 status_,
repo syncdc085c82012-12-28 08:54:41 -0800848 Nl80211Message::StringFromStatus(status_).c_str());
Wade Guthrie0d438532012-05-18 14:18:50 -0700849 break;
850 case kAuthFrameType:
851 StringAppendF(output, "; Auth status: %u: %s",
852 status_,
repo syncdc085c82012-12-28 08:54:41 -0800853 Nl80211Message::StringFromStatus(status_).c_str());
Wade Guthrie0d438532012-05-18 14:18:50 -0700854 break;
855
856 case kDisassocFrameType:
857 StringAppendF(output, "; Disassoc reason %u: %s",
Wade Guthried4977f22012-08-22 12:37:54 -0700858 reason_,
repo syncdc085c82012-12-28 08:54:41 -0800859 Nl80211Message::StringFromReason(reason_).c_str());
Wade Guthrie0d438532012-05-18 14:18:50 -0700860 break;
861 case kDeauthFrameType:
862 StringAppendF(output, "; Deauth reason %u: %s",
Wade Guthried4977f22012-08-22 12:37:54 -0700863 reason_,
repo syncdc085c82012-12-28 08:54:41 -0800864 Nl80211Message::StringFromReason(reason_).c_str());
Wade Guthrie0d438532012-05-18 14:18:50 -0700865 break;
866
867 default:
868 break;
869 }
870 output->append(" [frame: ");
871 }
872
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800873 const unsigned char *frame = frame_.GetConstData();
874 for (size_t i = 0; i < frame_.GetLength(); ++i) {
875 StringAppendF(output, "%02x, ", frame[i]);
Wade Guthrie0d438532012-05-18 14:18:50 -0700876 }
877 output->append("]");
878
879 return true;
880}
881
Wade Guthried4977f22012-08-22 12:37:54 -0700882bool Nl80211Frame::IsEqual(const Nl80211Frame &other) const {
Wade Guthrie8343f7f2012-12-04 13:52:32 -0800883 return frame_.Equals(other.frame_);
Wade Guthrie0d438532012-05-18 14:18:50 -0700884}
885
886//
repo syncdc085c82012-12-28 08:54:41 -0800887// Specific Nl80211Message types.
Wade Guthrie0d438532012-05-18 14:18:50 -0700888//
889
890const uint8_t AssociateMessage::kCommand = NL80211_CMD_ASSOCIATE;
891const char AssociateMessage::kCommandString[] = "NL80211_CMD_ASSOCIATE";
892
Wade Guthrie0d438532012-05-18 14:18:50 -0700893const uint8_t AuthenticateMessage::kCommand = NL80211_CMD_AUTHENTICATE;
894const char AuthenticateMessage::kCommandString[] = "NL80211_CMD_AUTHENTICATE";
895
Wade Guthrie0d438532012-05-18 14:18:50 -0700896const uint8_t CancelRemainOnChannelMessage::kCommand =
897 NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL;
898const char CancelRemainOnChannelMessage::kCommandString[] =
899 "NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL";
900
Wade Guthrie0d438532012-05-18 14:18:50 -0700901const uint8_t ConnectMessage::kCommand = NL80211_CMD_CONNECT;
902const char ConnectMessage::kCommandString[] = "NL80211_CMD_CONNECT";
903
Wade Guthrie0d438532012-05-18 14:18:50 -0700904const uint8_t DeauthenticateMessage::kCommand = NL80211_CMD_DEAUTHENTICATE;
905const char DeauthenticateMessage::kCommandString[] =
906 "NL80211_CMD_DEAUTHENTICATE";
907
Wade Guthrie0d438532012-05-18 14:18:50 -0700908const uint8_t DeleteStationMessage::kCommand = NL80211_CMD_DEL_STATION;
909const char DeleteStationMessage::kCommandString[] = "NL80211_CMD_DEL_STATION";
910
Wade Guthrie0d438532012-05-18 14:18:50 -0700911const uint8_t DisassociateMessage::kCommand = NL80211_CMD_DISASSOCIATE;
912const char DisassociateMessage::kCommandString[] = "NL80211_CMD_DISASSOCIATE";
913
Wade Guthrie0d438532012-05-18 14:18:50 -0700914const uint8_t DisconnectMessage::kCommand = NL80211_CMD_DISCONNECT;
915const char DisconnectMessage::kCommandString[] = "NL80211_CMD_DISCONNECT";
916
Wade Guthrie0d438532012-05-18 14:18:50 -0700917const uint8_t FrameTxStatusMessage::kCommand = NL80211_CMD_FRAME_TX_STATUS;
918const char FrameTxStatusMessage::kCommandString[] =
919 "NL80211_CMD_FRAME_TX_STATUS";
920
repo sync0efa9f02012-12-28 13:40:20 -0800921const uint8_t GetRegMessage::kCommand = NL80211_CMD_GET_REG;
922const char GetRegMessage::kCommandString[] = "NL80211_CMD_GET_REG";
923
Wade Guthrie0d438532012-05-18 14:18:50 -0700924const uint8_t JoinIbssMessage::kCommand = NL80211_CMD_JOIN_IBSS;
925const char JoinIbssMessage::kCommandString[] = "NL80211_CMD_JOIN_IBSS";
926
Wade Guthrie0d438532012-05-18 14:18:50 -0700927const uint8_t MichaelMicFailureMessage::kCommand =
928 NL80211_CMD_MICHAEL_MIC_FAILURE;
929const char MichaelMicFailureMessage::kCommandString[] =
930 "NL80211_CMD_MICHAEL_MIC_FAILURE";
931
Wade Guthrie0d438532012-05-18 14:18:50 -0700932const uint8_t NewScanResultsMessage::kCommand = NL80211_CMD_NEW_SCAN_RESULTS;
933const char NewScanResultsMessage::kCommandString[] =
934 "NL80211_CMD_NEW_SCAN_RESULTS";
935
Wade Guthrie0d438532012-05-18 14:18:50 -0700936const uint8_t NewStationMessage::kCommand = NL80211_CMD_NEW_STATION;
937const char NewStationMessage::kCommandString[] = "NL80211_CMD_NEW_STATION";
938
Wade Guthrie0d438532012-05-18 14:18:50 -0700939const uint8_t NewWifiMessage::kCommand = NL80211_CMD_NEW_WIPHY;
940const char NewWifiMessage::kCommandString[] = "NL80211_CMD_NEW_WIPHY";
941
Wade Guthrie0d438532012-05-18 14:18:50 -0700942const uint8_t NotifyCqmMessage::kCommand = NL80211_CMD_NOTIFY_CQM;
943const char NotifyCqmMessage::kCommandString[] = "NL80211_CMD_NOTIFY_CQM";
944
Wade Guthrie0d438532012-05-18 14:18:50 -0700945const uint8_t PmksaCandidateMessage::kCommand = NL80211_ATTR_PMKSA_CANDIDATE;
946const char PmksaCandidateMessage::kCommandString[] =
947 "NL80211_ATTR_PMKSA_CANDIDATE";
948
Wade Guthrie0d438532012-05-18 14:18:50 -0700949const uint8_t RegBeaconHintMessage::kCommand = NL80211_CMD_REG_BEACON_HINT;
950const char RegBeaconHintMessage::kCommandString[] =
951 "NL80211_CMD_REG_BEACON_HINT";
952
Wade Guthrie0d438532012-05-18 14:18:50 -0700953const uint8_t RegChangeMessage::kCommand = NL80211_CMD_REG_CHANGE;
954const char RegChangeMessage::kCommandString[] = "NL80211_CMD_REG_CHANGE";
955
Wade Guthrie0d438532012-05-18 14:18:50 -0700956const uint8_t RemainOnChannelMessage::kCommand = NL80211_CMD_REMAIN_ON_CHANNEL;
957const char RemainOnChannelMessage::kCommandString[] =
958 "NL80211_CMD_REMAIN_ON_CHANNEL";
959
Wade Guthrie0d438532012-05-18 14:18:50 -0700960const uint8_t RoamMessage::kCommand = NL80211_CMD_ROAM;
961const char RoamMessage::kCommandString[] = "NL80211_CMD_ROAM";
962
Wade Guthrie0d438532012-05-18 14:18:50 -0700963const uint8_t ScanAbortedMessage::kCommand = NL80211_CMD_SCAN_ABORTED;
964const char ScanAbortedMessage::kCommandString[] = "NL80211_CMD_SCAN_ABORTED";
965
Wade Guthrie71872472013-03-05 10:33:38 -0800966const uint8_t GetScanMessage::kCommand = NL80211_CMD_GET_SCAN;
967const char GetScanMessage::kCommandString[] = "NL80211_CMD_GET_SCAN";
968
Wade Guthrie0d438532012-05-18 14:18:50 -0700969const uint8_t TriggerScanMessage::kCommand = NL80211_CMD_TRIGGER_SCAN;
970const char TriggerScanMessage::kCommandString[] = "NL80211_CMD_TRIGGER_SCAN";
971
Wade Guthrie0d438532012-05-18 14:18:50 -0700972const uint8_t UnprotDeauthenticateMessage::kCommand =
973 NL80211_CMD_UNPROT_DEAUTHENTICATE;
974const char UnprotDeauthenticateMessage::kCommandString[] =
975 "NL80211_CMD_UNPROT_DEAUTHENTICATE";
976
Wade Guthrie0d438532012-05-18 14:18:50 -0700977const uint8_t UnprotDisassociateMessage::kCommand =
978 NL80211_CMD_UNPROT_DISASSOCIATE;
979const char UnprotDisassociateMessage::kCommandString[] =
980 "NL80211_CMD_UNPROT_DISASSOCIATE";
981
Wade Guthrie12f113a2013-03-12 17:15:46 -0700982// static
983NetlinkMessage *Nl80211Message::CreateMessage(const nlmsghdr *const_msg) {
984 if (!const_msg) {
985 LOG(ERROR) << "NULL |const_msg| parameter";
986 return NULL;
987 }
988 // Casting away constness since, while nlmsg_data doesn't change its
989 // parameter, it also doesn't declare its paramenter as const.
990 nlmsghdr *msg = const_cast<nlmsghdr *>(const_msg);
991 void *payload = nlmsg_data(msg);
992 genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(payload);
993 scoped_ptr<NetlinkMessage> message;
994
995 switch (gnlh->cmd) {
996 case AssociateMessage::kCommand:
997 return new AssociateMessage();
998 case AuthenticateMessage::kCommand:
999 return new AuthenticateMessage();
1000 case CancelRemainOnChannelMessage::kCommand:
1001 return new CancelRemainOnChannelMessage();
1002 case ConnectMessage::kCommand:
1003 return new ConnectMessage();
1004 case DeauthenticateMessage::kCommand:
1005 return new DeauthenticateMessage();
1006 case DeleteStationMessage::kCommand:
1007 return new DeleteStationMessage();
1008 case DisassociateMessage::kCommand:
1009 return new DisassociateMessage();
1010 case DisconnectMessage::kCommand:
1011 return new DisconnectMessage();
1012 case FrameTxStatusMessage::kCommand:
1013 return new FrameTxStatusMessage();
1014 case GetRegMessage::kCommand:
1015 return new GetRegMessage();
1016 case JoinIbssMessage::kCommand:
1017 return new JoinIbssMessage();
1018 case MichaelMicFailureMessage::kCommand:
1019 return new MichaelMicFailureMessage();
1020 case NewScanResultsMessage::kCommand:
1021 return new NewScanResultsMessage();
1022 case NewStationMessage::kCommand:
1023 return new NewStationMessage();
1024 case NewWifiMessage::kCommand:
1025 return new NewWifiMessage();
1026 case NotifyCqmMessage::kCommand:
1027 return new NotifyCqmMessage();
1028 case PmksaCandidateMessage::kCommand:
1029 return new PmksaCandidateMessage();
1030 case RegBeaconHintMessage::kCommand:
1031 return new RegBeaconHintMessage();
1032 case RegChangeMessage::kCommand:
1033 return new RegChangeMessage();
1034 case RemainOnChannelMessage::kCommand:
1035 return new RemainOnChannelMessage();
1036 case RoamMessage::kCommand:
1037 return new RoamMessage();
1038 case ScanAbortedMessage::kCommand:
1039 return new ScanAbortedMessage();
1040 case TriggerScanMessage::kCommand:
1041 return new TriggerScanMessage();
1042 case UnprotDeauthenticateMessage::kCommand:
1043 return new UnprotDeauthenticateMessage();
1044 case UnprotDisassociateMessage::kCommand:
1045 return new UnprotDisassociateMessage();
1046 default:
1047 LOG(WARNING) << "Unknown/unhandled netlink nl80211 message " << gnlh->cmd;
1048 break;
1049 }
1050 return NULL;
1051}
1052
Wade Guthrie0d438532012-05-18 14:18:50 -07001053//
1054// Factory class.
1055//
1056
Wade Guthrie12f113a2013-03-12 17:15:46 -07001057bool NetlinkMessageFactory::AddFactoryMethod(uint16_t message_type,
1058 FactoryMethod factory) {
1059 if (ContainsKey(factories_, message_type)) {
1060 LOG(WARNING) << "Message type " << message_type << " already exists.";
1061 return false;
1062 }
1063 if (message_type == NetlinkMessage::kIllegalMessageType) {
1064 LOG(ERROR) << "Not installing factory for illegal message type.";
1065 return false;
1066 }
1067 factories_[message_type] = factory;
1068 return true;
1069}
1070
1071NetlinkMessage *NetlinkMessageFactory::CreateMessage(
1072 const nlmsghdr *const_msg) const {
1073 if (!const_msg) {
1074 LOG(ERROR) << "NULL |const_msg| parameter";
Wade Guthrie0d438532012-05-18 14:18:50 -07001075 return NULL;
1076 }
1077
Wade Guthrief48a1952013-03-04 17:33:47 -08001078 scoped_ptr<NetlinkMessage> message;
repo syncdc085c82012-12-28 08:54:41 -08001079
Wade Guthrie12f113a2013-03-12 17:15:46 -07001080 if (const_msg->nlmsg_type == NoopMessage::kMessageType) {
repo sync0efa9f02012-12-28 13:40:20 -08001081 message.reset(new NoopMessage());
Wade Guthrie12f113a2013-03-12 17:15:46 -07001082 } else if (const_msg->nlmsg_type == DoneMessage::kMessageType) {
Wade Guthrie71872472013-03-05 10:33:38 -08001083 message.reset(new DoneMessage());
Wade Guthrie12f113a2013-03-12 17:15:46 -07001084 } else if (const_msg->nlmsg_type == OverrunMessage::kMessageType) {
Wade Guthrie71872472013-03-05 10:33:38 -08001085 message.reset(new OverrunMessage());
Wade Guthrie12f113a2013-03-12 17:15:46 -07001086 } else if (const_msg->nlmsg_type == ErrorAckMessage::kMessageType) {
Wade Guthrie71872472013-03-05 10:33:38 -08001087 message.reset(new ErrorAckMessage());
Wade Guthrie12f113a2013-03-12 17:15:46 -07001088 } else if (ContainsKey(factories_, const_msg->nlmsg_type)) {
1089 map<uint16_t, FactoryMethod>::const_iterator factory;
1090 factory = factories_.find(const_msg->nlmsg_type);
1091 message.reset(factory->second.Run(const_msg));
Wade Guthrie71872472013-03-05 10:33:38 -08001092 }
Wade Guthrie0d438532012-05-18 14:18:50 -07001093
Wade Guthrie12f113a2013-03-12 17:15:46 -07001094 // If no factory exists for this message _or_ if a factory exists but it
1095 // failed, there'll be no message. Handle either of those cases, by
1096 // creating an |UnknownMessage|.
1097 if (!message) {
1098 // Casting away constness since, while nlmsg_data doesn't change its
1099 // parameter, it also doesn't declare its paramenter as const.
1100 nlmsghdr *msg = const_cast<nlmsghdr *>(const_msg);
1101 ByteString payload(reinterpret_cast<char *>(nlmsg_data(msg)),
1102 nlmsg_datalen(msg));
1103 message.reset(new UnknownMessage(msg->nlmsg_type, payload));
1104 }
1105
1106 if (!message->InitFromNlmsg(const_msg)) {
Wade Guthrie71872472013-03-05 10:33:38 -08001107 LOG(ERROR) << "Message did not initialize properly";
1108 return NULL;
Wade Guthrie0d438532012-05-18 14:18:50 -07001109 }
1110
Wade Guthrie0d438532012-05-18 14:18:50 -07001111 return message.release();
1112}
1113
Wade Guthrie12f113a2013-03-12 17:15:46 -07001114//
1115// Data Collector
1116//
1117
repo syncdc085c82012-12-28 08:54:41 -08001118Nl80211MessageDataCollector *
1119 Nl80211MessageDataCollector::GetInstance() {
Wade Guthrie0d438532012-05-18 14:18:50 -07001120 return g_datacollector.Pointer();
1121}
1122
repo syncdc085c82012-12-28 08:54:41 -08001123Nl80211MessageDataCollector::Nl80211MessageDataCollector() {
Wade Guthrie0d438532012-05-18 14:18:50 -07001124 need_to_print[NL80211_ATTR_PMKSA_CANDIDATE] = true;
1125 need_to_print[NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL] = true;
1126 need_to_print[NL80211_CMD_DEL_STATION] = true;
1127 need_to_print[NL80211_CMD_FRAME_TX_STATUS] = true;
1128 need_to_print[NL80211_CMD_JOIN_IBSS] = true;
1129 need_to_print[NL80211_CMD_MICHAEL_MIC_FAILURE] = true;
1130 need_to_print[NL80211_CMD_NEW_WIPHY] = true;
1131 need_to_print[NL80211_CMD_REG_BEACON_HINT] = true;
1132 need_to_print[NL80211_CMD_REG_CHANGE] = true;
1133 need_to_print[NL80211_CMD_REMAIN_ON_CHANNEL] = true;
1134 need_to_print[NL80211_CMD_ROAM] = true;
1135 need_to_print[NL80211_CMD_SCAN_ABORTED] = true;
1136 need_to_print[NL80211_CMD_UNPROT_DEAUTHENTICATE] = true;
1137 need_to_print[NL80211_CMD_UNPROT_DISASSOCIATE] = true;
1138}
1139
repo syncdc085c82012-12-28 08:54:41 -08001140void Nl80211MessageDataCollector::CollectDebugData(
1141 const Nl80211Message &message, nlmsghdr *msg) {
Wade Guthrie0d438532012-05-18 14:18:50 -07001142 if (!msg) {
1143 LOG(ERROR) << "NULL |msg| parameter";
1144 return;
1145 }
1146
1147 bool doit = false;
1148
1149 map<uint8_t, bool>::const_iterator node;
Wade Guthriebdcdaa72013-03-04 12:47:12 -08001150 node = need_to_print.find(message.command());
Wade Guthrie0d438532012-05-18 14:18:50 -07001151 if (node != need_to_print.end())
1152 doit = node->second;
1153
1154 if (doit) {
Wade Guthried6153612012-08-23 11:36:14 -07001155 LOG(INFO) << "@@const unsigned char "
Wade Guthriebdcdaa72013-03-04 12:47:12 -08001156 << "k" << message.command_string()
Wade Guthried6153612012-08-23 11:36:14 -07001157 << "[] = {";
Wade Guthrie0d438532012-05-18 14:18:50 -07001158
Christopher Wileyefd521f2012-11-07 17:32:46 -08001159 int payload_bytes = nlmsg_datalen(msg);
Wade Guthrie0d438532012-05-18 14:18:50 -07001160
1161 size_t bytes = nlmsg_total_size(payload_bytes);
1162 unsigned char *rawdata = reinterpret_cast<unsigned char *>(msg);
Wade Guthried4977f22012-08-22 12:37:54 -07001163 for (size_t i = 0; i < bytes; ++i) {
Wade Guthried6153612012-08-23 11:36:14 -07001164 LOG(INFO) << " 0x"
Wade Guthrie0d438532012-05-18 14:18:50 -07001165 << std::hex << std::setfill('0') << std::setw(2)
1166 << + rawdata[i] << ",";
1167 }
Wade Guthried6153612012-08-23 11:36:14 -07001168 LOG(INFO) << "};";
Wade Guthriebdcdaa72013-03-04 12:47:12 -08001169 need_to_print[message.command()] = false;
Wade Guthrie0d438532012-05-18 14:18:50 -07001170 }
1171}
1172
1173} // namespace shill.