blob: d809e6eb6d45c085b25ba2f0dcb68f84856336cd [file] [log] [blame]
San Mehatdc266072009-05-06 11:16:52 -07001/*
2 * Copyright (C) 2008 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 */
San Mehat1441e762009-05-07 11:37:10 -070016
17#include <stdlib.h>
San Mehatdc266072009-05-06 11:16:52 -070018#include <errno.h>
19
20#define LOG_TAG "Supplicant"
21#include <cutils/log.h>
22#include <cutils/properties.h>
23
24#undef HAVE_LIBC_SYSTEM_PROPERTIES
25
26#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
27#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
28#include <sys/_system_properties.h>
29#endif
30
31#include "Supplicant.h"
32#include "SupplicantListener.h"
33#include "SupplicantState.h"
34#include "SupplicantEvent.h"
35#include "ScanResult.h"
San Mehat1441e762009-05-07 11:37:10 -070036#include "NetworkManager.h"
San Mehatdc266072009-05-06 11:16:52 -070037
38#include "libwpa_client/wpa_ctrl.h"
39
40#define IFACE_DIR "/data/system/wpa_supplicant"
41#define DRIVER_PROP_NAME "wlan.driver.status"
42#define SUPPLICANT_NAME "wpa_supplicant"
43#define SUPP_PROP_NAME "init.svc.wpa_supplicant"
44
45Supplicant::Supplicant() {
46 mCtrl = NULL;
47 mMonitor = NULL;
48 mListener = NULL;
49
50 mState = SupplicantState::UNKNOWN;
51
52 mLatestScanResults = new ScanResultCollection();
53
54 pthread_mutex_init(&mLatestScanResultsLock, NULL);
55}
56
57int Supplicant::start() {
San Mehatdc266072009-05-06 11:16:52 -070058 // XXX: Validate supplicant config file
59
60 char status[PROPERTY_VALUE_MAX] = {'\0'};
61 int count = 200;
62#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
63 const prop_info *pi;
64 unsigned int serial = 0;
65#endif
66
67 if (property_get(SUPP_PROP_NAME, status, NULL) &&
San Mehat1441e762009-05-07 11:37:10 -070068 !strcmp(status, "running")) {
69 LOGD("Supplicant already started");
70 } else {
71#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
72 pi = __system_property_find(SUPP_PROP_NAME);
73 if (pi != NULL)
74 serial = pi->serial;
75#endif
76
77 LOGD("Starting Supplicant");
78 property_set("ctl.start", SUPPLICANT_NAME);
79 sched_yield();
80 while (count--) {
81#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
82 if (!pi)
83 pi = __system_property_find(SUPP_PROP_NAME);
84 if (pi) {
85 __system_property_read(pi, NULL, status);
86 if (strcmp(status, "running") == 0)
87 break;
88 else if (pi->serial != serial &&
89 strcmp(status, "stopped") == 0) {
90 errno = EIO;
91 return -1;
92 }
93 }
94#else
95 if (property_get(SUPP_PROP_NAME, status, NULL)) {
96 if (strcmp(status, "running") == 0)
97 break;
98 }
99#endif
100 usleep(100000);
101 }
102 if (!count) {
103 errno = ETIMEDOUT;
104 return -1;
105 }
San Mehatdc266072009-05-06 11:16:52 -0700106 }
107
108 wpa_ctrl_cleanup();
San Mehatdc266072009-05-06 11:16:52 -0700109 if (connectToSupplicant()) {
110 LOGE("Error connecting to supplicant (%s)\n", strerror(errno));
111 return -1;
112 }
113 return 0;
114}
115
116int Supplicant::stop() {
San Mehatdc266072009-05-06 11:16:52 -0700117
118 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
119 int count = 50;
120
121 if (mListener->stopListener()) {
122 LOGW("Unable to stop supplicant listener (%s)", strerror(errno));
123 return -1;
124 }
125
126 if (property_get(SUPP_PROP_NAME, supp_status, NULL)
127 && strcmp(supp_status, "stopped") == 0) {
San Mehat1441e762009-05-07 11:37:10 -0700128 LOGD("Supplicant already stopped");
San Mehatdc266072009-05-06 11:16:52 -0700129 return 0;
130 }
131
San Mehat1441e762009-05-07 11:37:10 -0700132 LOGD("Stopping Supplicant");
San Mehatdc266072009-05-06 11:16:52 -0700133 property_set("ctl.stop", SUPPLICANT_NAME);
134 sched_yield();
135
136 while (count-- > 0) {
137 if (property_get(SUPP_PROP_NAME, supp_status, NULL)) {
138 if (strcmp(supp_status, "stopped") == 0)
139 break;
140 }
141 usleep(100000);
142 }
143
144 if (mCtrl) {
145 wpa_ctrl_close(mCtrl);
146 mCtrl = NULL;
147 }
148 if (mMonitor) {
149 wpa_ctrl_close(mMonitor);
150 mMonitor = NULL;
151 }
152
153 if (!count) {
154 LOGD("Timed out waiting for supplicant to stop");
155 errno = ETIMEDOUT;
156 return -1;
157 }
158
San Mehat1441e762009-05-07 11:37:10 -0700159 LOGD("Supplicant shutdown");
San Mehatdc266072009-05-06 11:16:52 -0700160
161 return 0;
162}
163
164bool Supplicant::isStarted() {
165 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
San Mehat1441e762009-05-07 11:37:10 -0700166
167 int rc = property_get(SUPP_PROP_NAME, supp_status, NULL);
168
169 LOGD("rc = %d, property = '%s'", rc, supp_status);
170
171 if (!strcmp(supp_status, "running"))
172 return true;
173
174 return false;
San Mehatdc266072009-05-06 11:16:52 -0700175}
176
177int Supplicant::connectToSupplicant() {
178 char ifname[256];
179 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
180
San Mehat1441e762009-05-07 11:37:10 -0700181 LOGD("connectToSupplicant()");
San Mehatdc266072009-05-06 11:16:52 -0700182 if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
183 || strcmp(supp_status, "running") != 0) {
184 LOGE("Supplicant not running, cannot connect");
185 return -1;
186 }
187
188 mCtrl = wpa_ctrl_open("tiwlan0");
189 if (mCtrl == NULL) {
190 LOGE("Unable to open connection to supplicant on \"%s\": %s",
191 "tiwlan0", strerror(errno));
192 return -1;
193 }
194 mMonitor = wpa_ctrl_open("tiwlan0");
195 if (mMonitor == NULL) {
196 wpa_ctrl_close(mCtrl);
197 mCtrl = NULL;
198 return -1;
199 }
200 if (wpa_ctrl_attach(mMonitor) != 0) {
201 wpa_ctrl_close(mMonitor);
202 wpa_ctrl_close(mCtrl);
203 mCtrl = mMonitor = NULL;
204 return -1;
205 }
206
207 mListener = new SupplicantListener(this, mMonitor);
208
209 if (mListener->startListener()) {
210 LOGE("Error - unable to start supplicant listener");
211 stop();
212 return -1;
213 }
214 return 0;
215}
216
217int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len)
218{
219 if (!mCtrl) {
220 errno = ENOTCONN;
221 return -1;
222 }
223
San Mehat1441e762009-05-07 11:37:10 -0700224// LOGD("sendCommand(): -> '%s'", cmd);
San Mehatdc266072009-05-06 11:16:52 -0700225
226 int rc;
227 if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2) {
228 errno = ETIMEDOUT;
229 return -1;
230 } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) {
San Mehat1441e762009-05-07 11:37:10 -0700231 LOGW("sendCommand(): <- '%s'", reply);
San Mehatdc266072009-05-06 11:16:52 -0700232 errno = EIO;
233 return -1;
234 }
235
236 if (!strncmp(cmd, "PING", 4) ||
237 !strncmp(cmd, "SCAN_RESULTS", 12))
238 reply[*reply_len] = '\0';
239
San Mehat1441e762009-05-07 11:37:10 -0700240// LOGD("sendCommand(): <- '%s'", reply);
San Mehatdc266072009-05-06 11:16:52 -0700241 return 0;
242}
243
244int Supplicant::triggerScan(bool active) {
245 char reply[255];
246 size_t len = sizeof(reply);
247
248 if (sendCommand((active ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"),
249 reply, &len)) {
250 LOGW("triggerScan(%d): Error setting scan mode (%s)", active,
251 strerror(errno));
252 return -1;
253 }
254 len = sizeof(reply);
255
256 if (sendCommand("SCAN", reply, &len)) {
257 LOGW("triggerScan(%d): Error initiating scan", active);
258 return -1;
259 }
260 return 0;
261}
262
263int Supplicant::onConnectedEvent(SupplicantEvent *evt) {
264 LOGD("onConnectedEvent(%s)", evt->getEvent());
265 return 0;
266}
267
268int Supplicant::onDisconnectedEvent(SupplicantEvent *evt) {
269 LOGD("onDisconnectedEvent(%s)", evt->getEvent());
270 return 0;
271}
272
273int Supplicant::onTerminatingEvent(SupplicantEvent *evt) {
274 LOGD("onTerminatingEvent(%s)", evt->getEvent());
275 return 0;
276}
277
278int Supplicant::onPasswordChangedEvent(SupplicantEvent *evt) {
279 LOGD("onPasswordChangedEvent(%s)", evt->getEvent());
280 return 0;
281}
282
283int Supplicant::onEapNotificationEvent(SupplicantEvent *evt) {
284 LOGD("onEapNotificationEvent(%s)", evt->getEvent());
285 return 0;
286}
287
288int Supplicant::onEapStartedEvent(SupplicantEvent *evt) {
289 LOGD("onEapStartedEvent(%s)", evt->getEvent());
290 return 0;
291}
292
293int Supplicant::onEapMethodEvent(SupplicantEvent *evt) {
294 LOGD("onEapMethodEvent(%s)", evt->getEvent());
295 return 0;
296}
297
298int Supplicant::onEapSuccessEvent(SupplicantEvent *evt) {
299 LOGD("onEapSuccessEvent(%s)", evt->getEvent());
300 return 0;
301}
302
303int Supplicant::onEapFailureEvent(SupplicantEvent *evt) {
304 LOGD("onEapFailureEvent(%s)", evt->getEvent());
305 return 0;
306}
307
308int Supplicant::onScanResultsEvent(SupplicantEvent *evt) {
309 LOGD("onScanResultsEvent(%s)", evt->getEvent());
310
311 if (!strcmp(evt->getEvent(), "Ready")) {
312 char *reply;
313
314 if (!(reply = (char *) malloc(4096))) {
315 errno = -ENOMEM;
316 return -1;
317 }
318
319 size_t len = 4096;
320
321 if (sendCommand("SCAN_RESULTS", reply, &len)) {
322 LOGW("onScanResultsEvent(%s): Error getting scan results (%s)",
323 evt->getEvent(), strerror(errno));
324 free(reply);
325 return -1;
326 }
327
328 pthread_mutex_lock(&mLatestScanResultsLock);
329 if (!mLatestScanResults->empty()) {
330 ScanResultCollection::iterator i;
331
332 for (i = mLatestScanResults->begin();
333 i !=mLatestScanResults->end(); ++i) {
334 delete *i;
335 }
336 mLatestScanResults->clear();
337 }
338
339 char *linep;
340 char *linep_next = NULL;
341
342 if (!strtok_r(reply, "\n", &linep_next)) {
343 free(reply);
San Mehat1441e762009-05-07 11:37:10 -0700344 pthread_mutex_unlock(&mLatestScanResultsLock);
345 return 0;
San Mehatdc266072009-05-06 11:16:52 -0700346 }
347
348 while((linep = strtok_r(NULL, "\n", &linep_next)))
349 mLatestScanResults->push_back(new ScanResult(linep));
San Mehat1441e762009-05-07 11:37:10 -0700350
351 char tmp[32];
352 sprintf(tmp, "WIFI_SCAN_RESULTS_READY:%d", mLatestScanResults->size());
353 NetworkManager::Instance()->getBroadcaster()->sendBroadcast(tmp);
San Mehatdc266072009-05-06 11:16:52 -0700354 pthread_mutex_unlock(&mLatestScanResultsLock);
355 free(reply);
356 } else {
357 LOGW("Unknown SCAN_RESULTS event (%s)", evt->getEvent());
358 }
359 return 0;
360}
361
362int Supplicant::onStateChangeEvent(SupplicantEvent *evt) {
San Mehat1441e762009-05-07 11:37:10 -0700363 char *bword, *last;
364 char *tmp = strdup(evt->getEvent());
365
366 if (!(bword = strtok_r(tmp, " ", &last))) {
367 LOGE("Malformatted state update (%s)", evt->getEvent());
368 free(tmp);
369 return 0;
370 }
371
372 if (!(bword = strtok_r(NULL, " ", &last))) {
373 LOGE("Malformatted state update (%s)", evt->getEvent());
374 free(tmp);
375 return 0;
376 }
377
378 mState = atoi(&bword[strlen("state=")]);
379 LOGD("State changed to %d", mState);
380 free(tmp);
San Mehatdc266072009-05-06 11:16:52 -0700381 return 0;
382}
383
384int Supplicant::onLinkSpeedEvent(SupplicantEvent *evt) {
385 LOGD("onLinkSpeedEvent(%s)", evt->getEvent());
386 return 0;
387}
388
389int Supplicant::onDriverStateEvent(SupplicantEvent *evt) {
390 LOGD("onDriverStateEvent(%s)", evt->getEvent());
391 return 0;
392}
393
394// XXX: Use a cursor + smartptr instead
San Mehat1441e762009-05-07 11:37:10 -0700395ScanResultCollection *Supplicant::createLatestScanResults() {
San Mehatdc266072009-05-06 11:16:52 -0700396 ScanResultCollection *d = new ScanResultCollection();
397 ScanResultCollection::iterator i;
398
399 pthread_mutex_lock(&mLatestScanResultsLock);
400 for (i = mLatestScanResults->begin(); i != mLatestScanResults->end(); ++i) {
401 d->push_back((*i)->clone());
402 }
403
404 pthread_mutex_unlock(&mLatestScanResultsLock);
405 return d;
406};