shill: Reorganizes Nl80211Message preparing to build a class hierarchy.
This is a reorganization of Nl80211Message so that breaking it into
an appropriate class hierarchy is clear and straight-forward. This CL
includes the following:
1. Moves NetlinkMessage encoding from |NetlinkSocket| up to
|Config80211| (because it makes more sense, there). This requires
exposing sequence number calculations through |Config80211| instead
of requiring access to a specific socket.
2. Breaks both the |Encode| and |InitFromNlmsg| methods into separate
header and body pieces (the header pieces will be broken-up into
their constituent parts when the NetlinkMessage class hierarchy is
created).
3. Changes the name of |message_type| into |command| to more closely
match the netlink data structures. Unfortunately, this is
necessary in order to add a _different_ |message_type| member (and
accessor) that is required by a different netlink data structure.
4. Adds a unittest for message encoding.
BUG=chromium-os:38221
TEST=unittest.
Change-Id: I2f01f3a4c6104bdd09498f143ce44518615e8150
Reviewed-on: https://gerrit.chromium.org/gerrit/44573
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Reviewed-by: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
Commit-Queue: Wade Guthrie <wdg@chromium.org>
diff --git a/callback80211_metrics.cc b/callback80211_metrics.cc
index 0583165..c47cc7c 100644
--- a/callback80211_metrics.cc
+++ b/callback80211_metrics.cc
@@ -20,10 +20,10 @@
void Callback80211Metrics::Config80211MessageCallback(
const Nl80211Message &message) {
- SLOG(WiFi, 3) << "Received " << message.message_type_string()
- << " (" << + message.message_type() << ")";
+ SLOG(WiFi, 3) << "Received " << message.command_string()
+ << " (" << + message.command() << ")";
if (metrics_ &&
- message.message_type() == DeauthenticateMessage::kCommand) {
+ message.command() == DeauthenticateMessage::kCommand) {
Metrics::WiFiDisconnectByWhom by_whom =
message.const_attributes()->IsFlagAttributeTrue(
NL80211_ATTR_DISCONNECTED_BY_AP) ?
diff --git a/config80211.cc b/config80211.cc
index 4e0b9e4..c37ad71 100644
--- a/config80211.cc
+++ b/config80211.cc
@@ -146,17 +146,15 @@
LOG(ERROR) << "Message is NULL.";
return false;
}
- uint32 sequence_number = message->sequence_number();
- if (!sequence_number) {
- sequence_number = sock_->GetSequenceNumber();
- message->set_sequence_number(sequence_number);
- }
+
+ ByteString message_string = message->Encode(this->GetSequenceNumber(),
+ sock_->family_id());
SLOG(WiFi, 6) << "NL Message " << message->sequence_number()
<< " Sending ===>";
message->Print(6);
- if (!sock_->SendMessage(message)) {
+ if (!sock_->SendMessage(message_string)) {
LOG(ERROR) << "Failed to send nl80211 message.";
return false;
}
@@ -164,12 +162,13 @@
LOG(INFO) << "Handler for message was null.";
return true;
}
- if (ContainsKey(message_handlers_, sequence_number)) {
+ if (ContainsKey(message_handlers_, message->sequence_number())) {
LOG(ERROR) << "Sent message, but already had a handler for this message?";
return false;
}
- message_handlers_[sequence_number] = handler;
- LOG(INFO) << "Sent nl80211 message with sequence number: " << sequence_number;
+ message_handlers_[message->sequence_number()] = handler;
+ LOG(INFO) << "Sent nl80211 message with sequence number: "
+ << message->sequence_number();
return true;
}
@@ -231,6 +230,11 @@
wifi_state_ = new_state;
}
+uint32_t Config80211::GetSequenceNumber() {
+ return sock_ ?
+ sock_->GetSequenceNumber() : Nl80211Message::kBroadcastSequenceNumber;
+}
+
bool Config80211::SubscribeToEvents(EventType type) {
bool it_worked = true;
if (!ContainsKey(subscribed_events_, type)) {
diff --git a/config80211.h b/config80211.h
index 5e0d55d..ff072b6 100644
--- a/config80211.h
+++ b/config80211.h
@@ -112,6 +112,10 @@
// subscription requests or down.
void SetWifiState(WifiState new_state);
+ // Gets the next sequence number for a NetlinkMessage to be sent over
+ // Config80211's netlink socket.
+ uint32_t GetSequenceNumber();
+
protected:
friend struct base::DefaultLazyInstanceTraits<Config80211>;
diff --git a/config80211_unittest.cc b/config80211_unittest.cc
index e35761d..cc807e5 100644
--- a/config80211_unittest.cc
+++ b/config80211_unittest.cc
@@ -57,8 +57,20 @@
const uint32_t kExpectedIfIndex = 4;
const uint32_t kWiPhy = 0;
+const uint16_t kNl80211FamilyId = 0x13;
const char kExpectedMacAddress[] = "c0:3f:0e:77:e8:7f";
+const uint8_t kMacAddressBytes[] = {
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f
+};
+
+const uint8_t kAssignedRespIeBytes[] = {
+ 0x01, 0x08, 0x82, 0x84,
+ 0x8b, 0x96, 0x0c, 0x12,
+ 0x18, 0x24, 0x32, 0x04,
+ 0x30, 0x48, 0x60, 0x6c
+};
+
// wlan0 (phy #0): scan started
@@ -349,17 +361,12 @@
} // namespace
-bool MockNl80211Socket::SendMessage(Nl80211Message *message) {
- if (!message) {
- LOG(ERROR) << "Null |message|";
- return false;
- }
+bool MockNl80211Socket::SendMessage(const ByteString &out_string) {
return true;
}
uint32_t MockNl80211Socket::GetSequenceNumber() {
- // Sequence number 0 is reserved for broadcast messages from the kernel.
- if (++sequence_number_ == 0)
+ if (++sequence_number_ == Nl80211Message::kBroadcastSequenceNumber)
++sequence_number_;
return sequence_number_;
}
@@ -572,7 +579,7 @@
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_TRIGGER_SCAN)));
EXPECT_NE(reinterpret_cast<Nl80211Message *>(NULL), message);
- EXPECT_EQ(NL80211_CMD_TRIGGER_SCAN, message->message_type());
+ EXPECT_EQ(NL80211_CMD_TRIGGER_SCAN, message->command());
{
uint32_t value;
@@ -621,7 +628,7 @@
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_NEW_SCAN_RESULTS)));
EXPECT_NE(reinterpret_cast<Nl80211Message *>(NULL), message);
- EXPECT_EQ(NL80211_CMD_NEW_SCAN_RESULTS, message->message_type());
+ EXPECT_EQ(NL80211_CMD_NEW_SCAN_RESULTS, message->command());
{
uint32_t value;
@@ -670,7 +677,7 @@
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_NEW_STATION)));
EXPECT_NE(reinterpret_cast<Nl80211Message *>(NULL), message);
- EXPECT_EQ(NL80211_CMD_NEW_STATION, message->message_type());
+ EXPECT_EQ(NL80211_CMD_NEW_STATION, message->command());
{
uint32_t value;
@@ -705,7 +712,7 @@
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_AUTHENTICATE)));
EXPECT_NE(reinterpret_cast<Nl80211Message *>(NULL), message);
- EXPECT_EQ(NL80211_CMD_AUTHENTICATE, message->message_type());
+ EXPECT_EQ(NL80211_CMD_AUTHENTICATE, message->command());
{
uint32_t value;
@@ -739,7 +746,7 @@
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_ASSOCIATE)));
EXPECT_NE(reinterpret_cast<Nl80211Message *>(NULL), message);
- EXPECT_EQ(NL80211_CMD_ASSOCIATE, message->message_type());
+ EXPECT_EQ(NL80211_CMD_ASSOCIATE, message->command());
{
uint32_t value;
@@ -773,7 +780,7 @@
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_CONNECT)));
EXPECT_NE(reinterpret_cast<Nl80211Message *>(NULL), message);
- EXPECT_EQ(NL80211_CMD_CONNECT, message->message_type());
+ EXPECT_EQ(NL80211_CMD_CONNECT, message->command());
{
uint32_t value;
@@ -810,13 +817,61 @@
}
}
+TEST_F(Config80211Test, Build_NL80211_CMD_CONNECT) {
+ SetupConfig80211Object();
+
+ // Build the message that is found in kNL80211_CMD_CONNECT.
+ ConnectMessage message;
+ EXPECT_TRUE(message.attributes()->CreateAttribute(NL80211_ATTR_WIPHY,
+ Bind(&NetlinkAttribute::NewNl80211AttributeFromId)));
+ EXPECT_TRUE(message.attributes()->SetU32AttributeValue(NL80211_ATTR_WIPHY,
+ kWiPhy));
+
+ EXPECT_TRUE(message.attributes()->CreateAttribute(NL80211_ATTR_IFINDEX,
+ Bind(&NetlinkAttribute::NewNl80211AttributeFromId)));
+ EXPECT_TRUE(message.attributes()->SetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, kExpectedIfIndex));
+
+ EXPECT_TRUE(message.attributes()->CreateAttribute(NL80211_ATTR_MAC,
+ Bind(&NetlinkAttribute::NewNl80211AttributeFromId)));
+ EXPECT_TRUE(message.attributes()->SetRawAttributeValue(NL80211_ATTR_MAC,
+ ByteString(kMacAddressBytes, arraysize(kMacAddressBytes))));
+
+ EXPECT_TRUE(message.attributes()->CreateAttribute(NL80211_ATTR_STATUS_CODE,
+ Bind(&NetlinkAttribute::NewNl80211AttributeFromId)));
+ EXPECT_TRUE(message.attributes()->SetU16AttributeValue(
+ NL80211_ATTR_STATUS_CODE, kExpectedConnectStatus));
+
+ EXPECT_TRUE(message.attributes()->CreateAttribute(NL80211_ATTR_RESP_IE,
+ Bind(&NetlinkAttribute::NewNl80211AttributeFromId)));
+ EXPECT_TRUE(message.attributes()->SetRawAttributeValue(NL80211_ATTR_RESP_IE,
+ ByteString(kAssignedRespIeBytes, arraysize(kAssignedRespIeBytes))));
+
+ // Encode the message to a ByteString and remove all the run-specific
+ // values.
+
+ // TODO(wdg): Get nl80211's family id from Config80211 after it starts
+ // keeping track of family id for each family name.
+ ByteString message_bytes = message.Encode(config80211_->GetSequenceNumber(),
+ kNl80211FamilyId);
+ nlmsghdr *header = reinterpret_cast<nlmsghdr *>(message_bytes.GetData());
+ header->nlmsg_flags = 0; // Overwrite with known values.
+ header->nlmsg_seq = 0;
+ header->nlmsg_pid = 0;
+
+ // Verify that the messages are equal.
+ EXPECT_TRUE(message_bytes.Equals(
+ ByteString(kNL80211_CMD_CONNECT, arraysize(kNL80211_CMD_CONNECT))));
+}
+
+
TEST_F(Config80211Test, Parse_NL80211_CMD_DEAUTHENTICATE) {
Nl80211Message *message = Nl80211MessageFactory::CreateMessage(
const_cast<nlmsghdr *>(
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DEAUTHENTICATE)));
EXPECT_NE(reinterpret_cast<Nl80211Message *>(NULL), message);
- EXPECT_EQ(NL80211_CMD_DEAUTHENTICATE, message->message_type());
+ EXPECT_EQ(NL80211_CMD_DEAUTHENTICATE, message->command());
{
uint32_t value;
@@ -850,7 +905,7 @@
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DISCONNECT)));
EXPECT_NE(reinterpret_cast<Nl80211Message *>(NULL), message);
- EXPECT_EQ(NL80211_CMD_DISCONNECT, message->message_type());
+ EXPECT_EQ(NL80211_CMD_DISCONNECT, message->command());
{
uint32_t value;
@@ -883,7 +938,7 @@
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_NOTIFY_CQM)));
EXPECT_NE(reinterpret_cast<Nl80211Message *>(NULL), message);
- EXPECT_EQ(NL80211_CMD_NOTIFY_CQM, message->message_type());
+ EXPECT_EQ(NL80211_CMD_NOTIFY_CQM, message->command());
{
@@ -926,7 +981,7 @@
reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DISASSOCIATE)));
EXPECT_NE(reinterpret_cast<Nl80211Message *>(NULL), message);
- EXPECT_EQ(NL80211_CMD_DISASSOCIATE, message->message_type());
+ EXPECT_EQ(NL80211_CMD_DISASSOCIATE, message->command());
{
diff --git a/mock_nl80211_socket.h b/mock_nl80211_socket.h
index 93d067d..bde76ca 100644
--- a/mock_nl80211_socket.h
+++ b/mock_nl80211_socket.h
@@ -24,7 +24,7 @@
MOCK_METHOD1(AddGroupMembership, bool(const std::string &group_name));
virtual uint32_t GetSequenceNumber();
- virtual bool SendMessage(Nl80211Message *message);
+ virtual bool SendMessage(const ByteString &message);
uint32 GetLastSequenceNumber() const { return sequence_number_; }
private:
diff --git a/netlink_socket.cc b/netlink_socket.cc
index aba280d..f45dbd6 100644
--- a/netlink_socket.cc
+++ b/netlink_socket.cc
@@ -73,10 +73,10 @@
return true;
}
-bool NetlinkSocket::SendMessage(Nl80211Message *message) {
- if (!message) {
- LOG(ERROR) << "NULL |message|.";
- return false;
+bool NetlinkSocket::SendMessage(const ByteString &out_msg) {
+ if (out_msg.GetLength() == 0) {
+ SLOG(WiFi, 3) << "Not sending empty message.";
+ return true;
}
if (!nl_sock_) {
@@ -84,8 +84,6 @@
return false;
}
- ByteString out_msg = message->Encode(family_id());
-
int result = HANDLE_EINTR(send(GetFd(), out_msg.GetConstData(),
out_msg.GetLength(), 0));
if (!result) {
diff --git a/netlink_socket.h b/netlink_socket.h
index edb1ee4..30228a9 100644
--- a/netlink_socket.h
+++ b/netlink_socket.h
@@ -43,7 +43,7 @@
namespace shill {
-class Nl80211Message;
+class ByteString;
// Provides an abstraction to a netlink socket. See
// http://www.infradead.org/~tgr/libnl/ for documentation on how netlink
@@ -73,7 +73,7 @@
virtual std::string GetSocketFamilyName() const = 0;
// Sends a message, returns true if successful.
- virtual bool SendMessage(Nl80211Message *message);
+ virtual bool SendMessage(const ByteString &message);
protected:
struct nl_sock *GetNlSock() { return nl_sock_; }
diff --git a/nl80211_message.cc b/nl80211_message.cc
index fe60011..60ea977 100644
--- a/nl80211_message.cc
+++ b/nl80211_message.cc
@@ -27,6 +27,7 @@
#include <ctype.h>
#include <endian.h>
#include <errno.h>
+#include <limits.h>
#include <linux/nl80211.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -52,7 +53,6 @@
#include "shill/netlink_attribute.h"
#include "shill/netlink_socket.h"
#include "shill/scope_logger.h"
-#include "shill/wifi.h"
using base::Bind;
using base::LazyInstance;
@@ -70,15 +70,19 @@
LAZY_INSTANCE_INITIALIZER;
} // namespace
-const char Nl80211Message::kBogusMacAddress[] = "XX:XX:XX:XX:XX:XX";
-
const uint8_t Nl80211Frame::kMinimumFrameByteCount = 26;
const uint8_t Nl80211Frame::kFrameTypeMask = 0xfc;
-const uint32_t Nl80211Message::kIllegalMessage = 0;
+// TODO(wdg): These will go into NetlinkMessage when that class exists.
+const uint32_t Nl80211Message::kBroadcastSequenceNumber = 0;
+const uint16_t Nl80211Message::kIllegalMessageType = UINT16_MAX;
+
+const char Nl80211Message::kBogusMacAddress[] = "XX:XX:XX:XX:XX:XX";
const unsigned int Nl80211Message::kEthernetAddressBytes = 6;
map<uint16_t, string> *Nl80211Message::reason_code_string_ = NULL;
map<uint16_t, string> *Nl80211Message::status_code_string_ = NULL;
+uint16_t Nl80211Message::nl80211_message_type_ = kIllegalMessageType;
+
// The nl messages look like this:
//
@@ -108,11 +112,30 @@
// Nl80211Message
//
-void Nl80211Message::Print(int log_level) const {
- SLOG(WiFi, log_level) << StringPrintf("Message %s (%d)",
- message_type_string(),
- message_type());
- attributes_->Print(log_level, 1);
+bool Nl80211Message::InitAndStripHeader(ByteString *input) {
+ if (!input) {
+ LOG(ERROR) << "NULL input";
+ return false;
+ }
+ // Read the nlmsghdr.
+ nlmsghdr *header = reinterpret_cast<nlmsghdr *>(input->GetData());
+ message_type_ = header->nlmsg_type;
+ flags_ = header->nlmsg_flags;
+ sequence_number_ = header->nlmsg_seq;
+
+ // Strip the nlmsghdr.
+ input->RemovePrefix(NLMSG_ALIGN(sizeof(struct nlmsghdr)));
+
+ // Read the genlmsghdr.
+ genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(input->GetData());
+ if (command_ != gnlh->cmd) {
+ LOG(WARNING) << "This object thinks it's a " << command_
+ << " but the message thinks it's a " << gnlh->cmd;
+ }
+
+ // Strip the genlmsghdr.
+ input->RemovePrefix(NLMSG_ALIGN(sizeof(struct genlmsghdr)));
+ return true;
}
bool Nl80211Message::InitFromNlmsg(const nlmsghdr *const_msg) {
@@ -120,23 +143,19 @@
LOG(ERROR) << "Null |msg| parameter";
return false;
}
+ ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
+ const_msg->nlmsg_len);
- // Netlink header.
- sequence_number_ = const_msg->nlmsg_seq;
- SLOG(WiFi, 6) << "NL Message " << sequence_number() << " <===";
-
- // Casting away constness, here, since the libnl code doesn't properly label
- // their stuff as const (even though it is).
- nlmsghdr *msg = const_cast<nlmsghdr *>(const_msg);
-
- // Genl message header.
- genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(nlmsg_data(msg));
+ if (!InitAndStripHeader(&message)) {
+ return false;
+ }
// Attributes.
// Parse the attributes from the nl message payload into the 'tb' array.
nlattr *tb[NL80211_ATTR_MAX + 1];
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
+ nla_parse(tb, NL80211_ATTR_MAX,
+ reinterpret_cast<nlattr *>(message.GetData()), message.GetLength(),
+ NULL);
for (int i = 0; i < NL80211_ATTR_MAX + 1; ++i) {
if (tb[i]) {
@@ -345,6 +364,13 @@
return true;
}
+void Nl80211Message::Print(int log_level) const {
+ SLOG(WiFi, log_level) << StringPrintf("Message %s (%d)",
+ command_string(),
+ command());
+ attributes_->Print(log_level, 1);
+}
+
// static
void Nl80211Message::PrintBytes(int log_level, const unsigned char *buf,
size_t num_bytes) {
@@ -607,42 +633,61 @@
return match->second;
}
-ByteString Nl80211Message::Encode(uint16_t nlmsg_type) const {
+ByteString Nl80211Message::EncodeHeader(uint32_t sequence_number,
+ uint16_t nlmsg_type) {
+ ByteString result;
+ sequence_number_ = sequence_number;
+ if (sequence_number_ == kBroadcastSequenceNumber) {
+ LOG(ERROR) << "Couldn't get a legal sequence number";
+ return result;
+ }
+
// Build netlink header.
nlmsghdr header;
size_t nlmsghdr_with_pad = NLMSG_ALIGN(sizeof(header));
header.nlmsg_len = nlmsghdr_with_pad;
header.nlmsg_type = nlmsg_type;
header.nlmsg_flags = NLM_F_REQUEST;
- header.nlmsg_seq = sequence_number();
+ header.nlmsg_seq = sequence_number_;
header.nlmsg_pid = getpid();
- // Build genl message header.
- genlmsghdr genl_header;
- size_t genlmsghdr_with_pad = NLMSG_ALIGN(sizeof(genl_header));
- header.nlmsg_len += genlmsghdr_with_pad;
- genl_header.cmd = message_type();
- genl_header.version = 1;
- genl_header.reserved = 0;
-
- // Assemble attributes (padding is included by AttributeList::Encode).
- ByteString attribute_bytes = attributes_->Encode();
- header.nlmsg_len += attribute_bytes.GetLength();
-
- // Now that we know the total message size, build the output ByteString.
- ByteString result;
-
// Netlink header + pad.
result.Append(ByteString(reinterpret_cast<unsigned char *>(&header),
sizeof(header)));
result.Resize(nlmsghdr_with_pad); // Zero-fill pad space (if any).
- // Genl message header + pad.
- result.Append(ByteString(reinterpret_cast<unsigned char *>(&genl_header),
- sizeof(genl_header)));
- result.Resize(nlmsghdr_with_pad + genlmsghdr_with_pad); // Zero-fill.
+ // Build and append the genl message header.
+ genlmsghdr genl_header;
+ genl_header.cmd = command();
+ genl_header.version = 1;
+ genl_header.reserved = 0;
- // Attributes including pad.
+ ByteString genl_header_string(
+ reinterpret_cast<unsigned char *>(&genl_header), sizeof(genl_header));
+ size_t genlmsghdr_with_pad = NLMSG_ALIGN(sizeof(genl_header));
+ genl_header_string.Resize(genlmsghdr_with_pad); // Zero-fill.
+
+ nlmsghdr *pheader = reinterpret_cast<nlmsghdr *>(result.GetData());
+ pheader->nlmsg_len += genlmsghdr_with_pad;
+ result.Append(genl_header_string);
+ return result;
+}
+
+ByteString Nl80211Message::Encode(uint32_t sequence_number,
+ uint16_t nlmsg_type) {
+ ByteString result(EncodeHeader(sequence_number, nlmsg_type));
+ if (result.GetLength() == 0) {
+ LOG(ERROR) << "Couldn't encode message header.";
+ return result;
+ }
+
+ // Build and append attributes (padding is included by
+ // AttributeList::Encode).
+ ByteString attribute_bytes = attributes_->Encode();
+
+ // Need to re-calculate |header| since |Append|, above, moves the data.
+ nlmsghdr *pheader = reinterpret_cast<nlmsghdr *>(result.GetData());
+ pheader->nlmsg_len += attribute_bytes.GetLength();
result.Append(attribute_bytes);
return result;
@@ -991,13 +1036,13 @@
bool doit = false;
map<uint8_t, bool>::const_iterator node;
- node = need_to_print.find(message.message_type());
+ node = need_to_print.find(message.command());
if (node != need_to_print.end())
doit = node->second;
if (doit) {
LOG(INFO) << "@@const unsigned char "
- << "k" << message.message_type_string()
+ << "k" << message.command_string()
<< "[] = {";
int payload_bytes = nlmsg_datalen(msg);
@@ -1010,7 +1055,7 @@
<< + rawdata[i] << ",";
}
LOG(INFO) << "};";
- need_to_print[message.message_type()] = false;
+ need_to_print[message.command()] = false;
}
}
diff --git a/nl80211_message.h b/nl80211_message.h
index dddc46d..10986fa 100644
--- a/nl80211_message.h
+++ b/nl80211_message.h
@@ -26,19 +26,28 @@
namespace shill {
+class Config80211;
+
// Class for messages received from libnl.
class Nl80211Message {
public:
+ static const uint32_t kBroadcastSequenceNumber;
+ static const uint16_t kIllegalMessageType;
static const unsigned int kEthernetAddressBytes;
static const char kBogusMacAddress[];
- Nl80211Message(uint8 message_type, const char *message_type_string)
- : message_type_(message_type),
- message_type_string_(message_type_string),
- sequence_number_(kIllegalMessage),
- attributes_(new AttributeList) {}
+ Nl80211Message(uint8 command, const char *command_string)
+ : attributes_(new AttributeList),
+ command_(command),
+ command_string_(command_string),
+ flags_(0),
+ message_type_(nl80211_message_type_),
+ sequence_number_(kBroadcastSequenceNumber) {}
virtual ~Nl80211Message() {}
+ uint8 command() const { return command_; }
+ const char *command_string() const { return command_string_; }
+
// Initializes the message with bytes from the kernel.
virtual bool InitFromNlmsg(const nlmsghdr *msg);
static void PrintBytes(int log_level, const unsigned char *buf,
@@ -78,15 +87,22 @@
static std::string StringFromReason(uint16_t reason);
static std::string StringFromStatus(uint16_t status);
- uint8 message_type() const { return message_type_; }
- const char *message_type_string() const { return message_type_string_; }
-
// Returns a netlink message suitable for Sockets::Send. Return value is
// empty on failure. |nlmsg_type| needs to be the family id returned by
// |genl_ctrl_resolve|.
- ByteString Encode(uint16_t nlmsg_type) const;
+ ByteString Encode(uint32_t sequence_number, uint16_t nlmsg_type);
protected:
+ // Reads the values from the |nlmsghdr| and |genlmsghdr| portions of the
+ // netlink message and removes those headers (and any padding that happens to
+ // be there) from |input| leaving, hopefully, the attributes.
+ bool InitAndStripHeader(ByteString *input);
+
+ // Returns a string of bytes representing an |nlmsghdr| with the members
+ // filled-in with values representing the current message, and any required
+ // padding.
+ ByteString EncodeHeader(uint32_t sequence_number, uint16_t nlmsg_type);
+
// Returns a string that should precede all user-bound message strings.
virtual std::string GetHeaderString() const;
@@ -109,15 +125,16 @@
friend class Config80211Test;
FRIEND_TEST(Config80211Test, NL80211_CMD_NOTIFY_CQM);
- static const uint32_t kIllegalMessage;
-
- const uint8 message_type_;
- const char *message_type_string_;
+ static uint16_t nl80211_message_type_;
static std::map<uint16_t, std::string> *reason_code_string_;
static std::map<uint16_t, std::string> *status_code_string_;
- uint32_t sequence_number_;
AttributeListRefPtr attributes_;
+ const uint8 command_;
+ const char *command_string_;
+ uint16_t flags_;
+ uint16_t message_type_;
+ uint32_t sequence_number_;
DISALLOW_COPY_AND_ASSIGN(Nl80211Message);
};