shill: Split Nl80211Message into class hierarchy.

Gotta apologize for this CL: it's a bit more gnarly than I'd like.
There're not that many modifications but, with all the moving of code,
it's harder to review than I'd like.  I found that, easier than gerrit,
cherry-pick the change, do a git show HEAD^:nl80211_message.[ch] > old.[ch],
and edit the old and new files, together.

With the exception of the following changes, the Nl80211Message code was
just split into the NetlinkMessage <|-- GenericNetlinkMessage <|--
Nl80211Message class hierarchy.

  1. In |NetlinkMessage::InitAndStripHeader|, a length check was
     added to verify that enough bytes for the |nlmsghdr| exists.
  2. In |GenericNetlinkMessage::Encode|, changed name of |attributes|
     variable to |attribute_string|.
  3. Split |EncodeHeader| and |InitAndStripHeader|, each, into
     |nlmsghdr| and |genlmsghdr| pieces.
  4. In |NetlinkMessage::EncodeHeader|, added encoding of |flags_| (that
     had, somehow, gotten missed in the previous CL -- all other
     |flags_| processing had been included.)
  5. Removed the following unused methods from |Nl80211Message|:
      - GetHeaderString
      - StringFromFrame
      - StringFromKeyType
      - StringFromRegInitiator
      - StringFromSsid

BUG=chromium-os:38221
TEST=unittest.

Change-Id: I208ede49fa8003d49eb487365f886a8f0d53da3f
Reviewed-on: https://gerrit.chromium.org/gerrit/44640
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Reviewed-by: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
Commit-Queue: Wade Guthrie <wdg@chromium.org>
diff --git a/nl80211_message.h b/nl80211_message.h
index 10986fa..3ecc022 100644
--- a/nl80211_message.h
+++ b/nl80211_message.h
@@ -28,38 +28,195 @@
 
 class Config80211;
 
-// Class for messages received from libnl.
-class Nl80211Message {
+// 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::AddFamilyByString:
+//
+//  config80211_->AddFamilyByString(Nl80211Message::kMessageType,
+//                                  Bind(&Nl80211Message::SetFamilyId));
+//
+// 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;
-  static const unsigned int kEthernetAddressBytes;
-  static const char kBogusMacAddress[];
 
-  Nl80211Message(uint8 command, const char *command_string)
-      : attributes_(new AttributeList),
+  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, uint16_t nlmsg_type) = 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,
+                                  uint16_t nlmsg_type);
+  // 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);
+};
+
+// 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),
-        flags_(0),
-        message_type_(nl80211_message_type_),
-        sequence_number_(kBroadcastSequenceNumber) {}
-  virtual ~Nl80211Message() {}
+        command_string_(command_string) {}
+  virtual ~GenericNetlinkMessage() {}
+
+  virtual ByteString Encode(uint32_t sequence_number, uint16_t nlmsg_type);
 
   uint8 command() const { return command_; }
   const char *command_string() const { return command_string_; }
 
-  // Initializes the message with bytes from the kernel.
-  virtual bool InitFromNlmsg(const nlmsghdr *msg);
-  static void PrintBytes(int log_level, const unsigned char *buf,
-                         size_t num_bytes);
-  uint32_t sequence_number() const { return sequence_number_; }
-  virtual void Print(int log_level) const;
-
-  void set_sequence_number(uint32_t seq) { sequence_number_ = seq; }
-
   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,
+                                  uint16_t nlmsg_type);
+  // 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);
+};
+
+// Class for messages received from the mac80211 drivers by way of the
+// cfg80211 kernel module.
+class Nl80211Message : public GenericNetlinkMessage {
+ public:
+  static const char kMessageTypeString[];
+  static const unsigned int kEthernetAddressBytes;
+  static const char kBogusMacAddress[];
+
+  Nl80211Message(uint8 command, const char *command_string)
+      : GenericNetlinkMessage(nl80211_message_type_, command, command_string) {}
+  virtual ~Nl80211Message() {}
+
+  virtual bool InitFromNlmsg(const nlmsghdr *msg);
+
+  uint8 command() const { return command_; }
+  const char *command_string() const { return command_string_; }
+  uint16_t message_type() const { return message_type_; }
+  uint32_t sequence_number() const { return sequence_number_; }
+  void set_sequence_number(uint32_t seq) { sequence_number_ = seq; }
+
   // TODO(wdg): This needs to be moved to AttributeMac.
   // Helper function to provide a string for a MAC address.  If no attribute
   // is found, this method returns 'false'.  On any error with a non-NULL
@@ -87,54 +244,10 @@
   static std::string StringFromReason(uint16_t reason);
   static std::string StringFromStatus(uint16_t status);
 
-  // Returns a netlink message suitable for Sockets::Send.  Return value is
-  // empty on failure.  |nlmsg_type| needs to be the family id returned by
-  // |genl_ctrl_resolve|.
-  ByteString Encode(uint32_t sequence_number, uint16_t nlmsg_type);
-
- protected:
-  // Reads the values from the |nlmsghdr| and |genlmsghdr| portions of the
-  // netlink message and removes those headers (and any padding that happens to
-  // be there) from |input| leaving, hopefully, the attributes.
-  bool InitAndStripHeader(ByteString *input);
-
-  // Returns a string of bytes representing an |nlmsghdr| with the members
-  // filled-in with values representing the current message, and any required
-  // padding.
-  ByteString EncodeHeader(uint32_t sequence_number, uint16_t nlmsg_type);
-
-  // Returns a string that should precede all user-bound message strings.
-  virtual std::string GetHeaderString() const;
-
-  // Returns a string that describes the contents of the frame pointed to by
-  // 'attr'.
-  std::string StringFromFrame(int attr_name) const;
-
-  // Converts key_type to a string.
-  static std::string StringFromKeyType(nl80211_key_type key_type);
-
-  // Returns a string representation of the REG initiator described by the
-  // method's parameter.
-  static std::string StringFromRegInitiator(__u8 initiator);
-
-  // Returns a string based on the SSID found in 'data'.  Non-printable
-  // characters are string-ized.
-  static std::string StringFromSsid(const uint8_t len, const uint8_t *data);
-
  private:
-  friend class Config80211Test;
-  FRIEND_TEST(Config80211Test, NL80211_CMD_NOTIFY_CQM);
-
-  static uint16_t nl80211_message_type_;
   static std::map<uint16_t, std::string> *reason_code_string_;
   static std::map<uint16_t, std::string> *status_code_string_;
-
-  AttributeListRefPtr attributes_;
-  const uint8 command_;
-  const char *command_string_;
-  uint16_t flags_;
-  uint16_t message_type_;
-  uint32_t sequence_number_;
+  static uint16_t nl80211_message_type_;
 
   DISALLOW_COPY_AND_ASSIGN(Nl80211Message);
 };
@@ -535,14 +648,17 @@
 // Factory class.
 //
 
-class Nl80211MessageFactory {
+class NetlinkMessageFactory {
  public:
   // Ownership of the message is passed to the caller and, as such, he should
   // delete it.
-  static Nl80211Message *CreateMessage(nlmsghdr *msg);
+  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.
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(Nl80211MessageFactory);
+  DISALLOW_COPY_AND_ASSIGN(NetlinkMessageFactory);
 };