shill: Add message-specific callbacks to the nl80211 code.

This allows users to create a one-off nl80211 message, install a
callback for that message, and then send the message to the kernel.
When the response is issued, the callback will be called and then
removed from the system.

BUG=chromium-os:35129
TEST=Manual and unit tests (including new ones).

Change-Id: I06bf8d16629f3eac226209b49827289e7a9cdca3
Reviewed-on: https://gerrit.chromium.org/gerrit/36904
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Ready: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
diff --git a/config80211_unittest.cc b/config80211_unittest.cc
index 4bcf6f2..9bae303 100644
--- a/config80211_unittest.cc
+++ b/config80211_unittest.cc
@@ -18,9 +18,13 @@
 #include <base/bind.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <net/if.h>
 #include <netlink/attr.h>
+#include <netlink/genl/genl.h>
+#include <netlink/msg.h>
 #include <netlink/netlink.h>
 
+#include "shill/kernel_bound_nlmessage.h"
 #include "shill/mock_callback80211_object.h"
 #include "shill/mock_nl80211_socket.h"
 #include "shill/nl80211_socket.h"
@@ -32,6 +36,7 @@
 using std::string;
 using std::vector;
 using testing::_;
+using testing::Invoke;
 using testing::Return;
 using testing::Test;
 
@@ -339,6 +344,8 @@
 
 }  // namespace
 
+unsigned int MockNl80211Socket::number_ = 0;
+
 class Config80211Test : public Test {
  public:
   Config80211Test() : config80211_(Config80211::GetInstance()) {}
@@ -390,6 +397,8 @@
   EXPECT_CALL(socket_, AddGroupMembership(_)).Times(0);
   EXPECT_CALL(socket_, DisableSequenceChecking()).Times(0);
   EXPECT_CALL(socket_, SetNetlinkCallback(_, _)).Times(0);
+  EXPECT_CALL(socket_, GetSequenceNumber())
+      .WillRepeatedly(Invoke(&MockNl80211Socket::GetNextNumber));
 
   EXPECT_TRUE(config80211_->AddBroadcastCallback(
       callback_object.GetCallback()));
@@ -439,6 +448,129 @@
   config80211_->SetWifiState(Config80211::kWifiUp);
 }
 
+TEST_F(Config80211Test, BroadcastCallbackTest) {
+  SetupConfig80211Object();
+
+  nlmsghdr *message = const_cast<nlmsghdr *>(
+        reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_DISCONNECT));
+
+  MockCallback80211 callback1(config80211_);
+  MockCallback80211 callback2(config80211_);
+  EXPECT_CALL(socket_, GetSequenceNumber())
+      .WillRepeatedly(Invoke(&MockNl80211Socket::GetNextNumber));
+
+  // Simple, 1 callback, case.
+  EXPECT_CALL(callback1, Config80211MessageCallback(_)).Times(1);
+  EXPECT_TRUE(callback1.InstallAsBroadcastCallback());
+  config80211_->OnNlMessageReceived(message);
+
+  // Add a second callback.
+  EXPECT_CALL(callback1, Config80211MessageCallback(_)).Times(1);
+  EXPECT_CALL(callback2, Config80211MessageCallback(_)).Times(1);
+  EXPECT_TRUE(callback2.InstallAsBroadcastCallback());
+  config80211_->OnNlMessageReceived(message);
+
+  // Verify that a callback can't be added twice.
+  EXPECT_CALL(callback1, Config80211MessageCallback(_)).Times(1);
+  EXPECT_CALL(callback2, Config80211MessageCallback(_)).Times(1);
+  EXPECT_FALSE(callback1.InstallAsBroadcastCallback());
+  config80211_->OnNlMessageReceived(message);
+
+  // Check that we can remove a callback.
+  EXPECT_CALL(callback1, Config80211MessageCallback(_)).Times(0);
+  EXPECT_CALL(callback2, Config80211MessageCallback(_)).Times(1);
+  EXPECT_TRUE(callback1.DeinstallAsCallback());
+  config80211_->OnNlMessageReceived(message);
+
+  // Check that re-adding the callback goes smoothly.
+  EXPECT_CALL(callback1, Config80211MessageCallback(_)).Times(1);
+  EXPECT_CALL(callback2, Config80211MessageCallback(_)).Times(1);
+  EXPECT_TRUE(callback1.InstallAsBroadcastCallback());
+  config80211_->OnNlMessageReceived(message);
+
+  // Check that ClearBroadcastCallbacks works.
+  config80211_->ClearBroadcastCallbacks();
+  EXPECT_CALL(callback1, Config80211MessageCallback(_)).Times(0);
+  EXPECT_CALL(callback2, Config80211MessageCallback(_)).Times(0);
+  config80211_->OnNlMessageReceived(message);
+}
+
+TEST_F(Config80211Test, MessageCallbackTest) {
+  // Setup.
+  SetupConfig80211Object();
+
+  EXPECT_CALL(socket_, GetSequenceNumber())
+      .WillRepeatedly(Invoke(&MockNl80211Socket::GetNextNumber));
+
+  MockCallback80211 callback_broadcast(config80211_);
+  EXPECT_TRUE(callback_broadcast.InstallAsBroadcastCallback());
+
+  KernelBoundNlMessage sent_message_1;
+  MockCallback80211 callback_sent_1(config80211_);
+  EXPECT_TRUE(sent_message_1.Init());
+  EXPECT_TRUE(sent_message_1.AddNetlinkHeader(&socket_, 0, NL_AUTO_SEQ, 0, 0, 0,
+                                              CTRL_CMD_GETFAMILY, 0));
+  LOG(INFO) << "Message 1 id:" << sent_message_1.GetId();
+
+  KernelBoundNlMessage sent_message_2;
+  MockCallback80211 callback_sent_2(config80211_);
+  EXPECT_TRUE(sent_message_2.Init());
+  EXPECT_TRUE(sent_message_2.AddNetlinkHeader(&socket_, 0, NL_AUTO_SEQ, 0, 0, 0,
+                                              CTRL_CMD_GETFAMILY, 0));
+  LOG(INFO) << "Message 2 id:" << sent_message_2.GetId();
+
+  // This is more testing the test code than the code, itself.
+  EXPECT_NE(sent_message_1.GetId(), sent_message_2.GetId());
+
+  // Set up the received message as a response to sent_message_1.
+  scoped_array<unsigned char> message_memory(
+      new unsigned char[sizeof(kNL80211_CMD_DISCONNECT)]);
+  memcpy(message_memory.get(), kNL80211_CMD_DISCONNECT,
+         sizeof(kNL80211_CMD_DISCONNECT));
+  nlmsghdr *received_message =
+        reinterpret_cast<nlmsghdr *>(message_memory.get());
+  received_message->nlmsg_seq = sent_message_1.GetId();
+
+  // Now, we can start the actual test...
+
+  // Verify that generic callback gets called for a message when no
+  // message-specific callback has been installed.
+  EXPECT_CALL(callback_broadcast, Config80211MessageCallback(_)).Times(1);
+  config80211_->OnNlMessageReceived(received_message);
+
+  // Install message-based callback; verify that message callback gets called.
+  EXPECT_TRUE(config80211_->SetMessageCallback(sent_message_1,
+                                               callback_sent_1.GetCallback()));
+  EXPECT_CALL(callback_sent_1, Config80211MessageCallback(_)).Times(1);
+  config80211_->OnNlMessageReceived(received_message);
+
+  // Verify that broadcast callback is called for the message after the
+  // message-specific callback is called once.
+  EXPECT_CALL(callback_broadcast, Config80211MessageCallback(_)).Times(1);
+  config80211_->OnNlMessageReceived(received_message);
+
+  // Install and then uninstall message-specific callback; verify broadcast
+  // callback is called on message receipt.
+  EXPECT_TRUE(config80211_->SetMessageCallback(sent_message_1,
+                                               callback_sent_1.GetCallback()));
+  EXPECT_TRUE(config80211_->UnsetMessageCallbackById(sent_message_1.GetId()));
+  EXPECT_CALL(callback_broadcast, Config80211MessageCallback(_)).Times(1);
+  config80211_->OnNlMessageReceived(received_message);
+
+  // Install callback for different message; verify that broadcast callback is
+  // called for _this_ message.
+  EXPECT_TRUE(config80211_->SetMessageCallback(sent_message_2,
+                                               callback_sent_2.GetCallback()));
+  EXPECT_CALL(callback_broadcast, Config80211MessageCallback(_)).Times(1);
+  config80211_->OnNlMessageReceived(received_message);
+
+  // Change the ID for the message to that of the second callback; verify that
+  // the appropriate callback is called for _that_ message.
+  received_message->nlmsg_seq = sent_message_2.GetId();
+  EXPECT_CALL(callback_sent_2, Config80211MessageCallback(_)).Times(1);
+  config80211_->OnNlMessageReceived(received_message);
+}
+
 TEST_F(Config80211Test, NL80211_CMD_TRIGGER_SCAN) {
   UserBoundNlMessage *message = UserBoundNlMessageFactory::CreateMessage(
       const_cast<nlmsghdr *>(