blob: 7a58698d4a880d8592c5cc56c95e1501965c3aab [file] [log] [blame]
Peter Qiu326b6cf2015-09-02 11:11:42 -07001//
2// Copyright (C) 2014 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Peter Qiuf0731732014-11-11 09:46:41 -080016
17#include "apmanager/config.h"
18
19#include <base/strings/stringprintf.h>
20#include <chromeos/dbus/service_constants.h>
21
Peter Qiubfd410e2015-01-09 15:14:20 -080022#include "apmanager/daemon.h"
Peter Qiufb39ba42014-11-21 09:09:59 -080023#include "apmanager/device.h"
24#include "apmanager/manager.h"
25
Peter Qiu376e4042014-11-13 09:40:28 -080026using chromeos::dbus_utils::AsyncEventSequencer;
27using chromeos::dbus_utils::ExportedObjectManager;
Peter Qiuf0731732014-11-11 09:46:41 -080028using chromeos::ErrorPtr;
29using std::string;
30
31namespace apmanager {
32
33// static
34const char Config::kHostapdConfigKeyBridgeInterface[] = "bridge";
35const char Config::kHostapdConfigKeyChannel[] = "channel";
36const char Config::kHostapdConfigKeyControlInterface[] = "ctrl_interface";
Peter Qiubfd410e2015-01-09 15:14:20 -080037const char Config::kHostapdConfigKeyControlInterfaceGroup[] =
38 "ctrl_interface_group";
Peter Qiuf0731732014-11-11 09:46:41 -080039const char Config::kHostapdConfigKeyDriver[] = "driver";
40const char Config::kHostapdConfigKeyFragmThreshold[] = "fragm_threshold";
Peter Qiu8e785b92014-11-24 10:01:08 -080041const char Config::kHostapdConfigKeyHTCapability[] = "ht_capab";
Peter Qiuf0731732014-11-11 09:46:41 -080042const char Config::kHostapdConfigKeyHwMode[] = "hw_mode";
43const char Config::kHostapdConfigKeyIeee80211ac[] = "ieee80211ac";
44const char Config::kHostapdConfigKeyIeee80211n[] = "ieee80211n";
45const char Config::kHostapdConfigKeyIgnoreBroadcastSsid[] =
46 "ignore_broadcast_ssid";
47const char Config::kHostapdConfigKeyInterface[] = "interface";
48const char Config::kHostapdConfigKeyRsnPairwise[] = "rsn_pairwise";
49const char Config::kHostapdConfigKeyRtsThreshold[] = "rts_threshold";
50const char Config::kHostapdConfigKeySsid[] = "ssid";
51const char Config::kHostapdConfigKeyWepDefaultKey[] = "wep_default_key";
52const char Config::kHostapdConfigKeyWepKey0[] = "wep_key0";
53const char Config::kHostapdConfigKeyWpa[] = "wpa";
54const char Config::kHostapdConfigKeyWpaKeyMgmt[] = "wpa_key_mgmt";
55const char Config::kHostapdConfigKeyWpaPassphrase[] = "wpa_passphrase";
56
57const char Config::kHostapdHwMode80211a[] = "a";
58const char Config::kHostapdHwMode80211b[] = "b";
59const char Config::kHostapdHwMode80211g[] = "g";
60
61// static
62const uint16_t Config::kPropertyDefaultChannel = 6;
63const uint16_t Config::kPropertyDefaultServerAddressIndex = 0;
64const bool Config::kPropertyDefaultHiddenNetwork = false;
65
66// static
67const char Config::kHostapdDefaultDriver[] = "nl80211";
68const char Config::kHostapdDefaultRsnPairwise[] = "CCMP";
69const char Config::kHostapdDefaultWpaKeyMgmt[] = "WPA-PSK";
70// Fragmentation threshold: disabled.
71const int Config::kHostapdDefaultFragmThreshold = 2346;
72// RTS threshold: disabled.
73const int Config::kHostapdDefaultRtsThreshold = 2347;
74
Peter Qiu8e785b92014-11-24 10:01:08 -080075// static
76const uint16_t Config::kBand24GHzChannelLow = 1;
77const uint16_t Config::kBand24GHzChannelHigh = 13;
78const uint32_t Config::kBand24GHzBaseFrequency = 2412;
79const uint16_t Config::kBand5GHzChannelLow = 34;
80const uint16_t Config::kBand5GHzChannelHigh = 165;
81const uint16_t Config::kBand5GHzBaseFrequency = 5170;
82
Peter Qiu68303292014-12-10 10:42:13 -080083// static
84const int Config::kSsidMinLength = 1;
85const int Config::kSsidMaxLength = 32;
86const int Config::kPassphraseMinLength = 8;
87const int Config::kPassphraseMaxLength = 63;
88
Peter Qiufb39ba42014-11-21 09:09:59 -080089Config::Config(Manager* manager, const string& service_path)
Peter Qiuf0731732014-11-11 09:46:41 -080090 : org::chromium::apmanager::ConfigAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080091 manager_(manager),
Peter Qiuf0731732014-11-11 09:46:41 -080092 dbus_path_(dbus::ObjectPath(
93 base::StringPrintf("%s/config", service_path.c_str()))) {
94 // Initialize default configuration values.
95 SetSecurityMode(kSecurityModeNone);
96 SetHwMode(kHwMode80211g);
97 SetOperationMode(kOperationModeServer);
98 SetServerAddressIndex(kPropertyDefaultServerAddressIndex);
99 SetChannel(kPropertyDefaultChannel);
100 SetHiddenNetwork(kPropertyDefaultHiddenNetwork);
Peter Qiu0ca183b2015-03-09 13:41:06 -0700101 SetFullDeviceControl(true);
Peter Qiuf0731732014-11-11 09:46:41 -0800102}
103
104Config::~Config() {}
105
Peter Qiu8e785b92014-11-24 10:01:08 -0800106// static.
107bool Config::GetFrequencyFromChannel(uint16_t channel, uint32_t* freq) {
108 bool ret_value = true;
109 if (channel >= kBand24GHzChannelLow && channel <= kBand24GHzChannelHigh) {
110 *freq = kBand24GHzBaseFrequency + (channel - kBand24GHzChannelLow) * 5;
111 } else if (channel >= kBand5GHzChannelLow &&
112 channel <= kBand5GHzChannelHigh) {
113 *freq = kBand5GHzBaseFrequency + (channel - kBand5GHzChannelLow) * 5;
114 } else {
115 ret_value = false;
116 }
117 return ret_value;
118}
119
Peter Qiu68303292014-12-10 10:42:13 -0800120bool Config::ValidateSsid(ErrorPtr* error, const string& value) {
121 if (value.length() < kSsidMinLength || value.length() > kSsidMaxLength) {
122 chromeos::Error::AddToPrintf(
123 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
124 "SSID must contain between %d and %d characters",
125 kSsidMinLength, kSsidMaxLength);
126 return false;
127 }
Peter Qiubf8e36c2014-12-03 22:59:45 -0800128 return true;
129}
130
Peter Qiu68303292014-12-10 10:42:13 -0800131bool Config::ValidateSecurityMode(ErrorPtr* error, const string& value) {
132 if (value != kSecurityModeNone && value != kSecurityModeRSN) {
133 chromeos::Error::AddToPrintf(
134 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
135 "Invalid/unsupported security mode [%s]", value.c_str());
136 return false;
137 }
138 return true;
139}
140
141bool Config::ValidatePassphrase(ErrorPtr* error, const string& value) {
142 if (value.length() < kPassphraseMinLength ||
143 value.length() > kPassphraseMaxLength) {
144 chromeos::Error::AddToPrintf(
145 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
146 "Passphrase must contain between %d and %d characters",
147 kPassphraseMinLength, kPassphraseMaxLength);
148 return false;
149 }
150 return true;
151}
152
153bool Config::ValidateHwMode(ErrorPtr* error, const string& value) {
154 if (value != kHwMode80211a && value != kHwMode80211b &&
155 value != kHwMode80211g && value != kHwMode80211n &&
156 value != kHwMode80211ac) {
157 chromeos::Error::AddToPrintf(
158 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
159 "Invalid HW mode [%s]", value.c_str());
160 return false;
161 }
162 return true;
163}
164
165bool Config::ValidateOperationMode(ErrorPtr* error, const string& value) {
166 if (value != kOperationModeServer && value != kOperationModeBridge) {
167 chromeos::Error::AddToPrintf(
168 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
169 "Invalid operation mode [%s]", value.c_str());
170 return false;
171 }
172 return true;
173}
174
175bool Config::ValidateChannel(ErrorPtr* error, const uint16_t& value) {
176 if ((value >= kBand24GHzChannelLow && value <= kBand24GHzChannelHigh) ||
177 (value >= kBand5GHzChannelLow && value <= kBand5GHzChannelHigh)) {
178 return true;
179 }
180 chromeos::Error::AddToPrintf(
181 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
182 "Invalid channel [%d]", value);
183 return false;
184}
185
Peter Qiu376e4042014-11-13 09:40:28 -0800186void Config::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800187 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -0800188 AsyncEventSequencer* sequencer) {
189 CHECK(!dbus_object_) << "Already registered";
190 dbus_object_.reset(
191 new chromeos::dbus_utils::DBusObject(
192 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800193 bus,
Peter Qiu376e4042014-11-13 09:40:28 -0800194 dbus_path_));
195 RegisterWithDBusObject(dbus_object_.get());
196 dbus_object_->RegisterAsync(
197 sequencer->GetHandler("Config.RegisterAsync() failed.", true));
198}
199
Peter Qiuf0731732014-11-11 09:46:41 -0800200bool Config::GenerateConfigFile(ErrorPtr* error, string* config_str) {
201 // SSID.
202 string ssid = GetSsid();
203 if (ssid.empty()) {
Peter Qiu376e4042014-11-13 09:40:28 -0800204 chromeos::Error::AddTo(
205 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
206 "SSID not specified");
Peter Qiuf0731732014-11-11 09:46:41 -0800207 return false;
208 }
209 base::StringAppendF(
210 config_str, "%s=%s\n", kHostapdConfigKeySsid, ssid.c_str());
211
Peter Qiu68303292014-12-10 10:42:13 -0800212 // Bridge interface is required for bridge mode operation.
213 if (GetOperationMode() == kOperationModeBridge) {
214 if (GetBridgeInterface().empty()) {
215 chromeos::Error::AddTo(
216 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
217 "Bridge interface not specified, required for bridge mode");
218 return false;
219 }
220 base::StringAppendF(config_str,
221 "%s=%s\n",
222 kHostapdConfigKeyBridgeInterface,
223 GetBridgeInterface().c_str());
224 }
225
Peter Qiuf0731732014-11-11 09:46:41 -0800226 // Channel.
227 base::StringAppendF(
228 config_str, "%s=%d\n", kHostapdConfigKeyChannel, GetChannel());
229
Peter Qiu8e785b92014-11-24 10:01:08 -0800230 // Interface.
231 if (!AppendInterface(error, config_str)) {
Peter Qiuf0731732014-11-11 09:46:41 -0800232 return false;
233 }
234
Peter Qiu8e785b92014-11-24 10:01:08 -0800235 // Hardware mode.
236 if (!AppendHwMode(error, config_str)) {
Peter Qiuf0731732014-11-11 09:46:41 -0800237 return false;
238 }
239
240 // Security mode configurations.
241 if (!AppendSecurityMode(error, config_str)) {
242 return false;
243 }
244
Peter Qiubfd410e2015-01-09 15:14:20 -0800245 // Control interface.
246 if (!control_interface_.empty()) {
247 base::StringAppendF(config_str,
248 "%s=%s\n",
249 kHostapdConfigKeyControlInterface,
250 control_interface_.c_str());
251 base::StringAppendF(config_str,
252 "%s=%s\n",
253 kHostapdConfigKeyControlInterfaceGroup,
254 Daemon::kAPManagerGroupName);
255 }
256
Peter Qiuf0731732014-11-11 09:46:41 -0800257 // Hostapd default configurations.
258 if (!AppendHostapdDefaults(error, config_str)) {
259 return false;
260 }
261
262 return true;
263}
264
Peter Qiufb39ba42014-11-21 09:09:59 -0800265bool Config::ClaimDevice() {
266 if (!device_) {
267 LOG(ERROR) << "Failed to claim device: device doesn't exist.";
268 return false;
269 }
Peter Qiu0ca183b2015-03-09 13:41:06 -0700270 return device_->ClaimDevice(GetFullDeviceControl());
Peter Qiufb39ba42014-11-21 09:09:59 -0800271}
272
273bool Config::ReleaseDevice() {
274 if (!device_) {
275 LOG(ERROR) << "Failed to release device: device doesn't exist.";
276 return false;
277 }
278 return device_->ReleaseDevice();
279}
280
Peter Qiu376e4042014-11-13 09:40:28 -0800281bool Config::AppendHwMode(ErrorPtr* error, std::string* config_str) {
Peter Qiuf0731732014-11-11 09:46:41 -0800282 string hw_mode = GetHwMode();
283 string hostapd_hw_mode;
284 if (hw_mode == kHwMode80211a) {
285 hostapd_hw_mode = kHostapdHwMode80211a;
286 } else if (hw_mode == kHwMode80211b) {
287 hostapd_hw_mode = kHostapdHwMode80211b;
288 } else if (hw_mode == kHwMode80211g) {
289 hostapd_hw_mode = kHostapdHwMode80211g;
290 } else if (hw_mode == kHwMode80211n) {
291 // Use 802.11a for 5GHz channel and 802.11g for 2.4GHz channel
292 if (GetChannel() >= 34) {
293 hostapd_hw_mode = kHostapdHwMode80211a;
294 } else {
295 hostapd_hw_mode = kHostapdHwMode80211g;
296 }
297 base::StringAppendF(config_str, "%s=1\n", kHostapdConfigKeyIeee80211n);
298
Peter Qiu8e785b92014-11-24 10:01:08 -0800299 // Get HT Capability.
300 string ht_cap;
301 if (!device_->GetHTCapability(GetChannel(), &ht_cap)) {
302 chromeos::Error::AddTo(
303 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
304 "Failed to get HT Capability");
305 return false;
306 }
307 base::StringAppendF(config_str, "%s=%s\n",
308 kHostapdConfigKeyHTCapability,
309 ht_cap.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800310 } else if (hw_mode == kHwMode80211ac) {
311 if (GetChannel() >= 34) {
312 hostapd_hw_mode = kHostapdHwMode80211a;
313 } else {
314 hostapd_hw_mode = kHostapdHwMode80211g;
315 }
316 base::StringAppendF(config_str, "%s=1\n", kHostapdConfigKeyIeee80211ac);
317
318 // TODO(zqiu): Determine VHT Capabilities based on the interface PHY's
319 // capababilites.
320 } else {
Peter Qiu376e4042014-11-13 09:40:28 -0800321 chromeos::Error::AddToPrintf(
322 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
323 "Invalid hardware mode: %s", hw_mode.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800324 return false;
325 }
326
327 base::StringAppendF(
328 config_str, "%s=%s\n", kHostapdConfigKeyHwMode, hostapd_hw_mode.c_str());
329 return true;
330}
331
Peter Qiu376e4042014-11-13 09:40:28 -0800332bool Config::AppendHostapdDefaults(ErrorPtr* error,
Peter Qiuf0731732014-11-11 09:46:41 -0800333 std::string* config_str) {
334 // Driver: NL80211.
335 base::StringAppendF(
336 config_str, "%s=%s\n", kHostapdConfigKeyDriver, kHostapdDefaultDriver);
337
338 // Fragmentation threshold: disabled.
339 base::StringAppendF(config_str,
340 "%s=%d\n",
341 kHostapdConfigKeyFragmThreshold,
342 kHostapdDefaultFragmThreshold);
343
344 // RTS threshold: disabled.
345 base::StringAppendF(config_str,
346 "%s=%d\n",
347 kHostapdConfigKeyRtsThreshold,
348 kHostapdDefaultRtsThreshold);
349
350 return true;
351}
352
Peter Qiu376e4042014-11-13 09:40:28 -0800353bool Config::AppendInterface(ErrorPtr* error,
Peter Qiuf0731732014-11-11 09:46:41 -0800354 std::string* config_str) {
355 string interface = GetInterfaceName();
356 if (interface.empty()) {
Peter Qiufb39ba42014-11-21 09:09:59 -0800357 // Ask manager for unused ap capable device.
358 device_ = manager_->GetAvailableDevice();
359 if (!device_) {
360 chromeos::Error::AddTo(
361 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
362 "No device available");
363 return false;
364 }
365 } else {
366 device_ = manager_->GetDeviceFromInterfaceName(interface);
Peter Qiu68303292014-12-10 10:42:13 -0800367 if (!device_) {
368 chromeos::Error::AddToPrintf(
369 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
370 "Unable to find device for the specified interface [%s]",
371 interface.c_str());
372 return false;
373 }
Garret Kelly0c0e9e72015-09-01 17:28:01 -0400374 if (device_->GetInUse()) {
Peter Qiufb39ba42014-11-21 09:09:59 -0800375 chromeos::Error::AddToPrintf(
376 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
377 "Device [%s] for interface [%s] already in use",
378 device_->GetDeviceName().c_str(),
379 interface.c_str());
380 return false;
381 }
Peter Qiuf0731732014-11-11 09:46:41 -0800382 }
383
Peter Qiufb39ba42014-11-21 09:09:59 -0800384 // Use the preferred AP interface from the device.
Peter Qiubf8e36c2014-12-03 22:59:45 -0800385 selected_interface_ = device_->GetPreferredApInterface();
386 base::StringAppendF(config_str,
387 "%s=%s\n",
388 kHostapdConfigKeyInterface,
389 selected_interface_.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800390 return true;
391}
392
Peter Qiu376e4042014-11-13 09:40:28 -0800393bool Config::AppendSecurityMode(ErrorPtr* error,
Peter Qiuf0731732014-11-11 09:46:41 -0800394 std::string* config_str) {
395 string security_mode = GetSecurityMode();
396 if (security_mode == kSecurityModeNone) {
397 // Nothing need to be done for open network.
398 return true;
399 }
400
401 if (security_mode == kSecurityModeRSN) {
402 string passphrase = GetPassphrase();
403 if (passphrase.empty()) {
Peter Qiu376e4042014-11-13 09:40:28 -0800404 chromeos::Error::AddToPrintf(
405 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
406 "Passphrase not set for security mode: %s", security_mode.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800407 return false;
408 }
409
410 base::StringAppendF(config_str, "%s=2\n", kHostapdConfigKeyWpa);
411 base::StringAppendF(config_str,
412 "%s=%s\n",
413 kHostapdConfigKeyRsnPairwise,
414 kHostapdDefaultRsnPairwise);
415 base::StringAppendF(config_str,
416 "%s=%s\n",
417 kHostapdConfigKeyWpaKeyMgmt,
418 kHostapdDefaultWpaKeyMgmt);
419 base::StringAppendF(config_str,
420 "%s=%s\n",
421 kHostapdConfigKeyWpaPassphrase,
422 passphrase.c_str());
423 return true;
424 }
425
Peter Qiuf0731732014-11-11 09:46:41 -0800426 chromeos::Error::AddToPrintf(
Peter Qiu376e4042014-11-13 09:40:28 -0800427 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
428 "Invalid security mode: %s", security_mode.c_str());
429 return false;
Peter Qiuf0731732014-11-11 09:46:41 -0800430}
431
432} // namespace apmanager