shill: Makes WiFi device get available wifi frequencies from kernel.

Plus a couple of whitespace fixes.  This CL is in preparation for
passing the list of wifi frequencies to a scan request.

BUG=chromium:222088
TEST=unittest and manual tests.  The manual tests consist of:
  - Start shill with log=-10/wifi.  On the target, in a shell window,
    do the following:
      o stop shill
      o shill --log-level=-10 --log-scopes=wifi
  - Wait five seconds (the code will do everything it needs to at
    startup).
  - Look in /var/log/net.log and verify the following:
      o Found frequency[xx] = yyyy
      o There should be several frequencies (at least in the open at Google).
      o 'xx' is a number, I'd expect it to start at 0.
      o 'yyyy' is a number in the 5000s or the 2000x.

Change-Id: I8f0526abc22a7e9e60fd964c96d05eb95fa10e78
Reviewed-on: https://gerrit.chromium.org/gerrit/49271
Reviewed-by: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
Commit-Queue: Wade Guthrie <wdg@chromium.org>
diff --git a/netlink_manager.cc b/netlink_manager.cc
index faa11ce..cef93e3 100644
--- a/netlink_manager.cc
+++ b/netlink_manager.cc
@@ -18,8 +18,8 @@
 #include "shill/generic_netlink_message.h"
 #include "shill/io_handler.h"
 #include "shill/logging.h"
-#include "shill/netlink_socket.h"
 #include "shill/netlink_message.h"
+#include "shill/netlink_socket.h"
 #include "shill/scope_logger.h"
 #include "shill/shill_time.h"
 
@@ -313,7 +313,7 @@
 }
 
 bool NetlinkManager::SendMessage(NetlinkMessage *message,
-                              const NetlinkMessageHandler &handler) {
+                                 const NetlinkMessageHandler &handler) {
   if (!message) {
     LOG(ERROR) << "Message is NULL.";
     return false;
diff --git a/netlink_manager_unittest.cc b/netlink_manager_unittest.cc
index f4fb78e..4f9b994 100644
--- a/netlink_manager_unittest.cc
+++ b/netlink_manager_unittest.cc
@@ -8,7 +8,6 @@
 // messages.
 
 // This file tests the public interface to NetlinkManager.
-
 #include "shill/netlink_manager.h"
 
 #include <gmock/gmock.h>
@@ -189,8 +188,8 @@
   netlink_manager_->OnNlMessageReceived(received_message);
 
   // Send the message and give our handler.  Verify that we get called back.
-  EXPECT_TRUE(netlink_manager_->SendMessage(&sent_message_1,
-                                        handler_sent_1.on_netlink_message()));
+  EXPECT_TRUE(netlink_manager_->SendMessage(
+      &sent_message_1, handler_sent_1.on_netlink_message()));
   // Make it appear that this message is in response to our sent message.
   received_message->nlmsg_seq = socket_.GetLastSequenceNumber();
   EXPECT_CALL(handler_sent_1, OnNetlinkMessage(_)).Times(1);
@@ -203,8 +202,8 @@
 
   // Install and then uninstall message-specific handler; verify broadcast
   // handler is called on message receipt.
-  EXPECT_TRUE(netlink_manager_->SendMessage(&sent_message_1,
-                                        handler_sent_1.on_netlink_message()));
+  EXPECT_TRUE(netlink_manager_->SendMessage(
+      &sent_message_1, handler_sent_1.on_netlink_message()));
   received_message->nlmsg_seq = socket_.GetLastSequenceNumber();
   EXPECT_TRUE(netlink_manager_->RemoveMessageHandler(sent_message_1));
   EXPECT_CALL(handler_broadcast, OnNetlinkMessage(_)).Times(1);
@@ -212,8 +211,8 @@
 
   // Install handler for different message; verify that broadcast handler is
   // called for _this_ message.
-  EXPECT_TRUE(netlink_manager_->SendMessage(&sent_message_2,
-                                        handler_sent_2.on_netlink_message()));
+  EXPECT_TRUE(netlink_manager_->SendMessage(
+      &sent_message_2, handler_sent_2.on_netlink_message()));
   EXPECT_CALL(handler_broadcast, OnNetlinkMessage(_)).Times(1);
   netlink_manager_->OnNlMessageReceived(received_message);
 
diff --git a/nl80211_message.cc b/nl80211_message.cc
index 3fc8baa..9f53b69 100644
--- a/nl80211_message.cc
+++ b/nl80211_message.cc
@@ -24,10 +24,10 @@
 
 #include "shill/nl80211_message.h"
 
-#include <limits.h>
 #include <netlink/msg.h>
 #include <netlink/netlink.h>
 
+#include <limits>
 #include <map>
 #include <string>
 #include <vector>
@@ -425,7 +425,9 @@
 // Nl80211Frame
 
 Nl80211Frame::Nl80211Frame(const ByteString &raw_frame)
-  : frame_type_(kIllegalFrameType), reason_(UINT16_MAX), status_(UINT16_MAX),
+  : frame_type_(kIllegalFrameType),
+    reason_(std::numeric_limits<uint16_t>::max()),
+    status_(std::numeric_limits<uint16_t>::max()),
     frame_(raw_frame) {
   const IEEE_80211::ieee80211_frame *frame =
       reinterpret_cast<const IEEE_80211::ieee80211_frame *>(
@@ -563,6 +565,11 @@
 const uint8_t GetWiphyMessage::kCommand = NL80211_CMD_GET_WIPHY;
 const char GetWiphyMessage::kCommandString[] = "NL80211_CMD_GET_WIPHY";
 
+GetWiphyMessage::GetWiphyMessage() : Nl80211Message(kCommand, kCommandString) {
+  attributes()->CreateAttribute(
+      NL80211_ATTR_IFINDEX, Bind(&NetlinkAttribute::NewNl80211AttributeFromId));
+}
+
 const uint8_t JoinIbssMessage::kCommand = NL80211_CMD_JOIN_IBSS;
 const char JoinIbssMessage::kCommandString[] = "NL80211_CMD_JOIN_IBSS";
 
diff --git a/nl80211_message.h b/nl80211_message.h
index ae65319..d9526a8 100644
--- a/nl80211_message.h
+++ b/nl80211_message.h
@@ -243,7 +243,7 @@
   static const uint8_t kCommand;
   static const char kCommandString[];
 
-  GetWiphyMessage() : Nl80211Message(kCommand, kCommandString) {}
+  GetWiphyMessage();
 
  private:
   DISALLOW_COPY_AND_ASSIGN(GetWiphyMessage);
diff --git a/wifi.cc b/wifi.cc
index 6b440cc..2e35ced 100644
--- a/wifi.cc
+++ b/wifi.cc
@@ -4,10 +4,10 @@
 
 #include "shill/wifi.h"
 
+#include <linux/if.h>  // Needs definitions from netinet/ether.h
+#include <netinet/ether.h>
 #include <stdio.h>
 #include <string.h>
-#include <netinet/ether.h>
-#include <linux/if.h>  // Needs definitions from netinet/ether.h
 
 #include <algorithm>
 #include <map>
@@ -178,6 +178,7 @@
                                       NetlinkManager::kEventTypeRegulatory);
   netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
                                       NetlinkManager::kEventTypeMlme);
+  ConfigureScanFrequencies();
 }
 
 void WiFi::Stop(Error *error, const EnabledStateChangedCallback &callback) {
@@ -1580,4 +1581,96 @@
   manager()->RegisterDevice(me);
 }
 
+void WiFi::ConfigureScanFrequencies() {
+  GetWiphyMessage get_wiphy;
+  get_wiphy.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
+                                               interface_index());
+  netlink_manager_->SendMessage(&get_wiphy,
+                                Bind(&WiFi::OnNewWiphy,
+                                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void WiFi::OnNewWiphy(const NetlinkMessage &netlink_message) {
+  // Note that we don't fail fatally from this routine because, while it
+  // provides frequencies for a progressive scan, a failed progressive scan is
+  // followed by a full scan (which doesn't use the frequency list provided by
+  // this call).
+  if (netlink_message.message_type() == ErrorAckMessage::kMessageType) {
+    const ErrorAckMessage *error_ack_message =
+        reinterpret_cast<const ErrorAckMessage *>(&netlink_message);
+    if (error_ack_message->error()) {
+      LOG(ERROR) << __func__ << ": Message (seq: "
+                 << netlink_message.sequence_number() << ") failed: "
+                 << error_ack_message->ToString();
+    } else {
+      SLOG(WiFi, 6) << __func__ << ": Message (seq: "
+                 << netlink_message.sequence_number() << ") ACKed";
+    }
+    return;
+  }
+
+  // We only handle a special set of messages, all of which are nl80211
+  // messages.
+  if (netlink_message.message_type() != Nl80211Message::GetMessageType()) {
+    LOG(ERROR) << "Received unexpected message type: "
+               << netlink_message.message_type();
+    return;
+  }
+
+  const Nl80211Message *nl80211_message =
+      dynamic_cast<const Nl80211Message *>(&netlink_message);
+  // Verify NL80211_CMD_NEW_WIPHY
+  if (nl80211_message->command() != NewWiphyMessage::kCommand) {
+    LOG(ERROR) << "Received unexpected command:"
+               << nl80211_message->command();
+    return;
+  }
+
+  // The attributes, for this message, are complicated.
+  // NL80211_ATTR_BANDS contains an array of bands...
+  AttributeListConstRefPtr wiphy_bands;
+  if (!nl80211_message->const_attributes()->ConstGetNestedAttributeList(
+      NL80211_ATTR_WIPHY_BANDS, &wiphy_bands)) {
+    LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_BANDS";
+    return;
+  }
+
+  AttributeIdIterator band_iter(*wiphy_bands);
+  for (; !band_iter.AtEnd(); band_iter.Advance()) {
+    AttributeListConstRefPtr wiphy_band;
+    if (!wiphy_bands->ConstGetNestedAttributeList(band_iter.GetId(),
+                                                  &wiphy_band)) {
+      LOG(WARNING) << "WiFi band " << band_iter.GetId() << " not found";
+      continue;
+    }
+
+    // ...Each band has a FREQS attribute...
+    AttributeListConstRefPtr frequencies;
+    if (!wiphy_band->ConstGetNestedAttributeList(NL80211_BAND_ATTR_FREQS,
+                                                 &frequencies)) {
+      LOG(ERROR) << "BAND " << band_iter.GetId()
+                 << " had no 'frequencies' attribute";
+      continue;
+    }
+
+    // ...And each FREQS attribute contains an array of information about the
+    // frequency...
+    AttributeIdIterator freq_iter(*frequencies);
+    for (; !freq_iter.AtEnd(); freq_iter.Advance()) {
+      AttributeListConstRefPtr frequency;
+      if (frequencies->ConstGetNestedAttributeList(freq_iter.GetId(),
+                                                   &frequency)) {
+        // ...Including the frequency, itself (the part we want).
+        uint32_t frequency_value = 0;
+        if (frequency->GetU32AttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
+                                            &frequency_value)) {
+          SLOG(WiFi, 5) << "Found frequency[" << freq_iter.GetId()
+                        << "] = " << frequency_value;
+          all_scan_frequencies_.insert(frequency_value);
+        }
+      }
+    }
+  }
+}
+
 }  // namespace shill
diff --git a/wifi.h b/wifi.h
index 8ce8828..6639828 100644
--- a/wifi.h
+++ b/wifi.h
@@ -76,6 +76,7 @@
 #include <time.h>
 
 #include <map>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -100,6 +101,7 @@
 class GeolocationInfo;
 class KeyValueStore;
 class NetlinkManager;
+class NetlinkMessage;
 class ProxyFactory;
 class SupplicantEAPStateHandler;
 class SupplicantInterfaceProxyInterface;
@@ -221,6 +223,8 @@
   static const int kPendingTimeoutSeconds;
   static const int kReconnectTimeoutSeconds;
 
+  // Gets the list of frequencies supported by this device.
+  void ConfigureScanFrequencies();
   void AppendBgscan(WiFiService *service,
                     std::map<std::string, DBus::Variant> *service_params) const;
   std::string GetBgscanMethod(const int &argument, Error *error);
@@ -341,6 +345,11 @@
 
   std::string GetServiceLeaseName(const WiFiService &service);
 
+  // Netlink message handler for NL80211_CMD_NEW_WIPHY messages; copies
+  // device's supported frequencies from that message into
+  // |all_scan_frequencies_|.
+  void OnNewWiphy(const NetlinkMessage &netlink_message);
+
   // Pointer to the provider object that maintains WiFiService objects.
   WiFiProvider *provider_;
 
@@ -402,6 +411,7 @@
   uint16 scan_interval_seconds_;
 
   NetlinkManager *netlink_manager_;
+  std::set<uint16_t> all_scan_frequencies_;
 
   DISALLOW_COPY_AND_ASSIGN(WiFi);
 };