shill: Makes unknown nl80211 messages look like Nl80211Messages.

Before, when NetlinkMessage::CreateMessage was given an nl80211 message
that it didn't recognize, the code generated something that was a
sort-of hybrid between a vanilla NetlinkMessage and an Nl80211Message
(with disasterous results).  This makes the unknown message look just
like an Nl80211Message.

The specific problem this addresses happened because a developer added a
new message type but hadn't, yet, added it to the factory.  This generated
an UnknownMessage and passed it to the message handler.

BUG=None
TEST=unitest

Change-Id: I78bc0861725c660f794c9eec2b99d23dded7d7a2
Reviewed-on: https://gerrit.chromium.org/gerrit/50525
Commit-Queue: Wade Guthrie <wdg@chromium.org>
Reviewed-by: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
diff --git a/generic_netlink_message.cc b/generic_netlink_message.cc
index 79526e7..3e0d04d 100644
--- a/generic_netlink_message.cc
+++ b/generic_netlink_message.cc
@@ -153,6 +153,7 @@
       return new GetFamilyMessage();
     default:
       LOG(WARNING) << "Unknown/unhandled netlink control message " << gnlh->cmd;
+      return new UnknownControlMessage(gnlh->cmd);
       break;
   }
   return NULL;
diff --git a/generic_netlink_message.h b/generic_netlink_message.h
index 3393bba..b6f9438 100644
--- a/generic_netlink_message.h
+++ b/generic_netlink_message.h
@@ -101,6 +101,9 @@
 
   // Message factory for all types of Control netlink message.
   static NetlinkMessage *CreateMessage(const nlmsghdr *const_msg);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ControlNetlinkMessage);
 };
 
 class NewFamilyMessage : public ControlNetlinkMessage {
@@ -125,6 +128,17 @@
   DISALLOW_COPY_AND_ASSIGN(GetFamilyMessage);
 };
 
+class UnknownControlMessage : public ControlNetlinkMessage {
+ public:
+  explicit UnknownControlMessage(uint8_t command)
+      : ControlNetlinkMessage(command, "<UNKNOWN CONTROL MESSAGE>"),
+        command_(command) {}
+
+ private:
+  uint8_t command_;
+  DISALLOW_COPY_AND_ASSIGN(UnknownControlMessage);
+};
+
 }  // namespace shill
 
 #endif  // SHILL_GENERIC_NETLINK_MESSAGE_H_
diff --git a/netlink_message_unittest.cc b/netlink_message_unittest.cc
index 8791220..93b9a04 100644
--- a/netlink_message_unittest.cc
+++ b/netlink_message_unittest.cc
@@ -14,18 +14,22 @@
 #include <string>
 #include <vector>
 
+#include <base/stringprintf.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include "shill/mock_log.h"
 #include "shill/mock_netlink_socket.h"
 #include "shill/netlink_attribute.h"
 #include "shill/refptr_types.h"
 
 using base::Bind;
+using base::StringPrintf;
 using base::Unretained;
 using std::string;
 using std::vector;
 using testing::_;
+using testing::EndsWith;
 using testing::Invoke;
 using testing::Return;
 using testing::Test;
@@ -344,6 +348,20 @@
   0x03, 0x00, 0x00, 0x00,
 };
 
+// This is just a NL80211_CMD_NEW_STATION message with the command changed to
+// 0xfe (which is, intentionally, not a supported command).
+
+const unsigned char kCmdNL80211_CMD_UNKNOWN = 0xfe;
+const unsigned char kNL80211_CMD_UNKNOWN[] = {
+  0x34, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xfe, 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,
+};
+
 const char kGetFamilyCommandString[] = "CTRL_CMD_GETFAMILY";
 
 }  // namespace
@@ -827,4 +845,22 @@
   }
 }
 
+// This test is to ensure that an unknown nl80211 message generates an
+// Nl80211UnknownMessage with all Nl80211 parts.
+TEST_F(NetlinkMessageTest, Parse_NL80211_CMD_UNKNOWN) {
+  ScopedMockLog log;
+  string logmessage = StringPrintf(
+      "Unknown/unhandled netlink nl80211 message 0x%02x",
+      kCmdNL80211_CMD_UNKNOWN);
+  EXPECT_CALL(log, Log(logging::LOG_WARNING, _, EndsWith(logmessage.c_str())));
+  NetlinkMessage *netlink_message =
+      message_factory_.CreateMessage(
+          reinterpret_cast<const nlmsghdr *>(kNL80211_CMD_UNKNOWN));
+  ASSERT_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 = dynamic_cast<Nl80211Message *>(netlink_message);
+  EXPECT_EQ(kCmdNL80211_CMD_UNKNOWN, message->command());
+}
+
 }  // namespace shill
diff --git a/nl80211_message.cc b/nl80211_message.cc
index 738e0e4..5b142c3 100644
--- a/nl80211_message.cc
+++ b/nl80211_message.cc
@@ -723,7 +723,9 @@
     case UnprotDisassociateMessage::kCommand:
       return new UnprotDisassociateMessage();
     default:
-      LOG(WARNING) << "Unknown/unhandled netlink nl80211 message " << gnlh->cmd;
+      LOG(WARNING) << StringPrintf(
+          "Unknown/unhandled netlink nl80211 message 0x%02x", gnlh->cmd);
+      return new UnknownNl80211Message(gnlh->cmd);
       break;
   }
   return NULL;
diff --git a/nl80211_message.h b/nl80211_message.h
index d6ed7af..1eb080f 100644
--- a/nl80211_message.h
+++ b/nl80211_message.h
@@ -418,6 +418,18 @@
 };
 
 
+class UnknownNl80211Message : public Nl80211Message {
+ public:
+  explicit UnknownNl80211Message(uint8_t command)
+      : Nl80211Message(command, "<UNKNOWN NL80211 MESSAGE>"),
+        command_(command) {}
+
+ private:
+  uint8_t command_;
+  DISALLOW_COPY_AND_ASSIGN(UnknownNl80211Message);
+};
+
+
 class UnprotDeauthenticateMessage : public Nl80211Message {
  public:
   static const uint8_t kCommand;