blob: 5d1e8a1123f1d375148f9da7a9a722cbd91f60f8 [file] [log] [blame]
Peter Qiuf0731732014-11-11 09:46:41 -08001// Copyright 2014 The Chromium OS 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 "apmanager/config.h"
6
7#include <base/strings/stringprintf.h>
8#include <chromeos/dbus/service_constants.h>
9
Peter Qiufb39ba42014-11-21 09:09:59 -080010#include "apmanager/device.h"
11#include "apmanager/manager.h"
12
Peter Qiu376e4042014-11-13 09:40:28 -080013using chromeos::dbus_utils::AsyncEventSequencer;
14using chromeos::dbus_utils::ExportedObjectManager;
Peter Qiuf0731732014-11-11 09:46:41 -080015using chromeos::ErrorPtr;
16using std::string;
17
18namespace apmanager {
19
20// static
21const char Config::kHostapdConfigKeyBridgeInterface[] = "bridge";
22const char Config::kHostapdConfigKeyChannel[] = "channel";
23const char Config::kHostapdConfigKeyControlInterface[] = "ctrl_interface";
24const char Config::kHostapdConfigKeyDriver[] = "driver";
25const char Config::kHostapdConfigKeyFragmThreshold[] = "fragm_threshold";
Peter Qiu8e785b92014-11-24 10:01:08 -080026const char Config::kHostapdConfigKeyHTCapability[] = "ht_capab";
Peter Qiuf0731732014-11-11 09:46:41 -080027const char Config::kHostapdConfigKeyHwMode[] = "hw_mode";
28const char Config::kHostapdConfigKeyIeee80211ac[] = "ieee80211ac";
29const char Config::kHostapdConfigKeyIeee80211n[] = "ieee80211n";
30const char Config::kHostapdConfigKeyIgnoreBroadcastSsid[] =
31 "ignore_broadcast_ssid";
32const char Config::kHostapdConfigKeyInterface[] = "interface";
33const char Config::kHostapdConfigKeyRsnPairwise[] = "rsn_pairwise";
34const char Config::kHostapdConfigKeyRtsThreshold[] = "rts_threshold";
35const char Config::kHostapdConfigKeySsid[] = "ssid";
36const char Config::kHostapdConfigKeyWepDefaultKey[] = "wep_default_key";
37const char Config::kHostapdConfigKeyWepKey0[] = "wep_key0";
38const char Config::kHostapdConfigKeyWpa[] = "wpa";
39const char Config::kHostapdConfigKeyWpaKeyMgmt[] = "wpa_key_mgmt";
40const char Config::kHostapdConfigKeyWpaPassphrase[] = "wpa_passphrase";
41
42const char Config::kHostapdHwMode80211a[] = "a";
43const char Config::kHostapdHwMode80211b[] = "b";
44const char Config::kHostapdHwMode80211g[] = "g";
45
46// static
47const uint16_t Config::kPropertyDefaultChannel = 6;
48const uint16_t Config::kPropertyDefaultServerAddressIndex = 0;
49const bool Config::kPropertyDefaultHiddenNetwork = false;
50
51// static
52const char Config::kHostapdDefaultDriver[] = "nl80211";
53const char Config::kHostapdDefaultRsnPairwise[] = "CCMP";
54const char Config::kHostapdDefaultWpaKeyMgmt[] = "WPA-PSK";
55// Fragmentation threshold: disabled.
56const int Config::kHostapdDefaultFragmThreshold = 2346;
57// RTS threshold: disabled.
58const int Config::kHostapdDefaultRtsThreshold = 2347;
59
Peter Qiu8e785b92014-11-24 10:01:08 -080060// static
61const uint16_t Config::kBand24GHzChannelLow = 1;
62const uint16_t Config::kBand24GHzChannelHigh = 13;
63const uint32_t Config::kBand24GHzBaseFrequency = 2412;
64const uint16_t Config::kBand5GHzChannelLow = 34;
65const uint16_t Config::kBand5GHzChannelHigh = 165;
66const uint16_t Config::kBand5GHzBaseFrequency = 5170;
67
Peter Qiu68303292014-12-10 10:42:13 -080068// static
69const int Config::kSsidMinLength = 1;
70const int Config::kSsidMaxLength = 32;
71const int Config::kPassphraseMinLength = 8;
72const int Config::kPassphraseMaxLength = 63;
73
Peter Qiufb39ba42014-11-21 09:09:59 -080074Config::Config(Manager* manager, const string& service_path)
Peter Qiuf0731732014-11-11 09:46:41 -080075 : org::chromium::apmanager::ConfigAdaptor(this),
Peter Qiufb39ba42014-11-21 09:09:59 -080076 manager_(manager),
Peter Qiuf0731732014-11-11 09:46:41 -080077 dbus_path_(dbus::ObjectPath(
78 base::StringPrintf("%s/config", service_path.c_str()))) {
79 // Initialize default configuration values.
80 SetSecurityMode(kSecurityModeNone);
81 SetHwMode(kHwMode80211g);
82 SetOperationMode(kOperationModeServer);
83 SetServerAddressIndex(kPropertyDefaultServerAddressIndex);
84 SetChannel(kPropertyDefaultChannel);
85 SetHiddenNetwork(kPropertyDefaultHiddenNetwork);
86}
87
88Config::~Config() {}
89
Peter Qiu8e785b92014-11-24 10:01:08 -080090// static.
91bool Config::GetFrequencyFromChannel(uint16_t channel, uint32_t* freq) {
92 bool ret_value = true;
93 if (channel >= kBand24GHzChannelLow && channel <= kBand24GHzChannelHigh) {
94 *freq = kBand24GHzBaseFrequency + (channel - kBand24GHzChannelLow) * 5;
95 } else if (channel >= kBand5GHzChannelLow &&
96 channel <= kBand5GHzChannelHigh) {
97 *freq = kBand5GHzBaseFrequency + (channel - kBand5GHzChannelLow) * 5;
98 } else {
99 ret_value = false;
100 }
101 return ret_value;
102}
103
Peter Qiu68303292014-12-10 10:42:13 -0800104bool Config::ValidateSsid(ErrorPtr* error, const string& value) {
105 if (value.length() < kSsidMinLength || value.length() > kSsidMaxLength) {
106 chromeos::Error::AddToPrintf(
107 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
108 "SSID must contain between %d and %d characters",
109 kSsidMinLength, kSsidMaxLength);
110 return false;
111 }
Peter Qiubf8e36c2014-12-03 22:59:45 -0800112 return true;
113}
114
Peter Qiu68303292014-12-10 10:42:13 -0800115bool Config::ValidateSecurityMode(ErrorPtr* error, const string& value) {
116 if (value != kSecurityModeNone && value != kSecurityModeRSN) {
117 chromeos::Error::AddToPrintf(
118 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
119 "Invalid/unsupported security mode [%s]", value.c_str());
120 return false;
121 }
122 return true;
123}
124
125bool Config::ValidatePassphrase(ErrorPtr* error, const string& value) {
126 if (value.length() < kPassphraseMinLength ||
127 value.length() > kPassphraseMaxLength) {
128 chromeos::Error::AddToPrintf(
129 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
130 "Passphrase must contain between %d and %d characters",
131 kPassphraseMinLength, kPassphraseMaxLength);
132 return false;
133 }
134 return true;
135}
136
137bool Config::ValidateHwMode(ErrorPtr* error, const string& value) {
138 if (value != kHwMode80211a && value != kHwMode80211b &&
139 value != kHwMode80211g && value != kHwMode80211n &&
140 value != kHwMode80211ac) {
141 chromeos::Error::AddToPrintf(
142 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
143 "Invalid HW mode [%s]", value.c_str());
144 return false;
145 }
146 return true;
147}
148
149bool Config::ValidateOperationMode(ErrorPtr* error, const string& value) {
150 if (value != kOperationModeServer && value != kOperationModeBridge) {
151 chromeos::Error::AddToPrintf(
152 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
153 "Invalid operation mode [%s]", value.c_str());
154 return false;
155 }
156 return true;
157}
158
159bool Config::ValidateChannel(ErrorPtr* error, const uint16_t& value) {
160 if ((value >= kBand24GHzChannelLow && value <= kBand24GHzChannelHigh) ||
161 (value >= kBand5GHzChannelLow && value <= kBand5GHzChannelHigh)) {
162 return true;
163 }
164 chromeos::Error::AddToPrintf(
165 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
166 "Invalid channel [%d]", value);
167 return false;
168}
169
Peter Qiu376e4042014-11-13 09:40:28 -0800170void Config::RegisterAsync(ExportedObjectManager* object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800171 const scoped_refptr<dbus::Bus>& bus,
Peter Qiu376e4042014-11-13 09:40:28 -0800172 AsyncEventSequencer* sequencer) {
173 CHECK(!dbus_object_) << "Already registered";
174 dbus_object_.reset(
175 new chromeos::dbus_utils::DBusObject(
176 object_manager,
Peter Qiuc9ce1f12014-12-05 11:14:29 -0800177 bus,
Peter Qiu376e4042014-11-13 09:40:28 -0800178 dbus_path_));
179 RegisterWithDBusObject(dbus_object_.get());
180 dbus_object_->RegisterAsync(
181 sequencer->GetHandler("Config.RegisterAsync() failed.", true));
182}
183
Peter Qiuf0731732014-11-11 09:46:41 -0800184bool Config::GenerateConfigFile(ErrorPtr* error, string* config_str) {
185 // SSID.
186 string ssid = GetSsid();
187 if (ssid.empty()) {
Peter Qiu376e4042014-11-13 09:40:28 -0800188 chromeos::Error::AddTo(
189 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
190 "SSID not specified");
Peter Qiuf0731732014-11-11 09:46:41 -0800191 return false;
192 }
193 base::StringAppendF(
194 config_str, "%s=%s\n", kHostapdConfigKeySsid, ssid.c_str());
195
Peter Qiu68303292014-12-10 10:42:13 -0800196 // Bridge interface is required for bridge mode operation.
197 if (GetOperationMode() == kOperationModeBridge) {
198 if (GetBridgeInterface().empty()) {
199 chromeos::Error::AddTo(
200 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
201 "Bridge interface not specified, required for bridge mode");
202 return false;
203 }
204 base::StringAppendF(config_str,
205 "%s=%s\n",
206 kHostapdConfigKeyBridgeInterface,
207 GetBridgeInterface().c_str());
208 }
209
Peter Qiuf0731732014-11-11 09:46:41 -0800210 // Channel.
211 base::StringAppendF(
212 config_str, "%s=%d\n", kHostapdConfigKeyChannel, GetChannel());
213
Peter Qiu8e785b92014-11-24 10:01:08 -0800214 // Interface.
215 if (!AppendInterface(error, config_str)) {
Peter Qiuf0731732014-11-11 09:46:41 -0800216 return false;
217 }
218
Peter Qiu8e785b92014-11-24 10:01:08 -0800219 // Hardware mode.
220 if (!AppendHwMode(error, config_str)) {
Peter Qiuf0731732014-11-11 09:46:41 -0800221 return false;
222 }
223
224 // Security mode configurations.
225 if (!AppendSecurityMode(error, config_str)) {
226 return false;
227 }
228
229 // Hostapd default configurations.
230 if (!AppendHostapdDefaults(error, config_str)) {
231 return false;
232 }
233
234 return true;
235}
236
Peter Qiufb39ba42014-11-21 09:09:59 -0800237bool Config::ClaimDevice() {
238 if (!device_) {
239 LOG(ERROR) << "Failed to claim device: device doesn't exist.";
240 return false;
241 }
242 return device_->ClaimDevice();
243}
244
245bool Config::ReleaseDevice() {
246 if (!device_) {
247 LOG(ERROR) << "Failed to release device: device doesn't exist.";
248 return false;
249 }
250 return device_->ReleaseDevice();
251}
252
Peter Qiu376e4042014-11-13 09:40:28 -0800253bool Config::AppendHwMode(ErrorPtr* error, std::string* config_str) {
Peter Qiuf0731732014-11-11 09:46:41 -0800254 string hw_mode = GetHwMode();
255 string hostapd_hw_mode;
256 if (hw_mode == kHwMode80211a) {
257 hostapd_hw_mode = kHostapdHwMode80211a;
258 } else if (hw_mode == kHwMode80211b) {
259 hostapd_hw_mode = kHostapdHwMode80211b;
260 } else if (hw_mode == kHwMode80211g) {
261 hostapd_hw_mode = kHostapdHwMode80211g;
262 } else if (hw_mode == kHwMode80211n) {
263 // Use 802.11a for 5GHz channel and 802.11g for 2.4GHz channel
264 if (GetChannel() >= 34) {
265 hostapd_hw_mode = kHostapdHwMode80211a;
266 } else {
267 hostapd_hw_mode = kHostapdHwMode80211g;
268 }
269 base::StringAppendF(config_str, "%s=1\n", kHostapdConfigKeyIeee80211n);
270
Peter Qiu8e785b92014-11-24 10:01:08 -0800271 // Get HT Capability.
272 string ht_cap;
273 if (!device_->GetHTCapability(GetChannel(), &ht_cap)) {
274 chromeos::Error::AddTo(
275 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
276 "Failed to get HT Capability");
277 return false;
278 }
279 base::StringAppendF(config_str, "%s=%s\n",
280 kHostapdConfigKeyHTCapability,
281 ht_cap.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800282 } else if (hw_mode == kHwMode80211ac) {
283 if (GetChannel() >= 34) {
284 hostapd_hw_mode = kHostapdHwMode80211a;
285 } else {
286 hostapd_hw_mode = kHostapdHwMode80211g;
287 }
288 base::StringAppendF(config_str, "%s=1\n", kHostapdConfigKeyIeee80211ac);
289
290 // TODO(zqiu): Determine VHT Capabilities based on the interface PHY's
291 // capababilites.
292 } else {
Peter Qiu376e4042014-11-13 09:40:28 -0800293 chromeos::Error::AddToPrintf(
294 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
295 "Invalid hardware mode: %s", hw_mode.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800296 return false;
297 }
298
299 base::StringAppendF(
300 config_str, "%s=%s\n", kHostapdConfigKeyHwMode, hostapd_hw_mode.c_str());
301 return true;
302}
303
Peter Qiu376e4042014-11-13 09:40:28 -0800304bool Config::AppendHostapdDefaults(ErrorPtr* error,
Peter Qiuf0731732014-11-11 09:46:41 -0800305 std::string* config_str) {
306 // Driver: NL80211.
307 base::StringAppendF(
308 config_str, "%s=%s\n", kHostapdConfigKeyDriver, kHostapdDefaultDriver);
309
310 // Fragmentation threshold: disabled.
311 base::StringAppendF(config_str,
312 "%s=%d\n",
313 kHostapdConfigKeyFragmThreshold,
314 kHostapdDefaultFragmThreshold);
315
316 // RTS threshold: disabled.
317 base::StringAppendF(config_str,
318 "%s=%d\n",
319 kHostapdConfigKeyRtsThreshold,
320 kHostapdDefaultRtsThreshold);
321
322 return true;
323}
324
Peter Qiu376e4042014-11-13 09:40:28 -0800325bool Config::AppendInterface(ErrorPtr* error,
Peter Qiuf0731732014-11-11 09:46:41 -0800326 std::string* config_str) {
327 string interface = GetInterfaceName();
328 if (interface.empty()) {
Peter Qiufb39ba42014-11-21 09:09:59 -0800329 // Ask manager for unused ap capable device.
330 device_ = manager_->GetAvailableDevice();
331 if (!device_) {
332 chromeos::Error::AddTo(
333 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
334 "No device available");
335 return false;
336 }
337 } else {
338 device_ = manager_->GetDeviceFromInterfaceName(interface);
Peter Qiu68303292014-12-10 10:42:13 -0800339 if (!device_) {
340 chromeos::Error::AddToPrintf(
341 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
342 "Unable to find device for the specified interface [%s]",
343 interface.c_str());
344 return false;
345 }
Peter Qiufb39ba42014-11-21 09:09:59 -0800346 if (device_->GetInUsed()) {
347 chromeos::Error::AddToPrintf(
348 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
349 "Device [%s] for interface [%s] already in use",
350 device_->GetDeviceName().c_str(),
351 interface.c_str());
352 return false;
353 }
Peter Qiuf0731732014-11-11 09:46:41 -0800354 }
355
Peter Qiufb39ba42014-11-21 09:09:59 -0800356 // Use the preferred AP interface from the device.
Peter Qiubf8e36c2014-12-03 22:59:45 -0800357 selected_interface_ = device_->GetPreferredApInterface();
358 base::StringAppendF(config_str,
359 "%s=%s\n",
360 kHostapdConfigKeyInterface,
361 selected_interface_.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800362 return true;
363}
364
Peter Qiu376e4042014-11-13 09:40:28 -0800365bool Config::AppendSecurityMode(ErrorPtr* error,
Peter Qiuf0731732014-11-11 09:46:41 -0800366 std::string* config_str) {
367 string security_mode = GetSecurityMode();
368 if (security_mode == kSecurityModeNone) {
369 // Nothing need to be done for open network.
370 return true;
371 }
372
373 if (security_mode == kSecurityModeRSN) {
374 string passphrase = GetPassphrase();
375 if (passphrase.empty()) {
Peter Qiu376e4042014-11-13 09:40:28 -0800376 chromeos::Error::AddToPrintf(
377 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
378 "Passphrase not set for security mode: %s", security_mode.c_str());
Peter Qiuf0731732014-11-11 09:46:41 -0800379 return false;
380 }
381
382 base::StringAppendF(config_str, "%s=2\n", kHostapdConfigKeyWpa);
383 base::StringAppendF(config_str,
384 "%s=%s\n",
385 kHostapdConfigKeyRsnPairwise,
386 kHostapdDefaultRsnPairwise);
387 base::StringAppendF(config_str,
388 "%s=%s\n",
389 kHostapdConfigKeyWpaKeyMgmt,
390 kHostapdDefaultWpaKeyMgmt);
391 base::StringAppendF(config_str,
392 "%s=%s\n",
393 kHostapdConfigKeyWpaPassphrase,
394 passphrase.c_str());
395 return true;
396 }
397
Peter Qiuf0731732014-11-11 09:46:41 -0800398 chromeos::Error::AddToPrintf(
Peter Qiu376e4042014-11-13 09:40:28 -0800399 error, FROM_HERE, chromeos::errors::dbus::kDomain, kConfigError,
400 "Invalid security mode: %s", security_mode.c_str());
401 return false;
Peter Qiuf0731732014-11-11 09:46:41 -0800402}
403
404} // namespace apmanager