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
18namespace weave {
19namespace privet {
20
21namespace {
22
23const int kDeviceNameSize = 20;
24// [DeviceName+Idx <= 20].[modelID == 5][flags == 2]prv
25const char kSsidFormat[] = "%s %s.%5.5s%2.2sprv";
26
27const char base64chars[] =
28    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
29
30bool 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
48WifiSsidGenerator::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
54std::string WifiSsidGenerator::GenerateFlags() const {
55  return GenerateFlagsInternal();
56}
57
58std::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
83std::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
97void WifiSsidGenerator::SetRandomForTests(int n) {
98  get_random_ = base::Bind(&base::RandInt, n, n);
99}
100
101}  // namespace privet
102}  // namespace weave
103