1 // 2 // Copyright (C) 2015 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/hostapd_monitor.h" 18 19 #include <sys/socket.h> 20 #include <sys/stat.h> 21 #include <sys/un.h> 22 23 #include <base/bind.h> 24 #include <base/logging.h> 25 #include <base/strings/stringprintf.h> 26 #include <shill/net/io_handler_factory_container.h> 27 #include <shill/net/sockets.h> 28 29 using base::Bind; 30 using base::Unretained; 31 using shill::IOHandlerFactoryContainer; 32 using std::string; 33 34 namespace apmanager { 35 36 // static. 37 #if !defined(__ANDROID__) 38 const char HostapdMonitor::kLocalPathFormat[] = 39 "/var/run/apmanager/hostapd/hostapd_ctrl_%s"; 40 #else 41 const char HostapdMonitor::kLocalPathFormat[] = 42 "/data/misc/apmanager/hostapd/hostapd_ctrl_%s"; 43 #endif // __ANDROID__ 44 45 const char HostapdMonitor::kHostapdCmdAttach[] = "ATTACH"; 46 const char HostapdMonitor::kHostapdRespOk[] = "OK\n"; 47 const char HostapdMonitor::kHostapdEventStationConnected[] = "AP-STA-CONNECTED"; 48 const char HostapdMonitor::kHostapdEventStationDisconnected[] = 49 "AP-STA-DISCONNECTED"; 50 const int HostapdMonitor::kHostapdCtrlIfaceCheckIntervalMs = 500; 51 const int HostapdMonitor::kHostapdCtrlIfaceCheckMaxAttempts = 5; 52 const int HostapdMonitor::kHostapdAttachTimeoutMs = 1000; 53 const int HostapdMonitor::kInvalidSocket = -1; 54 55 HostapdMonitor::HostapdMonitor(const EventCallback& callback, 56 const string& control_interface_path, 57 const string& network_interface_name) 58 : sockets_(new shill::Sockets()), 59 event_callback_(callback), 60 dest_path_(base::StringPrintf("%s/%s", 61 control_interface_path.c_str(), 62 network_interface_name.c_str())), 63 local_path_(base::StringPrintf(kLocalPathFormat, 64 network_interface_name.c_str())), 65 hostapd_socket_(kInvalidSocket), 66 io_handler_factory_( 67 IOHandlerFactoryContainer::GetInstance()->GetIOHandlerFactory()), 68 event_dispatcher_(EventDispatcher::GetInstance()), 69 weak_ptr_factory_(this), 70 started_(false) {} 71 72 HostapdMonitor::~HostapdMonitor() { 73 if (hostapd_socket_ != kInvalidSocket) { 74 unlink(local_path_.c_str()); 75 sockets_->Close(hostapd_socket_); 76 } 77 } 78 79 void HostapdMonitor::Start() { 80 if (started_) { 81 LOG(ERROR) << "HostapdMonitor already started"; 82 return; 83 } 84 85 hostapd_ctrl_iface_check_count_ = 0; 86 // Start off by checking the control interface file for the hostapd process. 87 event_dispatcher_->PostTask( 88 Bind(&HostapdMonitor::HostapdCtrlIfaceCheckTask, 89 weak_ptr_factory_.GetWeakPtr())); 90 started_ = true; 91 } 92 93 void HostapdMonitor::HostapdCtrlIfaceCheckTask() { 94 struct stat buf; 95 if (stat(dest_path_.c_str(), &buf) != 0) { 96 if (hostapd_ctrl_iface_check_count_ >= kHostapdCtrlIfaceCheckMaxAttempts) { 97 // This indicates the hostapd failed to start. Invoke callback indicating 98 // hostapd start failed. 99 LOG(ERROR) << "Timeout waiting for hostapd control interface"; 100 event_callback_.Run(kHostapdFailed, ""); 101 } else { 102 hostapd_ctrl_iface_check_count_++; 103 event_dispatcher_->PostDelayedTask( 104 base::Bind(&HostapdMonitor::HostapdCtrlIfaceCheckTask, 105 weak_ptr_factory_.GetWeakPtr()), 106 kHostapdCtrlIfaceCheckIntervalMs); 107 } 108 return; 109 } 110 111 // Control interface is up, meaning hostapd started successfully. 112 event_callback_.Run(kHostapdStarted, ""); 113 114 // Attach to the control interface to receive unsolicited event notifications. 115 AttachToHostapd(); 116 } 117 118 void HostapdMonitor::AttachToHostapd() { 119 if (hostapd_socket_ != kInvalidSocket) { 120 LOG(ERROR) << "Socket already initialized"; 121 return; 122 } 123 124 // Setup socket address for local file and remote file. 125 struct sockaddr_un local; 126 local.sun_family = AF_UNIX; 127 snprintf(local.sun_path, sizeof(local.sun_path), "%s", local_path_.c_str()); 128 struct sockaddr_un dest; 129 dest.sun_family = AF_UNIX; 130 snprintf(dest.sun_path, sizeof(dest.sun_path), "%s", dest_path_.c_str()); 131 132 // Setup socket for interprocess communication. 133 hostapd_socket_ = sockets_->Socket(PF_UNIX, SOCK_DGRAM, 0); 134 if (hostapd_socket_ < 0) { 135 LOG(ERROR) << "Failed to open hostapd socket"; 136 return; 137 } 138 if (sockets_->Bind(hostapd_socket_, 139 reinterpret_cast<struct sockaddr*>(&local), 140 sizeof(local)) < 0) { 141 PLOG(ERROR) << "Failed to bind to local socket"; 142 return; 143 } 144 if (sockets_->Connect(hostapd_socket_, 145 reinterpret_cast<struct sockaddr*>(&dest), 146 sizeof(dest)) < 0) { 147 PLOG(ERROR) << "Failed to connect"; 148 return; 149 } 150 151 // Setup IO Input handler. 152 hostapd_input_handler_.reset(io_handler_factory_->CreateIOInputHandler( 153 hostapd_socket_, 154 Bind(&HostapdMonitor::ParseMessage, Unretained(this)), 155 Bind(&HostapdMonitor::OnReadError, Unretained(this)))); 156 157 if (!SendMessage(kHostapdCmdAttach, strlen(kHostapdCmdAttach))) { 158 LOG(ERROR) << "Failed to attach to hostapd"; 159 return; 160 } 161 162 // Start a timer for ATTACH response. 163 attach_timeout_callback_.Reset( 164 Bind(&HostapdMonitor::AttachTimeoutHandler, 165 weak_ptr_factory_.GetWeakPtr())); 166 event_dispatcher_->PostDelayedTask(attach_timeout_callback_.callback(), 167 kHostapdAttachTimeoutMs); 168 return; 169 } 170 171 void HostapdMonitor::AttachTimeoutHandler() { 172 LOG(ERROR) << "Timeout waiting for attach response"; 173 } 174 175 // Method for sending message to hostapd control interface. 176 bool HostapdMonitor::SendMessage(const char* message, size_t length) { 177 if (sockets_->Send(hostapd_socket_, message, length, 0) < 0) { 178 PLOG(ERROR) << "Send to hostapd failed"; 179 return false; 180 } 181 182 return true; 183 } 184 185 void HostapdMonitor::ParseMessage(shill::InputData* data) { 186 string str(reinterpret_cast<const char*>(data->buf), data->len); 187 // "OK" response for the "ATTACH" command. 188 if (str == kHostapdRespOk) { 189 attach_timeout_callback_.Cancel(); 190 return; 191 } 192 193 // Event messages are in format of <[Level]>[Event] [Detail message]. 194 // For example: <2>AP-STA-CONNECTED 00:11:22:33:44:55 195 // Refer to wpa_ctrl.h for complete list of possible events. 196 if (str.find_first_of('<', 0) == 0 && str.find_first_of('>', 0) == 2) { 197 // Remove the log level. 198 string msg = str.substr(3); 199 string event; 200 string data; 201 size_t pos = msg.find_first_of(' ', 0); 202 if (pos == string::npos) { 203 event = msg; 204 } else { 205 event = msg.substr(0, pos); 206 data = msg.substr(pos + 1); 207 } 208 209 Event event_code; 210 if (event == kHostapdEventStationConnected) { 211 event_code = kStationConnected; 212 } else if (event == kHostapdEventStationDisconnected) { 213 event_code = kStationDisconnected; 214 } else { 215 LOG(INFO) << "Received unknown event: " << event; 216 return; 217 } 218 event_callback_.Run(event_code, data); 219 return; 220 } 221 222 LOG(INFO) << "Received unknown message: " << str; 223 } 224 225 void HostapdMonitor::OnReadError(const string& error_msg) { 226 LOG(FATAL) << "Hostapd Socket read returns error: " 227 << error_msg; 228 } 229 230 } // namespace apmanager 231