blob: ba865e0a9b43aadf96289589a6e07bb7ae7267cf [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>
Peter Qiu7a420d32015-09-22 11:25:15 -070020
21#if !defined(__ANDROID__)
Peter Qiuf0731732014-11-11 09:46:41 -080022#include <chromeos/dbus/service_constants.h>
Peter Qiu7a420d32015-09-22 11:25:15 -070023#else
24#include "dbus/apmanager/dbus-constants.h"
25#endif // __ANDROID__
Peter Qiuf0731732014-11-11 09:46:41 -080026
Peter Qiubfd410e2015-01-09 15:14:20 -080027#include "apmanager/daemon.h"
Peter Qiufb39ba42014-11-21 09:09:59 -080028#include "apmanager/device.h"
29#include "apmanager/manager.h"
30
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -070031using brillo::dbus_utils::AsyncEventSequencer;
32using brillo::dbus_utils::ExportedObjectManager;
33using brillo::ErrorPtr;
Peter Qiuf0731732014-11-11 09:46:41 -080034using std::string;
35
36namespace apmanager {
37
38// static
39const char Config::kHostapdConfigKeyBridgeInterface[] = "bridge";
40const char Config::kHostapdConfigKeyChannel[] = "channel";
41const char Config::kHostapdConfigKeyControlInterface[] = "ctrl_interface";
Peter Qiubfd410e2015-01-09 15:14:20 -080042const char Config::kHostapdConfigKeyControlInterfaceGroup[] =
43 "ctrl_interface_group";
Peter Qiuf0731732014-11-11 09:46:41 -080044const char Config::kHostapdConfigKeyDriver[] = "driver";
45const char Config::kHostapdConfigKeyFragmThreshold[] = "fragm_threshold";
Peter Qiu8e785b92014-11-24 10:01:08 -080046const char Config::kHostapdConfigKeyHTCapability[] = "ht_capab";
Peter Qiuf0731732014-11-11 09:46:41 -080047const char Config::kHostapdConfigKeyHwMode[] = "hw_mode";
48const char Config::kHostapdConfigKeyIeee80211ac[] = "ieee80211ac";
49const char Config::kHostapdConfigKeyIeee80211n[] = "ieee80211n";
50const char Config::kHostapdConfigKeyIgnoreBroadcastSsid[] =
51 "ignore_broadcast_ssid";
52const char Config::kHostapdConfigKeyInterface[] = "interface";
53const char Config::kHostapdConfigKeyRsnPairwise[] = "rsn_pairwise";
54const char Config::kHostapdConfigKeyRtsThreshold[] = "rts_threshold";
55const char Config::kHostapdConfigKeySsid[] = "ssid";
56const char Config::kHostapdConfigKeyWepDefaultKey[] = "wep_default_key";
57const char Config::kHostapdConfigKeyWepKey0[] = "wep_key0";
58const char Config::kHostapdConfigKeyWpa[] = "wpa";
59const char Config::kHostapdConfigKeyWpaKeyMgmt[] = "wpa_key_mgmt";
60const char Config::kHostapdConfigKeyWpaPassphrase[] = "wpa_passphrase";
61
62const char Config::kHostapdHwMode80211a[] = "a";
63const char Config::kHostapdHwMode80211b[] = "b";
64const char Config::kHostapdHwMode80211g[] = "g";
65
66// static
67const uint16_t Config::kPropertyDefaultChannel = 6;
68const uint16_t Config::kPropertyDefaultServerAddressIndex = 0;
69const bool Config::kPropertyDefaultHiddenNetwork = false;
70
71// static
72const char Config::kHostapdDefaultDriver[] = "nl80211";
73const char Config::kHostapdDefaultRsnPairwise[] = "CCMP";
74const char Config::kHostapdDefaultWpaKeyMgmt[] = "WPA-PSK";
75// Fragmentation threshold: disabled.
76const int Config::kHostapdDefaultFragmThreshold = 2346;
77// RTS threshold: disabled.
78const int Config::kHostapdDefaultRtsThreshold = 2347;
79
Peter Qiu8e785b92014-11-24 10:01:08 -080080// static
81const uint16_t Config::kBand24GHzChannelLow = 1;
82const uint16_t Config::kBand24GHzChannelHigh = 13;
83const uint32_t Config::kBand24GHzBaseFrequency = 2412;
84const uint16_t Config::kBand5GHzChannelLow = 34;
85const uint16_t Config::kBand5GHzChannelHigh = 165;
86const uint16_t Config::kBand5GHzBaseFrequency = 5170;
87
Peter Qiu68303292014-12-10 10:42:13 -080088// static
89const int Config::kSsidMinLength = 1;
90const int Config::kSsidMaxLength = 32;
91const int Config::kPassphraseMinLength = 8;
92const int Config::kPassphraseMaxLength = 63;
93
Peter Qiufb39ba42014-11-21 09:09:59 -080094Config::Config(Manager* manager, const string& service_path)
Peter Qiuf0731732014-11-11 09:46:41 -080095 : org::chromium::apmanager::ConfigAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080096 manager_(manager),
Peter Qiuf0731732014-11-11 09:46:41 -080097 dbus_path_(dbus::ObjectPath(
98 base::StringPrintf("%s/config", service_path.c_str()))) {
99 // Initialize default configuration values.
100 SetSecurityMode(kSecurityModeNone);
101 SetHwMode(kHwMode80211g);
102 SetOperationMode(kOperationModeServer);
103 SetServerAddressIndex(kPropertyDefaultServerAddressIndex);
104 SetChannel(kPropertyDefaultChannel);
105 SetHiddenNetwork(kPropertyDefaultHiddenNetwork);
Peter Qiu0ca183b2015-03-09 13:41:06 -0700106 SetFullDeviceControl(true);
Peter Qiuf0731732014-11-11 09:46:41 -0800107}
108
109Config::~Config() {}
110
Peter Qiu8e785b92014-11-24 10:01:08 -0800111// static.
112bool Config::GetFrequencyFromChannel(uint16_t channel, uint32_t* freq) {
113 bool ret_value = true;
114 if (channel >= kBand24GHzChannelLow && channel <= kBand24GHzChannelHigh) {
115 *freq = kBand24GHzBaseFrequency + (channel - kBand24GHzChannelLow) * 5;
116 } else if (channel >= kBand5GHzChannelLow &&
117 channel <= kBand5GHzChannelHigh) {
118 *freq = kBand5GHzBaseFrequency + (channel - kBand5GHzChannelLow) * 5;
119 } else {
120 ret_value = false;
121 }
122 return ret_value;
123}
124
Peter Qiu68303292014-12-10 10:42:13 -0800125bool Config::ValidateSsid(ErrorPtr* error, const string& value) {
126 if (value.length() < kSsidMinLength || value.length() > kSsidMaxLength) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700127 brillo::Error::AddToPrintf(
128 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu68303292014-12-10 10:42:13 -0800129 "SSID must contain between %d and %d characters",
130 kSsidMinLength, kSsidMaxLength);
131 return false;
132 }
Peter Qiubf8e36c2014-12-03 22:59:45 -0800133 return true;
134}
135
Peter Qiu68303292014-12-10 10:42:13 -0800136bool Config::ValidateSecurityMode(ErrorPtr* error, const string& value) {
137 if (value != kSecurityModeNone && value != kSecurityModeRSN) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700138 brillo::Error::AddToPrintf(
139 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu68303292014-12-10 10:42:13 -0800140 "Invalid/unsupported security mode [%s]", value.c_str());
141 return false;
142 }
143 return true;
144}
145
146bool Config::ValidatePassphrase(ErrorPtr* error, const string& value) {
147 if (value.length() < kPassphraseMinLength ||
148 value.length() > kPassphraseMaxLength) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700149 brillo::Error::AddToPrintf(
150 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu68303292014-12-10 10:42:13 -0800151 "Passphrase must contain between %d and %d characters",
152 kPassphraseMinLength, kPassphraseMaxLength);
153 return false;
154 }
155 return true;
156}
157
158bool Config::ValidateHwMode(ErrorPtr* error, const string& value) {
159 if (value != kHwMode80211a && value != kHwMode80211b &&
160 value != kHwMode80211g && value != kHwMode80211n &&
161 value != kHwMode80211ac) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700162 brillo::Error::AddToPrintf(
163 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu68303292014-12-10 10:42:13 -0800164 "Invalid HW mode [%s]", value.c_str());
165 return false;
166 }
167 return true;
168}
169
170bool Config::ValidateOperationMode(ErrorPtr* error, const string& value) {
171 if (value != kOperationModeServer && value != kOperationModeBridge) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700172 brillo::Error::AddToPrintf(
173 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu68303292014-12-10 10:42:13 -0800174 "Invalid operation mode [%s]", value.c_str());
175 return false;
176 }
177 return true;
178}
179
180bool Config::ValidateChannel(ErrorPtr* error, const uint16_t& value) {
181 if ((value >= kBand24GHzChannelLow && value <= kBand24GHzChannelHigh) ||
182 (value >= kBand5GHzChannelLow && value <= kBand5GHzChannelHigh)) {
183 return true;
184 }
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700185 brillo::Error::AddToPrintf(
186 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu68303292014-12-10 10:42:13 -0800187 "Invalid channel [%d]", value);
188 return false;
189}
190
Peter Qiu376e4042014-11-13 09:40:28 -0800191void Config::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800192 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -0800193 AsyncEventSequencer* sequencer) {
194 CHECK(!dbus_object_) << "Already registered";
195 dbus_object_.reset(
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700196 new brillo::dbus_utils::DBusObject(
Peter Qiu376e4042014-11-13 09:40:28 -0800197 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800198 bus,
Peter Qiu376e4042014-11-13 09:40:28 -0800199 dbus_path_));
200 RegisterWithDBusObject(dbus_object_.get());
201 dbus_object_->RegisterAsync(
202 sequencer->GetHandler("Config.RegisterAsync() failed.", true));
203}
204
Peter Qiuf0731732014-11-11 09:46:41 -0800205bool Config::GenerateConfigFile(ErrorPtr* error, string* config_str) {
206 // SSID.
207 string ssid = GetSsid();
208 if (ssid.empty()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700209 brillo::Error::AddTo(
210 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu376e4042014-11-13 09:40:28 -0800211 "SSID not specified");
Peter Qiuf0731732014-11-11 09:46:41 -0800212 return false;
213 }
214 base::StringAppendF(
215 config_str, "%s=%s\n", kHostapdConfigKeySsid, ssid.c_str());
216
Peter Qiu68303292014-12-10 10:42:13 -0800217 // Bridge interface is required for bridge mode operation.
218 if (GetOperationMode() == kOperationModeBridge) {
219 if (GetBridgeInterface().empty()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700220 brillo::Error::AddTo(
221 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu68303292014-12-10 10:42:13 -0800222 "Bridge interface not specified, required for bridge mode");
223 return false;
224 }
225 base::StringAppendF(config_str,
226 "%s=%s\n",
227 kHostapdConfigKeyBridgeInterface,
228 GetBridgeInterface().c_str());
229 }
230
Peter Qiuf0731732014-11-11 09:46:41 -0800231 // Channel.
232 base::StringAppendF(
233 config_str, "%s=%d\n", kHostapdConfigKeyChannel, GetChannel());
234
Peter Qiu8e785b92014-11-24 10:01:08 -0800235 // Interface.
236 if (!AppendInterface(error, config_str)) {
Peter Qiuf0731732014-11-11 09:46:41 -0800237 return false;
238 }
239
Peter Qiu8e785b92014-11-24 10:01:08 -0800240 // Hardware mode.
241 if (!AppendHwMode(error, config_str)) {
Peter Qiuf0731732014-11-11 09:46:41 -0800242 return false;
243 }
244
245 // Security mode configurations.
246 if (!AppendSecurityMode(error, config_str)) {
247 return false;
248 }
249
Peter Qiubfd410e2015-01-09 15:14:20 -0800250 // Control interface.
251 if (!control_interface_.empty()) {
252 base::StringAppendF(config_str,
253 "%s=%s\n",
254 kHostapdConfigKeyControlInterface,
255 control_interface_.c_str());
256 base::StringAppendF(config_str,
257 "%s=%s\n",
258 kHostapdConfigKeyControlInterfaceGroup,
259 Daemon::kAPManagerGroupName);
260 }
261
Peter Qiuf0731732014-11-11 09:46:41 -0800262 // Hostapd default configurations.
263 if (!AppendHostapdDefaults(error, config_str)) {
264 return false;
265 }
266
267 return true;
268}
269
Peter Qiufb39ba42014-11-21 09:09:59 -0800270bool Config::ClaimDevice() {
271 if (!device_) {
272 LOG(ERROR) << "Failed to claim device: device doesn't exist.";
273 return false;
274 }
Peter Qiu0ca183b2015-03-09 13:41:06 -0700275 return device_->ClaimDevice(GetFullDeviceControl());
Peter Qiufb39ba42014-11-21 09:09:59 -0800276}
277
278bool Config::ReleaseDevice() {
279 if (!device_) {
280 LOG(ERROR) << "Failed to release device: device doesn't exist.";
281 return false;
282 }
283 return device_->ReleaseDevice();
284}
285
Peter Qiu376e4042014-11-13 09:40:28 -0800286bool Config::AppendHwMode(ErrorPtr* error, std::string* config_str) {
Peter Qiuf0731732014-11-11 09:46:41 -0800287 string hw_mode = GetHwMode();
288 string hostapd_hw_mode;
289 if (hw_mode == kHwMode80211a) {
290 hostapd_hw_mode = kHostapdHwMode80211a;
291 } else if (hw_mode == kHwMode80211b) {
292 hostapd_hw_mode = kHostapdHwMode80211b;
293 } else if (hw_mode == kHwMode80211g) {
294 hostapd_hw_mode = kHostapdHwMode80211g;
295 } else if (hw_mode == kHwMode80211n) {
296 // Use 802.11a for 5GHz channel and 802.11g for 2.4GHz channel
297 if (GetChannel() >= 34) {
298 hostapd_hw_mode = kHostapdHwMode80211a;
299 } else {
300 hostapd_hw_mode = kHostapdHwMode80211g;
301 }
302 base::StringAppendF(config_str, "%s=1\n", kHostapdConfigKeyIeee80211n);
303
Peter Qiu8e785b92014-11-24 10:01:08 -0800304 // Get HT Capability.
305 string ht_cap;
306 if (!device_->GetHTCapability(GetChannel(), &ht_cap)) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700307 brillo::Error::AddTo(
308 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu8e785b92014-11-24 10:01:08 -0800309 "Failed to get HT Capability");
310 return false;
311 }
312 base::StringAppendF(config_str, "%s=%s\n",
313 kHostapdConfigKeyHTCapability,
314 ht_cap.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800315 } else if (hw_mode == kHwMode80211ac) {
316 if (GetChannel() >= 34) {
317 hostapd_hw_mode = kHostapdHwMode80211a;
318 } else {
319 hostapd_hw_mode = kHostapdHwMode80211g;
320 }
321 base::StringAppendF(config_str, "%s=1\n", kHostapdConfigKeyIeee80211ac);
322
323 // TODO(zqiu): Determine VHT Capabilities based on the interface PHY's
324 // capababilites.
325 } else {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700326 brillo::Error::AddToPrintf(
327 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu376e4042014-11-13 09:40:28 -0800328 "Invalid hardware mode: %s", hw_mode.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800329 return false;
330 }
331
332 base::StringAppendF(
333 config_str, "%s=%s\n", kHostapdConfigKeyHwMode, hostapd_hw_mode.c_str());
334 return true;
335}
336
Peter Qiu376e4042014-11-13 09:40:28 -0800337bool Config::AppendHostapdDefaults(ErrorPtr* error,
Peter Qiuf0731732014-11-11 09:46:41 -0800338 std::string* config_str) {
339 // Driver: NL80211.
340 base::StringAppendF(
341 config_str, "%s=%s\n", kHostapdConfigKeyDriver, kHostapdDefaultDriver);
342
343 // Fragmentation threshold: disabled.
344 base::StringAppendF(config_str,
345 "%s=%d\n",
346 kHostapdConfigKeyFragmThreshold,
347 kHostapdDefaultFragmThreshold);
348
349 // RTS threshold: disabled.
350 base::StringAppendF(config_str,
351 "%s=%d\n",
352 kHostapdConfigKeyRtsThreshold,
353 kHostapdDefaultRtsThreshold);
354
355 return true;
356}
357
Peter Qiu376e4042014-11-13 09:40:28 -0800358bool Config::AppendInterface(ErrorPtr* error,
Peter Qiuf0731732014-11-11 09:46:41 -0800359 std::string* config_str) {
360 string interface = GetInterfaceName();
361 if (interface.empty()) {
Peter Qiufb39ba42014-11-21 09:09:59 -0800362 // Ask manager for unused ap capable device.
363 device_ = manager_->GetAvailableDevice();
364 if (!device_) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700365 brillo::Error::AddTo(
366 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiufb39ba42014-11-21 09:09:59 -0800367 "No device available");
368 return false;
369 }
370 } else {
371 device_ = manager_->GetDeviceFromInterfaceName(interface);
Peter Qiu68303292014-12-10 10:42:13 -0800372 if (!device_) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700373 brillo::Error::AddToPrintf(
374 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu68303292014-12-10 10:42:13 -0800375 "Unable to find device for the specified interface [%s]",
376 interface.c_str());
377 return false;
378 }
Garret Kelly0c0e9e72015-09-01 17:28:01 -0400379 if (device_->GetInUse()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700380 brillo::Error::AddToPrintf(
381 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiufb39ba42014-11-21 09:09:59 -0800382 "Device [%s] for interface [%s] already in use",
383 device_->GetDeviceName().c_str(),
384 interface.c_str());
385 return false;
386 }
Peter Qiuf0731732014-11-11 09:46:41 -0800387 }
388
Peter Qiufb39ba42014-11-21 09:09:59 -0800389 // Use the preferred AP interface from the device.
Peter Qiubf8e36c2014-12-03 22:59:45 -0800390 selected_interface_ = device_->GetPreferredApInterface();
391 base::StringAppendF(config_str,
392 "%s=%s\n",
393 kHostapdConfigKeyInterface,
394 selected_interface_.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800395 return true;
396}
397
Peter Qiu376e4042014-11-13 09:40:28 -0800398bool Config::AppendSecurityMode(ErrorPtr* error,
Peter Qiuf0731732014-11-11 09:46:41 -0800399 std::string* config_str) {
400 string security_mode = GetSecurityMode();
401 if (security_mode == kSecurityModeNone) {
402 // Nothing need to be done for open network.
403 return true;
404 }
405
406 if (security_mode == kSecurityModeRSN) {
407 string passphrase = GetPassphrase();
408 if (passphrase.empty()) {
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700409 brillo::Error::AddToPrintf(
410 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu376e4042014-11-13 09:40:28 -0800411 "Passphrase not set for security mode: %s", security_mode.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800412 return false;
413 }
414
415 base::StringAppendF(config_str, "%s=2\n", kHostapdConfigKeyWpa);
416 base::StringAppendF(config_str,
417 "%s=%s\n",
418 kHostapdConfigKeyRsnPairwise,
419 kHostapdDefaultRsnPairwise);
420 base::StringAppendF(config_str,
421 "%s=%s\n",
422 kHostapdConfigKeyWpaKeyMgmt,
423 kHostapdDefaultWpaKeyMgmt);
424 base::StringAppendF(config_str,
425 "%s=%s\n",
426 kHostapdConfigKeyWpaPassphrase,
427 passphrase.c_str());
428 return true;
429 }
430
Alex Vakulenko8d0c31b2015-10-13 09:14:24 -0700431 brillo::Error::AddToPrintf(
432 error, FROM_HERE, brillo::errors::dbus::kDomain, kConfigError,
Peter Qiu376e4042014-11-13 09:40:28 -0800433 "Invalid security mode: %s", security_mode.c_str());
434 return false;
Peter Qiuf0731732014-11-11 09:46:41 -0800435}
436
437} // namespace apmanager