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 
IsSetupNeeded(const ConnectionState & state)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 
WifiSsidGenerator(const CloudDelegate * cloud,const WifiDelegate * wifi)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 
GenerateFlags() const54 std::string WifiSsidGenerator::GenerateFlags() const {
55   return GenerateFlagsInternal();
56 }
57 
GenerateFlagsInternal() const58 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 
GenerateSsid() const83 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 
SetRandomForTests(int n)97 void WifiSsidGenerator::SetRandomForTests(int n) {
98   get_random_ = base::Bind(&base::RandInt, n, n);
99 }
100 
101 }  // namespace privet
102 }  // namespace weave
103