shill: Config80211 Cleanup.

Just cleaning up a bunch of things that didn't fit anywhere else.

Added |ToString| methods to several classes to make them easier to debug
(changed some things from |AsString| to |ToString| to make it consistent
with the rest of the code base).

Put error-returning getters/setters in Nl80211Attribute to eliminate the
need for specific casts (and, removed the casts in other parts of the
code).

Converted AttributeList::attributes_ to use a smart pointer.

Removed AttributeList's dependency on Nl80211Attribute.

BUG=None.
TEST=Unit tests.

Change-Id: I630bf59a4f73bee71953fe8faeb1d8f6a168cb29
Reviewed-on: https://gerrit.chromium.org/gerrit/40144
Reviewed-by: mukesh agrawal <quiche@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/attribute_list.cc b/attribute_list.cc
index dd61ff8..ea797a0 100644
--- a/attribute_list.cc
+++ b/attribute_list.cc
@@ -14,30 +14,25 @@
 #include <string>
 
 #include <base/stl_util.h>
+#include <base/stringprintf.h>
 
 #include "shill/logging.h"
 #include "shill/nl80211_attribute.h"
 #include "shill/scope_logger.h"
 
+using base::StringAppendF;
 using base::WeakPtr;
 using std::map;
 using std::string;
 
 namespace shill {
 
-AttributeList::~AttributeList() {
-  map<int, Nl80211Attribute *>::iterator i;
-  for (i = attributes_.begin(); i != attributes_.end(); ++i) {
-    delete i->second;
-  }
-}
-
 bool AttributeList::CreateAttribute(nl80211_attrs id) {
   if (ContainsKey(attributes_, id)) {
     LOG(ERROR) << "Trying to re-add attribute: " << id;
     return false;
   }
-  attributes_[id] = Nl80211Attribute::NewFromName(id);
+  attributes_[id] = AttributePointer(Nl80211Attribute::NewFromName(id));
   return true;
 }
 
@@ -49,16 +44,29 @@
   return attributes_[id]->InitFromNlAttr(data);
 }
 
+string AttributeList::ToString() const {
+  string output;
+  map<int, AttributePointer>::const_iterator i;
+
+  for (i = attributes_.begin(); i != attributes_.end(); ++i) {
+    string attribute_string;
+    i->second->ToString(&attribute_string);
+    StringAppendF(&output, "   Attr: %s(%d)=%s, Type: %s\n",
+                  i->second->id_string(),
+                  i->second->id(),
+                  attribute_string.c_str(),
+                  i->second->datatype_string());
+  }
+  return output;
+}
+
 // U8 Attribute.
 
 bool AttributeList::GetU8AttributeValue(int id, uint8_t *value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeU8)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeU8 exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  const Nl80211U8Attribute *attr =
-      reinterpret_cast<const Nl80211U8Attribute *>(GetAttribute(id));
-  return attr->GetU8Value(value);
+  return attribute->GetU8Value(value);
 }
 
 bool AttributeList::CreateU8Attribute(int id, const char *id_string) {
@@ -66,31 +74,26 @@
     LOG(ERROR) << "Trying to re-add attribute: " << id;
     return false;
   }
-  attributes_[id] = new Nl80211U8Attribute(id, id_string);
+  attributes_[id] = AttributePointer(
+      new Nl80211U8Attribute(id, id_string));
   return true;
 }
 
 bool AttributeList::SetU8AttributeValue(int id, uint8_t value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeU8)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeU8 exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  Nl80211U8Attribute *attr =
-      reinterpret_cast<Nl80211U8Attribute *>(GetAttribute(id));
-  return attr->SetU8Value(value);
+  return attribute->SetU8Value(value);
 }
 
 
 // U16 Attribute.
 
 bool AttributeList::GetU16AttributeValue(int id, uint16_t *value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeU16)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeU16 exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  const Nl80211U16Attribute *attr =
-      reinterpret_cast<const Nl80211U16Attribute *>(GetAttribute(id));
-  return attr->GetU16Value(value);
+  return attribute->GetU16Value(value);
 }
 
 bool AttributeList::CreateU16Attribute(int id, const char *id_string) {
@@ -98,30 +101,25 @@
     LOG(ERROR) << "Trying to re-add attribute: " << id;
     return false;
   }
-  attributes_[id] = new Nl80211U16Attribute(id, id_string);
+  attributes_[id] = AttributePointer(
+      new Nl80211U16Attribute(id, id_string));
   return true;
 }
 
 bool AttributeList::SetU16AttributeValue(int id, uint16_t value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeU16)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeU16 exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  Nl80211U16Attribute *attr =
-      reinterpret_cast<Nl80211U16Attribute *>(GetAttribute(id));
-  return attr->SetU16Value(value);
+  return attribute->SetU16Value(value);
 }
 
 // U32 Attribute.
 
 bool AttributeList::GetU32AttributeValue(int id, uint32_t *value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeU32)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeU32 exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  const Nl80211U32Attribute *attr =
-      reinterpret_cast<const Nl80211U32Attribute *>(GetAttribute(id));
-  return attr->GetU32Value(value);
+  return attribute->GetU32Value(value);
 }
 
 bool AttributeList::CreateU32Attribute(int id, const char *id_string) {
@@ -129,30 +127,25 @@
     LOG(ERROR) << "Trying to re-add attribute: " << id;
     return false;
   }
-  attributes_[id] = new Nl80211U32Attribute(id, id_string);
+  attributes_[id] = AttributePointer(
+      new Nl80211U32Attribute(id, id_string));
   return true;
 }
 
 bool AttributeList::SetU32AttributeValue(int id, uint32_t value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeU32)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeU32 exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  Nl80211U32Attribute *attr =
-      reinterpret_cast<Nl80211U32Attribute *>(GetAttribute(id));
-  return attr->SetU32Value(value);
+  return attribute->SetU32Value(value);
 }
 
 // U64 Attribute.
 
 bool AttributeList::GetU64AttributeValue(int id, uint64_t *value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeU64)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeU64 exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  const Nl80211U64Attribute *attr =
-      reinterpret_cast<const Nl80211U64Attribute *>(GetAttribute(id));
-  return attr->GetU64Value(value);
+  return attribute->GetU64Value(value);
 }
 
 bool AttributeList::CreateU64Attribute(int id, const char *id_string) {
@@ -160,30 +153,25 @@
     LOG(ERROR) << "Trying to re-add attribute: " << id;
     return false;
   }
-  attributes_[id] = new Nl80211U64Attribute(id, id_string);
+  attributes_[id] = AttributePointer(
+      new Nl80211U64Attribute(id, id_string));
   return true;
 }
 
 bool AttributeList::SetU64AttributeValue(int id, uint64_t value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeU64)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeU64 exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  Nl80211U64Attribute *attr =
-      reinterpret_cast<Nl80211U64Attribute *>(GetAttribute(id));
-  return attr->SetU64Value(value);
+  return attribute->SetU64Value(value);
 }
 
 // Flag Attribute.
 
 bool AttributeList::GetFlagAttributeValue(int id, bool *value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeFlag)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeFlag exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  const Nl80211FlagAttribute *attr =
-      reinterpret_cast<const Nl80211FlagAttribute *>(GetAttribute(id));
-  return attr->GetFlagValue(value);
+  return attribute->GetFlagValue(value);
 }
 
 bool AttributeList::CreateFlagAttribute(int id, const char *id_string) {
@@ -191,27 +179,19 @@
     LOG(ERROR) << "Trying to re-add attribute: " << id;
     return false;
   }
-  attributes_[id] = new Nl80211FlagAttribute(id, id_string);
+  attributes_[id] = AttributePointer(
+      new Nl80211FlagAttribute(id, id_string));
   return true;
 }
 
 bool AttributeList::SetFlagAttributeValue(int id, bool value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeFlag)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeFlag exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  Nl80211FlagAttribute *attr =
-      reinterpret_cast<Nl80211FlagAttribute *>(GetAttribute(id));
-  return attr->SetFlagValue(value);
+  return attribute->SetFlagValue(value);
 }
 
 bool AttributeList::IsFlagAttributeTrue(int id) const {
-  // TODO(wdg): After message constructors add attributes, remove the following
-  // lines.
-  if (!HasAttribute(id, Nl80211Attribute::kTypeFlag)) {
-    return false;
-  }
-
   bool flag;
   if (!GetFlagAttributeValue(id, &flag)) {
     return false;
@@ -222,13 +202,10 @@
 // String Attribute.
 
 bool AttributeList::GetStringAttributeValue(int id, string *value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeString)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeString exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  const Nl80211StringAttribute *attr =
-      reinterpret_cast<const Nl80211StringAttribute *>(GetAttribute(id));
-  return attr->GetStringValue(value);
+  return attribute->GetStringValue(value);
 }
 
 bool AttributeList::CreateStringAttribute(int id, const char *id_string) {
@@ -236,31 +213,26 @@
     LOG(ERROR) << "Trying to re-add attribute: " << id;
     return false;
   }
-  attributes_[id] = new Nl80211StringAttribute(id, id_string);
+  attributes_[id] = AttributePointer(
+      new Nl80211StringAttribute(id, id_string));
   return true;
 }
 
 bool AttributeList::SetStringAttributeValue(int id, string value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeString)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeString exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  Nl80211StringAttribute *attr =
-      reinterpret_cast<Nl80211StringAttribute *>(GetAttribute(id));
-  return attr->SetStringValue(value);
+  return attribute->SetStringValue(value);
 }
 
 // Nested Attribute.
 
 bool AttributeList::GetNestedAttributeValue(
     int id, WeakPtr<AttributeList> *value) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeNested)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeNested exists.";
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  Nl80211NestedAttribute *attr =
-      reinterpret_cast<Nl80211NestedAttribute *>(GetAttribute(id));
-  return attr->GetNestedValue(value);
+  return attribute->GetNestedValue(value);
 }
 
 bool AttributeList::CreateNestedAttribute(int id, const char *id_string) {
@@ -268,23 +240,22 @@
     LOG(ERROR) << "Trying to re-add attribute: " << id;
     return false;
   }
-  attributes_[id] = new Nl80211NestedAttribute(id, id_string);
+  attributes_[id] = AttributePointer(
+      new Nl80211NestedAttribute(id, id_string));
   return true;
 }
 
 // Raw Attribute.
 
-bool AttributeList::GetRawAttributeValue(int id, ByteString *output) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeRaw)) {
-    LOG(ERROR) << "No attribute " << id << " of type kTypeRaw exists.";
+bool AttributeList::GetRawAttributeValue(int id,
+                                         ByteString *output) const {
+  Nl80211Attribute *attribute = GetAttribute(id);
+  if (!attribute)
     return false;
-  }
-  const Nl80211RawAttribute *attr =
-      reinterpret_cast<const Nl80211RawAttribute *>(GetAttribute(id));
 
   ByteString raw_value;
 
-  if (!attr->GetRawValue(&raw_value))
+  if (!attribute->GetRawValue(&raw_value))
     return false;
 
   if (output) {
@@ -300,8 +271,9 @@
   return true;
 }
 
-const Nl80211RawAttribute *AttributeList::GetRawAttribute(int id) const {
-  if (!HasAttribute(id, Nl80211Attribute::kTypeRaw)) {
+const Nl80211RawAttribute *AttributeList::GetRawAttribute(
+    int id) const {
+  if (!HasRawAttribute(id)) {
     LOG(ERROR) << "No attribute " << id << " of type kTypeRaw exists.";
     return NULL;
   }
@@ -311,23 +283,22 @@
 }
 
 Nl80211Attribute *AttributeList::GetAttribute(int id) const {
-  map<int, Nl80211Attribute *>::const_iterator i;
+  map<int, AttributePointer>::const_iterator i;
   i = attributes_.find(id);
   if (i == attributes_.end()) {
     return NULL;
   }
-  return i->second;
+  return i->second.get();
 }
 
-bool AttributeList::HasAttribute(int id,
-                                 Nl80211Attribute::Type datatype) const {
-  map<int, Nl80211Attribute *>::const_iterator i;
+bool AttributeList::HasRawAttribute(int id) const {
+  map<int, AttributePointer>::const_iterator i;
   i = attributes_.find(id);
   if (i == attributes_.end()) {
     LOG(ERROR) << "FALSE - Didn't find id " << id;
     return false;
   }
-  return (i->second->datatype() == datatype) ? true : false;
+  return (i->second->datatype() == Nl80211Attribute::kTypeRaw) ? true : false;
 }
 
 
diff --git a/attribute_list.h b/attribute_list.h
index 04f95fb..e733d01 100644
--- a/attribute_list.h
+++ b/attribute_list.h
@@ -10,9 +10,9 @@
 
 #include <map>
 #include <string>
+#include <tr1/memory>
 
 #include <base/memory/weak_ptr.h>
-#include "shill/nl80211_attribute.h"
 
 struct nlattr;
 namespace shill {
@@ -23,7 +23,7 @@
 
 class AttributeList : public base::SupportsWeakPtr<AttributeList> {
  public:
-  virtual ~AttributeList();
+  typedef std::tr1::shared_ptr<Nl80211Attribute> AttributePointer;
 
   // Instantiates an Nl80211Attribute of the appropriate type from |id|,
   // and adds it to |attributes_|.
@@ -35,6 +35,8 @@
   // their attributes as message templates.
   bool CreateAndInitFromNlAttr(nl80211_attrs id, const nlattr *data);
 
+  std::string ToString() const;
+
   bool GetU8AttributeValue(int id, uint8_t *value) const;
   bool GetU16AttributeValue(int id, uint16_t *value) const;
   bool GetU32AttributeValue(int id, uint32_t *value) const;
@@ -88,9 +90,11 @@
   // Using this to get around issues with const and operator[].
   Nl80211Attribute *GetAttribute(int id) const;
 
-  bool HasAttribute(int name, Nl80211Attribute::Type type) const;
+  // TODO(wdg): This is only used to support |GetRawAttribute|.  Delete this
+  // when that goes away.
+  bool HasRawAttribute(int id) const;
 
-  std::map<int, Nl80211Attribute *> attributes_;
+  std::map<int, AttributePointer> attributes_;
 };
 
 }  // namespace shill
diff --git a/callback80211_object.cc b/callback80211_object.cc
index 6d9c9d7..5268ac6 100644
--- a/callback80211_object.cc
+++ b/callback80211_object.cc
@@ -35,16 +35,13 @@
 
 void Callback80211Object::Config80211MessageCallback(
     const UserBoundNlMessage &message) {
-  // Show the simplified version of the message.
+  // Show the message-type-specific version of the message.
   string output("@");
   StringAppendF(&output, "%s", message.ToString().c_str());
   SLOG(WiFi, 2) << output;
 
-  // Show the more complicated version of the message.
-  SLOG(WiFi, 3) << "Received " << message.message_type_string()
-                << " (" << + message.message_type() << ")";
-
-  // TODO(wdg): Make a message->AsString() method.
+  // Show the generic, detailed, version of the message.
+  SLOG(WiFi, 3) << message.GenericToString();
 }
 
 bool Callback80211Object::InstallAsBroadcastCallback() {
diff --git a/config80211_unittest.cc b/config80211_unittest.cc
index 1aace3a..4d00231 100644
--- a/config80211_unittest.cc
+++ b/config80211_unittest.cc
@@ -56,7 +56,7 @@
 // These constants are consistent throughout the packets, below.
 
 const uint32_t kExpectedIfIndex = 4;
-const uint8_t kExpectedWifi = 0;
+const uint32_t kExpectedWifi = 0;
 const char kExpectedMacAddress[] = "c0:3f:0e:77:e8:7f";
 
 
diff --git a/nl80211_attribute.cc b/nl80211_attribute.cc
index 889f625..a8338ff 100644
--- a/nl80211_attribute.cc
+++ b/nl80211_attribute.cc
@@ -133,6 +133,76 @@
   return true;
 }
 
+bool Nl80211Attribute::GetU8Value(uint8_t *value) const {
+  LOG(ERROR) << "Attribute is not of type 'U8'";
+  return false;
+}
+
+bool Nl80211Attribute::SetU8Value(uint8_t value) {
+  LOG(ERROR) << "Attribute is not of type 'U8'";
+  return false;
+}
+
+bool Nl80211Attribute::GetU16Value(uint16_t *value) const {
+  LOG(ERROR) << "Attribute is not of type 'U16'";
+  return false;
+}
+
+bool Nl80211Attribute::SetU16Value(uint16_t value) {
+  LOG(ERROR) << "Attribute is not of type 'U16'";
+  return false;
+}
+
+bool Nl80211Attribute::GetU32Value(uint32_t *value) const {
+  LOG(ERROR) << "Attribute is not of type 'U32'";
+  return false;
+}
+
+bool Nl80211Attribute::SetU32Value(uint32_t value) {
+  LOG(ERROR) << "Attribute is not of type 'U32'";
+  return false;
+}
+
+bool Nl80211Attribute::GetU64Value(uint64_t *value) const {
+  LOG(ERROR) << "Attribute is not of type 'U64'";
+  return false;
+}
+
+bool Nl80211Attribute::SetU64Value(uint64_t value) {
+  LOG(ERROR) << "Attribute is not of type 'U64'";
+  return false;
+}
+
+bool Nl80211Attribute::GetFlagValue(bool *value) const {
+  LOG(ERROR) << "Attribute is not of type 'Flag'";
+  return false;
+}
+
+bool Nl80211Attribute::SetFlagValue(bool value) {
+  LOG(ERROR) << "Attribute is not of type 'Flag'";
+  return false;
+}
+
+bool Nl80211Attribute::GetStringValue(string *value) const {
+  LOG(ERROR) << "Attribute is not of type 'String'";
+  return false;
+}
+
+bool Nl80211Attribute::SetStringValue(string value) {
+  LOG(ERROR) << "Attribute is not of type 'String'";
+  return false;
+}
+
+bool Nl80211Attribute::GetNestedValue(WeakPtr<AttributeList> *value) {
+  LOG(ERROR) << "Attribute is not of type 'Nested'";
+  return false;
+}
+
+bool Nl80211Attribute::GetRawValue(ByteString *value) const {
+  LOG(ERROR) << "Attribute is not of type 'Raw'";
+  return false;
+}
+
 string Nl80211Attribute::RawToString() const {
   string output = " === RAW: ";
 
@@ -179,7 +249,7 @@
   return true;
 }
 
-bool Nl80211U8Attribute::AsString(string *output) const {
+bool Nl80211U8Attribute::ToString(string *output) const {
   if (!output) {
     LOG(ERROR) << "Null |output| parameter";
     return false;
@@ -221,7 +291,7 @@
   return true;
 }
 
-bool Nl80211U16Attribute::AsString(string *output) const {
+bool Nl80211U16Attribute::ToString(string *output) const {
   if (!output) {
     LOG(ERROR) << "Null |output| parameter";
     return false;
@@ -262,7 +332,7 @@
   return true;
 }
 
-bool Nl80211U32Attribute::AsString(string *output) const {
+bool Nl80211U32Attribute::ToString(string *output) const {
   if (!output) {
     LOG(ERROR) << "Null |output| parameter";
     return false;
@@ -303,7 +373,7 @@
   return true;
 }
 
-bool Nl80211U64Attribute::AsString(string *output) const {
+bool Nl80211U64Attribute::ToString(string *output) const {
   if (!output) {
     LOG(ERROR) << "Null |output| parameter";
     return false;
@@ -345,7 +415,7 @@
   return true;
 }
 
-bool Nl80211FlagAttribute::AsString(string *output) const {
+bool Nl80211FlagAttribute::ToString(string *output) const {
   if (!output) {
     LOG(ERROR) << "Null |output| parameter";
     return false;
@@ -385,12 +455,17 @@
   return true;
 }
 
-bool Nl80211StringAttribute::AsString(string *output) const {
+bool Nl80211StringAttribute::ToString(string *output) const {
   if (!output) {
     LOG(ERROR) << "Null |output| parameter";
     return false;
   }
-  return GetStringValue(output);
+  string value;
+  if (!GetStringValue(&value))
+    return false;
+
+  *output = StringPrintf("'%s'", value.c_str());
+  return true;
 }
 
 // Nl80211NestedAttribute
@@ -400,14 +475,11 @@
 
 Nl80211NestedAttribute::Nl80211NestedAttribute(int id,
                                                const char *id_string) :
-    Nl80211Attribute(id, id_string, kType, kMyTypeString),
-    value_(new AttributeList()) {
-}
+    Nl80211Attribute(id, id_string, kType, kMyTypeString) {}
 
-bool Nl80211NestedAttribute::GetNestedValue(
-    WeakPtr<AttributeList> *output) const {
+bool Nl80211NestedAttribute::GetNestedValue(WeakPtr<AttributeList> *output) {
   if (output) {
-    *output = value_->AsWeakPtr();
+    *output = value_.AsWeakPtr();
   }
   return true;
 }
@@ -434,7 +506,7 @@
   return true;
 }
 
-bool Nl80211RawAttribute::AsString(string *output) const {
+bool Nl80211RawAttribute::ToString(string *output) const {
   if (!output) {
     LOG(ERROR) << "Null |output| parameter";
     return false;
@@ -460,14 +532,14 @@
 
 Nl80211AttributeCqm::Nl80211AttributeCqm()
       : Nl80211NestedAttribute(kName, kNameString) {
-  value_->CreateU32Attribute(NL80211_ATTR_CQM_RSSI_THOLD,
-                             "NL80211_ATTR_CQM_RSSI_THOLD");
-  value_->CreateU32Attribute(NL80211_ATTR_CQM_RSSI_HYST,
-                             "NL80211_ATTR_CQM_RSSI_HYST");
-  value_->CreateU32Attribute(NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
-                             "NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT");
-  value_->CreateU32Attribute(NL80211_ATTR_CQM_PKT_LOSS_EVENT,
-                             "NL80211_ATTR_CQM_PKT_LOSS_EVENT");
+  value_.CreateU32Attribute(NL80211_ATTR_CQM_RSSI_THOLD,
+                            "NL80211_ATTR_CQM_RSSI_THOLD");
+  value_.CreateU32Attribute(NL80211_ATTR_CQM_RSSI_HYST,
+                            "NL80211_ATTR_CQM_RSSI_HYST");
+  value_.CreateU32Attribute(NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+                            "NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT");
+  value_.CreateU32Attribute(NL80211_ATTR_CQM_PKT_LOSS_EVENT,
+                            "NL80211_ATTR_CQM_PKT_LOSS_EVENT");
 }
 
 bool Nl80211AttributeCqm::InitFromNlAttr(const nlattr *const_data) {
@@ -493,22 +565,22 @@
   }
 
   if (cqm[NL80211_ATTR_CQM_RSSI_THOLD]) {
-    value_->SetU32AttributeValue(
+    value_.SetU32AttributeValue(
         NL80211_ATTR_CQM_RSSI_THOLD,
         nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THOLD]));
   }
   if (cqm[NL80211_ATTR_CQM_RSSI_HYST]) {
-    value_->SetU32AttributeValue(
+    value_.SetU32AttributeValue(
         NL80211_ATTR_CQM_RSSI_HYST,
         nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_HYST]));
   }
   if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) {
-    value_->SetU32AttributeValue(
+    value_.SetU32AttributeValue(
         NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
         nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]));
   }
   if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
-    value_->SetU32AttributeValue(
+    value_.SetU32AttributeValue(
         NL80211_ATTR_CQM_PKT_LOSS_EVENT,
         nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]));
   }
diff --git a/nl80211_attribute.h b/nl80211_attribute.h
index 5583bd3..8e3095d 100644
--- a/nl80211_attribute.h
+++ b/nl80211_attribute.h
@@ -12,9 +12,9 @@
 #include <map>
 #include <string>
 
-#include <base/memory/scoped_ptr.h>
 #include <base/memory/weak_ptr.h>
 
+#include "shill/attribute_list.h"
 #include "shill/byte_string.h"
 #include "shill/logging.h"
 
@@ -61,7 +61,7 @@
   int id() const { return id_; }
   virtual const char *id_string() const { return id_string_; }
   Type datatype() const { return datatype_; }
-  std::string datatype_string() const { return datatype_string_; }
+  const char *datatype_string() const { return datatype_string_; }
 
   // TODO(wdg): Since |data| is used, externally, to support |nla_parse_nested|,
   // make it protected once all functionality has been brought inside the
@@ -73,10 +73,32 @@
     return reinterpret_cast<const nlattr *>(data_.GetConstData());
   }
 
+  virtual bool GetU8Value(uint8_t *value) const;
+  virtual bool SetU8Value(uint8_t new_value);
+
+  virtual bool GetU16Value(uint16_t *value) const;
+  virtual bool SetU16Value(uint16_t value);
+
+  virtual bool GetU32Value(uint32_t *value) const;
+  virtual bool SetU32Value(uint32_t value);
+
+  virtual bool GetU64Value(uint64_t *value) const;
+  virtual bool SetU64Value(uint64_t value);
+
+  virtual bool GetFlagValue(bool *value) const;
+  virtual bool SetFlagValue(bool value);
+
+  virtual bool GetStringValue(std::string *value) const;
+  virtual bool SetStringValue(const std::string value);
+
+  virtual bool GetNestedValue(base::WeakPtr<AttributeList> *value);
+
+  virtual bool GetRawValue(ByteString *value) 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,
   // this method returns 'false' and |value| remains unchanged.
-  virtual bool AsString(std::string *value) const = 0;
+  virtual bool ToString(std::string *value) const = 0;
 
   // Writes the raw attribute data to a string.  For debug.
   std::string RawToString() const;
@@ -123,7 +145,7 @@
   bool InitFromNlAttr(const nlattr *data);
   bool GetU8Value(uint8_t *value) const;
   bool SetU8Value(uint8_t new_value);
-  bool AsString(std::string *value) const;
+  bool ToString(std::string *value) const;
 
  private:
   uint8_t value_;
@@ -154,7 +176,7 @@
   bool InitFromNlAttr(const nlattr *data);
   bool GetU16Value(uint16_t *value) const;
   bool SetU16Value(uint16_t new_value);
-  bool AsString(std::string *value) const;
+  bool ToString(std::string *value) const;
 
  private:
   uint16_t value_;
@@ -185,7 +207,7 @@
   bool InitFromNlAttr(const nlattr *data);
   bool GetU32Value(uint32_t *value) const;
   bool SetU32Value(uint32_t new_value);
-  bool AsString(std::string *value) const;
+  bool ToString(std::string *value) const;
 
  private:
   uint32_t value_;
@@ -251,7 +273,7 @@
   bool InitFromNlAttr(const nlattr *data);
   bool GetU64Value(uint64_t *value) const;
   bool SetU64Value(uint64_t new_value);
-  bool AsString(std::string *value) const;
+  bool ToString(std::string *value) const;
 
  private:
   uint64_t value_;
@@ -275,7 +297,7 @@
   bool InitFromNlAttr(const nlattr *data);
   bool GetFlagValue(bool *value) const;
   bool SetFlagValue(bool new_value);
-  bool AsString(std::string *value) const;
+  bool ToString(std::string *value) const;
 
  private:
   bool value_;
@@ -315,7 +337,7 @@
   bool InitFromNlAttr(const nlattr *data);
   bool GetStringValue(std::string *value) const;
   bool SetStringValue(const std::string new_value);
-  bool AsString(std::string *value) const;
+  bool ToString(std::string *value) const;
 
  private:
   std::string value_;
@@ -347,13 +369,13 @@
     LOG(FATAL) << "Try initializing a _specific_ nested type, instead.";
     return false;
   }
-  bool GetNestedValue(base::WeakPtr<AttributeList> *value) const;
-  bool AsString(std::string *value) const {
+  bool GetNestedValue(base::WeakPtr<AttributeList> *value);
+  bool ToString(std::string *value) const {
     return false;  // TODO(wdg):
   }
 
  protected:
-  scoped_ptr<AttributeList> value_;
+  AttributeList value_;
 };
 
 class Nl80211AttributeCqm : public Nl80211NestedAttribute {
@@ -362,8 +384,8 @@
   static const char kNameString[];
   Nl80211AttributeCqm();
   bool InitFromNlAttr(const nlattr *data);
-  bool AsString(std::string *value) const {
-    return true; // TODO(wdg): Need |AsString|.
+  bool ToString(std::string *value) const {
+    return true; // TODO(wdg): Need |ToString|.
   }
 };
 
@@ -393,7 +415,7 @@
   // be used for user-bound massages (via InitFromNlAttr).  The 'set' method
   // is intended for building kernel-bound messages and shouldn't be used with
   // raw data.
-  bool AsString(std::string *value) const;
+  bool ToString(std::string *value) const;
 };
 
 class Nl80211AttributeFrame : public Nl80211RawAttribute {
diff --git a/user_bound_nlmessage.cc b/user_bound_nlmessage.cc
index d82c8ae..9afaeaf 100644
--- a/user_bound_nlmessage.cc
+++ b/user_bound_nlmessage.cc
@@ -47,6 +47,7 @@
 #include "shill/attribute_list.h"
 #include "shill/ieee80211.h"
 #include "shill/logging.h"
+#include "shill/nl80211_attribute.h"
 #include "shill/scope_logger.h"
 
 using base::LazyInstance;
@@ -537,6 +538,14 @@
   return match->second;
 }
 
+string UserBoundNlMessage::GenericToString() const {
+  string output;
+  StringAppendF(&output, "Received %s (%d)\n",
+                message_type_string(), message_type());
+  StringAppendF(&output, "%s", attributes_.ToString().c_str());
+  return output;
+}
+
 Nl80211Frame::Nl80211Frame(const ByteString &raw_frame)
   : frame_type_(kIllegalFrameType), reason_(UINT16_MAX), status_(UINT16_MAX),
     frame_(raw_frame) {
diff --git a/user_bound_nlmessage.h b/user_bound_nlmessage.h
index 0b1b40a..cd6dbc0 100644
--- a/user_bound_nlmessage.h
+++ b/user_bound_nlmessage.h
@@ -18,6 +18,7 @@
 #include <gtest/gtest.h>
 
 #include "shill/attribute_list.h"
+#include "shill/byte_string.h"
 
 struct nlattr;
 struct nlmsghdr;
@@ -73,6 +74,8 @@
   static std::string StringFromReason(uint16_t reason);
   static std::string StringFromStatus(uint16_t status);
 
+  std::string GenericToString() const;
+
   // Returns a string that describes this message.
   virtual std::string ToString() const { return GetHeaderString(); }