blob: ed6a9fda1cd2d97b75cdfbecc79ff322b256b1a1 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Vitaly Buka17b0a8a2015-08-31 19:12:35 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Johan Euphrosine3523fdd2015-10-14 20:46:05 -07005#include "examples/provider/wifi_manager.h"
Vitaly Buka17b0a8a2015-08-31 19:12:35 -07006
7#include <arpa/inet.h>
Vitaly Buka17b0a8a2015-08-31 19:12:35 -07008#include <linux/wireless.h>
Vitaly Buka17b0a8a2015-08-31 19:12:35 -07009#include <sys/ioctl.h>
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070010#include <sys/wait.h>
11
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070012#include <fstream>
13
14#include <base/bind.h>
Vitaly Buka1e363672015-09-25 14:01:16 -070015#include <weave/provider/task_runner.h>
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070016
Vitaly Buka3d8feaf2015-10-28 13:10:53 -070017#include "examples/provider/event_network.h"
Johan Euphrosine3523fdd2015-10-14 20:46:05 -070018#include "examples/provider/ssl_stream.h"
Vitaly Bukacd850602015-09-21 17:23:57 -070019
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070020namespace weave {
21namespace examples {
22
23namespace {
24
25int ForkCmd(const std::string& path, const std::vector<std::string>& args) {
26 int pid = fork();
27 if (pid != 0)
28 return pid;
29
30 std::vector<const char*> args_vector;
31 args_vector.push_back(path.c_str());
32 for (auto& i : args)
33 args_vector.push_back(i.c_str());
34 args_vector.push_back(nullptr);
35
36 execvp(path.c_str(), const_cast<char**>(args_vector.data()));
37 NOTREACHED();
Vitaly Buka8cca9b12015-09-29 14:49:44 -070038 return 0;
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070039}
40
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070041} // namespace
42
Vitaly Buka3d8feaf2015-10-28 13:10:53 -070043WifiImpl::WifiImpl(provider::TaskRunner* task_runner, EventNetworkImpl* network)
44 : task_runner_{task_runner}, network_{network} {
Johan Euphrosinefdf75152015-11-06 01:16:22 -080045 CHECK_EQ(0u, getuid())
Vitaly Bukad57fa622015-10-28 11:28:02 -070046 << "WiFi manager expects root access to control WiFi capabilities";
Vitaly Buka1fd619a2015-09-24 11:46:05 -070047 StopAccessPoint();
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070048}
Johan Euphrosine09fcef62015-10-15 00:14:27 -070049WifiImpl::~WifiImpl() {
Vitaly Buka1fd619a2015-09-24 11:46:05 -070050 StopAccessPoint();
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070051}
52
Johan Euphrosine09fcef62015-10-15 00:14:27 -070053void WifiImpl::TryToConnect(const std::string& ssid,
Johan Euphrosine1ca3c222015-10-15 20:43:42 -070054 const std::string& passphrase,
55 int pid,
56 base::Time until,
57 const DoneCallback& callback) {
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070058 if (pid) {
59 int status = 0;
60 if (pid == waitpid(pid, &status, WNOWAIT)) {
61 int sockf_d = socket(AF_INET, SOCK_DGRAM, 0);
62 CHECK_GE(sockf_d, 0) << strerror(errno);
63
64 iwreq wreq = {};
65 snprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "wlan0");
66 std::string essid(' ', IW_ESSID_MAX_SIZE + 1);
67 wreq.u.essid.pointer = &essid[0];
68 wreq.u.essid.length = essid.size();
69 CHECK_GE(ioctl(sockf_d, SIOCGIWESSID, &wreq), 0) << strerror(errno);
70 essid.resize(wreq.u.essid.length);
71 close(sockf_d);
72
Vitaly Buka4ebd6412015-09-21 15:02:22 -070073 if (ssid == essid)
Vitaly Buka74763422015-10-11 00:39:52 -070074 return task_runner_->PostDelayedTask(FROM_HERE,
75 base::Bind(callback, nullptr), {});
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070076 pid = 0; // Try again.
77 }
78 }
79
80 if (pid == 0) {
81 pid = ForkCmd("nmcli",
82 {"dev", "wifi", "connect", ssid, "password", passphrase});
83 }
84
Vitaly Bukaaa301342015-09-21 16:08:33 -070085 if (base::Time::Now() >= until) {
86 ErrorPtr error;
87 Error::AddTo(&error, FROM_HERE, "wifi", "timeout",
88 "Timeout connecting to WiFI network.");
89 task_runner_->PostDelayedTask(
Vitaly Buka74763422015-10-11 00:39:52 -070090 FROM_HERE, base::Bind(callback, base::Passed(&error)), {});
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070091 return;
Vitaly Bukaaa301342015-09-21 16:08:33 -070092 }
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070093
94 task_runner_->PostDelayedTask(
Vitaly Buka74763422015-10-11 00:39:52 -070095 FROM_HERE,
Johan Euphrosine1ca3c222015-10-15 20:43:42 -070096 base::Bind(&WifiImpl::TryToConnect, weak_ptr_factory_.GetWeakPtr(), ssid,
97 passphrase, pid, until, callback),
Vitaly Buka17b0a8a2015-08-31 19:12:35 -070098 base::TimeDelta::FromSeconds(1));
99}
100
Johan Euphrosine09fcef62015-10-15 00:14:27 -0700101void WifiImpl::Connect(const std::string& ssid,
Johan Euphrosine1ca3c222015-10-15 20:43:42 -0700102 const std::string& passphrase,
103 const DoneCallback& callback) {
Vitaly Buka3d8feaf2015-10-28 13:10:53 -0700104 network_->SetSimulateOffline(false);
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700105 CHECK(!hostapd_started_);
106 if (hostapd_started_) {
Vitaly Bukaaa301342015-09-21 16:08:33 -0700107 ErrorPtr error;
108 Error::AddTo(&error, FROM_HERE, "wifi", "busy", "Running Access Point.");
109 task_runner_->PostDelayedTask(
Vitaly Buka74763422015-10-11 00:39:52 -0700110 FROM_HERE, base::Bind(callback, base::Passed(&error)), {});
Vitaly Bukaaa301342015-09-21 16:08:33 -0700111 return;
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700112 }
113
114 TryToConnect(ssid, passphrase, 0,
Vitaly Buka74763422015-10-11 00:39:52 -0700115 base::Time::Now() + base::TimeDelta::FromMinutes(1), callback);
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700116}
117
Johan Euphrosine09fcef62015-10-15 00:14:27 -0700118void WifiImpl::StartAccessPoint(const std::string& ssid) {
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700119 if (hostapd_started_)
120 return;
121
122 // Release wlan0 interface.
123 CHECK_EQ(0, std::system("nmcli nm wifi off"));
124 CHECK_EQ(0, std::system("rfkill unblock wlan"));
125 sleep(1);
126
127 std::string hostapd_conf = "/tmp/weave_hostapd.conf";
128 {
129 std::ofstream ofs(hostapd_conf);
130 ofs << "interface=wlan0" << std::endl;
131 ofs << "channel=1" << std::endl;
132 ofs << "ssid=" << ssid << std::endl;
133 }
134
135 CHECK_EQ(0, std::system(("hostapd -B -K " + hostapd_conf).c_str()));
136 hostapd_started_ = true;
137
138 for (size_t i = 0; i < 10; ++i) {
139 if (0 == std::system("ifconfig wlan0 192.168.76.1/24"))
140 break;
141 sleep(1);
142 }
143
144 std::string dnsmasq_conf = "/tmp/weave_dnsmasq.conf";
145 {
146 std::ofstream ofs(dnsmasq_conf.c_str());
147 ofs << "port=0" << std::endl;
148 ofs << "bind-interfaces" << std::endl;
149 ofs << "log-dhcp" << std::endl;
150 ofs << "dhcp-range=192.168.76.10,192.168.76.100" << std::endl;
151 ofs << "interface=wlan0" << std::endl;
152 ofs << "dhcp-leasefile=" << dnsmasq_conf << ".leases" << std::endl;
153 }
154
155 CHECK_EQ(0, std::system(("dnsmasq --conf-file=" + dnsmasq_conf).c_str()));
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700156}
157
Johan Euphrosine09fcef62015-10-15 00:14:27 -0700158void WifiImpl::StopAccessPoint() {
Vitaly Buka8cca9b12015-09-29 14:49:44 -0700159 base::IgnoreResult(std::system("pkill -f dnsmasq.*/tmp/weave"));
160 base::IgnoreResult(std::system("pkill -f hostapd.*/tmp/weave"));
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700161 CHECK_EQ(0, std::system("nmcli nm wifi on"));
162 hostapd_started_ = false;
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700163}
164
Johan Euphrosine09fcef62015-10-15 00:14:27 -0700165bool WifiImpl::HasWifiCapability() {
Vitaly Bukae22a73f2015-09-21 17:39:32 -0700166 return std::system("nmcli dev | grep ^wlan0") == 0;
167}
168
Vitaly Buka17b0a8a2015-08-31 19:12:35 -0700169} // namespace examples
170} // namespace weave