shill: Splits the netlink message factory between message types.
Provides a mechanism to register message factories with
|NetlinkMessageFactory|. Splits |NetlinkMessageFactory| into a generic
factory and one for |ControlNetlinkMessage| and |Nl80211Message|. Uses
the registration mechanism to install the control and nl80211 message
factories.
This CL also moves |UnknownMessage| from being a subtype of
|Nl80211Message| to being a subtype of |NetlinkMessage|.
Lucy has some 'splaining to do: At startup time, the message type isn't
known for some types of netlink message (notably, the nl80211 class of
messages). This message type is discovered, in the code, through the
|Config80211::AddFamilyByString| call. This CL adds a message factory
closure to that call so that Config80211 can install the factory when
the code knows the message type against which to register the factory.
BUG=chromium:220372
TEST=unittest and manual (restarted shill with log=-10,wifi and observed
messages of all types being created for netlink messages coming from the
kernel).
Change-Id: I496b405c20ef98b6e23e96e8088fc542ff29264c
Reviewed-on: https://gerrit.chromium.org/gerrit/45314
Commit-Queue: Wade Guthrie <wdg@chromium.org>
Reviewed-by: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
diff --git a/Makefile b/Makefile
index 42a57ce..3643a5d 100644
--- a/Makefile
+++ b/Makefile
@@ -424,6 +424,7 @@
mock_wimax_provider.o \
mock_wimax_service.o \
modem_info_unittest.o \
+ netlink_message_unittest.o \
netlink_socket_unittest.o \
nice_mock_control.o \
nss_unittest.o \
diff --git a/config80211.cc b/config80211.cc
index 57daffc..abea104 100644
--- a/config80211.cc
+++ b/config80211.cc
@@ -136,6 +136,11 @@
}
bool Config80211::Init() {
+ // Install message factory for control class of messages, which has
+ // statically-known message type.
+ message_factory_.AddFactoryMethod(
+ ControlNetlinkMessage::kMessageType,
+ Bind(&ControlNetlinkMessage::CreateMessage));
if (!sock_) {
sock_ = new NetlinkSocket;
if (!sock_) {
@@ -165,7 +170,8 @@
return (sock_ ? sock_->file_descriptor() : -1);
}
-uint16_t Config80211::GetFamily(string name) {
+uint16_t Config80211::GetFamily(string name,
+ const NetlinkMessageFactory::FactoryMethod &message_factory) {
MessageType &message_type = message_types_[name];
if (message_type.family_id != NetlinkMessage::kIllegalMessageType) {
return message_type.family_id;
@@ -230,6 +236,10 @@
InputData input_data(received.GetData(), received.GetLength());
OnRawNlMessageReceived(&input_data);
if (message_type.family_id != NetlinkMessage::kIllegalMessageType) {
+ uint16_t family_id = message_type.family_id;
+ if (family_id != NetlinkMessage::kIllegalMessageType) {
+ message_factory_.AddFactoryMethod(family_id, message_factory);
+ }
time->GetTimeMonotonic(&now);
timersub(&now, &start_time, &wait_duration);
SLOG(WiFi, 5) << "Found id " << message_type.family_id
@@ -255,7 +265,6 @@
return family->second.family_id;
}
-
bool Config80211::AddBroadcastHandler(const NetlinkMessageHandler &handler) {
list<NetlinkMessageHandler>::iterator i;
if (FindBroadcastHandler(handler)) {
@@ -400,7 +409,7 @@
return;
}
const uint32 sequence_number = msg->nlmsg_seq;
- scoped_ptr<NetlinkMessage> message(NetlinkMessageFactory::CreateMessage(msg));
+ scoped_ptr<NetlinkMessage> message(message_factory_.CreateMessage(msg));
if (message == NULL) {
SLOG(WiFi, 3) << "NL Message " << sequence_number << " <===";
SLOG(WiFi, 3) << __func__ << "(msg:NULL)";
diff --git a/config80211.h b/config80211.h
index cb2e9fa..9582f11 100644
--- a/config80211.h
+++ b/config80211.h
@@ -70,6 +70,8 @@
#include <base/bind.h>
#include <base/lazy_instance.h>
+#include "shill/nl80211_message.h"
+
struct nlmsghdr;
namespace shill {
@@ -117,12 +119,6 @@
static const char kEventTypeRegulatory[];
static const char kEventTypeMlme[];
- // This represents whether the cfg80211/mac80211 are installed in the kernel.
- enum WifiState {
- kWifiUp,
- kWifiDown
- };
-
// Config80211 is a singleton and this is the way to access it.
static Config80211 *GetInstance();
@@ -144,7 +140,8 @@
// |NetlinkMessage::kIllegalMessageType| if the message type could not be
// determined. May block so |GetFamily| should be called before entering the
// event loop.
- uint16_t GetFamily(std::string family_name);
+ uint16_t GetFamily(std::string family_name,
+ const NetlinkMessageFactory::FactoryMethod &message_factory);
// Retrieves a family id (message type) given the |name| string describing
// the message family.
@@ -191,10 +188,22 @@
private:
friend class Config80211Test;
+ friend class NetlinkMessageTest;
friend class ShillDaemonTest;
FRIEND_TEST(Config80211Test, AddLinkTest);
FRIEND_TEST(Config80211Test, BroadcastHandlerTest);
FRIEND_TEST(Config80211Test, MessageHandlerTest);
+ FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_TRIGGER_SCAN);
+ FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_NEW_SCAN_RESULTS);
+ FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_NEW_STATION);
+ FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_AUTHENTICATE);
+ FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_ASSOCIATE);
+ FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_CONNECT);
+ FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_DEAUTHENTICATE);
+ FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_DISCONNECT);
+ FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_NOTIFY_CQM);
+ FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_DISASSOCIATE);
+
typedef std::map<uint32_t, NetlinkMessageHandler> MessageHandlers;
static const long kMaximumNewFamilyWaitSeconds;
@@ -240,6 +249,7 @@
NetlinkSocket *sock_;
std::map<const std::string, MessageType> message_types_;
+ NetlinkMessageFactory message_factory_;
DISALLOW_COPY_AND_ASSIGN(Config80211);
};
diff --git a/config80211_unittest.cc b/config80211_unittest.cc
index 0c8a4ec..d22a735 100644
--- a/config80211_unittest.cc
+++ b/config80211_unittest.cc
@@ -11,25 +11,14 @@
#include "shill/config80211.h"
-#include <netlink/netlink.h>
-
-#include <string>
-#include <vector>
-
-#include <base/stl_util.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "shill/mock_netlink_socket.h"
-#include "shill/netlink_attribute.h"
#include "shill/nl80211_message.h"
-#include "shill/refptr_types.h"
using base::Bind;
using base::Unretained;
-using base::WeakPtr;
-using std::string;
-using std::vector;
using testing::_;
using testing::Invoke;
using testing::Return;
@@ -39,13 +28,6 @@
namespace {
-// The group_id of the scan and mlme groups are, for the purposes of this
-// test, arbitrary as long as they're different. The values, here, have been
-// extracted from a specific run on hardware but that was, in reality, just
-// being pedantic.
-const uint32_t kEventTypeScanId = 4;
-const uint32_t kEventTypeMlmeId = 6;
-
// These data blocks have been collected by shill using Config80211 while,
// simultaneously (and manually) comparing shill output with that of the 'iw'
// code from which it was derived. The test strings represent the raw packet
@@ -54,258 +36,11 @@
// These constants are consistent throughout the packets, below.
-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
-
-const uint32_t kScanFrequencyTrigger[] = {
- 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
- 2452, 2457, 2462, 2467, 2472, 2484, 5180, 5200,
- 5220, 5240, 5260, 5280, 5300, 5320, 5500, 5520,
- 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680,
- 5700, 5745, 5765, 5785, 5805, 5825
-};
-
-const unsigned char kNL80211_CMD_TRIGGER_SCAN[] = {
- 0x68, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x21, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x2d, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x34, 0x01, 0x2c, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x6c, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x01, 0x00, 0x71, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x02, 0x00, 0x76, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x03, 0x00, 0x7b, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x05, 0x00, 0x85, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x06, 0x00, 0x8a, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x07, 0x00, 0x8f, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x08, 0x00, 0x94, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x09, 0x00, 0x99, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0a, 0x00, 0x9e, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0b, 0x00, 0xa3, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0c, 0x00, 0xa8, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0d, 0x00, 0xb4, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0e, 0x00, 0x3c, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x0f, 0x00, 0x50, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x10, 0x00, 0x64, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x11, 0x00, 0x78, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x12, 0x00, 0x8c, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x13, 0x00, 0xa0, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x14, 0x00, 0xb4, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x15, 0x00, 0xc8, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x16, 0x00, 0x7c, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x17, 0x00, 0x90, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x18, 0x00, 0xa4, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x19, 0x00, 0xb8, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x1a, 0x00, 0xcc, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x1b, 0x00, 0xe0, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x1c, 0x00, 0xf4, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x1d, 0x00, 0x08, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x1e, 0x00, 0x1c, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x1f, 0x00, 0x30, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x20, 0x00, 0x44, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x21, 0x00, 0x71, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x22, 0x00, 0x85, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x23, 0x00, 0x99, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x24, 0x00, 0xad, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x25, 0x00, 0xc1, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-
-// wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452
-// 2457 2462 2467 2472 2484 5180 5200 5220 5240 5260 5280 5300 5320 5500 5520
-// 5540 5560 5580 5600 5620 5640 5660 5680 5700 5745 5765 5785 5805 5825, ""
-
-const uint32_t kScanFrequencyResults[] = {
- 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
- 2452, 2457, 2462, 2467, 2472, 2484, 5180, 5200,
- 5220, 5240, 5260, 5280, 5300, 5320, 5500, 5520,
- 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680,
- 5700, 5745, 5765, 5785, 5805, 5825
-};
-
-const unsigned char kNL80211_CMD_NEW_SCAN_RESULTS[] = {
- 0x68, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x22, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x2d, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x34, 0x01, 0x2c, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x6c, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x01, 0x00, 0x71, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x02, 0x00, 0x76, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x03, 0x00, 0x7b, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x05, 0x00, 0x85, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x06, 0x00, 0x8a, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x07, 0x00, 0x8f, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x08, 0x00, 0x94, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x09, 0x00, 0x99, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0a, 0x00, 0x9e, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0b, 0x00, 0xa3, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0c, 0x00, 0xa8, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0d, 0x00, 0xb4, 0x09, 0x00, 0x00,
- 0x08, 0x00, 0x0e, 0x00, 0x3c, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x0f, 0x00, 0x50, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x10, 0x00, 0x64, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x11, 0x00, 0x78, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x12, 0x00, 0x8c, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x13, 0x00, 0xa0, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x14, 0x00, 0xb4, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x15, 0x00, 0xc8, 0x14, 0x00, 0x00,
- 0x08, 0x00, 0x16, 0x00, 0x7c, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x17, 0x00, 0x90, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x18, 0x00, 0xa4, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x19, 0x00, 0xb8, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x1a, 0x00, 0xcc, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x1b, 0x00, 0xe0, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x1c, 0x00, 0xf4, 0x15, 0x00, 0x00,
- 0x08, 0x00, 0x1d, 0x00, 0x08, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x1e, 0x00, 0x1c, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x1f, 0x00, 0x30, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x20, 0x00, 0x44, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x21, 0x00, 0x71, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x22, 0x00, 0x85, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x23, 0x00, 0x99, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x24, 0x00, 0xad, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x25, 0x00, 0xc1, 0x16, 0x00, 0x00,
- 0x08, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-
-// wlan0: new station c0:3f:0e:77:e8:7f
-
-const uint32_t kNewStationExpectedGeneration = 275;
-
-const unsigned char kNL80211_CMD_NEW_STATION[] = {
- 0x34, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x13, 0x01, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x06, 0x00,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00,
- 0x08, 0x00, 0x2e, 0x00, 0x13, 0x01, 0x00, 0x00,
- 0x04, 0x00, 0x15, 0x00,
-};
-
-
-// wlan0 (phy #0): auth c0:3f:0e:77:e8:7f -> 48:5d:60:77:2d:cf status: 0:
-// Successful [frame: b0 00 3a 01 48 5d 60 77 2d cf c0 3f 0e 77 e8 7f c0
-// 3f 0e 77 e8 7f 30 07 00 00 02 00 00 00]
-
-const unsigned char kAuthenticateFrame[] = {
- 0xb0, 0x00, 0x3a, 0x01, 0x48, 0x5d, 0x60, 0x77,
- 0x2d, 0xcf, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x30, 0x07,
- 0x00, 0x00, 0x02, 0x00, 0x00, 0x00
-};
-
-const unsigned char kNL80211_CMD_AUTHENTICATE[] = {
- 0x48, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x25, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x22, 0x00, 0x33, 0x00,
- 0xb0, 0x00, 0x3a, 0x01, 0x48, 0x5d, 0x60, 0x77,
- 0x2d, 0xcf, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x30, 0x07,
- 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-
-// wlan0 (phy #0): assoc c0:3f:0e:77:e8:7f -> 48:5d:60:77:2d:cf status: 0:
-// Successful [frame: 10 00 3a 01 48 5d 60 77 2d cf c0 3f 0e 77 e8 7f c0 3f 0e
-// 77 e8 7f 40 07 01 04 00 00 01 c0 01 08 82 84 8b 96 0c 12 18 24 32 04 30 48
-// 60 6c]
-
-const unsigned char kAssociateFrame[] = {
- 0x10, 0x00, 0x3a, 0x01, 0x48, 0x5d, 0x60, 0x77,
- 0x2d, 0xcf, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x40, 0x07,
- 0x01, 0x04, 0x00, 0x00, 0x01, 0xc0, 0x01, 0x08,
- 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
- 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c
-};
-
-const unsigned char kNL80211_CMD_ASSOCIATE[] = {
- 0x58, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x26, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x32, 0x00, 0x33, 0x00,
- 0x10, 0x00, 0x3a, 0x01, 0x48, 0x5d, 0x60, 0x77,
- 0x2d, 0xcf, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x40, 0x07,
- 0x01, 0x04, 0x00, 0x00, 0x01, 0xc0, 0x01, 0x08,
- 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
- 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, 0x00, 0x00,
-};
-
-
-// wlan0 (phy #0): connected to c0:3f:0e:77:e8:7f
-
-const uint16_t kExpectedConnectStatus = 0;
-
-const unsigned char kNL80211_CMD_CONNECT[] = {
- 0x4c, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x2e, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x06, 0x00,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00,
- 0x06, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x14, 0x00, 0x4e, 0x00, 0x01, 0x08, 0x82, 0x84,
- 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x32, 0x04,
- 0x30, 0x48, 0x60, 0x6c,
-};
-
-
-// wlan0 (phy #0): deauth c0:3f:0e:77:e8:7f -> ff:ff:ff:ff:ff:ff reason 2:
-// Previous authentication no longer valid [frame: c0 00 00 00 ff ff ff ff
-// ff ff c0 3f 0e 77 e8 7f c0 3f 0e 77 e8 7f c0 0e 02 00]
-
-const unsigned char kDeauthenticateFrame[] = {
- 0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0xc0, 0x0e,
- 0x02, 0x00
-};
-
-const unsigned char kNL80211_CMD_DEAUTHENTICATE[] = {
- 0x44, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x27, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x33, 0x00,
- 0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0xc0, 0x0e,
- 0x02, 0x00, 0x00, 0x00,
-};
-
// wlan0 (phy #0): disconnected (by AP) reason: 2: Previous authentication no
// longer valid
-const uint16_t kExpectedDisconnectReason = 2;
-
const unsigned char kNL80211_CMD_DISCONNECT[] = {
0x30, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -315,47 +50,6 @@
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x47, 0x00,
};
-
-// wlan0 (phy #0): connection quality monitor event: peer c0:3f:0e:77:e8:7f
-// didn't ACK 50 packets
-
-const uint32_t kExpectedCqmNotAcked = 50;
-
-const unsigned char kNL80211_CMD_NOTIFY_CQM[] = {
- 0x3c, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x06, 0x00,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00,
- 0x0c, 0x00, 0x5e, 0x00, 0x08, 0x00, 0x04, 0x00,
- 0x32, 0x00, 0x00, 0x00,
-};
-
-
-// wlan0 (phy #0): disassoc 48:5d:60:77:2d:cf -> c0:3f:0e:77:e8:7f reason 3:
-// Deauthenticated because sending station is [frame: a0 00 00 00 c0 3f 0e
-// 77 e8 7f 48 5d 60 77 2d cf c0 3f 0e 77 e8 7f 00 00 03 00]
-
-const unsigned char kDisassociateFrame[] = {
- 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x0e, 0x77,
- 0xe8, 0x7f, 0x48, 0x5d, 0x60, 0x77, 0x2d, 0xcf,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00,
- 0x03, 0x00
-};
-
-const unsigned char kNL80211_CMD_DISASSOCIATE[] = {
- 0x44, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x28, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x33, 0x00,
- 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x0e, 0x77,
- 0xe8, 0x7f, 0x48, 0x5d, 0x60, 0x77, 0x2d, 0xcf,
- 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00,
-};
-
const char kGetFamilyCommandString[] = "CTRL_CMD_GETFAMILY";
} // namespace
@@ -369,8 +63,10 @@
Config80211Test() : config80211_(Config80211::GetInstance()) {
config80211_->message_types_[Nl80211Message::kMessageTypeString].family_id =
kNl80211FamilyId;
+ config80211_->message_factory_.AddFactoryMethod(
+ kNl80211FamilyId, Bind(&Nl80211Message::CreateMessage));
Nl80211Message::SetMessageType(
- config80211_->GetFamily(Nl80211Message::kMessageTypeString));
+ config80211_->GetMessageType(Nl80211Message::kMessageTypeString));
}
~Config80211Test() {
@@ -408,39 +104,11 @@
// TODO(wdg): Add a test for multi-part messages. crbug.com/224652
// TODO(wdg): Add a test for GetFaimily. crbug.com/224649
// TODO(wdg): Add a test for OnNewFamilyMessage. crbug.com/222486
+// TODO(wdg): Add a test for GetMessageType
// TODO(wdg): Add a test for SubscribeToEvents (verify that it handles bad input
// appropriately, and that it calls NetlinkSocket::SubscribeToEvents if input
// is good.)
-class TestHandlerObject {
- public:
- TestHandlerObject() :
- message_handler_(Bind(&TestHandlerObject::MessageHandler,
- Unretained(this))) { }
- void MessageHandler(const NetlinkMessage &msg) {
- }
- const Config80211::NetlinkMessageHandler &message_handler() const {
- return message_handler_;
- }
-
- private:
- Config80211::NetlinkMessageHandler message_handler_;
-};
-
-// Checks a config80211 parameter to make sure it contains |handler_arg|
-// in its list of broadcast handlers.
-MATCHER_P(ContainsHandler, handler_arg, "") {
- if (arg == reinterpret_cast<void *>(NULL)) {
- LOG(WARNING) << "NULL parameter";
- return false;
- }
- const Config80211 *config80211 = static_cast<Config80211 *>(arg);
- const Config80211::NetlinkMessageHandler message_handler =
- static_cast<const Config80211::NetlinkMessageHandler>(handler_arg);
-
- return config80211->FindBroadcastHandler(message_handler);
-}
-
TEST_F(Config80211Test, BroadcastHandlerTest) {
SetupConfig80211Object();
@@ -452,7 +120,11 @@
// Simple, 1 handler, case.
EXPECT_CALL(handler1, OnNetlinkMessage(_)).Times(1);
+ EXPECT_FALSE(
+ config80211_->FindBroadcastHandler(handler1.on_netlink_message()));
config80211_->AddBroadcastHandler(handler1.on_netlink_message());
+ EXPECT_TRUE(
+ config80211_->FindBroadcastHandler(handler1.on_netlink_message()));
config80211_->OnNlMessageReceived(message);
// Add a second handler.
@@ -552,469 +224,4 @@
config80211_->OnNlMessageReceived(received_message);
}
-TEST_F(Config80211Test, Parse_NL80211_CMD_TRIGGER_SCAN) {
- NetlinkMessage *netlink_message = NetlinkMessageFactory::CreateMessage(
- const_cast<nlmsghdr *>(
- reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_TRIGGER_SCAN)));
-
- EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
- EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
- // The follwing is legal if the message_type is kNl80211FamilyId.
- Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
-
- EXPECT_EQ(NL80211_CMD_TRIGGER_SCAN, message->command());
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_WIPHY, &value));
- EXPECT_EQ(kWiPhy, value);
- }
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_IFINDEX, &value));
- EXPECT_EQ(kExpectedIfIndex, value);
- }
-
- // Make sure the scan frequencies in the attribute are the ones we expect.
- {
- vector<uint32_t>list;
- EXPECT_TRUE(message->GetScanFrequenciesAttribute(
- NL80211_ATTR_SCAN_FREQUENCIES, &list));
- EXPECT_EQ(list.size(), arraysize(kScanFrequencyTrigger));
- int i = 0;
- vector<uint32_t>::const_iterator j = list.begin();
- while (j != list.end()) {
- EXPECT_EQ(kScanFrequencyTrigger[i], *j);
- ++i;
- ++j;
- }
- }
-
- {
- vector<string> ssids;
- EXPECT_TRUE(message->GetScanSsidsAttribute(NL80211_ATTR_SCAN_SSIDS,
- &ssids));
- EXPECT_EQ(1, ssids.size());
- EXPECT_EQ(0, ssids[0].compare("")); // Expect a single, empty SSID.
- }
-
- EXPECT_TRUE(message->const_attributes()->IsFlagAttributeTrue(
- NL80211_ATTR_SUPPORT_MESH_AUTH));
-}
-
-TEST_F(Config80211Test, Parse_NL80211_CMD_NEW_SCAN_RESULTS) {
- NetlinkMessage *netlink_message = NetlinkMessageFactory::CreateMessage(
- const_cast<nlmsghdr *>(
- reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_NEW_SCAN_RESULTS)));
-
- EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
- EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
- // The follwing is legal if the message_type is kNl80211FamilyId.
- Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
-
- EXPECT_EQ(NL80211_CMD_NEW_SCAN_RESULTS, message->command());
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_WIPHY, &value));
- EXPECT_EQ(kWiPhy, value);
- }
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_IFINDEX, &value));
- EXPECT_EQ(kExpectedIfIndex, value);
- }
-
- // Make sure the scan frequencies in the attribute are the ones we expect.
- {
- vector<uint32_t>list;
- EXPECT_TRUE(message->GetScanFrequenciesAttribute(
- NL80211_ATTR_SCAN_FREQUENCIES, &list));
- EXPECT_EQ(arraysize(kScanFrequencyResults), list.size());
- int i = 0;
- vector<uint32_t>::const_iterator j = list.begin();
- while (j != list.end()) {
- EXPECT_EQ(kScanFrequencyResults[i], *j);
- ++i;
- ++j;
- }
- }
-
- {
- vector<string> ssids;
- EXPECT_TRUE(message->GetScanSsidsAttribute(NL80211_ATTR_SCAN_SSIDS,
- &ssids));
- EXPECT_EQ(1, ssids.size());
- EXPECT_EQ(0, ssids[0].compare("")); // Expect a single, empty SSID.
- }
-
- EXPECT_TRUE(message->const_attributes()->IsFlagAttributeTrue(
- NL80211_ATTR_SUPPORT_MESH_AUTH));
-}
-
-TEST_F(Config80211Test, Parse_NL80211_CMD_NEW_STATION) {
- NetlinkMessage *netlink_message = NetlinkMessageFactory::CreateMessage(
- const_cast<nlmsghdr *>(
- reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_NEW_STATION)));
-
- EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
- EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
- // The follwing is legal if the message_type is kNl80211FamilyId.
- Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
- EXPECT_EQ(NL80211_CMD_NEW_STATION, message->command());
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_IFINDEX, &value));
- EXPECT_EQ(kExpectedIfIndex, value);
- }
-
- {
- string value;
- EXPECT_TRUE(message->GetMacAttributeString(NL80211_ATTR_MAC, &value));
- EXPECT_EQ(0, strncmp(value.c_str(), kExpectedMacAddress, value.length()));
- }
-
- {
- AttributeListConstRefPtr nested;
- EXPECT_TRUE(message->const_attributes()->ConstGetNestedAttributeList(
- NL80211_ATTR_STA_INFO, &nested));
- }
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_GENERATION, &value));
- EXPECT_EQ(kNewStationExpectedGeneration, value);
- }
-}
-
-TEST_F(Config80211Test, Parse_NL80211_CMD_AUTHENTICATE) {
- NetlinkMessage *netlink_message = NetlinkMessageFactory::CreateMessage(
- const_cast<nlmsghdr *>(
- reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_AUTHENTICATE)));
-
- EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
- EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
- // The follwing is legal if the message_type is kNl80211FamilyId.
- Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
- EXPECT_EQ(NL80211_CMD_AUTHENTICATE, message->command());
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_WIPHY, &value));
- EXPECT_EQ(kWiPhy, value);
- }
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_IFINDEX, &value));
- EXPECT_EQ(kExpectedIfIndex, value);
- }
-
- {
- ByteString rawdata;
- EXPECT_TRUE(message->const_attributes()->GetRawAttributeValue(
- NL80211_ATTR_FRAME, &rawdata));
- EXPECT_FALSE(rawdata.IsEmpty());
- Nl80211Frame frame(rawdata);
- Nl80211Frame expected_frame(ByteString(kAuthenticateFrame,
- sizeof(kAuthenticateFrame)));
- EXPECT_TRUE(frame.IsEqual(expected_frame));
- }
-}
-
-TEST_F(Config80211Test, Parse_NL80211_CMD_ASSOCIATE) {
- NetlinkMessage *netlink_message = NetlinkMessageFactory::CreateMessage(
- const_cast<nlmsghdr *>(
- reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_ASSOCIATE)));
-
- EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
- EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
- // The follwing is legal if the message_type is kNl80211FamilyId.
- Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
- EXPECT_EQ(NL80211_CMD_ASSOCIATE, message->command());
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_WIPHY, &value));
- EXPECT_EQ(kWiPhy, value);
- }
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_IFINDEX, &value));
- EXPECT_EQ(kExpectedIfIndex, value);
- }
-
- {
- ByteString rawdata;
- EXPECT_TRUE(message->const_attributes()->GetRawAttributeValue(
- NL80211_ATTR_FRAME, &rawdata));
- EXPECT_FALSE(rawdata.IsEmpty());
- Nl80211Frame frame(rawdata);
- Nl80211Frame expected_frame(ByteString(kAssociateFrame,
- sizeof(kAssociateFrame)));
- EXPECT_TRUE(frame.IsEqual(expected_frame));
- }
-}
-
-TEST_F(Config80211Test, Parse_NL80211_CMD_CONNECT) {
- NetlinkMessage *netlink_message = NetlinkMessageFactory::CreateMessage(
- const_cast<nlmsghdr *>(
- reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_CONNECT)));
-
- EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
- EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
- // The follwing is legal if the message_type is kNl80211FamilyId.
- Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
- EXPECT_EQ(NL80211_CMD_CONNECT, message->command());
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_WIPHY, &value));
- EXPECT_EQ(kWiPhy, value);
- }
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_IFINDEX, &value));
- EXPECT_EQ(kExpectedIfIndex, value);
- }
-
- {
- string value;
- EXPECT_TRUE(message->GetMacAttributeString(NL80211_ATTR_MAC, &value));
- EXPECT_EQ(0, strncmp(value.c_str(), kExpectedMacAddress, value.length()));
- }
-
- {
- uint16_t value;
- EXPECT_TRUE(message->const_attributes()->GetU16AttributeValue(
- NL80211_ATTR_STATUS_CODE, &value));
- EXPECT_EQ(kExpectedConnectStatus, value);
- }
-
- // TODO(wdg): Need to check the value of this attribute.
- {
- ByteString rawdata;
- EXPECT_TRUE(message->const_attributes()->GetRawAttributeValue(
- NL80211_ATTR_RESP_IE, &rawdata));
- }
-}
-
-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.
-
- ByteString message_bytes = message.Encode(config80211_->GetSequenceNumber());
- 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) {
- NetlinkMessage *netlink_message = NetlinkMessageFactory::CreateMessage(
- const_cast<nlmsghdr *>(
- reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DEAUTHENTICATE)));
-
- EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
- EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
- // The follwing is legal if the message_type is kNl80211FamilyId.
- Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
- EXPECT_EQ(NL80211_CMD_DEAUTHENTICATE, message->command());
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_WIPHY, &value));
- EXPECT_EQ(kWiPhy, value);
- }
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_IFINDEX, &value));
- EXPECT_EQ(kExpectedIfIndex, value);
- }
-
- {
- ByteString rawdata;
- EXPECT_TRUE(message->const_attributes()->GetRawAttributeValue(
- NL80211_ATTR_FRAME, &rawdata));
- EXPECT_FALSE(rawdata.IsEmpty());
- Nl80211Frame frame(rawdata);
- Nl80211Frame expected_frame(ByteString(kDeauthenticateFrame,
- sizeof(kDeauthenticateFrame)));
- EXPECT_TRUE(frame.IsEqual(expected_frame));
- }
-}
-
-TEST_F(Config80211Test, Parse_NL80211_CMD_DISCONNECT) {
- NetlinkMessage *netlink_message = NetlinkMessageFactory::CreateMessage(
- const_cast<nlmsghdr *>(
- reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DISCONNECT)));
-
- EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
- EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
- // The follwing is legal if the message_type is kNl80211FamilyId.
- Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
- EXPECT_EQ(NL80211_CMD_DISCONNECT, message->command());
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_WIPHY, &value));
- EXPECT_EQ(kWiPhy, value);
- }
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_IFINDEX, &value));
- EXPECT_EQ(kExpectedIfIndex, value);
- }
-
- {
- uint16_t value;
- EXPECT_TRUE(message->const_attributes()->GetU16AttributeValue(
- NL80211_ATTR_REASON_CODE, &value));
- EXPECT_EQ(kExpectedDisconnectReason, value);
- }
-
- EXPECT_TRUE(message->const_attributes()->IsFlagAttributeTrue(
- NL80211_ATTR_DISCONNECTED_BY_AP));
-}
-
-TEST_F(Config80211Test, Parse_NL80211_CMD_NOTIFY_CQM) {
- NetlinkMessage *netlink_message = NetlinkMessageFactory::CreateMessage(
- const_cast<nlmsghdr *>(
- reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_NOTIFY_CQM)));
-
- EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
- EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
- // The follwing is legal if the message_type is kNl80211FamilyId.
- Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
- EXPECT_EQ(NL80211_CMD_NOTIFY_CQM, message->command());
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_WIPHY, &value));
- EXPECT_EQ(kWiPhy, value);
- }
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_IFINDEX, &value));
- EXPECT_EQ(kExpectedIfIndex, value);
- }
-
- {
- string value;
- EXPECT_TRUE(message->GetMacAttributeString(NL80211_ATTR_MAC, &value));
- EXPECT_EQ(0, strncmp(value.c_str(), kExpectedMacAddress, value.length()));
- }
-
- {
- AttributeListConstRefPtr nested;
- EXPECT_TRUE(message->const_attributes()->ConstGetNestedAttributeList(
- NL80211_ATTR_CQM, &nested));
- uint32_t threshold_event;
- EXPECT_FALSE(nested->GetU32AttributeValue(
- NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, &threshold_event));
- uint32_t pkt_loss_event;
- EXPECT_TRUE(nested->GetU32AttributeValue(
- NL80211_ATTR_CQM_PKT_LOSS_EVENT, &pkt_loss_event));
- EXPECT_EQ(kExpectedCqmNotAcked, pkt_loss_event);
- }
-}
-
-TEST_F(Config80211Test, Parse_NL80211_CMD_DISASSOCIATE) {
- NetlinkMessage *netlink_message = NetlinkMessageFactory::CreateMessage(
- const_cast<nlmsghdr *>(
- reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DISASSOCIATE)));
-
- EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
- EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
- // The follwing is legal if the message_type is kNl80211FamilyId.
- Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
- EXPECT_EQ(NL80211_CMD_DISASSOCIATE, message->command());
-
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_WIPHY, &value));
- EXPECT_EQ(kWiPhy, value);
- }
-
- {
- uint32_t value;
- EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
- NL80211_ATTR_IFINDEX, &value));
- EXPECT_EQ(kExpectedIfIndex, value);
- }
-
- {
- ByteString rawdata;
- EXPECT_TRUE(message->const_attributes()->GetRawAttributeValue(
- NL80211_ATTR_FRAME, &rawdata));
- EXPECT_FALSE(rawdata.IsEmpty());
- Nl80211Frame frame(rawdata);
- Nl80211Frame expected_frame(ByteString(kDisassociateFrame,
- sizeof(kDisassociateFrame)));
- EXPECT_TRUE(frame.IsEqual(expected_frame));
- }
-}
-
} // namespace shill
diff --git a/netlink_message_unittest.cc b/netlink_message_unittest.cc
new file mode 100644
index 0000000..5eebade
--- /dev/null
+++ b/netlink_message_unittest.cc
@@ -0,0 +1,826 @@
+// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides tests for individual messages. It tests
+// NetlinkMessageFactory's ability to create specific message types and it
+// tests the various NetlinkMessage types' ability to parse those
+// messages.
+
+// This file tests the public interface to NetlinkMessage.
+
+#include "shill/nl80211_message.h"
+
+#include <string>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "shill/mock_netlink_socket.h"
+#include "shill/netlink_attribute.h"
+#include "shill/refptr_types.h"
+
+using base::Bind;
+using base::Unretained;
+using std::string;
+using std::vector;
+using testing::_;
+using testing::Invoke;
+using testing::Return;
+using testing::Test;
+
+namespace shill {
+
+namespace {
+
+// These data blocks have been collected by shill using Config80211 while,
+// simultaneously (and manually) comparing shill output with that of the 'iw'
+// code from which it was derived. The test strings represent the raw packet
+// data coming from the kernel. The comments above each of these strings is
+// the markup that "iw" outputs for ech of these packets.
+
+// These constants are consistent throughout the packets, below.
+
+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
+
+const uint32_t kScanFrequencyTrigger[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
+ 2452, 2457, 2462, 2467, 2472, 2484, 5180, 5200,
+ 5220, 5240, 5260, 5280, 5300, 5320, 5500, 5520,
+ 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680,
+ 5700, 5745, 5765, 5785, 5805, 5825
+};
+
+const unsigned char kNL80211_CMD_TRIGGER_SCAN[] = {
+ 0x68, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x21, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x2d, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x34, 0x01, 0x2c, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x6c, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x01, 0x00, 0x71, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x76, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x03, 0x00, 0x7b, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x05, 0x00, 0x85, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x06, 0x00, 0x8a, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x07, 0x00, 0x8f, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x08, 0x00, 0x94, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x09, 0x00, 0x99, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x0a, 0x00, 0x9e, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x0b, 0x00, 0xa3, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x0c, 0x00, 0xa8, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x0d, 0x00, 0xb4, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x0e, 0x00, 0x3c, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x0f, 0x00, 0x50, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x10, 0x00, 0x64, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x11, 0x00, 0x78, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x12, 0x00, 0x8c, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x13, 0x00, 0xa0, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x14, 0x00, 0xb4, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x15, 0x00, 0xc8, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x16, 0x00, 0x7c, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x17, 0x00, 0x90, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x18, 0x00, 0xa4, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x19, 0x00, 0xb8, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x1a, 0x00, 0xcc, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x1b, 0x00, 0xe0, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x1c, 0x00, 0xf4, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x1d, 0x00, 0x08, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x1e, 0x00, 0x1c, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x1f, 0x00, 0x30, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x20, 0x00, 0x44, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x21, 0x00, 0x71, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x22, 0x00, 0x85, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x23, 0x00, 0x99, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x24, 0x00, 0xad, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x25, 0x00, 0xc1, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+
+// wlan0 (phy #0): scan finished: 2412 2417 2422 2427 2432 2437 2442 2447 2452
+// 2457 2462 2467 2472 2484 5180 5200 5220 5240 5260 5280 5300 5320 5500 5520
+// 5540 5560 5580 5600 5620 5640 5660 5680 5700 5745 5765 5785 5805 5825, ""
+
+const uint32_t kScanFrequencyResults[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
+ 2452, 2457, 2462, 2467, 2472, 2484, 5180, 5200,
+ 5220, 5240, 5260, 5280, 5300, 5320, 5500, 5520,
+ 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680,
+ 5700, 5745, 5765, 5785, 5805, 5825
+};
+
+const unsigned char kNL80211_CMD_NEW_SCAN_RESULTS[] = {
+ 0x68, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x2d, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x34, 0x01, 0x2c, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x6c, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x01, 0x00, 0x71, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x76, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x03, 0x00, 0x7b, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x04, 0x00, 0x80, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x05, 0x00, 0x85, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x06, 0x00, 0x8a, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x07, 0x00, 0x8f, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x08, 0x00, 0x94, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x09, 0x00, 0x99, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x0a, 0x00, 0x9e, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x0b, 0x00, 0xa3, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x0c, 0x00, 0xa8, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x0d, 0x00, 0xb4, 0x09, 0x00, 0x00,
+ 0x08, 0x00, 0x0e, 0x00, 0x3c, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x0f, 0x00, 0x50, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x10, 0x00, 0x64, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x11, 0x00, 0x78, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x12, 0x00, 0x8c, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x13, 0x00, 0xa0, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x14, 0x00, 0xb4, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x15, 0x00, 0xc8, 0x14, 0x00, 0x00,
+ 0x08, 0x00, 0x16, 0x00, 0x7c, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x17, 0x00, 0x90, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x18, 0x00, 0xa4, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x19, 0x00, 0xb8, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x1a, 0x00, 0xcc, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x1b, 0x00, 0xe0, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x1c, 0x00, 0xf4, 0x15, 0x00, 0x00,
+ 0x08, 0x00, 0x1d, 0x00, 0x08, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x1e, 0x00, 0x1c, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x1f, 0x00, 0x30, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x20, 0x00, 0x44, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x21, 0x00, 0x71, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x22, 0x00, 0x85, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x23, 0x00, 0x99, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x24, 0x00, 0xad, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x25, 0x00, 0xc1, 0x16, 0x00, 0x00,
+ 0x08, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+
+// wlan0: new station c0:3f:0e:77:e8:7f
+
+const uint32_t kNewStationExpectedGeneration = 275;
+
+const unsigned char kNL80211_CMD_NEW_STATION[] = {
+ 0x34, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x13, 0x01, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x06, 0x00,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00,
+ 0x08, 0x00, 0x2e, 0x00, 0x13, 0x01, 0x00, 0x00,
+ 0x04, 0x00, 0x15, 0x00,
+};
+
+
+// wlan0 (phy #0): auth c0:3f:0e:77:e8:7f -> 48:5d:60:77:2d:cf status: 0:
+// Successful [frame: b0 00 3a 01 48 5d 60 77 2d cf c0 3f 0e 77 e8 7f c0
+// 3f 0e 77 e8 7f 30 07 00 00 02 00 00 00]
+
+const unsigned char kAuthenticateFrame[] = {
+ 0xb0, 0x00, 0x3a, 0x01, 0x48, 0x5d, 0x60, 0x77,
+ 0x2d, 0xcf, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x30, 0x07,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00
+};
+
+const unsigned char kNL80211_CMD_AUTHENTICATE[] = {
+ 0x48, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x25, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x22, 0x00, 0x33, 0x00,
+ 0xb0, 0x00, 0x3a, 0x01, 0x48, 0x5d, 0x60, 0x77,
+ 0x2d, 0xcf, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x30, 0x07,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+
+// wlan0 (phy #0): assoc c0:3f:0e:77:e8:7f -> 48:5d:60:77:2d:cf status: 0:
+// Successful [frame: 10 00 3a 01 48 5d 60 77 2d cf c0 3f 0e 77 e8 7f c0 3f 0e
+// 77 e8 7f 40 07 01 04 00 00 01 c0 01 08 82 84 8b 96 0c 12 18 24 32 04 30 48
+// 60 6c]
+
+const unsigned char kAssociateFrame[] = {
+ 0x10, 0x00, 0x3a, 0x01, 0x48, 0x5d, 0x60, 0x77,
+ 0x2d, 0xcf, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x40, 0x07,
+ 0x01, 0x04, 0x00, 0x00, 0x01, 0xc0, 0x01, 0x08,
+ 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
+ 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c
+};
+
+const unsigned char kNL80211_CMD_ASSOCIATE[] = {
+ 0x58, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x26, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x32, 0x00, 0x33, 0x00,
+ 0x10, 0x00, 0x3a, 0x01, 0x48, 0x5d, 0x60, 0x77,
+ 0x2d, 0xcf, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x40, 0x07,
+ 0x01, 0x04, 0x00, 0x00, 0x01, 0xc0, 0x01, 0x08,
+ 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24,
+ 0x32, 0x04, 0x30, 0x48, 0x60, 0x6c, 0x00, 0x00,
+};
+
+
+// wlan0 (phy #0): connected to c0:3f:0e:77:e8:7f
+
+const uint16_t kExpectedConnectStatus = 0;
+
+const unsigned char kNL80211_CMD_CONNECT[] = {
+ 0x4c, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2e, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x06, 0x00,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00,
+ 0x06, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x4e, 0x00, 0x01, 0x08, 0x82, 0x84,
+ 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x32, 0x04,
+ 0x30, 0x48, 0x60, 0x6c,
+};
+
+
+// wlan0 (phy #0): deauth c0:3f:0e:77:e8:7f -> ff:ff:ff:ff:ff:ff reason 2:
+// Previous authentication no longer valid [frame: c0 00 00 00 ff ff ff ff
+// ff ff c0 3f 0e 77 e8 7f c0 3f 0e 77 e8 7f c0 0e 02 00]
+
+const unsigned char kDeauthenticateFrame[] = {
+ 0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0xc0, 0x0e,
+ 0x02, 0x00
+};
+
+const unsigned char kNL80211_CMD_DEAUTHENTICATE[] = {
+ 0x44, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x27, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x33, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0xc0, 0x0e,
+ 0x02, 0x00, 0x00, 0x00,
+};
+
+
+// wlan0 (phy #0): disconnected (by AP) reason: 2: Previous authentication no
+// longer valid
+
+const uint16_t kExpectedDisconnectReason = 2;
+
+const unsigned char kNL80211_CMD_DISCONNECT[] = {
+ 0x30, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x36, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x47, 0x00,
+};
+
+
+// wlan0 (phy #0): connection quality monitor event: peer c0:3f:0e:77:e8:7f
+// didn't ACK 50 packets
+
+const uint32_t kExpectedCqmNotAcked = 50;
+
+const unsigned char kNL80211_CMD_NOTIFY_CQM[] = {
+ 0x3c, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x06, 0x00,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00,
+ 0x0c, 0x00, 0x5e, 0x00, 0x08, 0x00, 0x04, 0x00,
+ 0x32, 0x00, 0x00, 0x00,
+};
+
+
+// wlan0 (phy #0): disassoc 48:5d:60:77:2d:cf -> c0:3f:0e:77:e8:7f reason 3:
+// Deauthenticated because sending station is [frame: a0 00 00 00 c0 3f 0e
+// 77 e8 7f 48 5d 60 77 2d cf c0 3f 0e 77 e8 7f 00 00 03 00]
+
+const unsigned char kDisassociateFrame[] = {
+ 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x0e, 0x77,
+ 0xe8, 0x7f, 0x48, 0x5d, 0x60, 0x77, 0x2d, 0xcf,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00,
+ 0x03, 0x00
+};
+
+const unsigned char kNL80211_CMD_DISASSOCIATE[] = {
+ 0x44, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x33, 0x00,
+ 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x0e, 0x77,
+ 0xe8, 0x7f, 0x48, 0x5d, 0x60, 0x77, 0x2d, 0xcf,
+ 0xc0, 0x3f, 0x0e, 0x77, 0xe8, 0x7f, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00,
+};
+
+const char kGetFamilyCommandString[] = "CTRL_CMD_GETFAMILY";
+
+} // namespace
+
+class NetlinkMessageTest : public Test {
+ public:
+ NetlinkMessageTest() {
+ message_factory_.AddFactoryMethod(
+ kNl80211FamilyId, Bind(&Nl80211Message::CreateMessage));
+ Nl80211Message::SetMessageType(kNl80211FamilyId);
+ }
+
+ protected:
+ NetlinkMessageFactory message_factory_;
+};
+
+TEST_F(NetlinkMessageTest, Parse_NL80211_CMD_TRIGGER_SCAN) {
+ NetlinkMessage *netlink_message =
+ message_factory_.CreateMessage(const_cast<nlmsghdr *>(
+ reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_TRIGGER_SCAN)));
+
+ EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
+ EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
+ // The follwing is legal if the message_type is kNl80211FamilyId.
+ Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
+
+ EXPECT_EQ(NL80211_CMD_TRIGGER_SCAN, message->command());
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_WIPHY, &value));
+ EXPECT_EQ(kWiPhy, value);
+ }
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, &value));
+ EXPECT_EQ(kExpectedIfIndex, value);
+ }
+
+ // Make sure the scan frequencies in the attribute are the ones we expect.
+ {
+ vector<uint32_t>list;
+ EXPECT_TRUE(message->GetScanFrequenciesAttribute(
+ NL80211_ATTR_SCAN_FREQUENCIES, &list));
+ EXPECT_EQ(list.size(), arraysize(kScanFrequencyTrigger));
+ int i = 0;
+ vector<uint32_t>::const_iterator j = list.begin();
+ while (j != list.end()) {
+ EXPECT_EQ(kScanFrequencyTrigger[i], *j);
+ ++i;
+ ++j;
+ }
+ }
+
+ {
+ vector<string> ssids;
+ EXPECT_TRUE(message->GetScanSsidsAttribute(NL80211_ATTR_SCAN_SSIDS,
+ &ssids));
+ EXPECT_EQ(1, ssids.size());
+ EXPECT_EQ(0, ssids[0].compare("")); // Expect a single, empty SSID.
+ }
+
+ EXPECT_TRUE(message->const_attributes()->IsFlagAttributeTrue(
+ NL80211_ATTR_SUPPORT_MESH_AUTH));
+}
+
+TEST_F(NetlinkMessageTest, Parse_NL80211_CMD_NEW_SCAN_RESULTS) {
+ NetlinkMessage *netlink_message =
+ message_factory_.CreateMessage(const_cast<nlmsghdr *>(
+ reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_NEW_SCAN_RESULTS)));
+
+ EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
+ EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
+ // The follwing is legal if the message_type is kNl80211FamilyId.
+ Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
+
+ EXPECT_EQ(NL80211_CMD_NEW_SCAN_RESULTS, message->command());
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_WIPHY, &value));
+ EXPECT_EQ(kWiPhy, value);
+ }
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, &value));
+ EXPECT_EQ(kExpectedIfIndex, value);
+ }
+
+ // Make sure the scan frequencies in the attribute are the ones we expect.
+ {
+ vector<uint32_t>list;
+ EXPECT_TRUE(message->GetScanFrequenciesAttribute(
+ NL80211_ATTR_SCAN_FREQUENCIES, &list));
+ EXPECT_EQ(arraysize(kScanFrequencyResults), list.size());
+ int i = 0;
+ vector<uint32_t>::const_iterator j = list.begin();
+ while (j != list.end()) {
+ EXPECT_EQ(kScanFrequencyResults[i], *j);
+ ++i;
+ ++j;
+ }
+ }
+
+ {
+ vector<string> ssids;
+ EXPECT_TRUE(message->GetScanSsidsAttribute(NL80211_ATTR_SCAN_SSIDS,
+ &ssids));
+ EXPECT_EQ(1, ssids.size());
+ EXPECT_EQ(0, ssids[0].compare("")); // Expect a single, empty SSID.
+ }
+
+ EXPECT_TRUE(message->const_attributes()->IsFlagAttributeTrue(
+ NL80211_ATTR_SUPPORT_MESH_AUTH));
+}
+
+TEST_F(NetlinkMessageTest, Parse_NL80211_CMD_NEW_STATION) {
+ NetlinkMessage *netlink_message =
+ message_factory_.CreateMessage(const_cast<nlmsghdr *>(
+ reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_NEW_STATION)));
+
+ EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
+ EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
+ // The follwing is legal if the message_type is kNl80211FamilyId.
+ Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
+ EXPECT_EQ(NL80211_CMD_NEW_STATION, message->command());
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, &value));
+ EXPECT_EQ(kExpectedIfIndex, value);
+ }
+
+ {
+ string value;
+ EXPECT_TRUE(message->GetMacAttributeString(NL80211_ATTR_MAC, &value));
+ EXPECT_EQ(0, strncmp(value.c_str(), kExpectedMacAddress, value.length()));
+ }
+
+ {
+ AttributeListConstRefPtr nested;
+ EXPECT_TRUE(message->const_attributes()->ConstGetNestedAttributeList(
+ NL80211_ATTR_STA_INFO, &nested));
+ }
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_GENERATION, &value));
+ EXPECT_EQ(kNewStationExpectedGeneration, value);
+ }
+}
+
+TEST_F(NetlinkMessageTest, Parse_NL80211_CMD_AUTHENTICATE) {
+ NetlinkMessage *netlink_message =
+ message_factory_.CreateMessage(const_cast<nlmsghdr *>(
+ reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_AUTHENTICATE)));
+
+ EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
+ EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
+ // The follwing is legal if the message_type is kNl80211FamilyId.
+ Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
+ EXPECT_EQ(NL80211_CMD_AUTHENTICATE, message->command());
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_WIPHY, &value));
+ EXPECT_EQ(kWiPhy, value);
+ }
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, &value));
+ EXPECT_EQ(kExpectedIfIndex, value);
+ }
+
+ {
+ ByteString rawdata;
+ EXPECT_TRUE(message->const_attributes()->GetRawAttributeValue(
+ NL80211_ATTR_FRAME, &rawdata));
+ EXPECT_FALSE(rawdata.IsEmpty());
+ Nl80211Frame frame(rawdata);
+ Nl80211Frame expected_frame(ByteString(kAuthenticateFrame,
+ sizeof(kAuthenticateFrame)));
+ EXPECT_TRUE(frame.IsEqual(expected_frame));
+ }
+}
+
+TEST_F(NetlinkMessageTest, Parse_NL80211_CMD_ASSOCIATE) {
+ NetlinkMessage *netlink_message =
+ message_factory_.CreateMessage(const_cast<nlmsghdr *>(
+ reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_ASSOCIATE)));
+
+ EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
+ EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
+ // The follwing is legal if the message_type is kNl80211FamilyId.
+ Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
+ EXPECT_EQ(NL80211_CMD_ASSOCIATE, message->command());
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_WIPHY, &value));
+ EXPECT_EQ(kWiPhy, value);
+ }
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, &value));
+ EXPECT_EQ(kExpectedIfIndex, value);
+ }
+
+ {
+ ByteString rawdata;
+ EXPECT_TRUE(message->const_attributes()->GetRawAttributeValue(
+ NL80211_ATTR_FRAME, &rawdata));
+ EXPECT_FALSE(rawdata.IsEmpty());
+ Nl80211Frame frame(rawdata);
+ Nl80211Frame expected_frame(ByteString(kAssociateFrame,
+ sizeof(kAssociateFrame)));
+ EXPECT_TRUE(frame.IsEqual(expected_frame));
+ }
+}
+
+TEST_F(NetlinkMessageTest, Parse_NL80211_CMD_CONNECT) {
+ NetlinkMessage *netlink_message =
+ message_factory_.CreateMessage(const_cast<nlmsghdr *>(
+ reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_CONNECT)));
+
+ EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
+ EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
+ // The follwing is legal if the message_type is kNl80211FamilyId.
+ Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
+ EXPECT_EQ(NL80211_CMD_CONNECT, message->command());
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_WIPHY, &value));
+ EXPECT_EQ(kWiPhy, value);
+ }
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, &value));
+ EXPECT_EQ(kExpectedIfIndex, value);
+ }
+
+ {
+ string value;
+ EXPECT_TRUE(message->GetMacAttributeString(NL80211_ATTR_MAC, &value));
+ EXPECT_EQ(0, strncmp(value.c_str(), kExpectedMacAddress, value.length()));
+ }
+
+ {
+ uint16_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU16AttributeValue(
+ NL80211_ATTR_STATUS_CODE, &value));
+ EXPECT_EQ(kExpectedConnectStatus, value);
+ }
+
+ // TODO(wdg): Need to check the value of this attribute.
+ {
+ ByteString rawdata;
+ EXPECT_TRUE(message->const_attributes()->GetRawAttributeValue(
+ NL80211_ATTR_RESP_IE, &rawdata));
+ }
+}
+
+TEST_F(NetlinkMessageTest, Build_NL80211_CMD_CONNECT) {
+ // 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.
+ static const uint32_t kArbitrarySequenceNumber = 42;
+ ByteString message_bytes = message.Encode(kArbitrarySequenceNumber);
+ 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(NetlinkMessageTest, Parse_NL80211_CMD_DEAUTHENTICATE) {
+ NetlinkMessage *netlink_message =
+ message_factory_.CreateMessage(const_cast<nlmsghdr *>(
+ reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DEAUTHENTICATE)));
+
+ EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
+ EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
+ // The follwing is legal if the message_type is kNl80211FamilyId.
+ Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
+ EXPECT_EQ(NL80211_CMD_DEAUTHENTICATE, message->command());
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_WIPHY, &value));
+ EXPECT_EQ(kWiPhy, value);
+ }
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, &value));
+ EXPECT_EQ(kExpectedIfIndex, value);
+ }
+
+ {
+ ByteString rawdata;
+ EXPECT_TRUE(message->const_attributes()->GetRawAttributeValue(
+ NL80211_ATTR_FRAME, &rawdata));
+ EXPECT_FALSE(rawdata.IsEmpty());
+ Nl80211Frame frame(rawdata);
+ Nl80211Frame expected_frame(ByteString(kDeauthenticateFrame,
+ sizeof(kDeauthenticateFrame)));
+ EXPECT_TRUE(frame.IsEqual(expected_frame));
+ }
+}
+
+TEST_F(NetlinkMessageTest, Parse_NL80211_CMD_DISCONNECT) {
+ NetlinkMessage *netlink_message =
+ message_factory_.CreateMessage(const_cast<nlmsghdr *>(
+ reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DISCONNECT)));
+
+ EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
+ EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
+ // The follwing is legal if the message_type is kNl80211FamilyId.
+ Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
+ EXPECT_EQ(NL80211_CMD_DISCONNECT, message->command());
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_WIPHY, &value));
+ EXPECT_EQ(kWiPhy, value);
+ }
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, &value));
+ EXPECT_EQ(kExpectedIfIndex, value);
+ }
+
+ {
+ uint16_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU16AttributeValue(
+ NL80211_ATTR_REASON_CODE, &value));
+ EXPECT_EQ(kExpectedDisconnectReason, value);
+ }
+
+ EXPECT_TRUE(message->const_attributes()->IsFlagAttributeTrue(
+ NL80211_ATTR_DISCONNECTED_BY_AP));
+}
+
+TEST_F(NetlinkMessageTest, Parse_NL80211_CMD_NOTIFY_CQM) {
+ NetlinkMessage *netlink_message =
+ message_factory_.CreateMessage(const_cast<nlmsghdr *>(
+ reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_NOTIFY_CQM)));
+
+ EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
+ EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
+ // The follwing is legal if the message_type is kNl80211FamilyId.
+ Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
+ EXPECT_EQ(NL80211_CMD_NOTIFY_CQM, message->command());
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_WIPHY, &value));
+ EXPECT_EQ(kWiPhy, value);
+ }
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, &value));
+ EXPECT_EQ(kExpectedIfIndex, value);
+ }
+
+ {
+ string value;
+ EXPECT_TRUE(message->GetMacAttributeString(NL80211_ATTR_MAC, &value));
+ EXPECT_EQ(0, strncmp(value.c_str(), kExpectedMacAddress, value.length()));
+ }
+
+ {
+ AttributeListConstRefPtr nested;
+ EXPECT_TRUE(message->const_attributes()->ConstGetNestedAttributeList(
+ NL80211_ATTR_CQM, &nested));
+ uint32_t threshold_event;
+ EXPECT_FALSE(nested->GetU32AttributeValue(
+ NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, &threshold_event));
+ uint32_t pkt_loss_event;
+ EXPECT_TRUE(nested->GetU32AttributeValue(
+ NL80211_ATTR_CQM_PKT_LOSS_EVENT, &pkt_loss_event));
+ EXPECT_EQ(kExpectedCqmNotAcked, pkt_loss_event);
+ }
+}
+
+TEST_F(NetlinkMessageTest, Parse_NL80211_CMD_DISASSOCIATE) {
+ NetlinkMessage *netlink_message =
+ message_factory_.CreateMessage(const_cast<nlmsghdr *>(
+ reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DISASSOCIATE)));
+
+ EXPECT_NE(reinterpret_cast<NetlinkMessage *>(NULL), netlink_message);
+ EXPECT_EQ(kNl80211FamilyId, netlink_message->message_type());
+ // The follwing is legal if the message_type is kNl80211FamilyId.
+ Nl80211Message *message = reinterpret_cast<Nl80211Message *>(netlink_message);
+ EXPECT_EQ(NL80211_CMD_DISASSOCIATE, message->command());
+
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_WIPHY, &value));
+ EXPECT_EQ(kWiPhy, value);
+ }
+
+ {
+ uint32_t value;
+ EXPECT_TRUE(message->const_attributes()->GetU32AttributeValue(
+ NL80211_ATTR_IFINDEX, &value));
+ EXPECT_EQ(kExpectedIfIndex, value);
+ }
+
+ {
+ ByteString rawdata;
+ EXPECT_TRUE(message->const_attributes()->GetRawAttributeValue(
+ NL80211_ATTR_FRAME, &rawdata));
+ EXPECT_FALSE(rawdata.IsEmpty());
+ Nl80211Frame frame(rawdata);
+ Nl80211Frame expected_frame(ByteString(kDisassociateFrame,
+ sizeof(kDisassociateFrame)));
+ EXPECT_TRUE(frame.IsEqual(expected_frame));
+ }
+}
+
+} // namespace shill
diff --git a/nl80211_message.cc b/nl80211_message.cc
index d990a76..c0c2400 100644
--- a/nl80211_message.cc
+++ b/nl80211_message.cc
@@ -36,6 +36,7 @@
#include <base/bind.h>
#include <base/format_macros.h>
+#include <base/stl_util.h>
#include <base/stringprintf.h>
#include "shill/attribute_list.h"
@@ -186,6 +187,8 @@
}
}
+// ErrorAckMessage.
+
const uint16_t ErrorAckMessage::kMessageType = NLMSG_ERROR;
bool ErrorAckMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
@@ -224,6 +227,8 @@
SLOG(WiFi, log_level) << ToString();
}
+// NoopMessage.
+
const uint16_t NoopMessage::kMessageType = NLMSG_NOOP;
ByteString NoopMessage::Encode(uint32_t sequence_number) {
@@ -235,6 +240,8 @@
SLOG(WiFi, log_level) << ToString();
}
+// DoneMessage.
+
const uint16_t DoneMessage::kMessageType = NLMSG_DONE;
ByteString DoneMessage::Encode(uint32_t sequence_number) {
@@ -247,6 +254,8 @@
SLOG(WiFi, log_level) << ToString();
}
+// OverrunMessage.
+
const uint16_t OverrunMessage::kMessageType = NLMSG_OVERRUN;
ByteString OverrunMessage::Encode(uint32_t sequence_number) {
@@ -258,6 +267,24 @@
SLOG(WiFi, log_level) << ToString();
}
+// UnknownMessage.
+
+ByteString UnknownMessage::Encode(uint32_t sequence_number) {
+ LOG(ERROR) << "We're not supposed to send UNKNOWN messages to the kernel";
+ return ByteString();
+}
+
+void UnknownMessage::Print(int log_level) const {
+ int total_bytes = message_body_.GetLength();
+ const uint8_t *const_data = message_body_.GetConstData();
+
+ string output = StringPrintf("%d bytes:", total_bytes);
+ for (int i = 0; i < total_bytes; ++i) {
+ StringAppendF(&output, " 0x%02x", const_data[i]);
+ }
+ SLOG(WiFi, log_level) << output;
+}
+
// GenericNetlinkMessage
ByteString GenericNetlinkMessage::EncodeHeader(uint32_t sequence_number) {
@@ -731,6 +758,31 @@
const uint8_t GetFamilyMessage::kCommand = CTRL_CMD_GETFAMILY;
const char GetFamilyMessage::kCommandString[] = "CTRL_CMD_GETFAMILY";
+// static
+NetlinkMessage *ControlNetlinkMessage::CreateMessage(
+ const nlmsghdr *const_msg) {
+ if (!const_msg) {
+ LOG(ERROR) << "NULL |const_msg| parameter";
+ return NULL;
+ }
+ // Casting away constness since, while nlmsg_data doesn't change its
+ // parameter, it also doesn't declare its paramenter as const.
+ nlmsghdr *msg = const_cast<nlmsghdr *>(const_msg);
+ void *payload = nlmsg_data(msg);
+ genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(payload);
+
+ switch (gnlh->cmd) {
+ case NewFamilyMessage::kCommand:
+ return new NewFamilyMessage();
+ case GetFamilyMessage::kCommand:
+ return new GetFamilyMessage();
+ default:
+ LOG(WARNING) << "Unknown/unhandled netlink control message " << gnlh->cmd;
+ break;
+ }
+ return NULL;
+}
+
// Nl80211Frame
Nl80211Frame::Nl80211Frame(const ByteString &raw_frame)
@@ -831,7 +883,6 @@
return frame_.Equals(other.frame_);
}
-
//
// Specific Nl80211Message types.
//
@@ -918,9 +969,6 @@
const uint8_t TriggerScanMessage::kCommand = NL80211_CMD_TRIGGER_SCAN;
const char TriggerScanMessage::kCommandString[] = "NL80211_CMD_TRIGGER_SCAN";
-const uint8_t UnknownMessage::kCommand = 0xff;
-const char UnknownMessage::kCommandString[] = "<Unknown Message Type>";
-
const uint8_t UnprotDeauthenticateMessage::kCommand =
NL80211_CMD_UNPROT_DEAUTHENTICATE;
const char UnprotDeauthenticateMessage::kCommandString[] =
@@ -931,102 +979,131 @@
const char UnprotDisassociateMessage::kCommandString[] =
"NL80211_CMD_UNPROT_DISASSOCIATE";
+// static
+NetlinkMessage *Nl80211Message::CreateMessage(const nlmsghdr *const_msg) {
+ if (!const_msg) {
+ LOG(ERROR) << "NULL |const_msg| parameter";
+ return NULL;
+ }
+ // Casting away constness since, while nlmsg_data doesn't change its
+ // parameter, it also doesn't declare its paramenter as const.
+ nlmsghdr *msg = const_cast<nlmsghdr *>(const_msg);
+ void *payload = nlmsg_data(msg);
+ genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(payload);
+ scoped_ptr<NetlinkMessage> message;
+
+ switch (gnlh->cmd) {
+ case AssociateMessage::kCommand:
+ return new AssociateMessage();
+ case AuthenticateMessage::kCommand:
+ return new AuthenticateMessage();
+ case CancelRemainOnChannelMessage::kCommand:
+ return new CancelRemainOnChannelMessage();
+ case ConnectMessage::kCommand:
+ return new ConnectMessage();
+ case DeauthenticateMessage::kCommand:
+ return new DeauthenticateMessage();
+ case DeleteStationMessage::kCommand:
+ return new DeleteStationMessage();
+ case DisassociateMessage::kCommand:
+ return new DisassociateMessage();
+ case DisconnectMessage::kCommand:
+ return new DisconnectMessage();
+ case FrameTxStatusMessage::kCommand:
+ return new FrameTxStatusMessage();
+ case GetRegMessage::kCommand:
+ return new GetRegMessage();
+ case JoinIbssMessage::kCommand:
+ return new JoinIbssMessage();
+ case MichaelMicFailureMessage::kCommand:
+ return new MichaelMicFailureMessage();
+ case NewScanResultsMessage::kCommand:
+ return new NewScanResultsMessage();
+ case NewStationMessage::kCommand:
+ return new NewStationMessage();
+ case NewWifiMessage::kCommand:
+ return new NewWifiMessage();
+ case NotifyCqmMessage::kCommand:
+ return new NotifyCqmMessage();
+ case PmksaCandidateMessage::kCommand:
+ return new PmksaCandidateMessage();
+ case RegBeaconHintMessage::kCommand:
+ return new RegBeaconHintMessage();
+ case RegChangeMessage::kCommand:
+ return new RegChangeMessage();
+ case RemainOnChannelMessage::kCommand:
+ return new RemainOnChannelMessage();
+ case RoamMessage::kCommand:
+ return new RoamMessage();
+ case ScanAbortedMessage::kCommand:
+ return new ScanAbortedMessage();
+ case TriggerScanMessage::kCommand:
+ return new TriggerScanMessage();
+ case UnprotDeauthenticateMessage::kCommand:
+ return new UnprotDeauthenticateMessage();
+ case UnprotDisassociateMessage::kCommand:
+ return new UnprotDisassociateMessage();
+ default:
+ LOG(WARNING) << "Unknown/unhandled netlink nl80211 message " << gnlh->cmd;
+ break;
+ }
+ return NULL;
+}
+
//
// Factory class.
//
-// TODO(wdg): later, each message_type should register its own callback for
-// creating messages. For now, however, this is much easier.
-NetlinkMessage *NetlinkMessageFactory::CreateMessage(nlmsghdr *msg) {
- if (!msg) {
- LOG(ERROR) << "NULL |msg| parameter";
+bool NetlinkMessageFactory::AddFactoryMethod(uint16_t message_type,
+ FactoryMethod factory) {
+ if (ContainsKey(factories_, message_type)) {
+ LOG(WARNING) << "Message type " << message_type << " already exists.";
+ return false;
+ }
+ if (message_type == NetlinkMessage::kIllegalMessageType) {
+ LOG(ERROR) << "Not installing factory for illegal message type.";
+ return false;
+ }
+ factories_[message_type] = factory;
+ return true;
+}
+
+NetlinkMessage *NetlinkMessageFactory::CreateMessage(
+ const nlmsghdr *const_msg) const {
+ if (!const_msg) {
+ LOG(ERROR) << "NULL |const_msg| parameter";
return NULL;
}
scoped_ptr<NetlinkMessage> message;
- void *payload = nlmsg_data(msg);
- if (msg->nlmsg_type == NoopMessage::kMessageType) {
+ if (const_msg->nlmsg_type == NoopMessage::kMessageType) {
message.reset(new NoopMessage());
- } else if (msg->nlmsg_type == DoneMessage::kMessageType) {
+ } else if (const_msg->nlmsg_type == DoneMessage::kMessageType) {
message.reset(new DoneMessage());
- } else if (msg->nlmsg_type == OverrunMessage::kMessageType) {
+ } else if (const_msg->nlmsg_type == OverrunMessage::kMessageType) {
message.reset(new OverrunMessage());
- } else if (msg->nlmsg_type == ErrorAckMessage::kMessageType) {
+ } else if (const_msg->nlmsg_type == ErrorAckMessage::kMessageType) {
message.reset(new ErrorAckMessage());
- } else if (msg->nlmsg_type == ControlNetlinkMessage::kMessageType) {
- genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(payload);
-
- switch (gnlh->cmd) {
- case NewFamilyMessage::kCommand:
- message.reset(new NewFamilyMessage()); break;
- case GetFamilyMessage::kCommand:
- message.reset(new GetFamilyMessage()); break;
-
- default:
- message.reset(new UnknownMessage(gnlh->cmd)); break;
- }
- } else {
- genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(payload);
-
- switch (gnlh->cmd) {
- case AssociateMessage::kCommand:
- message.reset(new AssociateMessage()); break;
- case AuthenticateMessage::kCommand:
- message.reset(new AuthenticateMessage()); break;
- case CancelRemainOnChannelMessage::kCommand:
- message.reset(new CancelRemainOnChannelMessage()); break;
- case ConnectMessage::kCommand:
- message.reset(new ConnectMessage()); break;
- case DeauthenticateMessage::kCommand:
- message.reset(new DeauthenticateMessage()); break;
- case DeleteStationMessage::kCommand:
- message.reset(new DeleteStationMessage()); break;
- case DisassociateMessage::kCommand:
- message.reset(new DisassociateMessage()); break;
- case DisconnectMessage::kCommand:
- message.reset(new DisconnectMessage()); break;
- case FrameTxStatusMessage::kCommand:
- message.reset(new FrameTxStatusMessage()); break;
- case GetRegMessage::kCommand:
- message.reset(new GetRegMessage()); break;
- case JoinIbssMessage::kCommand:
- message.reset(new JoinIbssMessage()); break;
- case MichaelMicFailureMessage::kCommand:
- message.reset(new MichaelMicFailureMessage()); break;
- case NewScanResultsMessage::kCommand:
- message.reset(new NewScanResultsMessage()); break;
- case NewStationMessage::kCommand:
- message.reset(new NewStationMessage()); break;
- case NewWifiMessage::kCommand:
- message.reset(new NewWifiMessage()); break;
- case NotifyCqmMessage::kCommand:
- message.reset(new NotifyCqmMessage()); break;
- case PmksaCandidateMessage::kCommand:
- message.reset(new PmksaCandidateMessage()); break;
- case RegBeaconHintMessage::kCommand:
- message.reset(new RegBeaconHintMessage()); break;
- case RegChangeMessage::kCommand:
- message.reset(new RegChangeMessage()); break;
- case RemainOnChannelMessage::kCommand:
- message.reset(new RemainOnChannelMessage()); break;
- case RoamMessage::kCommand:
- message.reset(new RoamMessage()); break;
- case ScanAbortedMessage::kCommand:
- message.reset(new ScanAbortedMessage()); break;
- case TriggerScanMessage::kCommand:
- message.reset(new TriggerScanMessage()); break;
- case UnprotDeauthenticateMessage::kCommand:
- message.reset(new UnprotDeauthenticateMessage()); break;
- case UnprotDisassociateMessage::kCommand:
- message.reset(new UnprotDisassociateMessage()); break;
-
- default:
- message.reset(new UnknownMessage(gnlh->cmd)); break;
- }
+ } else if (ContainsKey(factories_, const_msg->nlmsg_type)) {
+ map<uint16_t, FactoryMethod>::const_iterator factory;
+ factory = factories_.find(const_msg->nlmsg_type);
+ message.reset(factory->second.Run(const_msg));
}
- if (!message->InitFromNlmsg(msg)) {
+ // If no factory exists for this message _or_ if a factory exists but it
+ // failed, there'll be no message. Handle either of those cases, by
+ // creating an |UnknownMessage|.
+ if (!message) {
+ // Casting away constness since, while nlmsg_data doesn't change its
+ // parameter, it also doesn't declare its paramenter as const.
+ nlmsghdr *msg = const_cast<nlmsghdr *>(const_msg);
+ ByteString payload(reinterpret_cast<char *>(nlmsg_data(msg)),
+ nlmsg_datalen(msg));
+ message.reset(new UnknownMessage(msg->nlmsg_type, payload));
+ }
+
+ if (!message->InitFromNlmsg(const_msg)) {
LOG(ERROR) << "Message did not initialize properly";
return NULL;
}
@@ -1034,6 +1111,10 @@
return message.release();
}
+//
+// Data Collector
+//
+
Nl80211MessageDataCollector *
Nl80211MessageDataCollector::GetInstance() {
return g_datacollector.Pointer();
diff --git a/nl80211_message.h b/nl80211_message.h
index 198b467..33b3dbc 100644
--- a/nl80211_message.h
+++ b/nl80211_message.h
@@ -181,6 +181,20 @@
DISALLOW_COPY_AND_ASSIGN(OverrunMessage);
};
+
+class UnknownMessage : public NetlinkMessage {
+ public:
+ UnknownMessage(uint16_t message_type, ByteString message_body) :
+ NetlinkMessage(message_type), message_body_(message_body) {}
+ virtual ByteString Encode(uint32_t sequence_number);
+ virtual void Print(int log_level) const;
+
+ private:
+ ByteString message_body_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnknownMessage);
+};
+
// Objects of the |GenericNetlinkMessage| type represent messages that contain
// a |genlmsghdr| after a |nlmsghdr|. These messages seem to all contain a
// payload that consists of a list of structured attributes (it's possible that
@@ -265,6 +279,9 @@
: GenericNetlinkMessage(kMessageType, command, command_string) {}
virtual bool InitFromNlmsg(const nlmsghdr *msg);
+
+ // Message factory for all types of Control netlink message.
+ static NetlinkMessage *CreateMessage(const nlmsghdr *const_msg);
};
class NewFamilyMessage : public ControlNetlinkMessage {
@@ -340,6 +357,9 @@
static std::string StringFromReason(uint16_t reason);
static std::string StringFromStatus(uint16_t status);
+ // Message factory for all types of Nl80211 message.
+ static NetlinkMessage *CreateMessage(const nlmsghdr *const_msg);
+
private:
static std::map<uint16_t, std::string> *reason_code_string_;
static std::map<uint16_t, std::string> *status_code_string_;
@@ -673,22 +693,6 @@
};
-class UnknownMessage : public Nl80211Message {
- public:
- explicit UnknownMessage(uint8_t command)
- : Nl80211Message(command, kCommandString),
- command_(command) {}
-
- static const uint8_t kCommand;
- static const char kCommandString[];
-
- private:
- uint8_t command_;
-
- DISALLOW_COPY_AND_ASSIGN(UnknownMessage);
-};
-
-
class UnprotDeauthenticateMessage : public Nl80211Message {
public:
static const uint8_t kCommand;
@@ -720,18 +724,24 @@
class NetlinkMessageFactory {
public:
+ typedef base::Callback<NetlinkMessage *(const nlmsghdr *msg)> FactoryMethod;
+
+ NetlinkMessageFactory() {}
+
+ // Adds a message factory for a specific message_type. Intended to be used
+ // at initialization.
+ bool AddFactoryMethod(uint16_t message_type, FactoryMethod factory);
+
// Ownership of the message is passed to the caller and, as such, he should
// delete it.
- static NetlinkMessage *CreateMessage(nlmsghdr *msg);
- // TODO(wdg): Need a way for a class to register a callback and a message
- // type. That way, CreateMessage can call the appropriate factory based on
- // the incoming message type.
+ NetlinkMessage *CreateMessage(const nlmsghdr *msg) const;
private:
+ std::map<uint16_t, FactoryMethod> factories_;
+
DISALLOW_COPY_AND_ASSIGN(NetlinkMessageFactory);
};
-
// Nl80211MessageDataCollector - this class is used to collect data to be
// used for unit tests. It is only invoked in this case.
diff --git a/shill_daemon.cc b/shill_daemon.cc
index 38866c8..55de12f 100644
--- a/shill_daemon.cc
+++ b/shill_daemon.cc
@@ -105,7 +105,8 @@
if (config80211_) {
config80211_->Init();
uint16_t nl80211_family_id = config80211_->GetFamily(
- Nl80211Message::kMessageTypeString);
+ Nl80211Message::kMessageTypeString,
+ Bind(&Nl80211Message::CreateMessage));
if (nl80211_family_id == NetlinkMessage::kIllegalMessageType) {
LOG(FATAL) << "Didn't get a legal message type for 'nl80211' messages.";
}