shill: Splits netlink_message and generic_... out of nl80211_message.*

This CL just splits netlink_message.h/.cc and
generic_netlink_message.h/.cc out of nl80211_message.h/.cc.  The name
"generic" is as regrettable as it is accurate -- messages in those files
use the |genlmsghdr| which is the "generic netlink message header".  This
change necessitated modifiying header file includes.  Other than those
minor (required) changes, this CL represents a straight cut (from
nl80211_message.*) and paste.

BUG=None
TEST=unittest

Change-Id: I79d1f96d8e942c1ca602015f48ce74099899fe63
Reviewed-on: https://gerrit.chromium.org/gerrit/47859
Reviewed-by: mukesh agrawal <quiche@chromium.org>
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 aff65c5..7c718da 100644
--- a/Makefile
+++ b/Makefile
@@ -233,6 +233,7 @@
 	event_dispatcher.o \
 	file_io.o \
 	file_reader.o \
+	generic_netlink_message.o \
 	geolocation_info.o \
 	glib.o \
 	glib_io_ready_handler.o \
@@ -253,8 +254,9 @@
 	metrics.o \
 	minijail.o \
 	modem_info.o \
-	netlink_socket.o \
 	netlink_attribute.o \
+	netlink_message.o \
+	netlink_socket.o \
 	nl80211_attribute.o \
 	nl80211_message.o \
 	nss.o \
diff --git a/config80211.cc b/config80211.cc
index abea104..7d09fd1 100644
--- a/config80211.cc
+++ b/config80211.cc
@@ -15,10 +15,11 @@
 #include "shill/attribute_list.h"
 #include "shill/error.h"
 #include "shill/event_dispatcher.h"
+#include "shill/generic_netlink_message.h"
 #include "shill/io_handler.h"
 #include "shill/logging.h"
 #include "shill/netlink_socket.h"
-#include "shill/nl80211_message.h"
+#include "shill/netlink_message.h"
 #include "shill/scope_logger.h"
 #include "shill/shill_time.h"
 
diff --git a/config80211.h b/config80211.h
index 9582f11..cfd92b5 100644
--- a/config80211.h
+++ b/config80211.h
@@ -70,7 +70,7 @@
 #include <base/bind.h>
 #include <base/lazy_instance.h>
 
-#include "shill/nl80211_message.h"
+#include "shill/netlink_message.h"
 
 struct nlmsghdr;
 
@@ -80,7 +80,6 @@
 class EventDispatcher;
 struct InputData;
 class IOHandler;
-class NetlinkMessage;
 class NetlinkSocket;
 
 // Config80211 is a singleton that coordinates sending netlink messages to,
@@ -100,8 +99,7 @@
   typedef base::Callback<void(const NetlinkMessage &)> NetlinkMessageHandler;
 
   // Encapsulates all the different things we know about a specific message
-  // type like its name, its id, and, eventually, a factory for creating
-  // messages of the designated type.
+  // type like its name, and its id.
   struct MessageType {
     MessageType();
 
diff --git a/generic_netlink_message.cc b/generic_netlink_message.cc
new file mode 100644
index 0000000..c9fa543
--- /dev/null
+++ b/generic_netlink_message.cc
@@ -0,0 +1,160 @@
+// 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.
+
+#include "shill/generic_netlink_message.h"
+
+#include <netlink/msg.h>
+#include <netlink/netlink.h>
+
+#include <base/bind.h>
+#include <base/stringprintf.h>
+
+#include "shill/logging.h"
+#include "shill/netlink_attribute.h"
+
+using base::Bind;
+using base::StringPrintf;
+
+namespace shill {
+
+ByteString GenericNetlinkMessage::EncodeHeader(uint32_t sequence_number) {
+  // Build nlmsghdr.
+  ByteString result(NetlinkMessage::EncodeHeader(sequence_number));
+  if (result.GetLength() == 0) {
+    LOG(ERROR) << "Couldn't encode message header.";
+    return result;
+  }
+
+  // Build and append the genl message header.
+  genlmsghdr genl_header;
+  genl_header.cmd = command();
+  genl_header.version = 1;
+  genl_header.reserved = 0;
+
+  ByteString genl_header_string(
+      reinterpret_cast<unsigned char *>(&genl_header), sizeof(genl_header));
+  size_t genlmsghdr_with_pad = NLMSG_ALIGN(sizeof(genl_header));
+  genl_header_string.Resize(genlmsghdr_with_pad);  // Zero-fill.
+
+  nlmsghdr *pheader = reinterpret_cast<nlmsghdr *>(result.GetData());
+  pheader->nlmsg_len += genlmsghdr_with_pad;
+  result.Append(genl_header_string);
+  return result;
+}
+
+ByteString GenericNetlinkMessage::Encode(uint32_t sequence_number) {
+  ByteString result(EncodeHeader(sequence_number));
+  if (result.GetLength() == 0) {
+    LOG(ERROR) << "Couldn't encode message header.";
+    return result;
+  }
+
+  // Build and append attributes (padding is included by
+  // AttributeList::Encode).
+  ByteString attribute_string = attributes_->Encode();
+
+  // Need to re-calculate |header| since |Append|, above, moves the data.
+  nlmsghdr *pheader = reinterpret_cast<nlmsghdr *>(result.GetData());
+  pheader->nlmsg_len += attribute_string.GetLength();
+  result.Append(attribute_string);
+
+  return result;
+}
+
+bool GenericNetlinkMessage::InitAndStripHeader(ByteString *input) {
+  if (!input) {
+    LOG(ERROR) << "NULL input";
+    return false;
+  }
+  if (!NetlinkMessage::InitAndStripHeader(input)) {
+    return false;
+  }
+
+  // Read the genlmsghdr.
+  genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(input->GetData());
+  if (command_ != gnlh->cmd) {
+    LOG(WARNING) << "This object thinks it's a " << command_
+                 << " but the message thinks it's a " << gnlh->cmd;
+  }
+
+  // Strip the genlmsghdr.
+  input->RemovePrefix(NLMSG_ALIGN(sizeof(struct genlmsghdr)));
+  return true;
+}
+
+void GenericNetlinkMessage::Print(int log_level) const {
+  SLOG(WiFi, log_level) << StringPrintf("Message %s (%d)",
+                                        command_string(),
+                                        command());
+  attributes_->Print(log_level, 1);
+}
+
+// Control Message
+
+const uint16_t ControlNetlinkMessage::kMessageType = GENL_ID_CTRL;
+
+bool ControlNetlinkMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
+  if (!const_msg) {
+    LOG(ERROR) << "Null |msg| parameter";
+    return false;
+  }
+  ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
+                     const_msg->nlmsg_len);
+
+  if (!InitAndStripHeader(&message)) {
+    return false;
+  }
+
+  // Attributes.
+  // Parse the attributes from the nl message payload into the 'tb' array.
+  nlattr *tb[CTRL_ATTR_MAX + 1];
+  nla_parse(tb, CTRL_ATTR_MAX,
+            reinterpret_cast<nlattr *>(message.GetData()), message.GetLength(),
+            NULL);
+
+  for (int i = 0; i < CTRL_ATTR_MAX + 1; ++i) {
+    if (tb[i]) {
+      // TODO(wdg): When Nl80211Messages instantiate their own attributes,
+      // this call should, instead, call |SetAttributeFromNlAttr|.
+      attributes_->CreateAndInitAttribute(
+          i, tb[i], Bind(&NetlinkAttribute::NewControlAttributeFromId));
+    }
+  }
+  return true;
+}
+
+// Specific Control types.
+
+const uint8_t NewFamilyMessage::kCommand = CTRL_CMD_NEWFAMILY;
+const char NewFamilyMessage::kCommandString[] = "CTRL_CMD_NEWFAMILY";
+
+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;
+}
+
+}  // namespace shill.
diff --git a/generic_netlink_message.h b/generic_netlink_message.h
new file mode 100644
index 0000000..23bd067
--- /dev/null
+++ b/generic_netlink_message.h
@@ -0,0 +1,130 @@
+// 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.
+
+#ifndef SHILL_GENERIC_NETLINK_MESSAGE_H_
+#define SHILL_GENERIC_NETLINK_MESSAGE_H_
+
+#include "shill/attribute_list.h"
+#include "shill/byte_string.h"
+#include "shill/netlink_message.h"
+#include "shill/refptr_types.h"
+
+struct nlmsghdr;
+
+namespace shill {
+
+// 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
+// some messages might have a genlmsghdr and a different kind of payload but I
+// haven't seen one, yet).  The genlmsghdr contains a command id that, when
+// combined with the family_id (from the nlmsghdr), describes the ultimate use
+// for the netlink message.
+//
+// An attribute contains a header and a chunk of data. The header contains an
+// id which is an enumerated value that describes the use of the attribute's
+// data (the datatype of the attribute's data is implied by the attribute id)
+// and the length of the header+data in bytes.  The attribute id is,
+// confusingly, called the type (or nla_type -- this is _not_ the data type of
+// the attribute).  Each family defines the meaning of the nla_types in the
+// context of messages in that family (for example, the nla_type with the
+// value 3 will always mean the same thing for attributes in the same family).
+// EXCEPTION: Some attributes are nested (that is, they contain a list of other
+// attributes rather than a single value).  Each nested attribute defines the
+// meaning of the nla_types in the context of attributes that are nested under
+// this attribute (for example, the nla_type with the value 3 will have a
+// different meaning when nested under another attribute -- that meaning is
+// defined by the attribute under which it is nested).  Fun.
+//
+// The GenericNetlink messages look like this:
+//
+// -----+-----+-+-------------------------------------------------+-+--
+//  ... |     | |              message payload                    | |
+//      |     | +------+-+----------------------------------------+ |
+//      | nl  | |      | |                attributes              | |
+//      | msg |p| genl |p+-----------+-+---------+-+--------+-----+p| ...
+//      | hdr |a| msg  |a|  struct   |p| attrib  |p| struct | ... |a|
+//      |     |d| hdr  |d|  nlattr   |a| payload |a| nlattr |     |d|
+//      |     | |      | |           |d|         |d|        |     | |
+// -----+-----+-+------+-+-----------+-+---------+-+--------+-----+-+--
+//                       |              ^        | |
+//                       |<-NLA_HDRLEN->|        | |
+//                       |              +---nla_data()
+//                       |<----nla_attr_size---->| |
+//                       |<-----nla_total_size---->|
+
+class GenericNetlinkMessage : public NetlinkMessage {
+ public:
+  GenericNetlinkMessage(uint16_t my_message_type, uint8 command,
+                        const char *command_string)
+      : NetlinkMessage(my_message_type),
+        attributes_(new AttributeList),
+        command_(command),
+        command_string_(command_string) {}
+  virtual ~GenericNetlinkMessage() {}
+
+  virtual ByteString Encode(uint32_t sequence_number);
+
+  uint8 command() const { return command_; }
+  const char *command_string() const { return command_string_; }
+  AttributeListConstRefPtr const_attributes() const { return attributes_; }
+  AttributeListRefPtr attributes() { return attributes_; }
+
+  virtual void Print(int log_level) const;
+
+ protected:
+  // Returns a string of bytes representing _both_ an |nlmsghdr| and a
+  // |genlmsghdr|, filled-in, and its padding.
+  virtual ByteString EncodeHeader(uint32_t sequence_number);
+  // Reads the |nlmsghdr| and |genlmsghdr| headers and removes them from
+  // |input|.
+  virtual bool InitAndStripHeader(ByteString *input);
+
+  AttributeListRefPtr attributes_;
+  const uint8 command_;
+  const char *command_string_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GenericNetlinkMessage);
+};
+
+// Control Messages
+
+class ControlNetlinkMessage : public GenericNetlinkMessage {
+ public:
+  static const uint16_t kMessageType;
+  ControlNetlinkMessage(uint8 command, const char *command_string)
+      : 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 {
+ public:
+  static const uint8_t kCommand;
+  static const char kCommandString[];
+
+  NewFamilyMessage() : ControlNetlinkMessage(kCommand, kCommandString) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NewFamilyMessage);
+};
+
+class GetFamilyMessage : public ControlNetlinkMessage {
+ public:
+  static const uint8_t kCommand;
+  static const char kCommandString[];
+
+  GetFamilyMessage() : ControlNetlinkMessage(kCommand, kCommandString) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GetFamilyMessage);
+};
+
+}  // namespace shill
+
+#endif  // SHILL_GENERIC_NETLINK_MESSAGE_H_
diff --git a/netlink_message.cc b/netlink_message.cc
new file mode 100644
index 0000000..9da1b16
--- /dev/null
+++ b/netlink_message.cc
@@ -0,0 +1,303 @@
+// Copyright (c) 2012 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.
+
+#include "shill/netlink_message.h"
+
+#include <limits.h>
+#include <netlink/msg.h>
+#include <netlink/netlink.h>
+
+#include <map>
+#include <string>
+
+#include <base/format_macros.h>
+#include <base/stl_util.h>
+#include <base/stringprintf.h>
+
+#include "shill/logging.h"
+
+using base::StringAppendF;
+using base::StringPrintf;
+using std::map;
+using std::min;
+using std::string;
+
+namespace shill {
+
+const uint32_t NetlinkMessage::kBroadcastSequenceNumber = 0;
+const uint16_t NetlinkMessage::kIllegalMessageType = UINT16_MAX;
+
+// NetlinkMessage
+
+ByteString NetlinkMessage::EncodeHeader(uint32_t sequence_number) {
+  ByteString result;
+  if (message_type_ == kIllegalMessageType) {
+    LOG(ERROR) << "Message type not set";
+    return result;
+  }
+  sequence_number_ = sequence_number;
+  if (sequence_number_ == kBroadcastSequenceNumber) {
+    LOG(ERROR) << "Couldn't get a legal sequence number";
+    return result;
+  }
+
+  // Build netlink header.
+  nlmsghdr header;
+  size_t nlmsghdr_with_pad = NLMSG_ALIGN(sizeof(header));
+  header.nlmsg_len = nlmsghdr_with_pad;
+  header.nlmsg_type = message_type_;
+  header.nlmsg_flags = NLM_F_REQUEST | flags_;
+  header.nlmsg_seq = sequence_number_;
+  header.nlmsg_pid = getpid();
+
+  // Netlink header + pad.
+  result.Append(ByteString(reinterpret_cast<unsigned char *>(&header),
+                           sizeof(header)));
+  result.Resize(nlmsghdr_with_pad);  // Zero-fill pad space (if any).
+  return result;
+}
+
+bool NetlinkMessage::InitAndStripHeader(ByteString *input) {
+  if (!input) {
+    LOG(ERROR) << "NULL input";
+    return false;
+  }
+  if (input->GetLength() < sizeof(nlmsghdr)) {
+    LOG(ERROR) << "Insufficient input to extract nlmsghdr";
+    return false;
+  }
+
+  // Read the nlmsghdr.
+  nlmsghdr *header = reinterpret_cast<nlmsghdr *>(input->GetData());
+  message_type_ = header->nlmsg_type;
+  flags_ = header->nlmsg_flags;
+  sequence_number_ = header->nlmsg_seq;
+
+  // Strip the nlmsghdr.
+  input->RemovePrefix(NLMSG_ALIGN(sizeof(struct nlmsghdr)));
+  return true;
+}
+
+bool NetlinkMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
+  if (!const_msg) {
+    LOG(ERROR) << "Null |const_msg| parameter";
+    return false;
+  }
+  ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
+                     const_msg->nlmsg_len);
+  if (!InitAndStripHeader(&message)) {
+    return false;
+  }
+  return true;
+}
+
+// static
+void NetlinkMessage::PrintBytes(int log_level, const unsigned char *buf,
+                                size_t num_bytes) {
+  SLOG(WiFi, log_level) << "Netlink Message -- Examining Bytes";
+  if (!buf) {
+    SLOG(WiFi, log_level) << "<NULL Buffer>";
+    return;
+  }
+
+  if (num_bytes >= sizeof(nlmsghdr)) {
+      const nlmsghdr *header = reinterpret_cast<const nlmsghdr *>(buf);
+      SLOG(WiFi, log_level) << StringPrintf(
+          "len:          %02x %02x %02x %02x = %u bytes",
+          buf[0], buf[1], buf[2], buf[3], header->nlmsg_len);
+
+      SLOG(WiFi, log_level) << StringPrintf(
+          "type | flags: %02x %02x %02x %02x - type:%u flags:%s%s%s%s%s",
+          buf[4], buf[5], buf[6], buf[7], header->nlmsg_type,
+          ((header->nlmsg_flags & NLM_F_REQUEST) ? " REQUEST" : ""),
+          ((header->nlmsg_flags & NLM_F_MULTI) ? " MULTI" : ""),
+          ((header->nlmsg_flags & NLM_F_ACK) ? " ACK" : ""),
+          ((header->nlmsg_flags & NLM_F_ECHO) ? " ECHO" : ""),
+          ((header->nlmsg_flags & NLM_F_DUMP_INTR) ? " BAD-SEQ" : ""));
+
+      SLOG(WiFi, log_level) << StringPrintf(
+          "sequence:     %02x %02x %02x %02x = %u",
+          buf[8], buf[9], buf[10], buf[11], header->nlmsg_seq);
+      SLOG(WiFi, log_level) << StringPrintf(
+          "pid:          %02x %02x %02x %02x = %u",
+          buf[12], buf[13], buf[14], buf[15], header->nlmsg_pid);
+      buf += sizeof(nlmsghdr);
+      num_bytes -= sizeof(nlmsghdr);
+  } else {
+    SLOG(WiFi, log_level) << "Not enough bytes (" << num_bytes
+                          << ") for a complete nlmsghdr (requires "
+                          << sizeof(nlmsghdr) << ").";
+  }
+
+  while (num_bytes) {
+    string output;
+    size_t bytes_this_row = min(num_bytes, static_cast<size_t>(32));
+    for (size_t i = 0; i < bytes_this_row; ++i) {
+      StringAppendF(&output, " %02x", *buf++);
+    }
+    SLOG(WiFi, log_level) << output;
+    num_bytes -= bytes_this_row;
+  }
+}
+
+// ErrorAckMessage.
+
+const uint16_t ErrorAckMessage::kMessageType = NLMSG_ERROR;
+
+bool ErrorAckMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
+  if (!const_msg) {
+    LOG(ERROR) << "Null |const_msg| parameter";
+    return false;
+  }
+  ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
+                     const_msg->nlmsg_len);
+  if (!InitAndStripHeader(&message)) {
+    return false;
+  }
+
+  // Get the error code from the payload.
+  error_ = *(reinterpret_cast<const uint32_t *>(message.GetConstData()));
+  return true;
+}
+
+ByteString ErrorAckMessage::Encode(uint32_t sequence_number) {
+  LOG(ERROR) << "We're not supposed to send errors or Acks to the kernel";
+  return ByteString();
+}
+
+string ErrorAckMessage::ToString() const {
+  string output;
+  if (error()) {
+    StringAppendF(&output, "NL80211_ERROR 0x%" PRIx32 ": %s",
+                  -error_, strerror(-error_));
+  } else {
+    StringAppendF(&output, "ACK");
+  }
+  return output;
+}
+
+void ErrorAckMessage::Print(int log_level) const {
+  SLOG(WiFi, log_level) << ToString();
+}
+
+// NoopMessage.
+
+const uint16_t NoopMessage::kMessageType = NLMSG_NOOP;
+
+ByteString NoopMessage::Encode(uint32_t sequence_number) {
+  LOG(ERROR) << "We're not supposed to send NOOP to the kernel";
+  return ByteString();
+}
+
+void NoopMessage::Print(int log_level) const {
+  SLOG(WiFi, log_level) << ToString();
+}
+
+// DoneMessage.
+
+const uint16_t DoneMessage::kMessageType = NLMSG_DONE;
+
+ByteString DoneMessage::Encode(uint32_t sequence_number) {
+  LOG(ERROR)
+      << "We're not supposed to send Done messages (are we?) to the kernel";
+  return ByteString();
+}
+
+void DoneMessage::Print(int log_level) const {
+  SLOG(WiFi, log_level) << ToString();
+}
+
+// OverrunMessage.
+
+const uint16_t OverrunMessage::kMessageType = NLMSG_OVERRUN;
+
+ByteString OverrunMessage::Encode(uint32_t sequence_number) {
+  LOG(ERROR) << "We're not supposed to send Overruns to the kernel";
+  return ByteString();
+}
+
+void OverrunMessage::Print(int log_level) const {
+  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;
+}
+
+//
+// Factory class.
+//
+
+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;
+
+  if (const_msg->nlmsg_type == NoopMessage::kMessageType) {
+    message.reset(new NoopMessage());
+  } else if (const_msg->nlmsg_type == DoneMessage::kMessageType) {
+    message.reset(new DoneMessage());
+  } else if (const_msg->nlmsg_type == OverrunMessage::kMessageType) {
+    message.reset(new OverrunMessage());
+  } else if (const_msg->nlmsg_type == ErrorAckMessage::kMessageType) {
+    message.reset(new ErrorAckMessage());
+  } 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 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;
+  }
+
+  return message.release();
+}
+
+}  // namespace shill.
diff --git a/netlink_message.h b/netlink_message.h
new file mode 100644
index 0000000..e19e6b0
--- /dev/null
+++ b/netlink_message.h
@@ -0,0 +1,219 @@
+// 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.
+
+#ifndef SHILL_NETLINK_MESSAGE_H_
+#define SHILL_NETLINK_MESSAGE_H_
+
+#include <map>
+#include <string>
+
+#include <base/bind.h>
+
+#include <gtest/gtest.h>  // for FRIEND_TEST.
+
+#include "shill/byte_string.h"
+
+struct nlmsghdr;
+
+namespace shill {
+
+// Netlink messages are sent over netlink sockets to talk between user-space
+// programs (like shill) and kernel modules (like the cfg80211 module).  Each
+// kernel module that talks netlink potentially adds its own family header to
+// the nlmsghdr (the top-level netlink message header) and, potentially, uses a
+// different payload format.  The NetlinkMessage class represents that which
+// is common between the different types of netlink message.
+//
+// The common portions of Netlink Messages start with a |nlmsghdr|.  Those
+// messages look something like the following (the functions, macros, and
+// datatypes described are provided by libnl -- see also
+// http://www.infradead.org/~tgr/libnl/doc/core.html):
+//
+//         |<--------------nlmsg_total_size()----------->|
+//         |       |<------nlmsg_datalen()-------------->|
+//         |       |                                     |
+//    -----+-----+-+-----------------------------------+-+----
+//     ... |     | |            netlink payload        | |
+//         |     | +------------+-+--------------------+ |
+//         | nl  | |            | |                    | | nl
+//         | msg |p| (optional) |p|                    |p| msg ...
+//         | hdr |a| family     |a|   family payload   |a| hdr
+//         |     |d| header     |d|                    |d|
+//         |     | |            | |                    | |
+//    -----+-----+-+------------+-+--------------------+-+----
+//                  ^
+//                  |
+//                  +-- nlmsg_data()
+//
+// All NetlinkMessages sent to the kernel need a valid message type (which is
+// found in the nlmsghdr structure) and all NetlinkMessages received from the
+// kernel have a valid message type.  Some message types (NLMSG_NOOP,
+// NLMSG_ERROR, and GENL_ID_CTRL, for example) are allocated statically; for
+// those, the |message_type_| is assigned directly.
+//
+// Other message types ("nl80211", for example), are assigned by the kernel
+// dynamically.  To get the message type, pass a closure to assign the
+// message_type along with the sting to Config80211::GetFamily:
+//
+//  nl80211_type = config80211_->GetFamily(Nl80211Message::kMessageType);
+//
+// Do all of this before you start to create NetlinkMessages so that
+// NetlinkMessage can be instantiated with a valid |message_type_|.
+
+class NetlinkMessage {
+ public:
+  static const uint32_t kBroadcastSequenceNumber;
+  static const uint16_t kIllegalMessageType;
+
+  explicit NetlinkMessage(uint16_t message_type) :
+      flags_(0), message_type_(message_type),
+      sequence_number_(kBroadcastSequenceNumber) {}
+  virtual ~NetlinkMessage() {}
+
+  // Returns a string of bytes representing the message (with it headers) and
+  // any necessary padding.  These bytes are appropriately formatted to be
+  // written to a netlink socket.
+  virtual ByteString Encode(uint32_t sequence_number) = 0;
+
+  // Initializes the |NetlinkMessage| from a complete and legal message
+  // (potentially received from the kernel via a netlink socket).
+  virtual bool InitFromNlmsg(const nlmsghdr *msg);
+
+  uint16_t message_type() const { return message_type_; }
+  void AddFlag(uint16_t new_flag) { flags_ |= new_flag; }
+  uint16_t flags() const { return flags_; }
+  uint32_t sequence_number() const { return sequence_number_; }
+  virtual void Print(int log_level) const = 0;
+
+  // Logs the message's raw bytes (with minimal interpretation).
+  static void PrintBytes(int log_level, const unsigned char *buf,
+                         size_t num_bytes);
+
+ protected:
+  friend class Config80211Test;
+  FRIEND_TEST(Config80211Test, NL80211_CMD_NOTIFY_CQM);
+
+  // Returns a string of bytes representing an |nlmsghdr|, filled-in, and its
+  // padding.
+  virtual ByteString EncodeHeader(uint32_t sequence_number);
+  // Reads the |nlmsghdr| and removes it from |input|.
+  virtual bool InitAndStripHeader(ByteString *input);
+
+  uint16_t flags_;
+  uint16_t message_type_;
+  uint32_t sequence_number_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NetlinkMessage);
+};
+
+
+// The Error and Ack messages are received from the kernel and are combined,
+// here, because they look so much alike (the only difference is that the
+// error code is 0 for the Ack messages).  Error messages are received from
+// the kernel in response to a sent message when there's a problem (such as
+// a malformed message or a busy kernel module).  Ack messages are received
+// from the kernel when a sent message has the NLM_F_ACK flag set, indicating
+// that an Ack is requested.
+class ErrorAckMessage : public NetlinkMessage {
+ public:
+  static const uint16_t kMessageType;
+
+  ErrorAckMessage() : NetlinkMessage(kMessageType), error_(0) {}
+  virtual bool InitFromNlmsg(const nlmsghdr *const_msg);
+  virtual ByteString Encode(uint32_t sequence_number);
+  virtual void Print(int log_level) const;
+  std::string ToString() const;
+  uint32_t error() const { return -error_; }
+
+ private:
+  uint32_t error_;
+
+  DISALLOW_COPY_AND_ASSIGN(ErrorAckMessage);
+};
+
+
+class NoopMessage : public NetlinkMessage {
+ public:
+  static const uint16_t kMessageType;
+
+  NoopMessage() : NetlinkMessage(kMessageType) {}
+  virtual ByteString Encode(uint32_t sequence_number);
+  virtual void Print(int log_level) const;
+  std::string ToString() const { return "<NOOP>"; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NoopMessage);
+};
+
+
+class DoneMessage : public NetlinkMessage {
+ public:
+  static const uint16_t kMessageType;
+
+  DoneMessage() : NetlinkMessage(kMessageType) {}
+  virtual ByteString Encode(uint32_t sequence_number);
+  virtual void Print(int log_level) const;
+  std::string ToString() const { return "<DONE with multipart message>"; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DoneMessage);
+};
+
+
+class OverrunMessage : public NetlinkMessage {
+ public:
+  static const uint16_t kMessageType;
+
+  OverrunMessage() : NetlinkMessage(kMessageType) {}
+  virtual ByteString Encode(uint32_t sequence_number);
+  virtual void Print(int log_level) const;
+  std::string ToString() const { return "<OVERRUN - data lost>"; }
+
+ private:
+  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);
+};
+
+
+//
+// Factory class.
+//
+
+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.
+  NetlinkMessage *CreateMessage(const nlmsghdr *msg) const;
+
+ private:
+  std::map<uint16_t, FactoryMethod> factories_;
+
+  DISALLOW_COPY_AND_ASSIGN(NetlinkMessageFactory);
+};
+
+}  // namespace shill
+
+#endif  // SHILL_NETLINK_MESSAGE_H_
diff --git a/netlink_socket.cc b/netlink_socket.cc
index 50790f6..d791702 100644
--- a/netlink_socket.cc
+++ b/netlink_socket.cc
@@ -5,10 +5,11 @@
 #include "shill/netlink_socket.h"
 
 #include <linux/if_packet.h>
+#include <linux/netlink.h>
 #include <sys/socket.h>
 
 #include "shill/logging.h"
-#include "shill/nl80211_message.h"
+#include "shill/netlink_message.h"
 #include "shill/sockets.h"
 
 // This is from a version of linux/socket.h that we don't have.
diff --git a/nl80211_message.cc b/nl80211_message.cc
index c0c2400..9b7e982 100644
--- a/nl80211_message.cc
+++ b/nl80211_message.cc
@@ -25,18 +25,14 @@
 #include "shill/nl80211_message.h"
 
 #include <limits.h>
-#include <netlink/attr.h>
 #include <netlink/msg.h>
 #include <netlink/netlink.h>
 
-#include <algorithm>
 #include <map>
 #include <string>
 #include <vector>
 
 #include <base/bind.h>
-#include <base/format_macros.h>
-#include <base/stl_util.h>
 #include <base/stringprintf.h>
 
 #include "shill/attribute_list.h"
@@ -48,9 +44,7 @@
 using base::Bind;
 using base::LazyInstance;
 using base::StringAppendF;
-using base::StringPrintf;
 using std::map;
-using std::min;
 using std::string;
 using std::vector;
 
@@ -64,9 +58,6 @@
 const uint8_t Nl80211Frame::kMinimumFrameByteCount = 26;
 const uint8_t Nl80211Frame::kFrameTypeMask = 0xfc;
 
-const uint32_t NetlinkMessage::kBroadcastSequenceNumber = 0;
-const uint16_t NetlinkMessage::kIllegalMessageType = UINT16_MAX;
-
 const char Nl80211Message::kBogusMacAddress[] = "XX:XX:XX:XX:XX:XX";
 const unsigned int Nl80211Message::kEthernetAddressBytes = 6;
 const char Nl80211Message::kMessageTypeString[] = "nl80211";
@@ -74,293 +65,6 @@
 map<uint16_t, string> *Nl80211Message::status_code_string_ = NULL;
 uint16_t Nl80211Message::nl80211_message_type_ = kIllegalMessageType;
 
-// NetlinkMessage
-
-ByteString NetlinkMessage::EncodeHeader(uint32_t sequence_number) {
-  ByteString result;
-  if (message_type_ == kIllegalMessageType) {
-    LOG(ERROR) << "Message type not set";
-    return result;
-  }
-  sequence_number_ = sequence_number;
-  if (sequence_number_ == kBroadcastSequenceNumber) {
-    LOG(ERROR) << "Couldn't get a legal sequence number";
-    return result;
-  }
-
-  // Build netlink header.
-  nlmsghdr header;
-  size_t nlmsghdr_with_pad = NLMSG_ALIGN(sizeof(header));
-  header.nlmsg_len = nlmsghdr_with_pad;
-  header.nlmsg_type = message_type_;
-  header.nlmsg_flags = NLM_F_REQUEST | flags_;
-  header.nlmsg_seq = sequence_number_;
-  header.nlmsg_pid = getpid();
-
-  // Netlink header + pad.
-  result.Append(ByteString(reinterpret_cast<unsigned char *>(&header),
-                           sizeof(header)));
-  result.Resize(nlmsghdr_with_pad);  // Zero-fill pad space (if any).
-  return result;
-}
-
-bool NetlinkMessage::InitAndStripHeader(ByteString *input) {
-  if (!input) {
-    LOG(ERROR) << "NULL input";
-    return false;
-  }
-  if (input->GetLength() < sizeof(nlmsghdr)) {
-    LOG(ERROR) << "Insufficient input to extract nlmsghdr";
-    return false;
-  }
-
-  // Read the nlmsghdr.
-  nlmsghdr *header = reinterpret_cast<nlmsghdr *>(input->GetData());
-  message_type_ = header->nlmsg_type;
-  flags_ = header->nlmsg_flags;
-  sequence_number_ = header->nlmsg_seq;
-
-  // Strip the nlmsghdr.
-  input->RemovePrefix(NLMSG_ALIGN(sizeof(struct nlmsghdr)));
-  return true;
-}
-
-bool NetlinkMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
-  if (!const_msg) {
-    LOG(ERROR) << "Null |const_msg| parameter";
-    return false;
-  }
-  ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
-                     const_msg->nlmsg_len);
-  if (!InitAndStripHeader(&message)) {
-    return false;
-  }
-  return true;
-}
-
-// static
-void NetlinkMessage::PrintBytes(int log_level, const unsigned char *buf,
-                                size_t num_bytes) {
-  SLOG(WiFi, log_level) << "Netlink Message -- Examining Bytes";
-  if (!buf) {
-    SLOG(WiFi, log_level) << "<NULL Buffer>";
-    return;
-  }
-
-  if (num_bytes >= sizeof(nlmsghdr)) {
-      const nlmsghdr *header = reinterpret_cast<const nlmsghdr *>(buf);
-      SLOG(WiFi, log_level) << StringPrintf(
-          "len:          %02x %02x %02x %02x = %u bytes",
-          buf[0], buf[1], buf[2], buf[3], header->nlmsg_len);
-
-      SLOG(WiFi, log_level) << StringPrintf(
-          "type | flags: %02x %02x %02x %02x - type:%u flags:%s%s%s%s%s",
-          buf[4], buf[5], buf[6], buf[7], header->nlmsg_type,
-          ((header->nlmsg_flags & NLM_F_REQUEST) ? " REQUEST" : ""),
-          ((header->nlmsg_flags & NLM_F_MULTI) ? " MULTI" : ""),
-          ((header->nlmsg_flags & NLM_F_ACK) ? " ACK" : ""),
-          ((header->nlmsg_flags & NLM_F_ECHO) ? " ECHO" : ""),
-          ((header->nlmsg_flags & NLM_F_DUMP_INTR) ? " BAD-SEQ" : ""));
-
-      SLOG(WiFi, log_level) << StringPrintf(
-          "sequence:     %02x %02x %02x %02x = %u",
-          buf[8], buf[9], buf[10], buf[11], header->nlmsg_seq);
-      SLOG(WiFi, log_level) << StringPrintf(
-          "pid:          %02x %02x %02x %02x = %u",
-          buf[12], buf[13], buf[14], buf[15], header->nlmsg_pid);
-      buf += sizeof(nlmsghdr);
-      num_bytes -= sizeof(nlmsghdr);
-  } else {
-    SLOG(WiFi, log_level) << "Not enough bytes (" << num_bytes
-                          << ") for a complete nlmsghdr (requires "
-                          << sizeof(nlmsghdr) << ").";
-  }
-
-  while (num_bytes) {
-    string output;
-    size_t bytes_this_row = min(num_bytes, static_cast<size_t>(32));
-    for (size_t i = 0; i < bytes_this_row; ++i) {
-      StringAppendF(&output, " %02x", *buf++);
-    }
-    SLOG(WiFi, log_level) << output;
-    num_bytes -= bytes_this_row;
-  }
-}
-
-// ErrorAckMessage.
-
-const uint16_t ErrorAckMessage::kMessageType = NLMSG_ERROR;
-
-bool ErrorAckMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
-  if (!const_msg) {
-    LOG(ERROR) << "Null |const_msg| parameter";
-    return false;
-  }
-  ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
-                     const_msg->nlmsg_len);
-  if (!InitAndStripHeader(&message)) {
-    return false;
-  }
-
-  // Get the error code from the payload.
-  error_ = *(reinterpret_cast<const uint32_t *>(message.GetConstData()));
-  return true;
-}
-
-ByteString ErrorAckMessage::Encode(uint32_t sequence_number) {
-  LOG(ERROR) << "We're not supposed to send errors or Acks to the kernel";
-  return ByteString();
-}
-
-string ErrorAckMessage::ToString() const {
-  string output;
-  if (error()) {
-    StringAppendF(&output, "NL80211_ERROR 0x%" PRIx32 ": %s",
-                  -error_, strerror(-error_));
-  } else {
-    StringAppendF(&output, "ACK");
-  }
-  return output;
-}
-
-void ErrorAckMessage::Print(int log_level) const {
-  SLOG(WiFi, log_level) << ToString();
-}
-
-// NoopMessage.
-
-const uint16_t NoopMessage::kMessageType = NLMSG_NOOP;
-
-ByteString NoopMessage::Encode(uint32_t sequence_number) {
-  LOG(ERROR) << "We're not supposed to send NOOP to the kernel";
-  return ByteString();
-}
-
-void NoopMessage::Print(int log_level) const {
-  SLOG(WiFi, log_level) << ToString();
-}
-
-// DoneMessage.
-
-const uint16_t DoneMessage::kMessageType = NLMSG_DONE;
-
-ByteString DoneMessage::Encode(uint32_t sequence_number) {
-  LOG(ERROR)
-      << "We're not supposed to send Done messages (are we?) to the kernel";
-  return ByteString();
-}
-
-void DoneMessage::Print(int log_level) const {
-  SLOG(WiFi, log_level) << ToString();
-}
-
-// OverrunMessage.
-
-const uint16_t OverrunMessage::kMessageType = NLMSG_OVERRUN;
-
-ByteString OverrunMessage::Encode(uint32_t sequence_number) {
-  LOG(ERROR) << "We're not supposed to send Overruns to the kernel";
-  return ByteString();
-}
-
-void OverrunMessage::Print(int log_level) const {
-  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) {
-  // Build nlmsghdr.
-  ByteString result(NetlinkMessage::EncodeHeader(sequence_number));
-  if (result.GetLength() == 0) {
-    LOG(ERROR) << "Couldn't encode message header.";
-    return result;
-  }
-
-  // Build and append the genl message header.
-  genlmsghdr genl_header;
-  genl_header.cmd = command();
-  genl_header.version = 1;
-  genl_header.reserved = 0;
-
-  ByteString genl_header_string(
-      reinterpret_cast<unsigned char *>(&genl_header), sizeof(genl_header));
-  size_t genlmsghdr_with_pad = NLMSG_ALIGN(sizeof(genl_header));
-  genl_header_string.Resize(genlmsghdr_with_pad);  // Zero-fill.
-
-  nlmsghdr *pheader = reinterpret_cast<nlmsghdr *>(result.GetData());
-  pheader->nlmsg_len += genlmsghdr_with_pad;
-  result.Append(genl_header_string);
-  return result;
-}
-
-ByteString GenericNetlinkMessage::Encode(uint32_t sequence_number) {
-  ByteString result(EncodeHeader(sequence_number));
-  if (result.GetLength() == 0) {
-    LOG(ERROR) << "Couldn't encode message header.";
-    return result;
-  }
-
-  // Build and append attributes (padding is included by
-  // AttributeList::Encode).
-  ByteString attribute_string = attributes_->Encode();
-
-  // Need to re-calculate |header| since |Append|, above, moves the data.
-  nlmsghdr *pheader = reinterpret_cast<nlmsghdr *>(result.GetData());
-  pheader->nlmsg_len += attribute_string.GetLength();
-  result.Append(attribute_string);
-
-  return result;
-}
-
-bool GenericNetlinkMessage::InitAndStripHeader(ByteString *input) {
-  if (!input) {
-    LOG(ERROR) << "NULL input";
-    return false;
-  }
-  if (!NetlinkMessage::InitAndStripHeader(input)) {
-    return false;
-  }
-
-  // Read the genlmsghdr.
-  genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(input->GetData());
-  if (command_ != gnlh->cmd) {
-    LOG(WARNING) << "This object thinks it's a " << command_
-                 << " but the message thinks it's a " << gnlh->cmd;
-  }
-
-  // Strip the genlmsghdr.
-  input->RemovePrefix(NLMSG_ALIGN(sizeof(struct genlmsghdr)));
-  return true;
-}
-
-void GenericNetlinkMessage::Print(int log_level) const {
-  SLOG(WiFi, log_level) << StringPrintf("Message %s (%d)",
-                                        command_string(),
-                                        command());
-  attributes_->Print(log_level, 1);
-}
-
-// Nl80211Message
-
 // static
 void Nl80211Message::SetMessageType(uint16_t message_type) {
   if (message_type == NetlinkMessage::kIllegalMessageType) {
@@ -715,74 +419,6 @@
   return match->second;
 }
 
-
-// Control Message
-
-const uint16_t ControlNetlinkMessage::kMessageType = GENL_ID_CTRL;
-
-bool ControlNetlinkMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
-  if (!const_msg) {
-    LOG(ERROR) << "Null |msg| parameter";
-    return false;
-  }
-  ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
-                     const_msg->nlmsg_len);
-
-  if (!InitAndStripHeader(&message)) {
-    return false;
-  }
-
-  // Attributes.
-  // Parse the attributes from the nl message payload into the 'tb' array.
-  nlattr *tb[CTRL_ATTR_MAX + 1];
-  nla_parse(tb, CTRL_ATTR_MAX,
-            reinterpret_cast<nlattr *>(message.GetData()), message.GetLength(),
-            NULL);
-
-  for (int i = 0; i < CTRL_ATTR_MAX + 1; ++i) {
-    if (tb[i]) {
-      // TODO(wdg): When Nl80211Messages instantiate their own attributes,
-      // this call should, instead, call |SetAttributeFromNlAttr|.
-      attributes_->CreateAndInitAttribute(
-          i, tb[i], Bind(&NetlinkAttribute::NewControlAttributeFromId));
-    }
-  }
-  return true;
-}
-
-// Specific Control types.
-
-const uint8_t NewFamilyMessage::kCommand = CTRL_CMD_NEWFAMILY;
-const char NewFamilyMessage::kCommandString[] = "CTRL_CMD_NEWFAMILY";
-
-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)
@@ -1051,67 +687,6 @@
 }
 
 //
-// Factory class.
-//
-
-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;
-
-  if (const_msg->nlmsg_type == NoopMessage::kMessageType) {
-    message.reset(new NoopMessage());
-  } else if (const_msg->nlmsg_type == DoneMessage::kMessageType) {
-    message.reset(new DoneMessage());
-  } else if (const_msg->nlmsg_type == OverrunMessage::kMessageType) {
-    message.reset(new OverrunMessage());
-  } else if (const_msg->nlmsg_type == ErrorAckMessage::kMessageType) {
-    message.reset(new ErrorAckMessage());
-  } 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 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;
-  }
-
-  return message.release();
-}
-
-//
 // Data Collector
 //
 
diff --git a/nl80211_message.h b/nl80211_message.h
index 33b3dbc..6d5c8ac 100644
--- a/nl80211_message.h
+++ b/nl80211_message.h
@@ -9,304 +9,15 @@
 #include <string>
 #include <vector>
 
-#include <base/basictypes.h>
 #include <base/lazy_instance.h>
 
-#include <gtest/gtest.h>  // for FRIEND_TEST.
-
-#include "shill/attribute_list.h"
 #include "shill/byte_string.h"
-#include "shill/refptr_types.h"
+#include "shill/generic_netlink_message.h"
 
 struct nlmsghdr;
 
 namespace shill {
 
-class Config80211;
-
-// Netlink messages are sent over netlink sockets to talk between user-space
-// programs (like shill) and kernel modules (like the cfg80211 module).  Each
-// kernel module that talks netlink potentially adds its own family header to
-// the nlmsghdr (the top-level netlink message header) and, potentially, uses a
-// different payload format.  The NetlinkMessage class represents that which
-// is common between the different types of netlink message.
-//
-// The common portions of Netlink Messages start with a |nlmsghdr|.  Those
-// messages look something like the following (the functions, macros, and
-// datatypes described are provided by libnl -- see also
-// http://www.infradead.org/~tgr/libnl/doc/core.html):
-//
-//         |<--------------nlmsg_total_size()----------->|
-//         |       |<------nlmsg_datalen()-------------->|
-//         |       |                                     |
-//    -----+-----+-+-----------------------------------+-+----
-//     ... |     | |            netlink payload        | |
-//         |     | +------------+-+--------------------+ |
-//         | nl  | |            | |                    | | nl
-//         | msg |p| (optional) |p|                    |p| msg ...
-//         | hdr |a| family     |a|   family payload   |a| hdr
-//         |     |d| header     |d|                    |d|
-//         |     | |            | |                    | |
-//    -----+-----+-+------------+-+--------------------+-+----
-//                  ^
-//                  |
-//                  +-- nlmsg_data()
-//
-// All NetlinkMessages sent to the kernel need a valid message type (which is
-// found in the nlmsghdr structure) and all NetlinkMessages received from the
-// kernel have a valid message type.  Some message types (NLMSG_NOOP,
-// NLMSG_ERROR, and GENL_ID_CTRL, for example) are allocated statically; for
-// those, the |message_type_| is assigned directly.
-//
-// Other message types ("nl80211", for example), are assigned by the kernel
-// dynamically.  To get the message type, pass a closure to assign the
-// message_type along with the sting to Config80211::GetFamily:
-//
-//  nl80211_type = config80211_->GetFamily(Nl80211Message::kMessageType);
-//
-// Do all of this before you start to create NetlinkMessages so that
-// NetlinkMessage can be instantiated with a valid |message_type_|.
-
-class NetlinkMessage {
- public:
-  static const uint32_t kBroadcastSequenceNumber;
-  static const uint16_t kIllegalMessageType;
-
-  explicit NetlinkMessage(uint16_t message_type) :
-      flags_(0), message_type_(message_type),
-      sequence_number_(kBroadcastSequenceNumber) {}
-  virtual ~NetlinkMessage() {}
-
-  // Returns a string of bytes representing the message (with it headers) and
-  // any necessary padding.  These bytes are appropriately formatted to be
-  // written to a netlink socket.
-  virtual ByteString Encode(uint32_t sequence_number) = 0;
-
-  // Initializes the |NetlinkMessage| from a complete and legal message
-  // (potentially received from the kernel via a netlink socket).
-  virtual bool InitFromNlmsg(const nlmsghdr *msg);
-
-  uint16_t message_type() const { return message_type_; }
-  void AddFlag(uint16_t new_flag) { flags_ |= new_flag; }
-  uint16_t flags() const { return flags_; }
-  uint32_t sequence_number() const { return sequence_number_; }
-  virtual void Print(int log_level) const = 0;
-
-  // Logs the message's raw bytes (with minimal interpretation).
-  static void PrintBytes(int log_level, const unsigned char *buf,
-                         size_t num_bytes);
-
- protected:
-  friend class Config80211Test;
-  FRIEND_TEST(Config80211Test, NL80211_CMD_NOTIFY_CQM);
-
-  // Returns a string of bytes representing an |nlmsghdr|, filled-in, and its
-  // padding.
-  virtual ByteString EncodeHeader(uint32_t sequence_number);
-  // Reads the |nlmsghdr| and removes it from |input|.
-  virtual bool InitAndStripHeader(ByteString *input);
-
-  uint16_t flags_;
-  uint16_t message_type_;
-  uint32_t sequence_number_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NetlinkMessage);
-};
-
-
-// The Error and Ack messages are received from the kernel and are combined,
-// here, because they look so much alike (the only difference is that the
-// error code is 0 for the Ack messages).  Error messages are received from
-// the kernel in response to a sent message when there's a problem (such as
-// a malformed message or a busy kernel module).  Ack messages are received
-// from the kernel when a sent message has the NLM_F_ACK flag set, indicating
-// that an Ack is requested.
-class ErrorAckMessage : public NetlinkMessage {
- public:
-  static const uint16_t kMessageType;
-
-  ErrorAckMessage() : NetlinkMessage(kMessageType), error_(0) {}
-  virtual bool InitFromNlmsg(const nlmsghdr *const_msg);
-  virtual ByteString Encode(uint32_t sequence_number);
-  virtual void Print(int log_level) const;
-  std::string ToString() const;
-  uint32_t error() const { return -error_; }
-
- private:
-  uint32_t error_;
-
-  DISALLOW_COPY_AND_ASSIGN(ErrorAckMessage);
-};
-
-
-class NoopMessage : public NetlinkMessage {
- public:
-  static const uint16_t kMessageType;
-
-  NoopMessage() : NetlinkMessage(kMessageType) {}
-  virtual ByteString Encode(uint32_t sequence_number);
-  virtual void Print(int log_level) const;
-  std::string ToString() const { return "<NOOP>"; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NoopMessage);
-};
-
-
-class DoneMessage : public NetlinkMessage {
- public:
-  static const uint16_t kMessageType;
-
-  DoneMessage() : NetlinkMessage(kMessageType) {}
-  virtual ByteString Encode(uint32_t sequence_number);
-  virtual void Print(int log_level) const;
-  std::string ToString() const { return "<DONE with multipart message>"; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DoneMessage);
-};
-
-
-class OverrunMessage : public NetlinkMessage {
- public:
-  static const uint16_t kMessageType;
-
-  OverrunMessage() : NetlinkMessage(kMessageType) {}
-  virtual ByteString Encode(uint32_t sequence_number);
-  virtual void Print(int log_level) const;
-  std::string ToString() const { return "<OVERRUN - data lost>"; }
-
- private:
-  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
-// some messages might have a genlmsghdr and a different kind of payload but I
-// haven't seen one, yet).  The genlmsghdr contains a command id that, when
-// combined with the family_id (from the nlmsghdr), describes the ultimate use
-// for the netlink message.
-//
-// An attribute contains a header and a chunk of data. The header contains an
-// id which is an enumerated value that describes the use of the attribute's
-// data (the datatype of the attribute's data is implied by the attribute id)
-// and the length of the header+data in bytes.  The attribute id is,
-// confusingly, called the type (or nla_type -- this is _not_ the data type of
-// the attribute).  Each family defines the meaning of the nla_types in the
-// context of messages in that family (for example, the nla_type with the
-// value 3 will always mean the same thing for attributes in the same family).
-// EXCEPTION: Some attributes are nested (that is, they contain a list of other
-// attributes rather than a single value).  Each nested attribute defines the
-// meaning of the nla_types in the context of attributes that are nested under
-// this attribute (for example, the nla_type with the value 3 will have a
-// different meaning when nested under another attribute -- that meaning is
-// defined by the attribute under which it is nested).  Fun.
-//
-// The GenericNetlink messages look like this:
-//
-// -----+-----+-+-------------------------------------------------+-+--
-//  ... |     | |              message payload                    | |
-//      |     | +------+-+----------------------------------------+ |
-//      | nl  | |      | |                attributes              | |
-//      | msg |p| genl |p+-----------+-+---------+-+--------+-----+p| ...
-//      | hdr |a| msg  |a|  struct   |p| attrib  |p| struct | ... |a|
-//      |     |d| hdr  |d|  nlattr   |a| payload |a| nlattr |     |d|
-//      |     | |      | |           |d|         |d|        |     | |
-// -----+-----+-+------+-+-----------+-+---------+-+--------+-----+-+--
-//                       |              ^        | |
-//                       |<-NLA_HDRLEN->|        | |
-//                       |              +---nla_data()
-//                       |<----nla_attr_size---->| |
-//                       |<-----nla_total_size---->|
-
-class GenericNetlinkMessage : public NetlinkMessage {
- public:
-  GenericNetlinkMessage(uint16_t my_message_type, uint8 command,
-                        const char *command_string)
-      : NetlinkMessage(my_message_type),
-        attributes_(new AttributeList),
-        command_(command),
-        command_string_(command_string) {}
-  virtual ~GenericNetlinkMessage() {}
-
-  virtual ByteString Encode(uint32_t sequence_number);
-
-  uint8 command() const { return command_; }
-  const char *command_string() const { return command_string_; }
-  AttributeListConstRefPtr const_attributes() const { return attributes_; }
-  AttributeListRefPtr attributes() { return attributes_; }
-
-  virtual void Print(int log_level) const;
-
- protected:
-  // Returns a string of bytes representing _both_ an |nlmsghdr| and a
-  // |genlmsghdr|, filled-in, and its padding.
-  virtual ByteString EncodeHeader(uint32_t sequence_number);
-  // Reads the |nlmsghdr| and |genlmsghdr| headers and removes them from
-  // |input|.
-  virtual bool InitAndStripHeader(ByteString *input);
-
-  AttributeListRefPtr attributes_;
-  const uint8 command_;
-  const char *command_string_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(GenericNetlinkMessage);
-};
-
-// Control Messages
-
-class ControlNetlinkMessage : public GenericNetlinkMessage {
- public:
-  static const uint16_t kMessageType;
-  ControlNetlinkMessage(uint8 command, const char *command_string)
-      : 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 {
- public:
-  static const uint8_t kCommand;
-  static const char kCommandString[];
-
-  NewFamilyMessage() : ControlNetlinkMessage(kCommand, kCommandString) {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NewFamilyMessage);
-};
-
-class GetFamilyMessage : public ControlNetlinkMessage {
- public:
-  static const uint8_t kCommand;
-  static const char kCommandString[];
-
-  GetFamilyMessage() : ControlNetlinkMessage(kCommand, kCommandString) {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(GetFamilyMessage);
-};
-
-
 // Class for messages received from the mac80211 drivers by way of the
 // cfg80211 kernel module.
 class Nl80211Message : public GenericNetlinkMessage {
@@ -717,31 +428,6 @@
   DISALLOW_COPY_AND_ASSIGN(UnprotDisassociateMessage);
 };
 
-
-//
-// Factory class.
-//
-
-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.
-  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.