blob: 94435987a2d5a3d1f799f8fdb6b196094d6f57dd [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 Mehat69772dc2009-05-10 09:27:07 -070018#include <sys/types.h>
19#include <fcntl.h>
San Mehatdc266072009-05-06 11:16:52 -070020#include <errno.h>
21
22#define LOG_TAG "Supplicant"
23#include <cutils/log.h>
24#include <cutils/properties.h>
25
San Mehat69772dc2009-05-10 09:27:07 -070026#include "private/android_filesystem_config.h"
27
San Mehatdc266072009-05-06 11:16:52 -070028#undef HAVE_LIBC_SYSTEM_PROPERTIES
29
30#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
31#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
32#include <sys/_system_properties.h>
33#endif
34
35#include "Supplicant.h"
36#include "SupplicantListener.h"
37#include "SupplicantState.h"
38#include "SupplicantEvent.h"
39#include "ScanResult.h"
San Mehat1441e762009-05-07 11:37:10 -070040#include "NetworkManager.h"
San Mehat8d3fc3f2009-05-12 14:36:32 -070041#include "ErrorCode.h"
San Mehatdc266072009-05-06 11:16:52 -070042
43#include "libwpa_client/wpa_ctrl.h"
44
45#define IFACE_DIR "/data/system/wpa_supplicant"
46#define DRIVER_PROP_NAME "wlan.driver.status"
47#define SUPPLICANT_NAME "wpa_supplicant"
48#define SUPP_PROP_NAME "init.svc.wpa_supplicant"
San Mehat69772dc2009-05-10 09:27:07 -070049#define SUPP_CONFIG_TEMPLATE "/system/etc/wifi/wpa_supplicant.conf"
50#define SUPP_CONFIG_FILE "/data/misc/wifi/wpa_supplicant.conf"
51
San Mehatdc266072009-05-06 11:16:52 -070052
53Supplicant::Supplicant() {
54 mCtrl = NULL;
55 mMonitor = NULL;
56 mListener = NULL;
57
58 mState = SupplicantState::UNKNOWN;
59
60 mLatestScanResults = new ScanResultCollection();
61
62 pthread_mutex_init(&mLatestScanResultsLock, NULL);
63}
64
65int Supplicant::start() {
San Mehat69772dc2009-05-10 09:27:07 -070066
67 if (setupConfig()) {
68 LOGW("Unable to setup supplicant.conf");
69 }
San Mehatdc266072009-05-06 11:16:52 -070070
71 char status[PROPERTY_VALUE_MAX] = {'\0'};
72 int count = 200;
73#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
74 const prop_info *pi;
75 unsigned int serial = 0;
76#endif
77
78 if (property_get(SUPP_PROP_NAME, status, NULL) &&
San Mehat1441e762009-05-07 11:37:10 -070079 !strcmp(status, "running")) {
San Mehat1441e762009-05-07 11:37:10 -070080 } else {
81#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
82 pi = __system_property_find(SUPP_PROP_NAME);
83 if (pi != NULL)
84 serial = pi->serial;
85#endif
86
87 LOGD("Starting Supplicant");
88 property_set("ctl.start", SUPPLICANT_NAME);
89 sched_yield();
90 while (count--) {
91#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
92 if (!pi)
93 pi = __system_property_find(SUPP_PROP_NAME);
94 if (pi) {
95 __system_property_read(pi, NULL, status);
96 if (strcmp(status, "running") == 0)
97 break;
98 else if (pi->serial != serial &&
99 strcmp(status, "stopped") == 0) {
100 errno = EIO;
101 return -1;
102 }
103 }
104#else
105 if (property_get(SUPP_PROP_NAME, status, NULL)) {
San Mehat69772dc2009-05-10 09:27:07 -0700106 if (!strcmp(status, "running"))
San Mehat1441e762009-05-07 11:37:10 -0700107 break;
108 }
109#endif
110 usleep(100000);
111 }
112 if (!count) {
113 errno = ETIMEDOUT;
114 return -1;
115 }
San Mehatdc266072009-05-06 11:16:52 -0700116 }
117
118 wpa_ctrl_cleanup();
San Mehatdc266072009-05-06 11:16:52 -0700119 if (connectToSupplicant()) {
120 LOGE("Error connecting to supplicant (%s)\n", strerror(errno));
121 return -1;
122 }
123 return 0;
124}
125
126int Supplicant::stop() {
San Mehatdc266072009-05-06 11:16:52 -0700127
128 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
129 int count = 50;
130
131 if (mListener->stopListener()) {
132 LOGW("Unable to stop supplicant listener (%s)", strerror(errno));
133 return -1;
134 }
135
136 if (property_get(SUPP_PROP_NAME, supp_status, NULL)
137 && strcmp(supp_status, "stopped") == 0) {
San Mehat1441e762009-05-07 11:37:10 -0700138 LOGD("Supplicant already stopped");
San Mehatdc266072009-05-06 11:16:52 -0700139 return 0;
140 }
141
San Mehat1441e762009-05-07 11:37:10 -0700142 LOGD("Stopping Supplicant");
San Mehatdc266072009-05-06 11:16:52 -0700143 property_set("ctl.stop", SUPPLICANT_NAME);
144 sched_yield();
145
146 while (count-- > 0) {
147 if (property_get(SUPP_PROP_NAME, supp_status, NULL)) {
148 if (strcmp(supp_status, "stopped") == 0)
149 break;
150 }
151 usleep(100000);
152 }
153
154 if (mCtrl) {
155 wpa_ctrl_close(mCtrl);
156 mCtrl = NULL;
157 }
158 if (mMonitor) {
159 wpa_ctrl_close(mMonitor);
160 mMonitor = NULL;
161 }
162
163 if (!count) {
164 LOGD("Timed out waiting for supplicant to stop");
165 errno = ETIMEDOUT;
166 return -1;
167 }
168
San Mehat1441e762009-05-07 11:37:10 -0700169 LOGD("Supplicant shutdown");
San Mehatdc266072009-05-06 11:16:52 -0700170
171 return 0;
172}
173
174bool Supplicant::isStarted() {
175 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
San Mehat1441e762009-05-07 11:37:10 -0700176
San Mehat8d3fc3f2009-05-12 14:36:32 -0700177 property_get(SUPP_PROP_NAME, supp_status, NULL);
San Mehat1441e762009-05-07 11:37:10 -0700178
179 if (!strcmp(supp_status, "running"))
180 return true;
181
182 return false;
San Mehatdc266072009-05-06 11:16:52 -0700183}
184
185int Supplicant::connectToSupplicant() {
186 char ifname[256];
187 char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
188
San Mehat1441e762009-05-07 11:37:10 -0700189 LOGD("connectToSupplicant()");
San Mehatdc266072009-05-06 11:16:52 -0700190 if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
191 || strcmp(supp_status, "running") != 0) {
192 LOGE("Supplicant not running, cannot connect");
193 return -1;
194 }
195
196 mCtrl = wpa_ctrl_open("tiwlan0");
197 if (mCtrl == NULL) {
198 LOGE("Unable to open connection to supplicant on \"%s\": %s",
199 "tiwlan0", strerror(errno));
200 return -1;
201 }
202 mMonitor = wpa_ctrl_open("tiwlan0");
203 if (mMonitor == NULL) {
204 wpa_ctrl_close(mCtrl);
205 mCtrl = NULL;
206 return -1;
207 }
208 if (wpa_ctrl_attach(mMonitor) != 0) {
209 wpa_ctrl_close(mMonitor);
210 wpa_ctrl_close(mCtrl);
211 mCtrl = mMonitor = NULL;
212 return -1;
213 }
214
215 mListener = new SupplicantListener(this, mMonitor);
216
217 if (mListener->startListener()) {
218 LOGE("Error - unable to start supplicant listener");
219 stop();
220 return -1;
221 }
222 return 0;
223}
224
225int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len)
226{
227 if (!mCtrl) {
228 errno = ENOTCONN;
229 return -1;
230 }
231
San Mehat1441e762009-05-07 11:37:10 -0700232// LOGD("sendCommand(): -> '%s'", cmd);
San Mehatdc266072009-05-06 11:16:52 -0700233
234 int rc;
235 if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2) {
236 errno = ETIMEDOUT;
237 return -1;
238 } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) {
San Mehat1441e762009-05-07 11:37:10 -0700239 LOGW("sendCommand(): <- '%s'", reply);
San Mehatdc266072009-05-06 11:16:52 -0700240 errno = EIO;
241 return -1;
242 }
243
244 if (!strncmp(cmd, "PING", 4) ||
245 !strncmp(cmd, "SCAN_RESULTS", 12))
246 reply[*reply_len] = '\0';
247
San Mehat1441e762009-05-07 11:37:10 -0700248// LOGD("sendCommand(): <- '%s'", reply);
San Mehatdc266072009-05-06 11:16:52 -0700249 return 0;
250}
251
252int Supplicant::triggerScan(bool active) {
253 char reply[255];
254 size_t len = sizeof(reply);
255
256 if (sendCommand((active ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"),
257 reply, &len)) {
258 LOGW("triggerScan(%d): Error setting scan mode (%s)", active,
259 strerror(errno));
260 return -1;
261 }
262 len = sizeof(reply);
263
264 if (sendCommand("SCAN", reply, &len)) {
265 LOGW("triggerScan(%d): Error initiating scan", active);
266 return -1;
267 }
268 return 0;
269}
270
271int Supplicant::onConnectedEvent(SupplicantEvent *evt) {
272 LOGD("onConnectedEvent(%s)", evt->getEvent());
273 return 0;
274}
275
276int Supplicant::onDisconnectedEvent(SupplicantEvent *evt) {
277 LOGD("onDisconnectedEvent(%s)", evt->getEvent());
278 return 0;
279}
280
281int Supplicant::onTerminatingEvent(SupplicantEvent *evt) {
282 LOGD("onTerminatingEvent(%s)", evt->getEvent());
283 return 0;
284}
285
286int Supplicant::onPasswordChangedEvent(SupplicantEvent *evt) {
287 LOGD("onPasswordChangedEvent(%s)", evt->getEvent());
288 return 0;
289}
290
291int Supplicant::onEapNotificationEvent(SupplicantEvent *evt) {
292 LOGD("onEapNotificationEvent(%s)", evt->getEvent());
293 return 0;
294}
295
296int Supplicant::onEapStartedEvent(SupplicantEvent *evt) {
297 LOGD("onEapStartedEvent(%s)", evt->getEvent());
298 return 0;
299}
300
301int Supplicant::onEapMethodEvent(SupplicantEvent *evt) {
302 LOGD("onEapMethodEvent(%s)", evt->getEvent());
303 return 0;
304}
305
306int Supplicant::onEapSuccessEvent(SupplicantEvent *evt) {
307 LOGD("onEapSuccessEvent(%s)", evt->getEvent());
308 return 0;
309}
310
311int Supplicant::onEapFailureEvent(SupplicantEvent *evt) {
312 LOGD("onEapFailureEvent(%s)", evt->getEvent());
313 return 0;
314}
315
316int Supplicant::onScanResultsEvent(SupplicantEvent *evt) {
San Mehatdc266072009-05-06 11:16:52 -0700317 if (!strcmp(evt->getEvent(), "Ready")) {
318 char *reply;
319
320 if (!(reply = (char *) malloc(4096))) {
321 errno = -ENOMEM;
322 return -1;
323 }
324
325 size_t len = 4096;
326
327 if (sendCommand("SCAN_RESULTS", reply, &len)) {
328 LOGW("onScanResultsEvent(%s): Error getting scan results (%s)",
329 evt->getEvent(), strerror(errno));
330 free(reply);
331 return -1;
332 }
333
334 pthread_mutex_lock(&mLatestScanResultsLock);
335 if (!mLatestScanResults->empty()) {
336 ScanResultCollection::iterator i;
337
338 for (i = mLatestScanResults->begin();
339 i !=mLatestScanResults->end(); ++i) {
340 delete *i;
341 }
342 mLatestScanResults->clear();
343 }
344
345 char *linep;
346 char *linep_next = NULL;
347
348 if (!strtok_r(reply, "\n", &linep_next)) {
349 free(reply);
San Mehat1441e762009-05-07 11:37:10 -0700350 pthread_mutex_unlock(&mLatestScanResultsLock);
351 return 0;
San Mehatdc266072009-05-06 11:16:52 -0700352 }
353
354 while((linep = strtok_r(NULL, "\n", &linep_next)))
355 mLatestScanResults->push_back(new ScanResult(linep));
San Mehat1441e762009-05-07 11:37:10 -0700356
San Mehat69772dc2009-05-10 09:27:07 -0700357 char tmp[128];
358 sprintf(tmp, "%d scan results ready", mLatestScanResults->size());
San Mehat8d3fc3f2009-05-12 14:36:32 -0700359 NetworkManager::Instance()->getBroadcaster()->
360 sendBroadcast(ErrorCode::UnsolicitedInformational, tmp, false);
San Mehatdc266072009-05-06 11:16:52 -0700361 pthread_mutex_unlock(&mLatestScanResultsLock);
362 free(reply);
363 } else {
364 LOGW("Unknown SCAN_RESULTS event (%s)", evt->getEvent());
365 }
366 return 0;
367}
368
369int Supplicant::onStateChangeEvent(SupplicantEvent *evt) {
San Mehat1441e762009-05-07 11:37:10 -0700370 char *bword, *last;
371 char *tmp = strdup(evt->getEvent());
372
373 if (!(bword = strtok_r(tmp, " ", &last))) {
374 LOGE("Malformatted state update (%s)", evt->getEvent());
375 free(tmp);
376 return 0;
377 }
378
379 if (!(bword = strtok_r(NULL, " ", &last))) {
380 LOGE("Malformatted state update (%s)", evt->getEvent());
381 free(tmp);
382 return 0;
383 }
384
385 mState = atoi(&bword[strlen("state=")]);
386 LOGD("State changed to %d", mState);
387 free(tmp);
San Mehatdc266072009-05-06 11:16:52 -0700388 return 0;
389}
390
391int Supplicant::onLinkSpeedEvent(SupplicantEvent *evt) {
392 LOGD("onLinkSpeedEvent(%s)", evt->getEvent());
393 return 0;
394}
395
396int Supplicant::onDriverStateEvent(SupplicantEvent *evt) {
397 LOGD("onDriverStateEvent(%s)", evt->getEvent());
398 return 0;
399}
400
401// XXX: Use a cursor + smartptr instead
San Mehat1441e762009-05-07 11:37:10 -0700402ScanResultCollection *Supplicant::createLatestScanResults() {
San Mehatdc266072009-05-06 11:16:52 -0700403 ScanResultCollection *d = new ScanResultCollection();
404 ScanResultCollection::iterator i;
405
406 pthread_mutex_lock(&mLatestScanResultsLock);
407 for (i = mLatestScanResults->begin(); i != mLatestScanResults->end(); ++i) {
408 d->push_back((*i)->clone());
409 }
410
411 pthread_mutex_unlock(&mLatestScanResultsLock);
412 return d;
San Mehat69772dc2009-05-10 09:27:07 -0700413}
414
415int Supplicant::setupConfig() {
416 char buf[2048];
417 int srcfd, destfd;
418 int nread;
419
420 if (access(SUPP_CONFIG_FILE, R_OK|W_OK) == 0) {
421 return 0;
422 } else if (errno != ENOENT) {
423 LOGE("Cannot access \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
424 return -1;
425 }
426
427 srcfd = open(SUPP_CONFIG_TEMPLATE, O_RDONLY);
428 if (srcfd < 0) {
429 LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
430 return -1;
431 }
432
433 destfd = open(SUPP_CONFIG_FILE, O_CREAT|O_WRONLY, 0660);
434 if (destfd < 0) {
435 close(srcfd);
436 LOGE("Cannot create \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
437 return -1;
438 }
439
440 while ((nread = read(srcfd, buf, sizeof(buf))) != 0) {
441 if (nread < 0) {
442 LOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
443 close(srcfd);
444 close(destfd);
445 unlink(SUPP_CONFIG_FILE);
446 return -1;
447 }
448 write(destfd, buf, nread);
449 }
450
451 close(destfd);
452 close(srcfd);
453
454 if (chown(SUPP_CONFIG_FILE, AID_SYSTEM, AID_WIFI) < 0) {
455 LOGE("Error changing group ownership of %s to %d: %s",
456 SUPP_CONFIG_FILE, AID_WIFI, strerror(errno));
457 unlink(SUPP_CONFIG_FILE);
458 return -1;
459 }
460 return 0;
461}