blob: 9bb6bf2c1822b34b4becafacf90423355d25a9a7 [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"
San Mehat1441e762009-05-07 11:37:10 -070032#include "NetworkManager.h"
San Mehat8d3fc3f2009-05-12 14:36:32 -070033#include "ErrorCode.h"
San Mehat3c5a6f02009-05-22 15:36:13 -070034#include "WifiController.h"
San Mehat3aff2d12009-06-15 14:10:44 -070035#include "SupplicantStatus.h"
San Mehatdc266072009-05-06 11:16:52 -070036
37#include "libwpa_client/wpa_ctrl.h"
38
39#define IFACE_DIR "/data/system/wpa_supplicant"
40#define DRIVER_PROP_NAME "wlan.driver.status"
San Mehat5d6d4172009-05-14 15:00:06 -070041#define SUPPLICANT_SERVICE_NAME "wpa_supplicant"
San Mehat69772dc2009-05-10 09:27:07 -070042#define SUPP_CONFIG_TEMPLATE "/system/etc/wifi/wpa_supplicant.conf"
43#define SUPP_CONFIG_FILE "/data/misc/wifi/wpa_supplicant.conf"
44
San Mehat3aff2d12009-06-15 14:10:44 -070045Supplicant::Supplicant(WifiController *wc, ISupplicantEventHandler *handlers) {
46 mHandlers = handlers;
San Mehat3c5a6f02009-05-22 15:36:13 -070047 mController = wc;
San Mehat3c5a6f02009-05-22 15:36:13 -070048 mInterfaceName = NULL;
San Mehatdc266072009-05-06 11:16:52 -070049 mCtrl = NULL;
50 mMonitor = NULL;
51 mListener = NULL;
San Mehat3c5a6f02009-05-22 15:36:13 -070052
San Mehat5d6d4172009-05-14 15:00:06 -070053 mServiceManager = new ServiceManager();
San Mehatdc266072009-05-06 11:16:52 -070054
San Mehat3c5a6f02009-05-22 15:36:13 -070055 mNetworks = new WifiNetworkCollection();
56 pthread_mutex_init(&mNetworksLock, NULL);
San Mehatdc266072009-05-06 11:16:52 -070057}
58
San Mehat5d6d4172009-05-14 15:00:06 -070059Supplicant::~Supplicant() {
60 delete mServiceManager;
San Mehat3c5a6f02009-05-22 15:36:13 -070061 if (mInterfaceName)
62 free(mInterfaceName);
San Mehat5d6d4172009-05-14 15:00:06 -070063}
64
San Mehatdc266072009-05-06 11:16:52 -070065int Supplicant::start() {
San Mehat69772dc2009-05-10 09:27:07 -070066
67 if (setupConfig()) {
68 LOGW("Unable to setup supplicant.conf");
69 }
San Mehat3c5a6f02009-05-22 15:36:13 -070070
San Mehat5d6d4172009-05-14 15:00:06 -070071 if (mServiceManager->start(SUPPLICANT_SERVICE_NAME)) {
72 LOGE("Error starting supplicant (%s)", strerror(errno));
73 return -1;
San Mehatdc266072009-05-06 11:16:52 -070074 }
75
76 wpa_ctrl_cleanup();
San Mehatdc266072009-05-06 11:16:52 -070077 if (connectToSupplicant()) {
78 LOGE("Error connecting to supplicant (%s)\n", strerror(errno));
79 return -1;
80 }
San Mehat3c5a6f02009-05-22 15:36:13 -070081
82 if (retrieveInterfaceName()) {
83 LOGE("Error retrieving interface name (%s)\n", strerror(errno));
84 return -1;
85 }
86
San Mehatdc266072009-05-06 11:16:52 -070087 return 0;
88}
89
90int Supplicant::stop() {
San Mehatdc266072009-05-06 11:16:52 -070091
San Mehatdc266072009-05-06 11:16:52 -070092 if (mListener->stopListener()) {
93 LOGW("Unable to stop supplicant listener (%s)", strerror(errno));
94 return -1;
95 }
96
San Mehat5d6d4172009-05-14 15:00:06 -070097 if (mServiceManager->stop(SUPPLICANT_SERVICE_NAME)) {
98 LOGW("Error stopping supplicant (%s)", strerror(errno));
San Mehatdc266072009-05-06 11:16:52 -070099 }
100
101 if (mCtrl) {
102 wpa_ctrl_close(mCtrl);
103 mCtrl = NULL;
104 }
105 if (mMonitor) {
106 wpa_ctrl_close(mMonitor);
107 mMonitor = NULL;
108 }
109
San Mehatdc266072009-05-06 11:16:52 -0700110 return 0;
111}
112
113bool Supplicant::isStarted() {
San Mehat5d6d4172009-05-14 15:00:06 -0700114 return mServiceManager->isRunning(SUPPLICANT_SERVICE_NAME);
San Mehatdc266072009-05-06 11:16:52 -0700115}
116
San Mehat3aff2d12009-06-15 14:10:44 -0700117SupplicantStatus *Supplicant::getStatus() {
118 char *reply;
119 size_t len = 4096;
120
121 if (!(reply = (char *) malloc(len))) {
122 errno = ENOMEM;
123 return NULL;
124 }
125
126 if (sendCommand("STATUS", reply, &len)) {
127 free(reply);
128 return NULL;
129 }
130
131 SupplicantStatus *ss = SupplicantStatus::createStatus(reply, len);
132
133 free (reply);
134 return ss;
135}
136
137/*
138 * Retrieves the list of networks from Supplicant
139 * and merge them into our current list
140 */
San Mehat3c5a6f02009-05-22 15:36:13 -0700141int Supplicant::refreshNetworkList() {
142 char *reply;
143 size_t len = 4096;
144
145 if (!(reply = (char *) malloc(len))) {
146 errno = ENOMEM;
San Mehatdc266072009-05-06 11:16:52 -0700147 return -1;
148 }
149
San Mehat3c5a6f02009-05-22 15:36:13 -0700150 if (sendCommand("LIST_NETWORKS", reply, &len)) {
151 free(reply);
152 return -1;
153 }
154
155 char *linep;
156 char *linep_next = NULL;
157
158 if (!strtok_r(reply, "\n", &linep_next)) {
159 LOGW("Malformatted network list\n");
San Mehat3aff2d12009-06-15 14:10:44 -0700160 free(reply);
161 errno = EIO;
162 return -1;
San Mehat3c5a6f02009-05-22 15:36:13 -0700163 }
164
San Mehat3aff2d12009-06-15 14:10:44 -0700165 pthread_mutex_lock(&mNetworksLock);
166
167 int num_added = 0;
168 int num_refreshed = 0;
169 int num_removed = 0;
170 while((linep = strtok_r(NULL, "\n", &linep_next))) {
171 // TODO: Move the decode into a static method so we
172 // don't create new_wn when we don't have to.
173 WifiNetwork *new_wn = new WifiNetwork(mController, this, linep);
174 WifiNetwork *merge_wn;
175
176 if ((merge_wn = this->lookupNetwork_UNLOCKED(new_wn->getNetworkId()))) {
177 num_refreshed++;
178 if (merge_wn->refresh()) {
179 LOGW("Error refreshing network %d (%s)",
180 merge_wn->getNetworkId(), strerror(errno));
181 }
182 delete new_wn;
183 } else {
184 num_added++;
185 new_wn->registerProperties();
186 mNetworks->push_back(new_wn);
187 if (new_wn->refresh()) {
188 LOGW("Unable to refresh network id %d (%s)",
189 new_wn->getNetworkId(), strerror(errno));
190 }
191 }
192 }
193
194 if (!mNetworks->empty()) {
195 // TODO: Add support for detecting removed networks
196 WifiNetworkCollection::iterator i;
197
198 for (i = mNetworks->begin(); i != mNetworks->end(); ++i) {
199 if (0) {
200 num_removed++;
201 (*i)->unregisterProperties();
202 delete (*i);
203 i = mNetworks->erase(i);
204 }
205 }
206 }
207
208
209 LOGD("Networks added %d, refreshed %d, removed %d\n",
210 num_added, num_refreshed, num_removed);
211 pthread_mutex_unlock(&mNetworksLock);
212
San Mehat3c5a6f02009-05-22 15:36:13 -0700213 free(reply);
214 return 0;
215}
216
217int Supplicant::connectToSupplicant() {
218 if (!isStarted())
219 LOGW("Supplicant service not running");
220
221 mCtrl = wpa_ctrl_open("tiwlan0"); // XXX:
San Mehatdc266072009-05-06 11:16:52 -0700222 if (mCtrl == NULL) {
223 LOGE("Unable to open connection to supplicant on \"%s\": %s",
224 "tiwlan0", strerror(errno));
225 return -1;
226 }
227 mMonitor = wpa_ctrl_open("tiwlan0");
228 if (mMonitor == NULL) {
229 wpa_ctrl_close(mCtrl);
230 mCtrl = NULL;
231 return -1;
232 }
233 if (wpa_ctrl_attach(mMonitor) != 0) {
234 wpa_ctrl_close(mMonitor);
235 wpa_ctrl_close(mCtrl);
236 mCtrl = mMonitor = NULL;
237 return -1;
238 }
239
San Mehat3aff2d12009-06-15 14:10:44 -0700240 mListener = new SupplicantListener(mHandlers, mMonitor);
San Mehat3c5a6f02009-05-22 15:36:13 -0700241
San Mehatdc266072009-05-06 11:16:52 -0700242 if (mListener->startListener()) {
243 LOGE("Error - unable to start supplicant listener");
244 stop();
245 return -1;
246 }
247 return 0;
248}
249
250int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len)
251{
252 if (!mCtrl) {
253 errno = ENOTCONN;
254 return -1;
255 }
256
San Mehat5d6d4172009-05-14 15:00:06 -0700257// LOGD("sendCommand(): -> '%s'", cmd);
San Mehatdc266072009-05-06 11:16:52 -0700258
259 int rc;
San Mehat3c5a6f02009-05-22 15:36:13 -0700260 memset(reply, 0, *reply_len);
San Mehatdc266072009-05-06 11:16:52 -0700261 if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2) {
262 errno = ETIMEDOUT;
263 return -1;
264 } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) {
San Mehat3c5a6f02009-05-22 15:36:13 -0700265 strcpy(reply, "FAIL");
San Mehatdc266072009-05-06 11:16:52 -0700266 errno = EIO;
267 return -1;
268 }
269
San Mehat3c5a6f02009-05-22 15:36:13 -0700270// LOGD("sendCommand(): <- '%s'", reply);
San Mehatdc266072009-05-06 11:16:52 -0700271 return 0;
272}
273
274int Supplicant::triggerScan(bool active) {
275 char reply[255];
276 size_t len = sizeof(reply);
277
278 if (sendCommand((active ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"),
279 reply, &len)) {
280 LOGW("triggerScan(%d): Error setting scan mode (%s)", active,
281 strerror(errno));
282 return -1;
283 }
284 len = sizeof(reply);
285
286 if (sendCommand("SCAN", reply, &len)) {
287 LOGW("triggerScan(%d): Error initiating scan", active);
288 return -1;
289 }
290 return 0;
291}
292
San Mehat3c5a6f02009-05-22 15:36:13 -0700293WifiNetwork *Supplicant::createNetwork() {
294 char reply[255];
San Mehat82a21162009-05-12 17:26:28 -0700295 size_t len = sizeof(reply) -1;
296
San Mehat82a21162009-05-12 17:26:28 -0700297 if (sendCommand("ADD_NETWORK", reply, &len))
San Mehat3c5a6f02009-05-22 15:36:13 -0700298 return NULL;
San Mehat82a21162009-05-12 17:26:28 -0700299
San Mehat3c5a6f02009-05-22 15:36:13 -0700300 if (reply[strlen(reply) -1] == '\n')
301 reply[strlen(reply) -1] = '\0';
302
303 WifiNetwork *wn = new WifiNetwork(mController, this, atoi(reply));
304 pthread_mutex_lock(&mNetworksLock);
305 mNetworks->push_back(wn);
306 pthread_mutex_unlock(&mNetworksLock);
307 return wn;
San Mehat82a21162009-05-12 17:26:28 -0700308}
309
San Mehat3c5a6f02009-05-22 15:36:13 -0700310int Supplicant::removeNetwork(WifiNetwork *wn) {
San Mehat82a21162009-05-12 17:26:28 -0700311 char req[64];
312
San Mehat3c5a6f02009-05-22 15:36:13 -0700313 sprintf(req, "REMOVE_NETWORK %d", wn->getNetworkId());
San Mehat82a21162009-05-12 17:26:28 -0700314 char reply[32];
315 size_t len = sizeof(reply) -1;
San Mehat3c5a6f02009-05-22 15:36:13 -0700316
San Mehat82a21162009-05-12 17:26:28 -0700317 if (sendCommand(req, reply, &len))
318 return -1;
San Mehat3c5a6f02009-05-22 15:36:13 -0700319
320 pthread_mutex_lock(&mNetworksLock);
321 WifiNetworkCollection::iterator it;
322 for (it = mNetworks->begin(); it != mNetworks->end(); ++it) {
323 if ((*it) == wn) {
324 mNetworks->erase(it);
325 break;
326 }
327 }
328 pthread_mutex_unlock(&mNetworksLock);
San Mehat82a21162009-05-12 17:26:28 -0700329 return 0;
330}
331
San Mehat3c5a6f02009-05-22 15:36:13 -0700332WifiNetwork *Supplicant::lookupNetwork(int networkId) {
333 pthread_mutex_lock(&mNetworksLock);
San Mehat3aff2d12009-06-15 14:10:44 -0700334 WifiNetwork *wn = lookupNetwork_UNLOCKED(networkId);
335 pthread_mutex_unlock(&mNetworksLock);
336 return wn;
337}
338
339WifiNetwork *Supplicant::lookupNetwork_UNLOCKED(int networkId) {
San Mehat3c5a6f02009-05-22 15:36:13 -0700340 WifiNetworkCollection::iterator it;
341 for (it = mNetworks->begin(); it != mNetworks->end(); ++it) {
342 if ((*it)->getNetworkId() == networkId) {
San Mehat3c5a6f02009-05-22 15:36:13 -0700343 return *it;
344 }
345 }
San Mehat3c5a6f02009-05-22 15:36:13 -0700346 errno = ENOENT;
347 return NULL;
348}
349
350WifiNetworkCollection *Supplicant::createNetworkList() {
351 WifiNetworkCollection *d = new WifiNetworkCollection();
352 WifiNetworkCollection::iterator i;
353
354 pthread_mutex_lock(&mNetworksLock);
355 for (i = mNetworks->begin(); i != mNetworks->end(); ++i)
356 d->push_back((*i)->clone());
357
358 pthread_mutex_unlock(&mNetworksLock);
359 return d;
360}
361
San Mehat69772dc2009-05-10 09:27:07 -0700362int Supplicant::setupConfig() {
363 char buf[2048];
364 int srcfd, destfd;
365 int nread;
366
367 if (access(SUPP_CONFIG_FILE, R_OK|W_OK) == 0) {
368 return 0;
369 } else if (errno != ENOENT) {
370 LOGE("Cannot access \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
371 return -1;
372 }
373
374 srcfd = open(SUPP_CONFIG_TEMPLATE, O_RDONLY);
375 if (srcfd < 0) {
376 LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
377 return -1;
378 }
379
380 destfd = open(SUPP_CONFIG_FILE, O_CREAT|O_WRONLY, 0660);
381 if (destfd < 0) {
382 close(srcfd);
383 LOGE("Cannot create \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
384 return -1;
385 }
386
387 while ((nread = read(srcfd, buf, sizeof(buf))) != 0) {
388 if (nread < 0) {
389 LOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
390 close(srcfd);
391 close(destfd);
392 unlink(SUPP_CONFIG_FILE);
393 return -1;
394 }
395 write(destfd, buf, nread);
396 }
397
398 close(destfd);
399 close(srcfd);
400
401 if (chown(SUPP_CONFIG_FILE, AID_SYSTEM, AID_WIFI) < 0) {
402 LOGE("Error changing group ownership of %s to %d: %s",
403 SUPP_CONFIG_FILE, AID_WIFI, strerror(errno));
404 unlink(SUPP_CONFIG_FILE);
405 return -1;
406 }
407 return 0;
408}
San Mehat3c5a6f02009-05-22 15:36:13 -0700409
410int Supplicant::setNetworkVar(int networkId, const char *var, const char *val) {
411 char reply[255];
412 size_t len = sizeof(reply) -1;
413
414 char *tmp;
415 asprintf(&tmp, "SET_NETWORK %d %s \"%s\"", networkId, var, val);
416 if (sendCommand(tmp, reply, &len)) {
417 free(tmp);
418 return -1;
419 }
420 free(tmp);
San Mehat3aff2d12009-06-15 14:10:44 -0700421
422 len = sizeof(reply) -1;
423 if (sendCommand("SAVE_CONFIG", reply, &len)) {
424 LOGE("Error saving config after %s = %s", var, val);
425 return -1;
426 }
San Mehat3c5a6f02009-05-22 15:36:13 -0700427 return 0;
428}
429
430const char *Supplicant::getNetworkVar(int networkId, const char *var,
431 char *buffer, size_t max) {
432 size_t len = max - 1;
433 char *tmp;
434
435 asprintf(&tmp, "GET_NETWORK %d %s", networkId, var);
436 if (sendCommand(tmp, buffer, &len)) {
437 free(tmp);
438 return NULL;
439 }
440 free(tmp);
441 return buffer;
442}
443
444int Supplicant::enableNetwork(int networkId, bool enabled) {
445 char req[64];
446
447 if (enabled)
448 sprintf(req, "ENABLE_NETWORK %d", networkId);
449 else
450 sprintf(req, "DISABLE_NETWORK %d", networkId);
451
452 char reply[16];
453 size_t len = sizeof(reply) -1;
454
455 if (sendCommand(req, reply, &len))
456 return -1;
457 return 0;
458}
459
460
461int Supplicant::retrieveInterfaceName() {
462 char reply[255];
463 size_t len = sizeof(reply) -1;
464
465 if (sendCommand("INTERFACES", reply, &len))
466 return -1;
467
468 reply[strlen(reply)-1] = '\0';
469 mInterfaceName = strdup(reply);
470 return 0;
471}