shill: Random cleanup.

For this checkin, I've done a number of small things.  I've:

  o Moved the parsing of incoming message attributes inside
    Nl80211Message::InitFromNlmsg (because it should be there).
  o Added Ack, Noop, and Error messages (along with their handling).
    This will improve message handling once I further abandon libnl.
  o Added NL80211_CMD_GET_REG message and handling.  There are several
    messages that aren't currently handled and I'm adding them as they
    become necessary.  This is one of those.
  o Removed the copy of the message that Nl80211Message was storing --
    it's no longer needed.

BUG=None.
TEST=unittests.

Change-Id: Ibf79e6a0ac32ed03cd37c81c68555801b9ab5d16
Reviewed-on: https://gerrit.chromium.org/gerrit/40278
Commit-Queue: Wade Guthrie <wdg@chromium.org>
Reviewed-by: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
diff --git a/nl80211_message.cc b/nl80211_message.cc
index 3fb4826..fd3ec10 100644
--- a/nl80211_message.cc
+++ b/nl80211_message.cc
@@ -103,21 +103,35 @@
 // Nl80211Message
 //
 
-// TODO(wdg): do the nlattr parsing inside here.
-bool Nl80211Message::Init(nlattr *tb[NL80211_ATTR_MAX + 1],
-                          nlmsghdr *msg) {
-  if (!tb) {
-    LOG(ERROR) << "Null |tb| parameter";
+bool Nl80211Message::InitFromNlmsg(const nlmsghdr *const_msg) {
+  if (!const_msg) {
+    LOG(ERROR) << "Null |msg| parameter";
     return false;
   }
 
-  message_ = msg;
-
+  // Netlink header.
+  sequence_number_ = const_msg->nlmsg_seq;
   SLOG(WiFi, 6) << "NL Message " << sequence_number() << " <===";
 
+  // Casting away constness, here, since the libnl code doesn't properly label
+  // their stuff as const (even though it is).
+  nlmsghdr *msg = const_cast<nlmsghdr *>(const_msg);
+
+  // Genl message header.
+  genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(nlmsg_data(msg));
+
+  // Attributes.
+  // Parse the attributes from the nl message payload into the 'tb' array.
+  nlattr *tb[NL80211_ATTR_MAX + 1];
+  nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+            genlmsg_attrlen(gnlh, 0), NULL);
+
   for (int i = 0; i < NL80211_ATTR_MAX + 1; ++i) {
     if (tb[i]) {
-      attributes_.CreateAndInitFromNlAttr(static_cast<nl80211_attrs>(i), tb[i]);
+      // TODO(wdg): When Nl80211Messages instantiate their own attributes,
+      // this call should, instead, call |SetAttributeFromNlAttr|.
+      attributes_.CreateAndInitFromNlAttr(static_cast<enum nl80211_attrs>(i),
+                                          tb[i]);
     }
   }
 
@@ -684,6 +698,14 @@
 // Specific Nl80211Message types.
 //
 
+// An Ack is not a GENL message and, as such, has no command.
+const uint8_t AckMessage::kCommand = NL80211_CMD_UNSPEC;
+const char AckMessage::kCommandString[] = "NL80211_ACK";
+
+string AckMessage::ToString() const {
+  return "NL80211_ACK";
+}
+
 const uint8_t AssociateMessage::kCommand = NL80211_CMD_ASSOCIATE;
 const char AssociateMessage::kCommandString[] = "NL80211_CMD_ASSOCIATE";
 
@@ -809,6 +831,20 @@
   return output;
 }
 
+// An Error is not a GENL message and, as such, has no command.
+const uint8_t ErrorMessage::kCommand = NL80211_CMD_UNSPEC;
+const char ErrorMessage::kCommandString[] = "NL80211_ERROR";
+
+ErrorMessage::ErrorMessage(uint32_t error)
+  : Nl80211Message(kCommand, kCommandString), error_(error) {}
+
+string ErrorMessage::ToString() const {
+  string output;
+  StringAppendF(&output, "NL80211_ERROR %" PRIx32 ": %s",
+                error_, strerror(error_));
+  return output;
+}
+
 const uint8_t FrameTxStatusMessage::kCommand = NL80211_CMD_FRAME_TX_STATUS;
 const char FrameTxStatusMessage::kCommandString[] =
     "NL80211_CMD_FRAME_TX_STATUS";
@@ -824,6 +860,10 @@
   return output;
 }
 
+const uint8_t GetRegMessage::kCommand = NL80211_CMD_GET_REG;
+const char GetRegMessage::kCommandString[] = "NL80211_CMD_GET_REG";
+
+
 const uint8_t JoinIbssMessage::kCommand = NL80211_CMD_JOIN_IBSS;
 const char JoinIbssMessage::kCommandString[] = "NL80211_CMD_JOIN_IBSS";
 
@@ -863,7 +903,7 @@
   }
   uint32_t key_type_val = UINT32_MAX;
   if (attributes().GetU32AttributeValue(NL80211_ATTR_KEY_TYPE, &key_type_val)) {
-    nl80211_key_type key_type = static_cast<nl80211_key_type >(key_type_val);
+    nl80211_key_type key_type = static_cast<nl80211_key_type>(key_type_val);
     StringAppendF(&output, " Key Type %s", StringFromKeyType(key_type).c_str());
   }
 
@@ -935,6 +975,14 @@
   return output;
 }
 
+// A NOOP is not a GENL message and, as such, has no command.
+const uint8_t NoopMessage::kCommand = NL80211_CMD_UNSPEC;
+const char NoopMessage::kCommandString[] = "NL80211_NOOP";
+
+string NoopMessage::ToString() const {
+  return "NL80211_NOOP";
+}
+
 const uint8_t NotifyCqmMessage::kCommand = NL80211_CMD_NOTIFY_CQM;
 const char NotifyCqmMessage::kCommandString[] = "NL80211_CMD_NOTIFY_CQM";
 
@@ -1310,80 +1358,84 @@
   }
 
   scoped_ptr<Nl80211Message> message;
+  void *payload = nlmsg_data(msg);
 
-  genlmsghdr *gnlh =
-      reinterpret_cast<genlmsghdr *>(nlmsg_data(msg));
+  if (msg->nlmsg_type == NLMSG_NOOP) {
+    SLOG(WiFi, 6) << "Creating a NOP message";
+    message.reset(new NoopMessage());
+  } else if (msg->nlmsg_type == NLMSG_ERROR) {
+    uint32_t error_code = *(reinterpret_cast<uint32_t *>(payload));
+    if (error_code) {
+      SLOG(WiFi, 6) << "Creating an ERROR message:" << error_code;
+      message.reset(new ErrorMessage(error_code));
+    } else {
+      SLOG(WiFi, 6) << "Creating an ACK message";
+      message.reset(new AckMessage());
+    }
+  } else {
+    SLOG(WiFi, 6) << "Creating a Regular message";
+    genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(payload);
 
-  if (!gnlh) {
-    LOG(ERROR) << "NULL gnlh";
-    return NULL;
-  }
+    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;
 
-  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 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;
+    }
 
-    default:
-      message.reset(new UnknownMessage(gnlh->cmd)); break;
-      break;
-  }
-
-  nlattr *tb[NL80211_ATTR_MAX + 1];
-
-  // Parse the attributes from the nl message payload (which starts at the
-  // header) into the 'tb' array.
-  nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-            genlmsg_attrlen(gnlh, 0), NULL);
-
-  if (!message->Init(tb, msg)) {
-    LOG(ERROR) << "Message did not initialize properly";
-    return NULL;
+    if (!message->InitFromNlmsg(msg)) {
+      LOG(ERROR) << "Message did not initialize properly";
+      return NULL;
+    }
   }
 
   return message.release();