1 // 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 // 16 17 #include "apmanager/service.h" 18 19 #include <signal.h> 20 21 #include <base/bind.h> 22 #include <base/strings/stringprintf.h> 23 #include <brillo/errors/error.h> 24 25 #if !defined(__ANDROID__) 26 #include <chromeos/dbus/service_constants.h> 27 #else 28 #include <dbus/apmanager/dbus-constants.h> 29 #endif // __ANDROID__ 30 31 #if defined(__BRILLO__) 32 #include "apmanager/event_dispatcher.h" 33 #endif // __BRILLO__ 34 35 #include "apmanager/control_interface.h" 36 #include "apmanager/manager.h" 37 38 using std::string; 39 40 namespace apmanager { 41 42 // static. 43 #if !defined(__ANDROID__) 44 const char Service::kHostapdPath[] = "/usr/sbin/hostapd"; 45 const char Service::kHostapdConfigPathFormat[] = 46 "/var/run/apmanager/hostapd/hostapd-%d.conf"; 47 const char Service::kHostapdControlInterfacePath[] = 48 "/var/run/apmanager/hostapd/ctrl_iface"; 49 #else 50 const char Service::kHostapdPath[] = "/system/bin/hostapd"; 51 const char Service::kHostapdConfigPathFormat[] = 52 "/data/misc/apmanager/hostapd/hostapd-%d.conf"; 53 const char Service::kHostapdControlInterfacePath[] = 54 "/data/misc/apmanager/hostapd/ctrl_iface"; 55 #endif // __ANDROID__ 56 57 #if defined(__BRILLO__) 58 const int Service::kAPInterfaceCheckIntervalMilliseconds = 200; 59 const int Service::kAPInterfaceCheckMaxAttempts = 5; 60 #endif // __BRILLO__ 61 62 const int Service::kTerminationTimeoutSeconds = 2; 63 64 // static. Service state definitions. 65 const char Service::kStateIdle[] = "Idle"; 66 const char Service::kStateStarting[] = "Starting"; 67 const char Service::kStateStarted[] = "Started"; 68 const char Service::kStateFailed[] = "Failed"; 69 70 Service::Service(Manager* manager, int service_identifier) 71 : manager_(manager), 72 identifier_(service_identifier), 73 config_(new Config(manager, service_identifier)), 74 adaptor_(manager->control_interface()->CreateServiceAdaptor(this)), 75 dhcp_server_factory_(DHCPServerFactory::GetInstance()), 76 file_writer_(FileWriter::GetInstance()), 77 process_factory_(ProcessFactory::GetInstance()) { 78 adaptor_->SetConfig(config_.get()); 79 adaptor_->SetState(kStateIdle); 80 // TODO(zqiu): come up with better server address management. This is good 81 // enough for now. 82 config_->SetServerAddressIndex(identifier_ & 0xFF); 83 84 #if defined(__BRILLO__) 85 event_dispatcher_ = EventDispatcher::GetInstance(); 86 start_in_progress_ = false; 87 #endif 88 } 89 90 Service::~Service() { 91 // Stop hostapd process if still running. 92 if (IsHostapdRunning()) { 93 ReleaseResources(); 94 } 95 } 96 97 bool Service::StartInternal(Error* error) { 98 if (IsHostapdRunning()) { 99 Error::PopulateAndLog( 100 error, Error::kInternalError, "Service already running", FROM_HERE); 101 return false; 102 } 103 104 // Setup hostapd control interface path. 105 config_->set_control_interface(kHostapdControlInterfacePath); 106 107 // Generate hostapd configuration content. 108 string config_str; 109 if (!config_->GenerateConfigFile(error, &config_str)) { 110 return false; 111 } 112 113 // Write configuration to a file. 114 string config_file_name = base::StringPrintf(kHostapdConfigPathFormat, 115 identifier_); 116 if (!file_writer_->Write(config_file_name, config_str)) { 117 Error::PopulateAndLog(error, 118 Error::kInternalError, 119 "Failed to write configuration to a file", 120 FROM_HERE); 121 return false; 122 } 123 124 // Claim the device needed for this ap service. 125 if (!config_->ClaimDevice()) { 126 Error::PopulateAndLog(error, 127 Error::kInternalError, 128 "Failed to claim the device for this service", 129 FROM_HERE); 130 return false; 131 } 132 133 // Start hostapd process. 134 if (!StartHostapdProcess(config_file_name)) { 135 Error::PopulateAndLog( 136 error, Error::kInternalError, "Failed to start hostapd", FROM_HERE); 137 // Release the device claimed for this service. 138 config_->ReleaseDevice(); 139 return false; 140 } 141 142 // Start DHCP server if in server mode. 143 if (config_->GetOperationMode() == kOperationModeServer) { 144 dhcp_server_.reset( 145 dhcp_server_factory_->CreateDHCPServer(config_->GetServerAddressIndex(), 146 config_->selected_interface())); 147 if (!dhcp_server_->Start()) { 148 Error::PopulateAndLog(error, 149 Error::kInternalError, 150 "Failed to start DHCP server", 151 FROM_HERE); 152 ReleaseResources(); 153 return false; 154 } 155 manager_->RequestDHCPPortAccess(config_->selected_interface()); 156 } 157 158 // Start monitoring hostapd. 159 if (!hostapd_monitor_) { 160 hostapd_monitor_.reset( 161 new HostapdMonitor(base::Bind(&Service::HostapdEventCallback, 162 weak_factory_.GetWeakPtr()), 163 config_->control_interface(), 164 config_->selected_interface())); 165 } 166 hostapd_monitor_->Start(); 167 168 // Update service state. 169 adaptor_->SetState(kStateStarting); 170 171 return true; 172 } 173 174 void Service::Start(const base::Callback<void(const Error&)>& result_callback) { 175 Error error; 176 177 #if !defined(__BRILLO__) 178 StartInternal(&error); 179 result_callback.Run(error); 180 #else 181 if (start_in_progress_) { 182 Error::PopulateAndLog( 183 &error, Error::kInternalError, "Start already in progress", FROM_HERE); 184 result_callback.Run(error); 185 return; 186 } 187 188 string interface_name; 189 if (!manager_->SetupApModeInterface(&interface_name)) { 190 Error::PopulateAndLog(&error, 191 Error::kInternalError, 192 "Failed to setup AP mode interface", 193 FROM_HERE); 194 result_callback.Run(error); 195 return; 196 } 197 198 event_dispatcher_->PostDelayedTask( 199 base::Bind(&Service::APInterfaceCheckTask, 200 weak_factory_.GetWeakPtr(), 201 interface_name, 202 0, // Initial check count. 203 result_callback), 204 kAPInterfaceCheckIntervalMilliseconds); 205 #endif 206 } 207 208 bool Service::Stop(Error* error) { 209 if (!IsHostapdRunning()) { 210 Error::PopulateAndLog(error, 211 Error::kInternalError, 212 "Service is not currently running", FROM_HERE); 213 return false; 214 } 215 216 ReleaseResources(); 217 adaptor_->SetState(kStateIdle); 218 return true; 219 } 220 221 #if defined(__BRILLO__) 222 void Service::HandleStartFailure() { 223 // Restore station mode interface. 224 string station_mode_interface; 225 manager_->SetupStationModeInterface(&station_mode_interface); 226 227 // Reset state variables. 228 start_in_progress_ = false; 229 } 230 231 void Service::APInterfaceCheckTask( 232 const string& interface_name, 233 int check_count, 234 const base::Callback<void(const Error&)>& result_callback) { 235 Error error; 236 237 // Check if the AP interface is enumerated. 238 if (manager_->GetDeviceFromInterfaceName(interface_name)) { 239 // Explicitly set the interface name to avoid picking other interface. 240 config_->SetInterfaceName(interface_name); 241 if (!StartInternal(&error)) { 242 HandleStartFailure(); 243 } 244 result_callback.Run(error); 245 return; 246 } 247 248 check_count++; 249 if (check_count >= kAPInterfaceCheckMaxAttempts) { 250 Error::PopulateAndLog(&error, 251 Error::kInternalError, 252 "Timeout waiting for AP interface to be enumerated", 253 FROM_HERE); 254 HandleStartFailure(); 255 result_callback.Run(error); 256 return; 257 } 258 259 event_dispatcher_->PostDelayedTask( 260 base::Bind(&Service::APInterfaceCheckTask, 261 weak_factory_.GetWeakPtr(), 262 interface_name, 263 check_count, 264 result_callback), 265 kAPInterfaceCheckIntervalMilliseconds); 266 } 267 #endif // __BRILLO__ 268 269 bool Service::IsHostapdRunning() { 270 return hostapd_process_ && hostapd_process_->pid() != 0 && 271 brillo::Process::ProcessExists(hostapd_process_->pid()); 272 } 273 274 bool Service::StartHostapdProcess(const string& config_file_path) { 275 hostapd_process_.reset(process_factory_->CreateProcess()); 276 hostapd_process_->AddArg(kHostapdPath); 277 hostapd_process_->AddArg(config_file_path); 278 if (!hostapd_process_->Start()) { 279 hostapd_process_.reset(); 280 return false; 281 } 282 return true; 283 } 284 285 void Service::StopHostapdProcess() { 286 if (!hostapd_process_->Kill(SIGTERM, kTerminationTimeoutSeconds)) { 287 hostapd_process_->Kill(SIGKILL, kTerminationTimeoutSeconds); 288 } 289 hostapd_process_.reset(); 290 } 291 292 void Service::ReleaseResources() { 293 hostapd_monitor_.reset(); 294 StopHostapdProcess(); 295 dhcp_server_.reset(); 296 manager_->ReleaseDHCPPortAccess(config_->selected_interface()); 297 #if defined(__BRILLO__) 298 // Restore station mode interface. 299 string station_mode_interface; 300 manager_->SetupStationModeInterface(&station_mode_interface); 301 #endif // __BRILLO__ 302 // Only release device after mode switching had completed, to 303 // make sure the station mode interface gets enumerated by 304 // shill. 305 config_->ReleaseDevice(); 306 } 307 308 void Service::HostapdEventCallback(HostapdMonitor::Event event, 309 const std::string& data) { 310 switch (event) { 311 case HostapdMonitor::kHostapdFailed: 312 adaptor_->SetState(kStateFailed); 313 break; 314 case HostapdMonitor::kHostapdStarted: 315 adaptor_->SetState(kStateStarted); 316 break; 317 case HostapdMonitor::kStationConnected: 318 LOG(INFO) << "Station connected: " << data; 319 break; 320 case HostapdMonitor::kStationDisconnected: 321 LOG(INFO) << "Station disconnected: " << data; 322 break; 323 default: 324 LOG(ERROR) << "Unknown event: " << event; 325 break; 326 } 327 } 328 329 } // namespace apmanager 330