shill: Add type-specific children of Nl80211Attribute type.

This checkin adds all the type-specific children of the Nl80211Attribute
type without actually changing any of the code that's called (that's
planned for a later checkin).

The next checkin includes all the attributes necessary to use
Nl80211Attribute.  After that, we'll go for the functionality changes
(which, BTW, passes unittests).

BUG=chromium-os:36637
TEST=unittests.

Change-Id: Ib3944e3b18faeec322ea93cd989daa9bbeb0c0c7
Reviewed-on: https://gerrit.chromium.org/gerrit/39319
Commit-Ready: Wade Guthrie <wdg@chromium.org>
Reviewed-by: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
diff --git a/callback80211_metrics.cc b/callback80211_metrics.cc
index 27b5bc3..fb5d0f1 100644
--- a/callback80211_metrics.cc
+++ b/callback80211_metrics.cc
@@ -29,12 +29,9 @@
                     Metrics::kDisconnectedByAp : Metrics::kDisconnectedNotByAp;
     uint16_t reason = static_cast<uint16_t>(
         IEEE_80211::kReasonCodeInvalid);
-    void *rawdata = NULL;
-    int frame_byte_count = 0;
-    if (message.GetRawAttributeData(NL80211_ATTR_FRAME, &rawdata,
-                                    &frame_byte_count)) {
-      const uint8_t *frame_data = reinterpret_cast<const uint8_t *>(rawdata);
-      Nl80211Frame frame(frame_data, frame_byte_count);
+    ByteString rawdata;
+    if (message.GetRawAttributeData(NL80211_ATTR_FRAME, &rawdata)) {
+      Nl80211Frame frame(rawdata);
       reason = frame.reason();
     }
     IEEE_80211::WiFiReasonCode reason_enum =
diff --git a/callback80211_object.h b/callback80211_object.h
index 68152c2..120cb1c 100644
--- a/callback80211_object.h
+++ b/callback80211_object.h
@@ -8,12 +8,7 @@
 #ifndef SHILL_CALLBACK80211_OBJECT_H
 #define SHILL_CALLBACK80211_OBJECT_H
 
-#include <iomanip>
-#include <map>
-#include <string>
-
 #include <base/basictypes.h>
-#include <base/bind.h>
 #include <base/memory/weak_ptr.h>
 
 #include "shill/config80211.h"
diff --git a/config80211_unittest.cc b/config80211_unittest.cc
index d6faf00..d9e93c8 100644
--- a/config80211_unittest.cc
+++ b/config80211_unittest.cc
@@ -11,6 +11,12 @@
 
 #include "shill/config80211.h"
 
+#include <net/if.h>
+#include <netlink/attr.h>
+#include <netlink/genl/genl.h>
+#include <netlink/msg.h>
+#include <netlink/netlink.h>
+
 #include <list>
 #include <string>
 #include <vector>
@@ -18,15 +24,11 @@
 #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_attribute.h"
 #include "shill/nl80211_socket.h"
 #include "shill/user_bound_nlmessage.h"
 
@@ -706,16 +708,12 @@
   }
 
   {
-    void *rawdata = NULL;
-    int frame_byte_count = 0;
-    EXPECT_TRUE(message->GetRawAttributeData(NL80211_ATTR_FRAME, &rawdata,
-                                             &frame_byte_count));
-    EXPECT_NE(rawdata, reinterpret_cast<void *>(NULL));
-    const uint8_t *frame_data = reinterpret_cast<const uint8_t *>(rawdata);
-
-    Nl80211Frame frame(frame_data, frame_byte_count);
-    Nl80211Frame expected_frame(kAuthenticateFrame, sizeof(kAuthenticateFrame));
-
+    ByteString rawdata;
+    EXPECT_TRUE(message->GetRawAttributeData(NL80211_ATTR_FRAME, &rawdata));
+    EXPECT_FALSE(rawdata.IsEmpty());
+    Nl80211Frame frame(rawdata);
+    Nl80211Frame expected_frame(ByteString(kAuthenticateFrame,
+                                           sizeof(kAuthenticateFrame)));
     EXPECT_TRUE(frame.IsEqual(expected_frame));
   }
 }
@@ -741,16 +739,12 @@
   }
 
   {
-    void *rawdata = NULL;
-    int frame_byte_count = 0;
-    EXPECT_TRUE(message->GetRawAttributeData(NL80211_ATTR_FRAME, &rawdata,
-                                             &frame_byte_count));
-    EXPECT_NE(rawdata, reinterpret_cast<void *>(NULL));
-    const uint8_t *frame_data = reinterpret_cast<const uint8_t *>(rawdata);
-
-    Nl80211Frame frame(frame_data, frame_byte_count);
-    Nl80211Frame expected_frame(kAssociateFrame, sizeof(kAssociateFrame));
-
+    ByteString rawdata;
+    EXPECT_TRUE(message->GetRawAttributeData(NL80211_ATTR_FRAME, &rawdata));
+    EXPECT_FALSE(rawdata.IsEmpty());
+    Nl80211Frame frame(rawdata);
+    Nl80211Frame expected_frame(ByteString(kAssociateFrame,
+                                           sizeof(kAssociateFrame)));
     EXPECT_TRUE(frame.IsEqual(expected_frame));
   }
 }
@@ -812,17 +806,12 @@
   }
 
   {
-    void *rawdata = NULL;
-    int frame_byte_count = 0;
-    EXPECT_TRUE(message->GetRawAttributeData(NL80211_ATTR_FRAME, &rawdata,
-                                             &frame_byte_count));
-    EXPECT_NE(rawdata, reinterpret_cast<void *>(NULL));
-    const uint8_t *frame_data = reinterpret_cast<const uint8_t *>(rawdata);
-
-    Nl80211Frame frame(frame_data, frame_byte_count);
-    Nl80211Frame expected_frame(kDeauthenticateFrame,
-                                sizeof(kDeauthenticateFrame));
-
+    ByteString rawdata;
+    EXPECT_TRUE(message->GetRawAttributeData(NL80211_ATTR_FRAME, &rawdata));
+    EXPECT_FALSE(rawdata.IsEmpty());
+    Nl80211Frame frame(rawdata);
+    Nl80211Frame expected_frame(ByteString(kDeauthenticateFrame,
+                                           sizeof(kDeauthenticateFrame)));
     EXPECT_TRUE(frame.IsEqual(expected_frame));
   }
 }
@@ -905,7 +894,7 @@
 
     EXPECT_FALSE(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
     EXPECT_TRUE(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]);
-    EXPECT_EQ(nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]),
+    EXPECT_EQ(Nl80211Attribute::NlaGetU32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]),
               kExpectedCqmNotAcked);
   }
 }
@@ -932,16 +921,12 @@
   }
 
   {
-    void *rawdata = NULL;
-    int frame_byte_count = 0;
-    EXPECT_TRUE(message->GetRawAttributeData(NL80211_ATTR_FRAME, &rawdata,
-                                             &frame_byte_count));
-    EXPECT_NE(rawdata, reinterpret_cast<void *>(NULL));
-    const uint8_t *frame_data = reinterpret_cast<const uint8_t *>(rawdata);
-
-    Nl80211Frame frame(frame_data, frame_byte_count);
-    Nl80211Frame expected_frame(kDisassociateFrame, sizeof(kDisassociateFrame));
-
+    ByteString rawdata;
+    EXPECT_TRUE(message->GetRawAttributeData(NL80211_ATTR_FRAME, &rawdata));
+    EXPECT_FALSE(rawdata.IsEmpty());
+    Nl80211Frame frame(rawdata);
+    Nl80211Frame expected_frame(ByteString(kDisassociateFrame,
+                                           sizeof(kDisassociateFrame)));
     EXPECT_TRUE(frame.IsEqual(expected_frame));
   }
 }
diff --git a/kernel_bound_nlmessage.h b/kernel_bound_nlmessage.h
index e4595c4..6a55986 100644
--- a/kernel_bound_nlmessage.h
+++ b/kernel_bound_nlmessage.h
@@ -41,7 +41,7 @@
   // CTRL_CMD_GETFAMILY.
   explicit KernelBoundNlMessage(uint8 command)
       : command_(command),
-        message_(NULL) {};
+        message_(NULL) {}
   virtual ~KernelBoundNlMessage();
 
   // Non-trivial initialization.
diff --git a/nl80211_attribute.cc b/nl80211_attribute.cc
index d54b524..44753bc 100644
--- a/nl80211_attribute.cc
+++ b/nl80211_attribute.cc
@@ -64,7 +64,7 @@
   return true;
 }
 
-// Retrieves a pointer to the raw attribute data but not the header.
+// Copies raw attribute data but not the header.
 bool Nl80211Attribute::GetRawData(ByteString *output) const {
   if (!output) {
     LOG(ERROR) << "Null |output| parameter";
@@ -92,21 +92,108 @@
   return output;
 }
 
+// Nl80211U8Attribute
+
+const char Nl80211U8Attribute::kMyTypeString[] = "uint8_t";
+const Nl80211Attribute::Type Nl80211U8Attribute::kType =
+    Nl80211Attribute::kTypeU8;
+
+bool Nl80211U8Attribute::InitFromNlAttr(const nlattr *input) {
+  if (!input) {
+    LOG(ERROR) << "Null |input| parameter";
+    return false;
+  }
+
+  uint8_t data = NlaGetU8(input);
+  SetU8Value(data);
+  return Nl80211Attribute::InitFromNlAttr(input);
+}
+
+bool Nl80211U8Attribute::GetU8Value(uint8_t *output) const {
+  if (!output) {
+    LOG(ERROR) << "Null |output| parameter";
+    return false;
+  }
+  *output = value_;
+  return true;
+}
+
+bool Nl80211U8Attribute::SetU8Value(uint8_t new_value) {
+  value_ = new_value;
+  return true;
+}
+
+bool Nl80211U8Attribute::AsString(string *output) const {
+  if (!output) {
+    LOG(ERROR) << "Null |output| parameter";
+    return false;
+  }
+  uint8_t value;
+  if (!GetU8Value(&value))
+    return false;
+  *output = StringPrintf("%u", value);
+  return true;
+}
+
+
+// Nl80211U16Attribute
+
+const char Nl80211U16Attribute::kMyTypeString[] = "uint16_t";
+const Nl80211Attribute::Type Nl80211U16Attribute::kType =
+    Nl80211Attribute::kTypeU16;
+
+bool Nl80211U16Attribute::InitFromNlAttr(const nlattr *input) {
+  if (!input) {
+    LOG(ERROR) << "Null |input| parameter";
+    return false;
+  }
+
+  uint16_t data = NlaGetU16(input);
+  SetU16Value(data);
+  return Nl80211Attribute::InitFromNlAttr(input);
+}
+
+bool Nl80211U16Attribute::GetU16Value(uint16_t *output) const {
+  if (!output) {
+    LOG(ERROR) << "Null |output| parameter";
+    return false;
+  }
+  *output = value_;
+  return true;
+}
+
+bool Nl80211U16Attribute::SetU16Value(uint16_t new_value) {
+  value_ = new_value;
+  return true;
+}
+
+bool Nl80211U16Attribute::AsString(string *output) const {
+  if (!output) {
+    LOG(ERROR) << "Null |output| parameter";
+    return false;
+  }
+  uint16_t value;
+  if (!GetU16Value(&value))
+    return false;
+  *output = StringPrintf("%u", value);
+  return true;
+}
+
 // Nl80211U32Attribute::
 
 const char Nl80211U32Attribute::kMyTypeString[] = "uint32_t";
 const Nl80211Attribute::Type Nl80211U32Attribute::kType =
     Nl80211Attribute::kTypeU32;
 
-bool Nl80211U32Attribute::InitFromNlAttr(const nlattr *param) {
-  if (!param) {
-    LOG(ERROR) << "Null |param| parameter";
+bool Nl80211U32Attribute::InitFromNlAttr(const nlattr *input) {
+  if (!input) {
+    LOG(ERROR) << "Null |input| parameter";
     return false;
   }
 
-  uint32_t data = nla_get_u32(const_cast<nlattr *>(param));
+  uint32_t data = NlaGetU32(input);
   SetU32Value(data);
-  return Nl80211Attribute::InitFromNlAttr(param);
+  return Nl80211Attribute::InitFromNlAttr(input);
 }
 
 bool Nl80211U32Attribute::GetU32Value(uint32_t *output) const {
@@ -135,19 +222,145 @@
   return true;
 }
 
+// Nl80211U64Attribute
+
+const char Nl80211U64Attribute::kMyTypeString[] = "uint64_t";
+const Nl80211Attribute::Type Nl80211U64Attribute::kType =
+    Nl80211Attribute::kTypeU64;
+
+bool Nl80211U64Attribute::InitFromNlAttr(const nlattr *input) {
+  if (!input) {
+    LOG(ERROR) << "Null |input| parameter";
+    return false;
+  }
+
+  uint64_t data = NlaGetU64(input);
+  SetU64Value(data);
+  return Nl80211Attribute::InitFromNlAttr(input);
+}
+
+bool Nl80211U64Attribute::GetU64Value(uint64_t *output) const {
+  if (!output) {
+    LOG(ERROR) << "Null |output| parameter";
+    return false;
+  }
+  *output = value_;
+  return true;
+}
+
+bool Nl80211U64Attribute::SetU64Value(uint64_t new_value) {
+  value_ = new_value;
+  return true;
+}
+
+bool Nl80211U64Attribute::AsString(string *output) const {
+  if (!output) {
+    LOG(ERROR) << "Null |output| parameter";
+    return false;
+  }
+  uint64_t value;
+  if (!GetU64Value(&value))
+    return false;
+  *output = StringPrintf("%" PRIu64, value);
+  return true;
+}
+
+// Nl80211FlagAttribute
+
+const char Nl80211FlagAttribute::kMyTypeString[] = "flag";
+const Nl80211Attribute::Type Nl80211FlagAttribute::kType =
+    Nl80211Attribute::kTypeFlag;
+
+bool Nl80211FlagAttribute::InitFromNlAttr(const nlattr *input) {
+  if (!input) {
+    LOG(ERROR) << "Null |input| parameter";
+    return false;
+  }
+
+  // The existence of the parameter means it's true
+  SetFlagValue(true);
+  return Nl80211Attribute::InitFromNlAttr(input);
+}
+
+
+bool Nl80211FlagAttribute::GetFlagValue(bool *output) const {
+  if (!output) {
+    LOG(ERROR) << "Null |output| parameter";
+    return false;
+  }
+  *output = value_;
+  return true;
+}
+
+bool Nl80211FlagAttribute::SetFlagValue(bool new_value) {
+  value_ = new_value;
+  return true;
+}
+
+bool Nl80211FlagAttribute::AsString(string *output) const {
+  if (!output) {
+    LOG(ERROR) << "Null |output| parameter";
+    return false;
+  }
+  bool value;
+  if (!GetFlagValue(&value))
+    return false;
+  *output = StringPrintf("%s", value ? "true" : "false");
+  return true;
+}
+
+// Nl80211StringAttribute
+
+const char Nl80211StringAttribute::kMyTypeString[] = "string";
+const Nl80211Attribute::Type Nl80211StringAttribute::kType =
+    Nl80211Attribute::kTypeString;
+
+bool Nl80211StringAttribute::InitFromNlAttr(const nlattr *input) {
+  if (!input) {
+    LOG(ERROR) << "Null |input| parameter";
+    return false;
+  }
+
+  SetStringValue(NlaGetString(input));
+  return Nl80211Attribute::InitFromNlAttr(input);
+}
+
+bool Nl80211StringAttribute::GetStringValue(string *output) const {
+  if (!output) {
+    LOG(ERROR) << "Null |output| parameter";
+    return false;
+  }
+  *output = value_;
+  return true;
+}
+
+bool Nl80211StringAttribute::SetStringValue(const string new_value) {
+  value_ = new_value;
+  return true;
+}
+
+bool Nl80211StringAttribute::AsString(string *output) const {
+  if (!output) {
+    LOG(ERROR) << "Null |output| parameter";
+    return false;
+  }
+  return GetStringValue(output);
+}
+
+
 // Nl80211RawAttribute
 
 const char Nl80211RawAttribute::kMyTypeString[] = "<raw>";
 const Nl80211Attribute::Type Nl80211RawAttribute::kType =
     Nl80211Attribute::kTypeRaw;
 
-bool Nl80211RawAttribute::InitFromNlAttr(const nlattr *param) {
-  if (!param) {
-    LOG(ERROR) << "Null |param| parameter";
+bool Nl80211RawAttribute::InitFromNlAttr(const nlattr *input) {
+  if (!input) {
+    LOG(ERROR) << "Null |input| parameter";
     return false;
   }
 
-  return Nl80211Attribute::InitFromNlAttr(param);
+  return Nl80211Attribute::InitFromNlAttr(input);
 }
 
 bool Nl80211RawAttribute::GetRawValue(const ByteString **output) const {
@@ -164,6 +377,7 @@
     LOG(ERROR) << "Null |output| parameter";
     return false;
   }
+  // TODO(wdg): Make sure that 'data' is valid.
   const uint8_t *raw_data = reinterpret_cast<const uint8_t *>(data());
   int total_bytes = nla_len(data());
   *output = StringPrintf("%d bytes:", total_bytes);
diff --git a/nl80211_attribute.h b/nl80211_attribute.h
index 9ead8ee..d5916ab 100644
--- a/nl80211_attribute.h
+++ b/nl80211_attribute.h
@@ -6,6 +6,7 @@
 #define SHILL_NLATTRIBUTE_H_
 
 #include <linux/nl80211.h>
+#include <netlink/attr.h>
 #include <netlink/netlink.h>
 
 #include <map>
@@ -78,7 +79,7 @@
   // If successful, returns 'true' and sets *|value| to the raw attribute data
   // (after the header) for this attribute.  Otherwise, returns 'false' and
   // leaves |value| unchanged.
-  bool GetRawData(ByteString *value) const;
+  bool GetRawData(ByteString *output) const;
 
   // Fill a string with characters that represents the value of the attribute.
   // If no attribute is found or if the type isn't trivially stringizable,
@@ -88,6 +89,24 @@
   // Writes the raw attribute data to a string.  For debug.
   std::string RawToString() const;
 
+  // Note that |nla_get_*| don't change their arguments but don't declare
+  // themselves as 'const', either.  These methods wrap the const castness.
+  static char *NlaGetString(const nlattr *input) {
+    return nla_get_string(const_cast<nlattr *>(input));
+  }
+  static uint8_t NlaGetU8(const nlattr *input) {
+    return nla_get_u8(const_cast<nlattr *>(input));
+  }
+  static uint16_t NlaGetU16(const nlattr *input) {
+    return nla_get_u16(const_cast<nlattr *>(input));
+  }
+  static uint32_t NlaGetU32(const nlattr *input) {
+    return nla_get_u32(const_cast<nlattr *>(input));
+  }
+  static uint64_t NlaGetU64(const nlattr *input) {
+    return nla_get_u64(const_cast<nlattr *>(input));
+  }
+
  protected:
   // Raw data corresponding to the value in any of the child classes.
   // TODO(wdg): When 'data()' is removed, move this to the Nl80211RawAttribute
@@ -104,6 +123,36 @@
 // Type-specific sub-classes.  These provide their own type-specific data get
 // and set functions.
 
+class Nl80211U8Attribute : public Nl80211Attribute {
+ public:
+  static const char kMyTypeString[];
+  static const Type kType;
+  Nl80211U8Attribute(nl80211_attrs name, const char *name_string)
+      : Nl80211Attribute(name, name_string, kType, kMyTypeString) {}
+  bool InitFromNlAttr(const nlattr *data);
+  bool GetU8Value(uint8_t *value) const;
+  bool SetU8Value(uint8_t new_value);
+  bool AsString(std::string *value) const;
+
+ private:
+  uint8_t value_;
+};
+
+class Nl80211U16Attribute : public Nl80211Attribute {
+ public:
+  static const char kMyTypeString[];
+  static const Type kType;
+  Nl80211U16Attribute(nl80211_attrs name, const char *name_string)
+      : Nl80211Attribute(name, name_string, kType, kMyTypeString) {}
+  bool InitFromNlAttr(const nlattr *data);
+  bool GetU16Value(uint16_t *value) const;
+  bool SetU16Value(uint16_t new_value);
+  bool AsString(std::string *value) const;
+
+ private:
+  uint16_t value_;
+};
+
 class Nl80211U32Attribute : public Nl80211Attribute {
  public:
   static const char kMyTypeString[];
@@ -119,7 +168,50 @@
   uint32_t value_;
 };
 
-// TODO(wdg): Add more data types.
+class Nl80211U64Attribute : public Nl80211Attribute {
+ public:
+  static const char kMyTypeString[];
+  static const Type kType;
+  Nl80211U64Attribute(nl80211_attrs name, const char *name_string)
+      : Nl80211Attribute(name, name_string, kType, kMyTypeString) {}
+  bool InitFromNlAttr(const nlattr *data);
+  bool GetU64Value(uint64_t *value) const;
+  bool SetU64Value(uint64_t new_value);
+  bool AsString(std::string *value) const;
+
+ private:
+  uint64_t value_;
+};
+
+class Nl80211FlagAttribute : public Nl80211Attribute {
+ public:
+  static const char kMyTypeString[];
+  static const Type kType;
+  Nl80211FlagAttribute(nl80211_attrs name, const char *name_string)
+      : Nl80211Attribute(name, name_string, kType, kMyTypeString) {}
+  bool InitFromNlAttr(const nlattr *data);
+  bool GetFlagValue(bool *value) const;
+  bool SetFlagValue(bool new_value);
+  bool AsString(std::string *value) const;
+
+ private:
+  bool value_;
+};
+
+class Nl80211StringAttribute : public Nl80211Attribute {
+ public:
+  static const char kMyTypeString[];
+  static const Type kType;
+  Nl80211StringAttribute(nl80211_attrs name, const char *name_string)
+      : Nl80211Attribute(name, name_string, kType, kMyTypeString) {}
+  bool InitFromNlAttr(const nlattr *data);
+  bool GetStringValue(std::string *value) const;
+  bool SetStringValue(const std::string new_value);
+  bool AsString(std::string *value) const;
+
+ private:
+  std::string value_;
+};
 
 class Nl80211RawAttribute : public Nl80211Attribute {
  public:
diff --git a/user_bound_nlmessage.cc b/user_bound_nlmessage.cc
index 9fce829..e822316 100644
--- a/user_bound_nlmessage.cc
+++ b/user_bound_nlmessage.cc
@@ -28,9 +28,9 @@
 #include <endian.h>
 #include <errno.h>
 
-#include <netinet/in.h>
 #include <linux/nl80211.h>
 #include <net/if.h>
+#include <netinet/in.h>
 #include <netlink/attr.h>
 #include <netlink/genl/ctrl.h>
 #include <netlink/genl/family.h>
@@ -47,6 +47,7 @@
 
 #include "shill/ieee80211.h"
 #include "shill/logging.h"
+#include "shill/nl80211_attribute.h"
 #include "shill/scope_logger.h"
 
 using base::LazyInstance;
@@ -69,7 +70,7 @@
 const uint8_t Nl80211Frame::kFrameTypeMask = 0xfc;
 
 const uint32_t UserBoundNlMessage::kIllegalMessage = 0xFFFFFFFF;
-const int UserBoundNlMessage::kEthernetAddressBytes = 6;
+const unsigned int UserBoundNlMessage::kEthernetAddressBytes = 6;
 map<uint16_t, string> *UserBoundNlMessage::reason_code_string_ = NULL;
 map<uint16_t, string> *UserBoundNlMessage::status_code_string_ = NULL;
 
@@ -383,23 +384,18 @@
 
 // Returns the raw attribute data but not the header.
 bool UserBoundNlMessage::GetRawAttributeData(enum nl80211_attrs name,
-                                             void **value,
-                                             int *length) const {
+                                             ByteString *value) const {
   if (!value) {
     LOG(ERROR) << "Null |value| parameter";
     return false;
   }
-
   const nlattr *attr = GetAttribute(name);
   if (!attr) {
-    *value = NULL;
+    value->Clear();
     return false;
   }
-
-  if (length) {
-    *length = nla_len(attr);
-  }
-  *value = nla_data(attr);
+  *value = ByteString(reinterpret_cast<unsigned char *>(nla_data(attr)),
+                      nla_len(attr));
   return true;
 }
 
@@ -415,7 +411,7 @@
     return false;
   }
 
-  value->assign(nla_get_string(const_cast<nlattr *>(attr)));
+  value->assign(Nl80211Attribute::NlaGetString(attr));
   return true;
 }
 
@@ -431,7 +427,7 @@
     return false;
   }
 
-  *value = nla_get_u8(const_cast<nlattr *>(attr));
+  *value = Nl80211Attribute::NlaGetU8(attr);
   return true;
 }
 
@@ -447,7 +443,7 @@
     return false;
   }
 
-  *value = nla_get_u16(const_cast<nlattr *>(attr));
+  *value = Nl80211Attribute::NlaGetU16(attr);
   return true;
 }
 
@@ -463,7 +459,7 @@
     return false;
   }
 
-  *value = nla_get_u32(const_cast<nlattr *>(attr));
+  *value = Nl80211Attribute::NlaGetU32(attr);
   return true;
 }
 
@@ -479,7 +475,7 @@
     return false;
   }
 
-  *value = nla_get_u64(const_cast<nlattr *>(attr));
+  *value = Nl80211Attribute::NlaGetU64(attr);
   return true;
 }
 
@@ -491,13 +487,12 @@
     return false;
   }
 
-  void *rawdata_void = NULL;
-  if (!GetRawAttributeData(name, &rawdata_void, NULL)) {
+  ByteString data;
+  if (!GetRawAttributeData(name, &data)) {
     value->assign(kBogusMacAddress);
     return false;
   }
-  const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(rawdata_void);
-  value->assign(StringFromMacAddress(rawdata));
+  value->assign(StringFromMacAddress(data.GetConstData()));
 
   return true;
 }
@@ -512,20 +507,21 @@
 
   value->clear();
   if (AttributeExists(name)) {
-    void *rawdata = NULL;
-    int len = 0;
-    if (GetRawAttributeData(name, &rawdata, &len) && rawdata) {
+    ByteString rawdata;
+    if (GetRawAttributeData(name, &rawdata) && !rawdata.IsEmpty()) {
       nlattr *nst = NULL;
-      nlattr *attr_data = reinterpret_cast<nlattr *>(rawdata);
+      // |nla_for_each_attr| requires a non-const parameter even though it
+      // doesn't change the data.
+      nlattr *attr_data = reinterpret_cast<nlattr *>(rawdata.GetData());
       int rem_nst;
+      int len = rawdata.GetLength();
 
       nla_for_each_attr(nst, attr_data, len, rem_nst) {
-        value->push_back(nla_get_u32(nst));
+        value->push_back(Nl80211Attribute::NlaGetU32(nst));
       }
     }
     return true;
   }
-
   return false;
 }
 
@@ -538,12 +534,14 @@
   }
 
   if (AttributeExists(name)) {
-    void *rawdata = NULL;
-    int len = 0;
-    if (GetRawAttributeData(name, &rawdata, &len) && rawdata) {
+    ByteString rawdata;
+    if (GetRawAttributeData(name, &rawdata) && !rawdata.IsEmpty()) {
       nlattr *nst = NULL;
-      nlattr *data = reinterpret_cast<nlattr *>(rawdata);
+      // |nla_for_each_attr| requires a non-const parameter even though it
+      // doesn't change the data.
+      nlattr *data = reinterpret_cast<nlattr *>(rawdata.GetData());
       int rem_nst;
+      int len = rawdata.GetLength();
 
       nla_for_each_attr(nst, data, len, rem_nst) {
         value->push_back(StringFromSsid(nla_len(nst),
@@ -553,7 +551,6 @@
     }
     return true;
   }
-
   return false;
 }
 
@@ -980,7 +977,7 @@
 
 const nlattr *UserBoundNlMessage::GetAttribute(enum nl80211_attrs name)
     const {
-  map<enum nl80211_attrs, nlattr *>::const_iterator match;
+  map<nl80211_attrs, nlattr *>::const_iterator match;
   match = attributes_.find(name);
   // This method may be called to explore the existence of the attribute so
   // we'll not emit an error if it's not found.
@@ -1015,13 +1012,9 @@
 
 string UserBoundNlMessage::StringFromFrame(enum nl80211_attrs attr_name) const {
   string output;
-
-  void *rawdata = NULL;
-  int frame_byte_count = 0;
-  if (GetRawAttributeData(attr_name, &rawdata, &frame_byte_count) && rawdata) {
-    const uint8_t *frame_data = reinterpret_cast<const uint8_t *>(rawdata);
-
-    Nl80211Frame frame(frame_data, frame_byte_count);
+  ByteString frame_data;
+  if (GetRawAttributeData(attr_name, &frame_data) && !frame_data.IsEmpty()) {
+    Nl80211Frame frame(frame_data);
     frame.ToString(&output);
   } else {
     output.append(" [no frame]");
@@ -1054,7 +1047,7 @@
   } else {
     StringAppendF(&output, "%02x", arg[0]);
 
-    for (int i = 1; i < kEthernetAddressBytes ; ++i) {
+    for (unsigned int i = 1; i < kEthernetAddressBytes ; ++i) {
       StringAppendF(&output, ":%02x", arg[i]);
     }
   }
@@ -1131,20 +1124,15 @@
   return match->second;
 }
 
-Nl80211Frame::Nl80211Frame(const uint8_t *raw_frame, int frame_byte_count)
+Nl80211Frame::Nl80211Frame(const ByteString &raw_frame)
   : frame_type_(kIllegalFrameType), reason_(UINT16_MAX), status_(UINT16_MAX),
-    frame_(0), byte_count_(0) {
-  if (raw_frame == NULL)
-    return;
-
-  frame_ = new uint8_t[frame_byte_count];
-  memcpy(frame_, raw_frame, frame_byte_count);
-  byte_count_ = frame_byte_count;
+    frame_(raw_frame) {
   const IEEE_80211::ieee80211_frame *frame =
-      reinterpret_cast<const IEEE_80211::ieee80211_frame *>(frame_);
+      reinterpret_cast<const IEEE_80211::ieee80211_frame *>(
+          frame_.GetConstData());
 
   // Now, let's populate the other stuff.
-  if (frame_byte_count >= kMinimumFrameByteCount) {
+  if (frame_.GetLength() >= kMinimumFrameByteCount) {
     mac_from_ =
         UserBoundNlMessage::StringFromMacAddress(&frame->destination_mac[0]);
     mac_to_ = UserBoundNlMessage::StringFromMacAddress(&frame->source_mac[0]);
@@ -1171,28 +1159,23 @@
   }
 }
 
-Nl80211Frame::~Nl80211Frame() {
-  delete [] frame_;
-  frame_ = NULL;
-}
-
 bool Nl80211Frame::ToString(string *output) const {
   if (!output) {
     LOG(ERROR) << "NULL |output|";
     return false;
   }
 
-  if ((byte_count_ == 0) || (frame_ == reinterpret_cast<uint8_t *>(NULL))) {
+  if (frame_.IsEmpty()) {
     output->append(" [no frame]");
     return true;
   }
 
-  if (byte_count_ < kMinimumFrameByteCount) {
+  if (frame_.GetLength() < kMinimumFrameByteCount) {
     output->append(" [invalid frame: ");
   } else {
     StringAppendF(output, " %s -> %s", mac_from_.c_str(), mac_to_.c_str());
 
-    switch (frame_[0] & kFrameTypeMask) {
+    switch (frame_.GetConstData()[0] & kFrameTypeMask) {
     case kAssocResponseFrameType:
       StringAppendF(output, "; AssocResponse status: %u: %s",
                     status_,
@@ -1226,8 +1209,9 @@
     output->append(" [frame: ");
   }
 
-  for (int i = 0; i < byte_count_; ++i) {
-    StringAppendF(output, "%02x, ", frame_[i]);
+  const unsigned char *frame = frame_.GetConstData();
+  for (size_t i = 0; i < frame_.GetLength(); ++i) {
+    StringAppendF(output, "%02x, ", frame[i]);
   }
   output->append("]");
 
@@ -1235,17 +1219,7 @@
 }
 
 bool Nl80211Frame::IsEqual(const Nl80211Frame &other) const {
-  if (byte_count_ != other.byte_count_) {
-    return false;
-  }
-
-  for (int i = 0; i < byte_count_; ++i) {
-    if (frame_[i] != other.frame_[i]) {
-      return false;
-    }
-  }
-
-  return true;
+  return frame_.Equals(other.frame_);
 }
 
 
@@ -1418,12 +1392,10 @@
   }
 
   if (AttributeExists(NL80211_ATTR_KEY_SEQ)) {
-    void *rawdata = NULL;
-    int length = 0;
-    if (GetRawAttributeData(NL80211_ATTR_KEY_SEQ, &rawdata, &length) &&
-        rawdata && length == 6) {
-      const unsigned char *seq = reinterpret_cast<const unsigned char *>(
-          rawdata);
+    ByteString rawdata;
+    if (GetRawAttributeData(NL80211_ATTR_KEY_SEQ, &rawdata) &&
+        rawdata.GetLength() == UserBoundNlMessage::kEthernetAddressBytes) {
+      const unsigned char *seq = rawdata.GetConstData();
       StringAppendF(&output, " seq=%02x%02x%02x%02x%02x%02x",
                     seq[0], seq[1], seq[2], seq[3], seq[4], seq[5]);
     }
@@ -1518,6 +1490,8 @@
   output.append("connection quality monitor event: ");
 
   const nlattr *const_data = GetAttribute(NL80211_ATTR_CQM);
+  // Note that |nla_parse_nested| doesn't change |const_data| but doesn't
+  // declare itself as 'const', either.  Hence the cast.
   nlattr *cqm_attr = const_cast<nlattr *>(const_data);
 
   nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
@@ -1530,7 +1504,8 @@
   if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) {
     enum nl80211_cqm_rssi_threshold_event rssi_event =
         static_cast<enum nl80211_cqm_rssi_threshold_event>(
-          nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]));
+          Nl80211Attribute::NlaGetU32(
+              cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]));
     if (rssi_event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH)
       output.append("RSSI went above threshold");
     else
@@ -1541,11 +1516,11 @@
     GetMacAttributeString(NL80211_ATTR_MAC, &mac);
     StringAppendF(&output, "peer %s didn't ACK %" PRIu32 " packets",
                   mac.c_str(),
-                  nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]));
+                  Nl80211Attribute::NlaGetU32(
+                      cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]));
   } else {
     output.append("unknown event");
   }
-
   return output;
 }
 
@@ -1620,13 +1595,16 @@
 
   nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
 
+  // Note that |nla_parse_nested| doesn't change its parameters but doesn't
+  // declare itself as 'const', either.  Hence the cast.
   if (nla_parse_nested(tb_freq,
                        NL80211_FREQUENCY_ATTR_MAX,
                        const_cast<nlattr *>(tb),
                        const_cast<nla_policy *>(kBeaconFreqPolicy)))
     return -EINVAL;
 
-  chan->center_freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+  chan->center_freq = Nl80211Attribute::NlaGetU32(
+      tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
 
   if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
     chan->passive_scan = true;
@@ -1922,7 +1900,7 @@
   // 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);
+            genlmsg_attrlen(gnlh, 0), NULL);
 
   if (!message->Init(tb, msg)) {
     LOG(ERROR) << "Message did not initialize properly";
diff --git a/user_bound_nlmessage.h b/user_bound_nlmessage.h
index f11c90b..43d6089 100644
--- a/user_bound_nlmessage.h
+++ b/user_bound_nlmessage.h
@@ -5,18 +5,18 @@
 #ifndef SHILL_USER_BOUND_NLMESSAGE_H_
 #define SHILL_USER_BOUND_NLMESSAGE_H_
 
+#include <linux/nl80211.h>
+
 #include <iomanip>
 #include <map>
-#include <vector>
 #include <string>
+#include <vector>
 
 #include <base/basictypes.h>
 #include <base/bind.h>
 #include <base/lazy_instance.h>
 #include <gtest/gtest.h>
 
-#include <linux/nl80211.h>
-
 #include "shill/nl80211_attribute.h"
 
 struct nlattr;
@@ -27,8 +27,7 @@
 // Class for messages received from libnl.
 class UserBoundNlMessage {
  public:
-  // TODO(wdg): break 'Attribute' into its own class to handle
-  // nested attributes better.
+  static const unsigned int kEthernetAddressBytes;
 
   // A const iterator to the attribute names in the attributes_ map of a
   // UserBoundNlMessage.  The purpose, here, is to hide the way that the
@@ -73,8 +72,6 @@
   // attributes inside a message object.
 
   AttributeNameIterator *GetAttributeNameIterator() const;
-  bool HasAttributes() const { return !attributes_.empty(); }
-  uint32_t GetAttributeCount() const { return attributes_.size(); }
 
   // Other ways to see the internals of the object.
 
@@ -91,13 +88,11 @@
   // Returns a string describing the data type of a given attribute.
   std::string GetAttributeTypeString(nl80211_attrs name) const;
 
-  // If successful, returns 'true' and sets *|value| to the raw attribute data
-  // (after the header) for this attribute and, if |length| is not
-  // null, *|length| to the number of bytes of data available.  If no
-  // attribute by this name exists in this message, sets *|value| to NULL and
-  // returns 'false'.  If otherwise unsuccessful, returns 'false' and leaves
-  // |value| and |length| unchanged.
-  bool GetRawAttributeData(nl80211_attrs name, void **value, int *length) const;
+  // If successful, returns 'true' and the raw attribute data (after the
+  // header) into |value| for this attribute.  If no attribute by this name
+  // exists in this message, clears |value| and returns 'false'.  If otherwise
+  // unsuccessful, returns 'false' and leaves |value| unchanged.
+  bool GetRawAttributeData(nl80211_attrs name, ByteString *value) const;
 
   // Each of these methods set |value| with the value of the specified
   // attribute (if the attribute is not found, |value| remains unchanged).
@@ -182,7 +177,6 @@
   FRIEND_TEST(Config80211Test, NL80211_CMD_NOTIFY_CQM);
 
   static const uint32_t kIllegalMessage;
-  static const int kEthernetAddressBytes;
 
   nlmsghdr *message_;
   const uint8 message_type_;
@@ -207,8 +201,7 @@
     kIllegalFrameType = 0xff
   };
 
-  Nl80211Frame(const uint8_t *frame, int frame_byte_count);
-  ~Nl80211Frame();
+  Nl80211Frame(const ByteString &init);
   bool ToString(std::string *output) const;
   bool IsEqual(const Nl80211Frame &other) const;
   uint16_t reason() const { return reason_; }
@@ -223,8 +216,7 @@
   uint8_t frame_type_;
   uint16_t reason_;
   uint16_t status_;
-  uint8_t *frame_;
-  int byte_count_;
+  ByteString frame_;
 
   DISALLOW_COPY_AND_ASSIGN(Nl80211Frame);
 };