blob: 6737d9172191fd24aedcbde84b994b18489c84f1 [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 Mehat5d6d4172009-05-14 15:00:06 -070028#include <sysutils/ServiceManager.h>
San Mehatdc266072009-05-06 11:16:52 -070029
30#include "Supplicant.h"
31#include "SupplicantListener.h"
32#include "SupplicantState.h"
33#include "SupplicantEvent.h"
34#include "ScanResult.h"
San Mehat1441e762009-05-07 11:37:10 -070035#include "NetworkManager.h"
San Mehat8d3fc3f2009-05-12 14:36:32 -070036#include "ErrorCode.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"
San Mehat5d6d4172009-05-14 15:00:06 -070042#define SUPPLICANT_SERVICE_NAME "wpa_supplicant"
San Mehat69772dc2009-05-10 09:27:07 -070043#define SUPP_CONFIG_TEMPLATE "/system/etc/wifi/wpa_supplicant.conf"
44#define SUPP_CONFIG_FILE "/data/misc/wifi/wpa_supplicant.conf"
45
San Mehatdc266072009-05-06 11:16:52 -070046Supplicant::Supplicant() {
47 mCtrl = NULL;
48 mMonitor = NULL;
49 mListener = NULL;
50
51 mState = SupplicantState::UNKNOWN;
52
San Mehat5d6d4172009-05-14 15:00:06 -070053 mServiceManager = new ServiceManager();
San Mehatdc266072009-05-06 11:16:52 -070054
San Mehat5d6d4172009-05-14 15:00:06 -070055 mLatestScanResults = new ScanResultCollection();
San Mehatdc266072009-05-06 11:16:52 -070056 pthread_mutex_init(&mLatestScanResultsLock, NULL);
57}
58
San Mehat5d6d4172009-05-14 15:00:06 -070059Supplicant::~Supplicant() {
60 delete mServiceManager;
61}
62
San Mehatdc266072009-05-06 11:16:52 -070063int Supplicant::start() {
San Mehat69772dc2009-05-10 09:27:07 -070064
65 if (setupConfig()) {
66 LOGW("Unable to setup supplicant.conf");
67 }
San Mehat5d6d4172009-05-14 15:00:06 -070068
69 if (mServiceManager->start(SUPPLICANT_SERVICE_NAME)) {
70 LOGE("Error starting supplicant (%s)", strerror(errno));
71 return -1;
San Mehatdc266072009-05-06 11:16:52 -070072 }
73
74 wpa_ctrl_cleanup();
San Mehatdc266072009-05-06 11:16:52 -070075 if (connectToSupplicant()) {
76 LOGE("Error connecting to supplicant (%s)\n", strerror(errno));
77 return -1;
78 }
79 return 0;
80}
81
82int Supplicant::stop() {
San Mehatdc266072009-05-06 11:16:52 -070083
San Mehatdc266072009-05-06 11:16:52 -070084 if (mListener->stopListener()) {
85 LOGW("Unable to stop supplicant listener (%s)", strerror(errno));
86 return -1;
87 }
88
San Mehat5d6d4172009-05-14 15:00:06 -070089 if (mServiceManager->stop(SUPPLICANT_SERVICE_NAME)) {
90 LOGW("Error stopping supplicant (%s)", strerror(errno));
San Mehatdc266072009-05-06 11:16:52 -070091 }
92
93 if (mCtrl) {
94 wpa_ctrl_close(mCtrl);
95 mCtrl = NULL;
96 }
97 if (mMonitor) {
98 wpa_ctrl_close(mMonitor);
99 mMonitor = NULL;
100 }
101
San Mehatdc266072009-05-06 11:16:52 -0700102 return 0;
103}
104
105bool Supplicant::isStarted() {
San Mehat5d6d4172009-05-14 15:00:06 -0700106 return mServiceManager->isRunning(SUPPLICANT_SERVICE_NAME);
San Mehatdc266072009-05-06 11:16:52 -0700107}
108
109int Supplicant::connectToSupplicant() {
San Mehat5d6d4172009-05-14 15:00:06 -0700110 if (!isStarted()) {
San Mehatdc266072009-05-06 11:16:52 -0700111 LOGE("Supplicant not running, cannot connect");
112 return -1;
113 }
114
115 mCtrl = wpa_ctrl_open("tiwlan0");
116 if (mCtrl == NULL) {
117 LOGE("Unable to open connection to supplicant on \"%s\": %s",
118 "tiwlan0", strerror(errno));
119 return -1;
120 }
121 mMonitor = wpa_ctrl_open("tiwlan0");
122 if (mMonitor == NULL) {
123 wpa_ctrl_close(mCtrl);
124 mCtrl = NULL;
125 return -1;
126 }
127 if (wpa_ctrl_attach(mMonitor) != 0) {
128 wpa_ctrl_close(mMonitor);
129 wpa_ctrl_close(mCtrl);
130 mCtrl = mMonitor = NULL;
131 return -1;
132 }
133
134 mListener = new SupplicantListener(this, mMonitor);
135
136 if (mListener->startListener()) {
137 LOGE("Error - unable to start supplicant listener");
138 stop();
139 return -1;
140 }
141 return 0;
142}
143
144int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len)
145{
146 if (!mCtrl) {
147 errno = ENOTCONN;
148 return -1;
149 }
150
San Mehat5d6d4172009-05-14 15:00:06 -0700151// LOGD("sendCommand(): -> '%s'", cmd);
San Mehatdc266072009-05-06 11:16:52 -0700152
153 int rc;
154 if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2) {
155 errno = ETIMEDOUT;
156 return -1;
157 } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) {
San Mehat1441e762009-05-07 11:37:10 -0700158 LOGW("sendCommand(): <- '%s'", reply);
San Mehatdc266072009-05-06 11:16:52 -0700159 errno = EIO;
160 return -1;
161 }
162
163 if (!strncmp(cmd, "PING", 4) ||
164 !strncmp(cmd, "SCAN_RESULTS", 12))
165 reply[*reply_len] = '\0';
166
San Mehat5d6d4172009-05-14 15:00:06 -0700167// LOGD("sendCommand(): <- '%s'", reply);
San Mehatdc266072009-05-06 11:16:52 -0700168 return 0;
169}
170
171int Supplicant::triggerScan(bool active) {
172 char reply[255];
173 size_t len = sizeof(reply);
174
175 if (sendCommand((active ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"),
176 reply, &len)) {
177 LOGW("triggerScan(%d): Error setting scan mode (%s)", active,
178 strerror(errno));
179 return -1;
180 }
181 len = sizeof(reply);
182
183 if (sendCommand("SCAN", reply, &len)) {
184 LOGW("triggerScan(%d): Error initiating scan", active);
185 return -1;
186 }
187 return 0;
188}
189
190int Supplicant::onConnectedEvent(SupplicantEvent *evt) {
191 LOGD("onConnectedEvent(%s)", evt->getEvent());
192 return 0;
193}
194
195int Supplicant::onDisconnectedEvent(SupplicantEvent *evt) {
196 LOGD("onDisconnectedEvent(%s)", evt->getEvent());
197 return 0;
198}
199
200int Supplicant::onTerminatingEvent(SupplicantEvent *evt) {
201 LOGD("onTerminatingEvent(%s)", evt->getEvent());
202 return 0;
203}
204
205int Supplicant::onPasswordChangedEvent(SupplicantEvent *evt) {
206 LOGD("onPasswordChangedEvent(%s)", evt->getEvent());
207 return 0;
208}
209
210int Supplicant::onEapNotificationEvent(SupplicantEvent *evt) {
211 LOGD("onEapNotificationEvent(%s)", evt->getEvent());
212 return 0;
213}
214
215int Supplicant::onEapStartedEvent(SupplicantEvent *evt) {
216 LOGD("onEapStartedEvent(%s)", evt->getEvent());
217 return 0;
218}
219
220int Supplicant::onEapMethodEvent(SupplicantEvent *evt) {
221 LOGD("onEapMethodEvent(%s)", evt->getEvent());
222 return 0;
223}
224
225int Supplicant::onEapSuccessEvent(SupplicantEvent *evt) {
226 LOGD("onEapSuccessEvent(%s)", evt->getEvent());
227 return 0;
228}
229
230int Supplicant::onEapFailureEvent(SupplicantEvent *evt) {
231 LOGD("onEapFailureEvent(%s)", evt->getEvent());
232 return 0;
233}
234
235int Supplicant::onScanResultsEvent(SupplicantEvent *evt) {
San Mehatdc266072009-05-06 11:16:52 -0700236 if (!strcmp(evt->getEvent(), "Ready")) {
237 char *reply;
238
239 if (!(reply = (char *) malloc(4096))) {
240 errno = -ENOMEM;
241 return -1;
242 }
243
244 size_t len = 4096;
245
246 if (sendCommand("SCAN_RESULTS", reply, &len)) {
247 LOGW("onScanResultsEvent(%s): Error getting scan results (%s)",
248 evt->getEvent(), strerror(errno));
249 free(reply);
250 return -1;
251 }
252
253 pthread_mutex_lock(&mLatestScanResultsLock);
254 if (!mLatestScanResults->empty()) {
255 ScanResultCollection::iterator i;
256
257 for (i = mLatestScanResults->begin();
258 i !=mLatestScanResults->end(); ++i) {
259 delete *i;
260 }
261 mLatestScanResults->clear();
262 }
263
264 char *linep;
265 char *linep_next = NULL;
266
267 if (!strtok_r(reply, "\n", &linep_next)) {
268 free(reply);
San Mehat1441e762009-05-07 11:37:10 -0700269 pthread_mutex_unlock(&mLatestScanResultsLock);
270 return 0;
San Mehatdc266072009-05-06 11:16:52 -0700271 }
272
273 while((linep = strtok_r(NULL, "\n", &linep_next)))
274 mLatestScanResults->push_back(new ScanResult(linep));
San Mehat1441e762009-05-07 11:37:10 -0700275
San Mehat69772dc2009-05-10 09:27:07 -0700276 char tmp[128];
San Mehat82a21162009-05-12 17:26:28 -0700277 sprintf(tmp, "Scan results ready (%d)", mLatestScanResults->size());
San Mehat8d3fc3f2009-05-12 14:36:32 -0700278 NetworkManager::Instance()->getBroadcaster()->
279 sendBroadcast(ErrorCode::UnsolicitedInformational, tmp, false);
San Mehatdc266072009-05-06 11:16:52 -0700280 pthread_mutex_unlock(&mLatestScanResultsLock);
281 free(reply);
282 } else {
283 LOGW("Unknown SCAN_RESULTS event (%s)", evt->getEvent());
284 }
285 return 0;
286}
287
288int Supplicant::onStateChangeEvent(SupplicantEvent *evt) {
San Mehat1441e762009-05-07 11:37:10 -0700289 char *bword, *last;
290 char *tmp = strdup(evt->getEvent());
291
292 if (!(bword = strtok_r(tmp, " ", &last))) {
293 LOGE("Malformatted state update (%s)", evt->getEvent());
294 free(tmp);
295 return 0;
296 }
297
298 if (!(bword = strtok_r(NULL, " ", &last))) {
299 LOGE("Malformatted state update (%s)", evt->getEvent());
300 free(tmp);
301 return 0;
302 }
303
304 mState = atoi(&bword[strlen("state=")]);
305 LOGD("State changed to %d", mState);
306 free(tmp);
San Mehatdc266072009-05-06 11:16:52 -0700307 return 0;
308}
309
310int Supplicant::onLinkSpeedEvent(SupplicantEvent *evt) {
311 LOGD("onLinkSpeedEvent(%s)", evt->getEvent());
312 return 0;
313}
314
315int Supplicant::onDriverStateEvent(SupplicantEvent *evt) {
316 LOGD("onDriverStateEvent(%s)", evt->getEvent());
317 return 0;
318}
319
320// XXX: Use a cursor + smartptr instead
San Mehat1441e762009-05-07 11:37:10 -0700321ScanResultCollection *Supplicant::createLatestScanResults() {
San Mehatdc266072009-05-06 11:16:52 -0700322 ScanResultCollection *d = new ScanResultCollection();
323 ScanResultCollection::iterator i;
324
325 pthread_mutex_lock(&mLatestScanResultsLock);
326 for (i = mLatestScanResults->begin(); i != mLatestScanResults->end(); ++i) {
327 d->push_back((*i)->clone());
328 }
329
330 pthread_mutex_unlock(&mLatestScanResultsLock);
331 return d;
San Mehat69772dc2009-05-10 09:27:07 -0700332}
333
San Mehat82a21162009-05-12 17:26:28 -0700334WifiNetworkCollection *Supplicant::createNetworkList() {
335 WifiNetworkCollection *d = new WifiNetworkCollection();
336 return d;
337}
338
339int Supplicant::addNetwork() {
340 char reply[32];
341 size_t len = sizeof(reply) -1;
342
343 memset(reply, 0, sizeof(reply));
344 if (sendCommand("ADD_NETWORK", reply, &len))
345 return -1;
346
347 return atoi(reply);
348}
349
350int Supplicant::removeNetwork(int networkId) {
351 char req[64];
352
353 sprintf(req, "REMOVE_NETWORK %d", networkId);
354 char reply[32];
355 size_t len = sizeof(reply) -1;
356 memset(reply, 0, sizeof(reply));
357
358 if (sendCommand(req, reply, &len))
359 return -1;
360 return 0;
361}
362
San Mehat69772dc2009-05-10 09:27:07 -0700363int Supplicant::setupConfig() {
364 char buf[2048];
365 int srcfd, destfd;
366 int nread;
367
368 if (access(SUPP_CONFIG_FILE, R_OK|W_OK) == 0) {
369 return 0;
370 } else if (errno != ENOENT) {
371 LOGE("Cannot access \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
372 return -1;
373 }
374
375 srcfd = open(SUPP_CONFIG_TEMPLATE, O_RDONLY);
376 if (srcfd < 0) {
377 LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
378 return -1;
379 }
380
381 destfd = open(SUPP_CONFIG_FILE, O_CREAT|O_WRONLY, 0660);
382 if (destfd < 0) {
383 close(srcfd);
384 LOGE("Cannot create \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
385 return -1;
386 }
387
388 while ((nread = read(srcfd, buf, sizeof(buf))) != 0) {
389 if (nread < 0) {
390 LOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
391 close(srcfd);
392 close(destfd);
393 unlink(SUPP_CONFIG_FILE);
394 return -1;
395 }
396 write(destfd, buf, nread);
397 }
398
399 close(destfd);
400 close(srcfd);
401
402 if (chown(SUPP_CONFIG_FILE, AID_SYSTEM, AID_WIFI) < 0) {
403 LOGE("Error changing group ownership of %s to %d: %s",
404 SUPP_CONFIG_FILE, AID_WIFI, strerror(errno));
405 unlink(SUPP_CONFIG_FILE);
406 return -1;
407 }
408 return 0;
409}