| /* |
| * 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 |