shill: Adds BSS nl80211 attribute.
The BSS attribute, which is contained in the
NL80211_CMD_NEW_SCAN_RESULTS netlink message, contains SSID information
received from a scan.
BUG=chromium:221118
TEST=unittest.
Change-Id: I20766ae6d73ae5729e4ae8de47cac8bcbf5b3fe9
Reviewed-on: https://gerrit.chromium.org/gerrit/48013
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 a0d441f..33e1b95 100644
--- a/attribute_list.cc
+++ b/attribute_list.cc
@@ -221,6 +221,16 @@
return true;
}
+bool AttributeList::CreateSsidAttribute(int id, const char *id_string) {
+ if (ContainsKey(attributes_, id)) {
+ LOG(ERROR) << "Trying to re-add attribute: " << id;
+ return false;
+ }
+ attributes_[id] = AttributePointer(
+ new NetlinkSsidAttribute(id, id_string));
+ return true;
+}
+
bool AttributeList::SetStringAttributeValue(int id, string value) {
NetlinkAttribute *attribute = GetAttribute(id);
if (!attribute)
diff --git a/attribute_list.h b/attribute_list.h
index 1e6503d..58ad37b 100644
--- a/attribute_list.h
+++ b/attribute_list.h
@@ -49,6 +49,9 @@
// attributes exist).
ByteString Encode() const;
+ // Create, get, and set attributes of the given types. Attributes are
+ // accessed via an integer |id|. |id_string| is a string used to describe
+ // the attribute in debug output.
bool CreateU8Attribute(int id, const char *id_string);
bool SetU8AttributeValue(int id, uint8_t value);
bool GetU8AttributeValue(int id, uint8_t *value) const;
@@ -74,6 +77,8 @@
bool IsFlagAttributeTrue(int id) const;
bool CreateStringAttribute(int id, const char *id_string);
+ // SSID attributes are derived from string attributes.
+ bool CreateSsidAttribute(int id, const char *id_string);
bool SetStringAttributeValue(int id, std::string value);
bool GetStringAttributeValue(int id, std::string *value) const;
diff --git a/netlink_attribute.cc b/netlink_attribute.cc
index af1c842..a934074 100644
--- a/netlink_attribute.cc
+++ b/netlink_attribute.cc
@@ -15,6 +15,7 @@
#include "shill/control_netlink_attribute.h"
#include "shill/logging.h"
#include "shill/nl80211_attribute.h"
+#include "shill/wifi.h"
using std::map;
using std::string;
@@ -42,6 +43,9 @@
NetlinkAttribute *NetlinkAttribute::NewNl80211AttributeFromId(int id) {
scoped_ptr<NetlinkAttribute> attr;
switch (id) {
+ case NL80211_ATTR_BSS:
+ attr.reset(new Nl80211AttributeBss());
+ break;
case NL80211_ATTR_COOKIE:
attr.reset(new Nl80211AttributeCookie());
break;
@@ -626,6 +630,21 @@
value_.size() + 1);
}
+// SSID attribute.
+
+bool NetlinkSsidAttribute::ToString(string *output) const {
+ if (!output) {
+ LOG(ERROR) << "Null |output| parameter";
+ return false;
+ }
+ string value;
+ if (!GetStringValue(&value))
+ return false;
+
+ *output = WiFi::LogSSID(value);
+ return true;
+}
+
// NetlinkNestedAttribute
const char NetlinkNestedAttribute::kMyTypeString[] = "nested";
diff --git a/netlink_attribute.h b/netlink_attribute.h
index 33cffd6..43e4575 100644
--- a/netlink_attribute.h
+++ b/netlink_attribute.h
@@ -249,13 +249,27 @@
virtual bool SetStringValue(const std::string new_value);
virtual bool ToString(std::string *value) const;
virtual ByteString Encode() const;
+ std::string value() const { return value_; }
+ void set_value(const std::string &value) { value_ = value; }
private:
std::string value_;
-
DISALLOW_COPY_AND_ASSIGN(NetlinkStringAttribute);
};
+// SSID attributes are just string attributes with different output semantics.
+class NetlinkSsidAttribute : public NetlinkStringAttribute {
+ public:
+ NetlinkSsidAttribute(int id, const char *id_string)
+ : NetlinkStringAttribute(id, id_string) {}
+
+ // NOTE: |ToString| or |Print| must be used for logging to allow scrubbing.
+ virtual bool ToString(std::string *output) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NetlinkSsidAttribute);
+};
+
class NetlinkNestedAttribute : public NetlinkAttribute {
public:
static const char kMyTypeString[];
diff --git a/nl80211_attribute.cc b/nl80211_attribute.cc
index a921fc7..92dac5c 100644
--- a/nl80211_attribute.cc
+++ b/nl80211_attribute.cc
@@ -6,13 +6,150 @@
#include <netlink/attr.h>
+#include <string>
+
+#include <base/bind.h>
+#include <base/format_macros.h>
+#include <base/stringprintf.h>
+
#include "shill/logging.h"
+using base::Bind;
+using base::StringPrintf;
+using std::string;
+
namespace shill {
const int Nl80211AttributeCookie::kName = NL80211_ATTR_COOKIE;
const char Nl80211AttributeCookie::kNameString[] = "NL80211_ATTR_COOKIE";
+const int Nl80211AttributeBss::kName = NL80211_ATTR_BSS;
+const char Nl80211AttributeBss::kNameString[] = "NL80211_ATTR_BSS";
+const int Nl80211AttributeBss::kChannelsAttributeId = 0x24;
+const int Nl80211AttributeBss::kChallengeTextAttributeId = 0x10;
+const int Nl80211AttributeBss::kCountryInfoAttributeId = 0x07;
+const int Nl80211AttributeBss::kDSParameterSetAttributeId = 0x03;
+const int Nl80211AttributeBss::kErpAttributeId = 0x2a;
+const int Nl80211AttributeBss::kExtendedRatesAttributeId = 0x32;
+const int Nl80211AttributeBss::kHtCapAttributeId = 0x2d;
+const int Nl80211AttributeBss::kHtInfoAttributeId = 0x3d;
+const int Nl80211AttributeBss::kPowerCapabilityAttributeId = 0x21;
+const int Nl80211AttributeBss::kPowerConstraintAttributeId = 0x20;
+const int Nl80211AttributeBss::kRequestAttributeId = 0x0a;
+const int Nl80211AttributeBss::kRsnAttributeId = 0x30;
+const int Nl80211AttributeBss::kSsidAttributeId = 0x00;
+const int Nl80211AttributeBss::kSupportedRatesAttributeId = 0x01;
+const int Nl80211AttributeBss::kTcpReportAttributeId = 0x23;
+const int Nl80211AttributeBss::kVendorSpecificAttributeId = 0xdd;
+
+static const char kSsidString[] = "SSID";
+static const char kRatesString[] = "Rates";
+
+Nl80211AttributeBss::Nl80211AttributeBss()
+ : NetlinkNestedAttribute(kName, kNameString) {
+ nested_template_.push_back(NestedData(NLA_U32, "__NL80211_BSS_INVALID",
+ false));
+ nested_template_.push_back(NestedData(NLA_UNSPEC, "NL80211_BSS_BSSID",
+ false));
+ nested_template_.push_back(NestedData(NLA_U32, "NL80211_BSS_FREQUENCY",
+ false));
+ nested_template_.push_back(NestedData(NLA_U64, "NL80211_BSS_TSF", false));
+ nested_template_.push_back(NestedData(NLA_U16, "NL80211_BSS_BEACON_INTERVAL",
+ false));
+ nested_template_.push_back(NestedData(NLA_U16, "NL80211_BSS_CAPABILITY",
+ false));
+ nested_template_.push_back(NestedData(
+ NLA_UNSPEC, "NL80211_BSS_INFORMATION_ELEMENTS", false,
+ Bind(&Nl80211AttributeBss::ParseInformationElements)));
+ nested_template_.push_back(NestedData(NLA_U32, "NL80211_BSS_SIGNAL_MBM",
+ false));
+ nested_template_.push_back(NestedData(NLA_U8, "NL80211_BSS_SIGNAL_UNSPEC",
+ false));
+ nested_template_.push_back(NestedData(NLA_U32, "NL80211_BSS_STATUS",
+ false));
+ nested_template_.push_back(NestedData(NLA_U32, "NL80211_BSS_SEEN_MS_AGO",
+ false));
+ nested_template_.push_back(NestedData(NLA_UNSPEC, "NL80211_BSS_BEACON_IES",
+ false));
+}
+
+bool Nl80211AttributeBss::ParseInformationElements(
+ AttributeList *attribute_list, size_t id, const string &attribute_name,
+ ByteString data) {
+ if (!attribute_list) {
+ LOG(ERROR) << "NULL |attribute_list| parameter";
+ return false;
+ }
+ attribute_list->CreateNestedAttribute(id, attribute_name.c_str());
+
+ // Now, handle the nested data.
+ AttributeListRefPtr ie_attribute;
+ if (!attribute_list->GetNestedAttributeList(id, &ie_attribute) ||
+ !ie_attribute) {
+ LOG(ERROR) << "Couldn't get attribute " << attribute_name
+ << " which we just created.";
+ return false;
+ }
+ while (data.GetLength()) {
+ const uint8_t *sub_attribute = data.GetConstData();
+ const size_t kHeaderBytes = 2;
+ uint8_t type = sub_attribute[0];
+ uint8_t payload_bytes = sub_attribute[1];
+ const uint8_t *payload = &sub_attribute[kHeaderBytes];
+ // See http://dox.ipxe.org/ieee80211_8h_source.html for more info on types
+ // and data inside information elements.
+ switch (type) {
+ case kSsidAttributeId: {
+ ie_attribute->CreateSsidAttribute(type, kSsidString);
+ if (payload_bytes == 0) {
+ ie_attribute->SetStringAttributeValue(type, "");
+ } else {
+ ie_attribute->SetStringAttributeValue(type, string(
+ reinterpret_cast<const char *>(payload), payload_bytes));
+ }
+ break;
+ }
+ case kSupportedRatesAttributeId:
+ case kExtendedRatesAttributeId: {
+ ie_attribute->CreateNestedAttribute(type, kRatesString);
+ AttributeListRefPtr rates_attribute;
+ if (!ie_attribute->GetNestedAttributeList(type, &rates_attribute) ||
+ !rates_attribute) {
+ LOG(ERROR) << "Couldn't get attribute " << attribute_name
+ << " which we just created.";
+ break;
+ }
+ // Extract each rate, add it to the list.
+ for (size_t i = 0; i < payload_bytes; ++i) {
+ string rate_name = StringPrintf("Rate-%zu", i);
+ rates_attribute->CreateU8Attribute(i, rate_name.c_str());
+ rates_attribute->SetU8AttributeValue(i, payload[i]);
+ }
+ ie_attribute->SetNestedAttributeHasAValue(type);
+ break;
+ }
+ case kDSParameterSetAttributeId:
+ case kCountryInfoAttributeId:
+ case kRequestAttributeId:
+ case kChallengeTextAttributeId:
+ case kPowerConstraintAttributeId:
+ case kPowerCapabilityAttributeId:
+ case kTcpReportAttributeId:
+ case kChannelsAttributeId:
+ case kErpAttributeId:
+ case kHtCapAttributeId:
+ case kRsnAttributeId:
+ case kHtInfoAttributeId:
+ case kVendorSpecificAttributeId:
+ default:
+ break;
+ }
+ data.RemovePrefix(kHeaderBytes + payload_bytes);
+ }
+ attribute_list->SetNestedAttributeHasAValue(id);
+ return true;
+}
+
const int Nl80211AttributeCqm::kName = NL80211_ATTR_CQM;
const char Nl80211AttributeCqm::kNameString[] = "NL80211_ATTR_CQM";
@@ -42,8 +179,8 @@
const char Nl80211AttributeFrame::kNameString[] = "NL80211_ATTR_FRAME";
const int Nl80211AttributeGeneration::kName = NL80211_ATTR_GENERATION;
-const char Nl80211AttributeGeneration::kNameString[]
- = "NL80211_ATTR_GENERATION";
+const char Nl80211AttributeGeneration::kNameString[] =
+ "NL80211_ATTR_GENERATION";
const int Nl80211AttributeIfindex::kName = NL80211_ATTR_IFINDEX;
const char Nl80211AttributeIfindex::kNameString[] = "NL80211_ATTR_IFINDEX";
diff --git a/nl80211_attribute.h b/nl80211_attribute.h
index 463ac70..99974cc 100644
--- a/nl80211_attribute.h
+++ b/nl80211_attribute.h
@@ -211,6 +211,39 @@
// Nested.
+class Nl80211AttributeBss : public NetlinkNestedAttribute {
+ public:
+ static const int kName;
+ static const char kNameString[];
+ // These are sorted alphabetically.
+ static const int kChallengeTextAttributeId;
+ static const int kChannelsAttributeId;
+ static const int kCountryInfoAttributeId;
+ static const int kDSParameterSetAttributeId;
+ static const int kErpAttributeId;
+ static const int kExtendedRatesAttributeId;
+ static const int kHtCapAttributeId;
+ static const int kHtInfoAttributeId;
+ static const int kPowerCapabilityAttributeId;
+ static const int kPowerConstraintAttributeId;
+ static const int kRequestAttributeId;
+ static const int kRsnAttributeId;
+ static const int kSsidAttributeId;
+ static const int kSupportedRatesAttributeId;
+ static const int kTcpReportAttributeId;
+ static const int kVendorSpecificAttributeId;
+
+ Nl80211AttributeBss();
+
+ private:
+ static bool ParseInformationElements(AttributeList *attribute_list,
+ size_t id,
+ const std::string &attribute_name,
+ ByteString data);
+
+ DISALLOW_COPY_AND_ASSIGN(Nl80211AttributeBss);
+};
+
class Nl80211AttributeCqm : public NetlinkNestedAttribute {
public:
static const int kName;
diff --git a/wifi_service_unittest.cc b/wifi_service_unittest.cc
index bd89b81..3078eee 100644
--- a/wifi_service_unittest.cc
+++ b/wifi_service_unittest.cc
@@ -360,7 +360,7 @@
WiFiServiceRefPtr wifi_service = MakeSimpleService(flimflam::kSecurityWpa);
ReadablePropertyConstIterator<string> it =
(wifi_service->store()).GetStringPropertiesIter();
- for( ; !it.AtEnd(); it.Advance())
+ for ( ; !it.AtEnd(); it.Advance())
EXPECT_NE(it.Key(), flimflam::kPassphraseProperty);
}