Home | History | Annotate | Download | only in privet
      1 // Copyright 2015 The Weave Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/privet/wifi_ssid_generator.h"
      6 
      7 #include <bitset>
      8 
      9 #include <base/bind.h>
     10 #include <base/rand_util.h>
     11 #include <base/strings/string_number_conversions.h>
     12 #include <base/strings/stringprintf.h>
     13 
     14 #include "src/privet/cloud_delegate.h"
     15 #include "src/privet/device_delegate.h"
     16 #include "src/privet/wifi_delegate.h"
     17 
     18 namespace weave {
     19 namespace privet {
     20 
     21 namespace {
     22 
     23 const int kDeviceNameSize = 20;
     24 // [DeviceName+Idx <= 20].[modelID == 5][flags == 2]prv
     25 const char kSsidFormat[] = "%s %s.%5.5s%2.2sprv";
     26 
     27 const char base64chars[] =
     28     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     29 
     30 bool IsSetupNeeded(const ConnectionState& state) {
     31   if (state.error())
     32     return true;
     33   switch (state.status()) {
     34     case ConnectionState::kUnconfigured:
     35       return true;
     36     case ConnectionState::kDisabled:
     37     case ConnectionState::kConnecting:
     38     case ConnectionState::kOnline:
     39     case ConnectionState::kOffline:
     40       return false;
     41   }
     42   CHECK(false);
     43   return false;
     44 }
     45 
     46 }  // namespace
     47 
     48 WifiSsidGenerator::WifiSsidGenerator(const CloudDelegate* cloud,
     49                                      const WifiDelegate* wifi)
     50     : gcd_(cloud), wifi_(wifi), get_random_(base::Bind(&base::RandInt, 0, 99)) {
     51   CHECK(gcd_);
     52 }
     53 
     54 std::string WifiSsidGenerator::GenerateFlags() const {
     55   return GenerateFlagsInternal();
     56 }
     57 
     58 std::string WifiSsidGenerator::GenerateFlagsInternal() const {
     59   std::bitset<6> flags1;
     60   // Device needs WiFi configuration.
     61   flags1[0] = wifi_ && IsSetupNeeded(wifi_->GetConnectionState());
     62 
     63   // Device needs GCD registration.
     64   flags1[1] = IsSetupNeeded(gcd_->GetConnectionState());
     65 
     66   std::bitset<6> flags2;
     67 
     68   if (wifi_) {
     69     std::set<WifiType> types = wifi_->GetTypes();
     70     // Device supports 2.4Ghz WiFi networks.
     71     flags2[0] = types.find(WifiType::kWifi24) != types.end();
     72 
     73     // Device supports 5.0Ghz WiFi networks.
     74     flags2[1] = types.find(WifiType::kWifi50) != types.end();
     75   }
     76 
     77   std::string result{2, base64chars[0]};
     78   result[0] = base64chars[flags1.to_ulong()];
     79   result[1] = base64chars[flags2.to_ulong()];
     80   return result;
     81 }
     82 
     83 std::string WifiSsidGenerator::GenerateSsid() const {
     84   std::string name = gcd_->GetName();
     85   std::string model_id = gcd_->GetModelId();
     86   std::string idx = base::IntToString(get_random_.Run());
     87   name = name.substr(0, kDeviceNameSize - idx.size() - 1);
     88   CHECK_EQ(5u, model_id.size());
     89 
     90   std::string result =
     91       base::StringPrintf(kSsidFormat, name.c_str(), idx.c_str(),
     92                          model_id.c_str(), GenerateFlagsInternal().c_str());
     93   CHECK_EQ(result[result.size() - 11], '.');
     94   return result;
     95 }
     96 
     97 void WifiSsidGenerator::SetRandomForTests(int n) {
     98   get_random_ = base::Bind(&base::RandInt, n, n);
     99 }
    100 
    101 }  // namespace privet
    102 }  // namespace weave
    103