/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define LOG_TAG "WifiController"
#include <cutils/log.h>
#include "Supplicant.h"
#include "WifiController.h"
#include "WifiScanner.h"
#include "NetworkManager.h"
#include "ErrorCode.h"
#include "WifiNetwork.h"
#include "ISupplicantEventHandler.h"
#include "SupplicantState.h"
#include "SupplicantStatus.h"
#include "SupplicantAssociatingEvent.h"
#include "SupplicantAssociatedEvent.h"
#include "SupplicantConnectedEvent.h"
#include "SupplicantScanResultsEvent.h"
#include "SupplicantStateChangeEvent.h"
#include "SupplicantConnectionTimeoutEvent.h"
#include "SupplicantDisconnectedEvent.h"
WifiController::WifiController(PropertyManager *mPropMngr,
IControllerHandler *handlers,
char *modpath, char *modname, char *modargs) :
Controller("WIFI", mPropMngr, handlers) {
strncpy(mModulePath, modpath, sizeof(mModulePath));
strncpy(mModuleName, modname, sizeof(mModuleName));
strncpy(mModuleArgs, modargs, sizeof(mModuleArgs));
mLatestScanResults = new ScanResultCollection();
pthread_mutex_init(&mLatestScanResultsLock, NULL);
mSupplicant = new Supplicant(this, this);
mScanner = new WifiScanner(mSupplicant, 10);
mCurrentScanMode = 0;
mEnabled = false;
mSupplicantState = SupplicantState::UNKNOWN;
}
int WifiController::start() {
mPropMngr->registerProperty("wifi.enabled", this);
return 0;
}
int WifiController::stop() {
mPropMngr->unregisterProperty("wifi.enabled");
return 0;
}
int WifiController::enable() {
if (!isPoweredUp()) {
LOGI("Powering up");
sendStatusBroadcast("Powering up WiFi hardware");
if (powerUp()) {
LOGE("Powerup failed (%s)", strerror(errno));
return -1;
}
}
if (mModuleName[0] != '\0' && !isKernelModuleLoaded(mModuleName)) {
LOGI("Loading driver");
sendStatusBroadcast("Loading WiFi driver");
if (loadKernelModule(mModulePath, mModuleArgs)) {
LOGE("Kernel module load failed (%s)", strerror(errno));
goto out_powerdown;
}
}
if (!isFirmwareLoaded()) {
LOGI("Loading firmware");
sendStatusBroadcast("Loading WiFI firmware");
if (loadFirmware()) {
LOGE("Firmware load failed (%s)", strerror(errno));
goto out_powerdown;
}
}
if (!mSupplicant->isStarted()) {
LOGI("Starting WPA Supplicant");
sendStatusBroadcast("Starting WPA Supplicant");
if (mSupplicant->start()) {
LOGE("Supplicant start failed (%s)", strerror(errno));
goto out_unloadmodule;
}
}
if (Controller::bindInterface(mSupplicant->getInterfaceName())) {
LOGE("Error binding interface (%s)", strerror(errno));
goto out_unloadmodule;
}
if (mSupplicant->refreshNetworkList())
LOGW("Error getting list of networks (%s)", strerror(errno));
mPropMngr->registerProperty("wifi.supplicant.state", this);
mPropMngr->registerProperty("wifi.scanmode", this);
mPropMngr->registerProperty("wifi.interface", this);
LOGI("Enabled successfully");
return 0;
out_unloadmodule:
if (mModuleName[0] != '\0' && !isKernelModuleLoaded(mModuleName)) {
if (unloadKernelModule(mModuleName)) {
LOGE("Unable to unload module after failure!");
}
}
out_powerdown:
if (powerDown()) {
LOGE("Unable to powerdown after failure!");
}
return -1;
}
void WifiController::sendStatusBroadcast(const char *msg) {
NetworkManager::Instance()->
getBroadcaster()->
sendBroadcast(ErrorCode::UnsolicitedInformational, msg, false);
}
int WifiController::disable() {
mPropMngr->unregisterProperty("wifi.scanmode");
mPropMngr->unregisterProperty("wifi.supplicant.state");
mPropMngr->unregisterProperty("wifi.scanmode");
if (mSupplicant->isStarted()) {
sendStatusBroadcast("Stopping WPA Supplicant");
if (mSupplicant->stop()) {
LOGE("Supplicant stop failed (%s)", strerror(errno));
return -1;
}
} else
LOGW("disable(): Supplicant not running?");
if (mModuleName[0] != '\0' && isKernelModuleLoaded(mModuleName)) {
sendStatusBroadcast("Unloading WiFi driver");
if (unloadKernelModule(mModuleName)) {
LOGE("Unable to unload module (%s)", strerror(errno));
return -1;
}
}
if (isPoweredUp()) {
sendStatusBroadcast("Powering down WiFi hardware");
if (powerDown()) {
LOGE("Powerdown failed (%s)", strerror(errno));
return -1;
}
}
return 0;
}
int WifiController::loadFirmware() {
return 0;
}
int WifiController::setScanMode(uint32_t mode) {
int rc = 0;
if (mCurrentScanMode == mode)
return 0;
if (!(mode & SCAN_ENABLE_MASK)) {
if (mCurrentScanMode & SCAN_REPEAT_MASK)
mScanner->stop();
} else if (mode & SCAN_REPEAT_MASK)
rc = mScanner->start(mode & SCAN_ACTIVE_MASK);
else
rc = mSupplicant->triggerScan(mode & SCAN_ACTIVE_MASK);
mCurrentScanMode = mode;
return rc;
}
WifiNetwork *WifiController::createNetwork() {
WifiNetwork *wn = mSupplicant->createNetwork();
return wn;
}
int WifiController::removeNetwork(int networkId) {
WifiNetwork *wn = mSupplicant->lookupNetwork(networkId);
if (!wn)
return -1;
return mSupplicant->removeNetwork(wn);
}
ScanResultCollection *WifiController::createScanResults() {
ScanResultCollection *d = new ScanResultCollection();
ScanResultCollection::iterator i;
pthread_mutex_lock(&mLatestScanResultsLock);
for (i = mLatestScanResults->begin(); i != mLatestScanResults->end(); ++i)
d->push_back((*i)->clone());
pthread_mutex_unlock(&mLatestScanResultsLock);
return d;
}
WifiNetworkCollection *WifiController::createNetworkList() {
return mSupplicant->createNetworkList();
}
int WifiController::set(const char *name, const char *value) {
int rc;
if (!strcmp(name, "wifi.enabled")) {
int en = atoi(value);
if (en == mEnabled)
return 0;
rc = (en ? enable() : disable());
if (!rc)
mEnabled = en;
} else if (!strcmp(name, "wifi.interface")) {
errno = EROFS;
return -1;
} else if (!strcmp(name, "wifi.scanmode"))
return setScanMode((uint32_t) strtoul(value, NULL, 0));
else if (!strcmp(name, "wifi.supplicant.state")) {
errno = EROFS;
return -1;
} else
return Controller::set(name, value);
return rc;
}
const char *WifiController::get(const char *name, char *buffer, size_t maxsize) {
if (!strcmp(name, "wifi.enabled"))
snprintf(buffer, maxsize, "%d", mEnabled);
else if (!strcmp(name, "wifi.interface")) {
snprintf(buffer, maxsize, "%s",
(getBoundInterface() ? getBoundInterface() : "none"));
} else if (!strcmp(name, "wifi.scanmode"))
snprintf(buffer, maxsize, "0x%.8x", mCurrentScanMode);
else if (!strcmp(name, "wifi.supplicant.state"))
return SupplicantState::toString(mSupplicantState, buffer, maxsize);
else
return Controller::get(name, buffer, maxsize);
return buffer;
}
void WifiController::onAssociatingEvent(SupplicantAssociatingEvent *evt) {
LOGD("onAssociatingEvent(%s, %s, %d)",
(evt->getBssid() ? evt->getBssid() : "n/a"),
(evt->getSsid() ? evt->getSsid() : "n/a"),
evt->getFreq());
}
void WifiController::onAssociatedEvent(SupplicantAssociatedEvent *evt) {
LOGD("onAssociatedEvent(%s)", evt->getBssid());
}
void WifiController::onConnectedEvent(SupplicantConnectedEvent *evt) {
LOGD("onConnectedEvent(%s, %d)", evt->getBssid(), evt->getReassociated());
SupplicantStatus *ss = mSupplicant->getStatus();
WifiNetwork *wn;
if (ss->getWpaState() != SupplicantState::COMPLETED) {
char tmp[32];
LOGW("onConnected() with SupplicantState = %s!",
SupplicantState::toString(ss->getWpaState(), tmp,
sizeof(tmp)));
return;
}
if (ss->getId() == -1) {
LOGW("onConnected() with id = -1!");
return;
}
if (!(wn = mSupplicant->lookupNetwork(ss->getId()))) {
LOGW("Error looking up connected network id %d (%s)",
ss->getId(), strerror(errno));
return;
}
delete ss;
mHandlers->onInterfaceConnected(this, wn->getIfaceCfg());
}
void WifiController::onScanResultsEvent(SupplicantScanResultsEvent *evt) {
char *reply;
if (!(reply = (char *) malloc(4096))) {
LOGE("Out of memory");
return;
}
size_t len = 4096;
if (mSupplicant->sendCommand("SCAN_RESULTS", reply, &len)) {
LOGW("onScanResultsEvent: Error getting scan results (%s)",
strerror(errno));
free(reply);
return;
}
pthread_mutex_lock(&mLatestScanResultsLock);
if (!mLatestScanResults->empty()) {
ScanResultCollection::iterator i;
for (i = mLatestScanResults->begin();
i !=mLatestScanResults->end(); ++i) {
delete *i;
}
mLatestScanResults->clear();
}
char *linep;
char *linep_next = NULL;
if (!strtok_r(reply, "\n", &linep_next)) {
free(reply);
pthread_mutex_unlock(&mLatestScanResultsLock);
return;
}
while((linep = strtok_r(NULL, "\n", &linep_next)))
mLatestScanResults->push_back(new ScanResult(linep));
char *tmp;
asprintf(&tmp, "Scan results ready (%d)", mLatestScanResults->size());
NetworkManager::Instance()->getBroadcaster()->
sendBroadcast(ErrorCode::UnsolicitedInformational, tmp, false);
free(tmp);
pthread_mutex_unlock(&mLatestScanResultsLock);
free(reply);
}
void WifiController::onStateChangeEvent(SupplicantStateChangeEvent *evt) {
char tmp[32];
char tmp2[32];
LOGD("onStateChangeEvent(%s -> %s)",
SupplicantState::toString(mSupplicantState, tmp, sizeof(tmp)),
SupplicantState::toString(evt->getState(), tmp2, sizeof(tmp2)));
mSupplicantState = evt->getState();
}
void WifiController::onConnectionTimeoutEvent(SupplicantConnectionTimeoutEvent *evt) {
LOGD("onConnectionTimeoutEvent(%s)", evt->getBssid());
}
void WifiController::onDisconnectedEvent(SupplicantDisconnectedEvent *evt) {
mHandlers->onInterfaceDisconnected(this, getBoundInterface());
}
#if 0
void WifiController::onTerminatingEvent(SupplicantEvent *evt) {
LOGD("onTerminatingEvent(%s)", evt->getEvent());
}
void WifiController::onPasswordChangedEvent(SupplicantEvent *evt) {
LOGD("onPasswordChangedEvent(%s)", evt->getEvent());
}
void WifiController::onEapNotificationEvent(SupplicantEvent *evt) {
LOGD("onEapNotificationEvent(%s)", evt->getEvent());
}
void WifiController::onEapStartedEvent(SupplicantEvent *evt) {
LOGD("onEapStartedEvent(%s)", evt->getEvent());
}
void WifiController::onEapMethodEvent(SupplicantEvent *evt) {
LOGD("onEapMethodEvent(%s)", evt->getEvent());
}
void WifiController::onEapSuccessEvent(SupplicantEvent *evt) {
LOGD("onEapSuccessEvent(%s)", evt->getEvent());
}
void WifiController::onEapFailureEvent(SupplicantEvent *evt) {
LOGD("onEapFailureEvent(%s)", evt->getEvent());
}
void WifiController::onLinkSpeedEvent(SupplicantEvent *evt) {
LOGD("onLinkSpeedEvent(%s)", evt->getEvent());
}
void WifiController::onDriverStateEvent(SupplicantEvent *evt) {
LOGD("onDriverStateEvent(%s)", evt->getEvent());
}
#endif