Vitaly Buka | 4615e0d | 2015-10-14 15:35:12 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Weave Authors. All rights reserved. |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Johan Euphrosine | 3523fdd | 2015-10-14 20:46:05 -0700 | [diff] [blame] | 5 | #include "examples/provider/wifi_manager.h" |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 6 | |
| 7 | #include <arpa/inet.h> |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 8 | #include <linux/wireless.h> |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 9 | #include <sys/ioctl.h> |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 10 | #include <sys/wait.h> |
| 11 | |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 12 | #include <fstream> |
| 13 | |
| 14 | #include <base/bind.h> |
Vitaly Buka | 1e36367 | 2015-09-25 14:01:16 -0700 | [diff] [blame] | 15 | #include <weave/provider/task_runner.h> |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 16 | |
Vitaly Buka | 3d8feaf | 2015-10-28 13:10:53 -0700 | [diff] [blame] | 17 | #include "examples/provider/event_network.h" |
Johan Euphrosine | 3523fdd | 2015-10-14 20:46:05 -0700 | [diff] [blame] | 18 | #include "examples/provider/ssl_stream.h" |
Vitaly Buka | cd85060 | 2015-09-21 17:23:57 -0700 | [diff] [blame] | 19 | |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 20 | namespace weave { |
| 21 | namespace examples { |
| 22 | |
| 23 | namespace { |
| 24 | |
| 25 | int 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 Buka | 8cca9b1 | 2015-09-29 14:49:44 -0700 | [diff] [blame] | 38 | return 0; |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 39 | } |
| 40 | |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 41 | } // namespace |
| 42 | |
Vitaly Buka | 3d8feaf | 2015-10-28 13:10:53 -0700 | [diff] [blame] | 43 | WifiImpl::WifiImpl(provider::TaskRunner* task_runner, EventNetworkImpl* network) |
| 44 | : task_runner_{task_runner}, network_{network} { |
Johan Euphrosine | fdf7515 | 2015-11-06 01:16:22 -0800 | [diff] [blame] | 45 | CHECK_EQ(0u, getuid()) |
Vitaly Buka | d57fa62 | 2015-10-28 11:28:02 -0700 | [diff] [blame] | 46 | << "WiFi manager expects root access to control WiFi capabilities"; |
Vitaly Buka | 1fd619a | 2015-09-24 11:46:05 -0700 | [diff] [blame] | 47 | StopAccessPoint(); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 48 | } |
Johan Euphrosine | 09fcef6 | 2015-10-15 00:14:27 -0700 | [diff] [blame] | 49 | WifiImpl::~WifiImpl() { |
Vitaly Buka | 1fd619a | 2015-09-24 11:46:05 -0700 | [diff] [blame] | 50 | StopAccessPoint(); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 51 | } |
| 52 | |
Johan Euphrosine | 09fcef6 | 2015-10-15 00:14:27 -0700 | [diff] [blame] | 53 | void WifiImpl::TryToConnect(const std::string& ssid, |
Johan Euphrosine | 1ca3c22 | 2015-10-15 20:43:42 -0700 | [diff] [blame] | 54 | const std::string& passphrase, |
| 55 | int pid, |
| 56 | base::Time until, |
| 57 | const DoneCallback& callback) { |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 58 | 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 Buka | 4ebd641 | 2015-09-21 15:02:22 -0700 | [diff] [blame] | 73 | if (ssid == essid) |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 74 | return task_runner_->PostDelayedTask(FROM_HERE, |
| 75 | base::Bind(callback, nullptr), {}); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 76 | 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 Buka | aa30134 | 2015-09-21 16:08:33 -0700 | [diff] [blame] | 85 | 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 Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 90 | FROM_HERE, base::Bind(callback, base::Passed(&error)), {}); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 91 | return; |
Vitaly Buka | aa30134 | 2015-09-21 16:08:33 -0700 | [diff] [blame] | 92 | } |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 93 | |
| 94 | task_runner_->PostDelayedTask( |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 95 | FROM_HERE, |
Johan Euphrosine | 1ca3c22 | 2015-10-15 20:43:42 -0700 | [diff] [blame] | 96 | base::Bind(&WifiImpl::TryToConnect, weak_ptr_factory_.GetWeakPtr(), ssid, |
| 97 | passphrase, pid, until, callback), |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 98 | base::TimeDelta::FromSeconds(1)); |
| 99 | } |
| 100 | |
Johan Euphrosine | 09fcef6 | 2015-10-15 00:14:27 -0700 | [diff] [blame] | 101 | void WifiImpl::Connect(const std::string& ssid, |
Johan Euphrosine | 1ca3c22 | 2015-10-15 20:43:42 -0700 | [diff] [blame] | 102 | const std::string& passphrase, |
| 103 | const DoneCallback& callback) { |
Vitaly Buka | 3d8feaf | 2015-10-28 13:10:53 -0700 | [diff] [blame] | 104 | network_->SetSimulateOffline(false); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 105 | CHECK(!hostapd_started_); |
| 106 | if (hostapd_started_) { |
Vitaly Buka | aa30134 | 2015-09-21 16:08:33 -0700 | [diff] [blame] | 107 | ErrorPtr error; |
| 108 | Error::AddTo(&error, FROM_HERE, "wifi", "busy", "Running Access Point."); |
| 109 | task_runner_->PostDelayedTask( |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 110 | FROM_HERE, base::Bind(callback, base::Passed(&error)), {}); |
Vitaly Buka | aa30134 | 2015-09-21 16:08:33 -0700 | [diff] [blame] | 111 | return; |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 112 | } |
| 113 | |
| 114 | TryToConnect(ssid, passphrase, 0, |
Vitaly Buka | 7476342 | 2015-10-11 00:39:52 -0700 | [diff] [blame] | 115 | base::Time::Now() + base::TimeDelta::FromMinutes(1), callback); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 116 | } |
| 117 | |
Johan Euphrosine | 09fcef6 | 2015-10-15 00:14:27 -0700 | [diff] [blame] | 118 | void WifiImpl::StartAccessPoint(const std::string& ssid) { |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 119 | 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 Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 156 | } |
| 157 | |
Johan Euphrosine | 09fcef6 | 2015-10-15 00:14:27 -0700 | [diff] [blame] | 158 | void WifiImpl::StopAccessPoint() { |
Vitaly Buka | 8cca9b1 | 2015-09-29 14:49:44 -0700 | [diff] [blame] | 159 | base::IgnoreResult(std::system("pkill -f dnsmasq.*/tmp/weave")); |
| 160 | base::IgnoreResult(std::system("pkill -f hostapd.*/tmp/weave")); |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 161 | CHECK_EQ(0, std::system("nmcli nm wifi on")); |
| 162 | hostapd_started_ = false; |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 163 | } |
| 164 | |
Johan Euphrosine | 09fcef6 | 2015-10-15 00:14:27 -0700 | [diff] [blame] | 165 | bool WifiImpl::HasWifiCapability() { |
Vitaly Buka | e22a73f | 2015-09-21 17:39:32 -0700 | [diff] [blame] | 166 | return std::system("nmcli dev | grep ^wlan0") == 0; |
| 167 | } |
| 168 | |
Vitaly Buka | 17b0a8a | 2015-08-31 19:12:35 -0700 | [diff] [blame] | 169 | } // namespace examples |
| 170 | } // namespace weave |