diff --git a/nexus/Android.mk b/nexus/Android.mk new file mode 100644 index 000000000..e76cb27e7 --- /dev/null +++ b/nexus/Android.mk @@ -0,0 +1,47 @@ +BUILD_NEXUS := false +ifeq ($(BUILD_NEXUS),true) + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + main.cpp \ + NetworkManager.cpp \ + CommandListener.cpp \ + Controller.cpp \ + WifiController.cpp \ + LoopController.cpp \ + NexusCommand.cpp \ + TiwlanWifiController.cpp \ + Supplicant.cpp \ + SupplicantEvent.cpp \ + SupplicantListener.cpp \ + VpnController.cpp \ + ScanResult.cpp \ + +LOCAL_MODULE:= nexus + +LOCAL_C_INCLUDES := $(KERNEL_HEADERS) + +LOCAL_CFLAGS := + +LOCAL_SHARED_LIBRARIES := libsysutils libwpa_client libutils + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= \ + nexctl.c \ + +LOCAL_MODULE:= nexctl + +LOCAL_C_INCLUDES := $(KERNEL_HEADERS) + +LOCAL_CFLAGS := + +LOCAL_SHARED_LIBRARIES := libutils + +include $(BUILD_EXECUTABLE) + +endif # ifeq ($(BUILD_NEXUS),true) diff --git a/nexus/CommandListener.cpp b/nexus/CommandListener.cpp new file mode 100644 index 000000000..cdb1db51f --- /dev/null +++ b/nexus/CommandListener.cpp @@ -0,0 +1,124 @@ +/* + * 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 +#include + +#define LOG_TAG "CommandListener" +#include + +#include "CommandListener.h" +#include "Controller.h" +#include "NetworkManager.h" +#include "WifiController.h" + +CommandListener::CommandListener(NetworkManager *netman) : + FrameworkListener("nexus") { + mNetman = netman; + + registerCmd(new WifiEnableCmd(netman)); + registerCmd(new WifiDisableCmd(netman)); + registerCmd(new WifiScanCmd(netman)); + + registerCmd(new VpnEnableCmd(netman)); + registerCmd(new VpnDisableCmd(netman)); +} + +/* ------------- + * Wifi Commands + * ------------ */ + +CommandListener::WifiEnableCmd::WifiEnableCmd(NetworkManager *netman) : + NexusCommand("wifi_enable", netman) { +} + +int CommandListener::WifiEnableCmd::runCommand(char *data) { + Controller *c = mNetman->findController("WIFI"); + char buffer[32]; + + sprintf(buffer, "WIFI_ENABLE:%d", (c->enable() ? errno : 0)); + mNetman->getFrameworkManager()->sendMsg(buffer); + return 0; +} + +CommandListener::WifiDisableCmd::WifiDisableCmd(NetworkManager *netman) : + NexusCommand("wifi_disable", netman) { +} + +int CommandListener::WifiDisableCmd::runCommand(char *data) { + Controller *c = mNetman->findController("WIFI"); + char buffer[32]; + + sprintf(buffer, "WIFI_DISABLE:%d", (c->disable() ? errno : 0)); + mNetman->getFrameworkManager()->sendMsg(buffer); + return 0; +} + +CommandListener::WifiScanCmd::WifiScanCmd(NetworkManager *netman) : + NexusCommand("wifi_scan", netman) { +} + +int CommandListener::WifiScanCmd::runCommand(char *data) { + LOGD("WifiScanCmd(%s)", data); + WifiController *wc = (WifiController *) mNetman->findController("WIFI"); + char buffer[32]; + int mode = 0; + char *bword, *last; + + if (!(bword = strtok_r(data, ":", &last))) { + errno = EINVAL; + return -1; + } + + if (!(bword = strtok_r(NULL, ":", &last))) { + errno = EINVAL; + return -1; + } + + mode = atoi(bword); + + sprintf(buffer, "WIFI_SCAN:%d", (wc->setScanMode(mode) ? errno : 0)); + mNetman->getFrameworkManager()->sendMsg(buffer); + return 0; +} + +/* ------------ + * Vpn Commands + * ------------ */ +CommandListener::VpnEnableCmd::VpnEnableCmd(NetworkManager *netman) : + NexusCommand("vpn_enable", netman) { +} + +int CommandListener::VpnEnableCmd::runCommand(char *data) { + Controller *c = mNetman->findController("VPN"); + char buffer[32]; + + sprintf(buffer, "VPN_ENABLE:%d", (c->enable() ? errno : 0)); + mNetman->getFrameworkManager()->sendMsg(buffer); + return 0; +} + +CommandListener::VpnDisableCmd::VpnDisableCmd(NetworkManager *netman) : + NexusCommand("vpn_disable", netman) { +} + +int CommandListener::VpnDisableCmd::runCommand(char *data) { + Controller *c = mNetman->findController("VPN"); + char buffer[32]; + + sprintf(buffer, "VPN_DISABLE:%d", (c->disable() ? errno : 0)); + mNetman->getFrameworkManager()->sendMsg(buffer); + return 0; +} diff --git a/nexus/CommandListener.h b/nexus/CommandListener.h new file mode 100644 index 000000000..261c0936a --- /dev/null +++ b/nexus/CommandListener.h @@ -0,0 +1,70 @@ +/* + * 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. + */ +#ifndef _COMMANDLISTENER_H__ +#define _COMMANDLISTENER_H__ + +#include +#include "NexusCommand.h" + +class NetworkManager; + +class CommandListener : public FrameworkListener { +protected: + NetworkManager *mNetman; + +public: + CommandListener(NetworkManager *netman); + virtual ~CommandListener() {} + +private: + class WifiEnableCmd : public NexusCommand { + public: + WifiEnableCmd(NetworkManager *); + virtual ~WifiEnableCmd() {} + int runCommand(char *data); + }; + + class WifiDisableCmd : public NexusCommand { + public: + WifiDisableCmd(NetworkManager *); + virtual ~WifiDisableCmd() {} + int runCommand(char *data); + }; + + class WifiScanCmd : public NexusCommand { + public: + WifiScanCmd(NetworkManager *); + virtual ~WifiScanCmd() {} + int runCommand(char *data); + }; + + class VpnEnableCmd : public NexusCommand { + public: + VpnEnableCmd(NetworkManager *); + virtual ~VpnEnableCmd() {} + int runCommand(char *data); + }; + + class VpnDisableCmd : public NexusCommand { + public: + VpnDisableCmd(NetworkManager *); + virtual ~VpnDisableCmd() {} + int runCommand(char *data); + }; + +}; + +#endif diff --git a/nexus/Controller.cpp b/nexus/Controller.cpp new file mode 100644 index 000000000..cc1a18730 --- /dev/null +++ b/nexus/Controller.cpp @@ -0,0 +1,144 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "Controller" + +#include + +#include "Controller.h" + +extern "C" int init_module(void *, unsigned int, const char *); +extern "C" int delete_module(const char *, unsigned int); + +Controller::Controller(const char *name) { + mName = name; +} + +int Controller::start() { + return 0; +} + +int Controller::stop() { + return 0; +} + +int Controller::loadKernelModule(char *modpath, const char *args) { + void *module; + unsigned int size; + + LOGD("loadKernelModule(%s, %s)", modpath, args); + + module = loadFile(modpath, &size); + if (!module) { + errno = -EIO; + return -1; + } + + int rc = init_module(module, size, args); + free (module); + return rc; +} + +int Controller::unloadKernelModule(const char *modtag) { + int rc = -1; + int retries = 10; + + LOGD("unloadKernelModule(%s)", modtag); + while (retries--) { + rc = delete_module(modtag, O_NONBLOCK | O_EXCL); + if (rc < 0 && errno == EAGAIN) + usleep(1000*500); + else + break; + } + + if (rc != 0) { + LOGW("Unable to unload kernel driver '%s' (%s)", modtag, + strerror(errno)); + } + return rc; +} + +bool Controller::isKernelModuleLoaded(const char *modtag) { + FILE *fp = fopen("/proc/modules", "r"); + + if (!fp) { + LOGE("Unable to open /proc/modules (%s)", strerror(errno)); + return false; + } + + char line[255]; + while(fgets(line, sizeof(line), fp)) { + char *endTag = strchr(line, ' '); + + if (!endTag) { + LOGW("Unable to find tag for line '%s'", line); + continue; + } + if (!strncmp(line, modtag, (endTag - line))) { + fclose(fp); + return true; + } + } + + fclose(fp); + return false; +} + + +void *Controller::loadFile(char *filename, unsigned int *_size) +{ + int ret, fd; + struct stat sb; + ssize_t size; + void *buffer = NULL; + + /* open the file */ + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + + /* find out how big it is */ + if (fstat(fd, &sb) < 0) + goto bail; + size = sb.st_size; + + /* allocate memory for it to be read into */ + buffer = malloc(size); + if (!buffer) + goto bail; + + /* slurp it into our buffer */ + ret = read(fd, buffer, size); + if (ret != size) + goto bail; + + /* let the caller know how big it is */ + *_size = size; + +bail: + close(fd); + return buffer; +} diff --git a/nexus/Controller.h b/nexus/Controller.h new file mode 100644 index 000000000..8e69978fa --- /dev/null +++ b/nexus/Controller.h @@ -0,0 +1,47 @@ +/* + * 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. + */ +#ifndef _CONTROLLER_H +#define _CONTROLLER_H + +#include "../../../frameworks/base/include/utils/List.h" + +class Controller { +private: + const char *mName; + +public: + Controller(const char *name); + virtual ~Controller() {} + + virtual int start(); + virtual int stop(); + + virtual int enable() = 0; + virtual int disable() = 0; + + virtual const char *getName() { return mName; } + +protected: + int loadKernelModule(char *modpath, const char *args); + bool isKernelModuleLoaded(const char *modtag); + int unloadKernelModule(const char *modtag); + +private: + void *loadFile(char *filename, unsigned int *_size); +}; + +typedef android::List ControllerCollection; +#endif diff --git a/nexus/LoopController.cpp b/nexus/LoopController.cpp new file mode 100644 index 000000000..38037ac34 --- /dev/null +++ b/nexus/LoopController.cpp @@ -0,0 +1,32 @@ +/* + * 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 + +#include "LoopController.h" + +LoopController::LoopController() : + Controller("LOOP") { +} + +int LoopController::enable() { + errno = ENOSYS; + return -1; +} + +int LoopController::disable() { + errno = ENOSYS; + return -1; +} diff --git a/nexus/LoopController.h b/nexus/LoopController.h new file mode 100644 index 000000000..8b899779d --- /dev/null +++ b/nexus/LoopController.h @@ -0,0 +1,30 @@ +/* + * 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. + */ +#ifndef _LOOP_CONTROLLER_H +#define _LOOP_CONTROLLER_H + +#include "Controller.h" + +class LoopController : public Controller { +public: + LoopController(); + virtual ~LoopController() {} + + int enable(); + int disable(); +}; + +#endif diff --git a/nexus/NetworkManager.cpp b/nexus/NetworkManager.cpp new file mode 100644 index 000000000..9c649459d --- /dev/null +++ b/nexus/NetworkManager.cpp @@ -0,0 +1,100 @@ +/* + * 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 +#include + +#define LOG_TAG "Nexus" + +#include + +#include "NetworkManager.h" +#include "CommandListener.h" +#include "LoopController.h" +#include "VpnController.h" + +#include "TiwlanWifiController.h" + +NetworkManager::NetworkManager() { + mListener = new CommandListener(this); + mFm = new FrameworkManager(mListener); + mControllers = new ControllerCollection(); +} + +int NetworkManager::run() { + LOGD("NetworkManager::start()"); + + // XXX: Factory needed + addController(new LoopController()); + addController(new TiwlanWifiController("/system/lib/modules/wlan.ko", "wlan", "")); + addController(new VpnController()); + //addController(new GenericController("rmnet0")); + + if (startControllers()) { + LOGW("Unable to start all controllers (%s)", strerror(errno)); + } + mFm->run(); + return 0; +} + +void NetworkManager::addController(Controller *c) { + mControllers->push_back(c); +} + +int NetworkManager::startControllers() { + int rc = 0; + ControllerCollection::iterator i; + + for (i = mControllers->begin(); i != mControllers->end(); ++i) { + int irc = (*i)->start(); + LOGD("Controller '%s' start rc = %d", (*i)->getName(), irc); + if (irc && !rc) + rc = irc; + } + return rc; +} + +int NetworkManager::stopControllers() { + int rc = 0; + ControllerCollection::iterator i; + + for (i = mControllers->begin(); i != mControllers->end(); ++i) { + int irc = (*i)->stop(); + LOGD("Controller '%s' stop rc = %d", (*i)->getName(), irc); + if (irc && !rc) + rc = irc; + } + return rc; +} + +Controller *NetworkManager::findController(const char *name) { + ControllerCollection::iterator i; + for (i = mControllers->begin(); i != mControllers->end(); ++i) { + if (!strcmp((*i)->getName(), name)) + return *i; + } + LOGW("Controller '%s' not found", name); + return NULL; +} + +int NetworkManager::onInterfaceCreated(Controller *c, char *name) { + LOGD("Interface %s created by controller %s", name, c->getName()); + return 0; +} + +int NetworkManager::onInterfaceDestroyed(Controller *c, char *name) { + LOGD("Interface %s destroyed by controller %s", name, c->getName()); + return 0; +} diff --git a/nexus/NetworkManager.h b/nexus/NetworkManager.h new file mode 100644 index 000000000..8f362a95f --- /dev/null +++ b/nexus/NetworkManager.h @@ -0,0 +1,51 @@ +/* + * 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. + */ +#ifndef _NETWORKMANAGER_H +#define _NETWORKMANAGER_H + +#include "Controller.h" + +#include + +class NetworkManager { +private: + FrameworkListener *mListener; + FrameworkManager *mFm; + ControllerCollection *mControllers; + +public: + NetworkManager(); + virtual ~NetworkManager() {} + + int run(); + +private: + void addController(Controller *c); + int startControllers(); + int stopControllers(); + +public: + Controller *findController(const char *name); + ControllerCollection *getControllers() { return mControllers; } + FrameworkManager *getFrameworkManager() { return mFm; } + +public: +// XXX: Extract these into an interface + int onInterfaceCreated(Controller *c, char *name); + int onInterfaceDestroyed(Controller *c, char *name); + +}; +#endif diff --git a/nexus/NexusCommand.cpp b/nexus/NexusCommand.cpp new file mode 100644 index 000000000..090113c09 --- /dev/null +++ b/nexus/NexusCommand.cpp @@ -0,0 +1,21 @@ +/* + * 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 "NexusCommand.h" + +NexusCommand::NexusCommand(const char *cmd, NetworkManager *netman) : + FrameworkCommand(cmd) { + mNetman = netman; +} diff --git a/nexus/NexusCommand.h b/nexus/NexusCommand.h new file mode 100644 index 000000000..204541c1d --- /dev/null +++ b/nexus/NexusCommand.h @@ -0,0 +1,32 @@ +/* + * 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. + */ +#ifndef _NEXUS_COMMAND_H +#define _NEXUS_COMMAND_H + +#include + +class NetworkManager; + +class NexusCommand : public FrameworkCommand { +protected: + NetworkManager *mNetman; + +public: + NexusCommand(const char *cmd, NetworkManager *netman); + virtual ~NexusCommand() {} +}; + +#endif diff --git a/nexus/ScanResult.cpp b/nexus/ScanResult.cpp new file mode 100644 index 000000000..b7237b574 --- /dev/null +++ b/nexus/ScanResult.cpp @@ -0,0 +1,74 @@ +/* + * 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 + +#define LOG_TAG "ScanResult" +#include + +#include "ScanResult.h" + +ScanResult::ScanResult() { +} + +ScanResult::ScanResult(char *rawResult) { + char *tok, *next = NULL; + + if (!(tok = strtok_r(rawResult, "\t", &next))) + goto out_bad; + mBssid = strdup(tok); + + if (!(tok = strtok_r(NULL, "\t", &next))) + goto out_bad; + mFreq = atoi(tok); + + if (!(tok = strtok_r(NULL, "\t", &next))) + goto out_bad; + mLevel = atoi(tok); + + if (!(tok = strtok_r(rawResult, "\t", &next))) + goto out_bad; + mFlags = strdup(tok); + + if (!(tok = strtok_r(rawResult, "\t", &next))) + goto out_bad; + mSsid = strdup(tok); + + return; + + out_bad: + LOGW("Malformatted scan result (%s)", rawResult); +} + +ScanResult::~ScanResult() { + if (mBssid) + free(mBssid); + if (mFlags) + free(mFlags); + if (mSsid) + free(mSsid); +} + +ScanResult *ScanResult::clone() { + ScanResult *r = new ScanResult(); + + r->mBssid = strdup(mBssid); + r->mFreq = mFreq; + r->mLevel = mLevel; + r->mFlags = strdup(mFlags); + r->mSsid = strdup(mSsid); + + return r; +} diff --git a/nexus/ScanResult.h b/nexus/ScanResult.h new file mode 100644 index 000000000..79b2b659f --- /dev/null +++ b/nexus/ScanResult.h @@ -0,0 +1,47 @@ +/* + * 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. + */ +#ifndef _SCAN_RESULT_H +#define _SCAN_RESULT_H + +#include + +#include "../../../frameworks/base/include/utils/List.h" + +class ScanResult { + char *mBssid; + uint32_t mFreq; + int mLevel; + char *mFlags; + char *mSsid; + +private: + ScanResult(); + +public: + ScanResult(char *rawResult); + virtual ~ScanResult(); + + ScanResult *clone(); + + const char *getBssid() { return mBssid; } + uint32_t getFreq() { return mFreq; } + const char *getFlags() { return mFlags; } + const char *getSsid() { return mSsid; } +}; + +typedef android::List ScanResultCollection; + +#endif diff --git a/nexus/Supplicant.cpp b/nexus/Supplicant.cpp new file mode 100644 index 000000000..215a8b347 --- /dev/null +++ b/nexus/Supplicant.cpp @@ -0,0 +1,377 @@ +/* + * 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 + +#define LOG_TAG "Supplicant" +#include +#include + +#undef HAVE_LIBC_SYSTEM_PROPERTIES + +#ifdef HAVE_LIBC_SYSTEM_PROPERTIES +#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ +#include +#endif + +#include "Supplicant.h" +#include "SupplicantListener.h" +#include "SupplicantState.h" +#include "SupplicantEvent.h" +#include "ScanResult.h" + +#include "libwpa_client/wpa_ctrl.h" + +#define IFACE_DIR "/data/system/wpa_supplicant" +#define DRIVER_PROP_NAME "wlan.driver.status" +#define SUPPLICANT_NAME "wpa_supplicant" +#define SUPP_PROP_NAME "init.svc.wpa_supplicant" + +Supplicant::Supplicant() { + mCtrl = NULL; + mMonitor = NULL; + mListener = NULL; + + mState = SupplicantState::UNKNOWN; + + mLatestScanResults = new ScanResultCollection(); + + pthread_mutex_init(&mLatestScanResultsLock, NULL); +} + +int Supplicant::start() { + LOGD("start():"); + // XXX: Validate supplicant config file + + char status[PROPERTY_VALUE_MAX] = {'\0'}; + int count = 200; +#ifdef HAVE_LIBC_SYSTEM_PROPERTIES + const prop_info *pi; + unsigned int serial = 0; +#endif + + if (property_get(SUPP_PROP_NAME, status, NULL) && + strcmp(status, "running") == 0) { + return 0; + } + + wpa_ctrl_cleanup(); +#ifdef HAVE_LIBC_SYSTEM_PROPERTIES + pi = __system_property_find(SUPP_PROP_NAME); + if (pi != NULL) + serial = pi->serial; +#endif + + property_set("ctl.start", SUPPLICANT_NAME); + sched_yield(); + while (count--) { +#ifdef HAVE_LIBC_SYSTEM_PROPERTIES + if (!pi) + pi = __system_property_find(SUPP_PROP_NAME); + if (pi) { + __system_property_read(pi, NULL, status); + if (strcmp(status, "running") == 0) + return 0; + else if (pi->serial != serial && + strcmp(status, "stopped") == 0) { + errno = EIO; + return -1; + } + } +#else + if (property_get(SUPP_PROP_NAME, status, NULL)) { + if (strcmp(status, "running") == 0) + break; + } +#endif + usleep(100000); + } + + if (!count) { + errno = ETIMEDOUT; + return -1; + } + + if (connectToSupplicant()) { + LOGE("Error connecting to supplicant (%s)\n", strerror(errno)); + return -1; + } + return 0; +} + +int Supplicant::stop() { + LOGD("stop()"); + + char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; + int count = 50; + + if (mListener->stopListener()) { + LOGW("Unable to stop supplicant listener (%s)", strerror(errno)); + return -1; + } + + if (property_get(SUPP_PROP_NAME, supp_status, NULL) + && strcmp(supp_status, "stopped") == 0) { + return 0; + } + + property_set("ctl.stop", SUPPLICANT_NAME); + sched_yield(); + + while (count-- > 0) { + if (property_get(SUPP_PROP_NAME, supp_status, NULL)) { + if (strcmp(supp_status, "stopped") == 0) + break; + } + usleep(100000); + } + + if (mCtrl) { + wpa_ctrl_close(mCtrl); + mCtrl = NULL; + } + if (mMonitor) { + wpa_ctrl_close(mMonitor); + mMonitor = NULL; + } + + if (!count) { + LOGD("Timed out waiting for supplicant to stop"); + errno = ETIMEDOUT; + return -1; + } + + LOGD("Stopped OK"); + + return 0; +} + +bool Supplicant::isStarted() { + char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; + if (!property_get(SUPP_PROP_NAME, supp_status, NULL) || + !strcmp(supp_status, "running")) { + return false; + } + return true; +} + +int Supplicant::connectToSupplicant() { + char ifname[256]; + char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; + + if (!property_get(SUPP_PROP_NAME, supp_status, NULL) + || strcmp(supp_status, "running") != 0) { + LOGE("Supplicant not running, cannot connect"); + return -1; + } + + mCtrl = wpa_ctrl_open("tiwlan0"); + if (mCtrl == NULL) { + LOGE("Unable to open connection to supplicant on \"%s\": %s", + "tiwlan0", strerror(errno)); + return -1; + } + mMonitor = wpa_ctrl_open("tiwlan0"); + if (mMonitor == NULL) { + wpa_ctrl_close(mCtrl); + mCtrl = NULL; + return -1; + } + if (wpa_ctrl_attach(mMonitor) != 0) { + wpa_ctrl_close(mMonitor); + wpa_ctrl_close(mCtrl); + mCtrl = mMonitor = NULL; + return -1; + } + + mListener = new SupplicantListener(this, mMonitor); + + if (mListener->startListener()) { + LOGE("Error - unable to start supplicant listener"); + stop(); + return -1; + } + return 0; +} + +int Supplicant::sendCommand(const char *cmd, char *reply, size_t *reply_len) +{ + if (!mCtrl) { + errno = ENOTCONN; + return -1; + } + + LOGD("sendCommand(): -> '%s'", cmd); + + int rc; + if ((rc = wpa_ctrl_request(mCtrl, cmd, strlen(cmd), reply, reply_len, NULL)) == -2) { + errno = ETIMEDOUT; + return -1; + } else if (rc < 0 || !strncmp(reply, "FAIL", 4)) { + errno = EIO; + return -1; + } + + if (!strncmp(cmd, "PING", 4) || + !strncmp(cmd, "SCAN_RESULTS", 12)) + reply[*reply_len] = '\0'; + + LOGD("sendCommand(): <- '%s'", reply); + return 0; +} + +int Supplicant::triggerScan(bool active) { + char reply[255]; + size_t len = sizeof(reply); + + if (sendCommand((active ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"), + reply, &len)) { + LOGW("triggerScan(%d): Error setting scan mode (%s)", active, + strerror(errno)); + return -1; + } + len = sizeof(reply); + + if (sendCommand("SCAN", reply, &len)) { + LOGW("triggerScan(%d): Error initiating scan", active); + return -1; + } + return 0; +} + +int Supplicant::onConnectedEvent(SupplicantEvent *evt) { + LOGD("onConnectedEvent(%s)", evt->getEvent()); + return 0; +} + +int Supplicant::onDisconnectedEvent(SupplicantEvent *evt) { + LOGD("onDisconnectedEvent(%s)", evt->getEvent()); + return 0; +} + +int Supplicant::onTerminatingEvent(SupplicantEvent *evt) { + LOGD("onTerminatingEvent(%s)", evt->getEvent()); + return 0; +} + +int Supplicant::onPasswordChangedEvent(SupplicantEvent *evt) { + LOGD("onPasswordChangedEvent(%s)", evt->getEvent()); + return 0; +} + +int Supplicant::onEapNotificationEvent(SupplicantEvent *evt) { + LOGD("onEapNotificationEvent(%s)", evt->getEvent()); + return 0; +} + +int Supplicant::onEapStartedEvent(SupplicantEvent *evt) { + LOGD("onEapStartedEvent(%s)", evt->getEvent()); + return 0; +} + +int Supplicant::onEapMethodEvent(SupplicantEvent *evt) { + LOGD("onEapMethodEvent(%s)", evt->getEvent()); + return 0; +} + +int Supplicant::onEapSuccessEvent(SupplicantEvent *evt) { + LOGD("onEapSuccessEvent(%s)", evt->getEvent()); + return 0; +} + +int Supplicant::onEapFailureEvent(SupplicantEvent *evt) { + LOGD("onEapFailureEvent(%s)", evt->getEvent()); + return 0; +} + +int Supplicant::onScanResultsEvent(SupplicantEvent *evt) { + LOGD("onScanResultsEvent(%s)", evt->getEvent()); + + if (!strcmp(evt->getEvent(), "Ready")) { + char *reply; + + if (!(reply = (char *) malloc(4096))) { + errno = -ENOMEM; + return -1; + } + + size_t len = 4096; + + if (sendCommand("SCAN_RESULTS", reply, &len)) { + LOGW("onScanResultsEvent(%s): Error getting scan results (%s)", + evt->getEvent(), strerror(errno)); + free(reply); + return -1; + } + + 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); + return 0;; + } + + while((linep = strtok_r(NULL, "\n", &linep_next))) + mLatestScanResults->push_back(new ScanResult(linep)); + + pthread_mutex_unlock(&mLatestScanResultsLock); + free(reply); + } else { + LOGW("Unknown SCAN_RESULTS event (%s)", evt->getEvent()); + } + return 0; +} + +int Supplicant::onStateChangeEvent(SupplicantEvent *evt) { + LOGD("onStateChangeEvent(%s)", evt->getEvent()); + // XXX: Update mState + return 0; +} + +int Supplicant::onLinkSpeedEvent(SupplicantEvent *evt) { + LOGD("onLinkSpeedEvent(%s)", evt->getEvent()); + return 0; +} + +int Supplicant::onDriverStateEvent(SupplicantEvent *evt) { + LOGD("onDriverStateEvent(%s)", evt->getEvent()); + return 0; +} + +// XXX: Use a cursor + smartptr instead +const ScanResultCollection *Supplicant::getLatestScanResults() { + 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; +}; diff --git a/nexus/Supplicant.h b/nexus/Supplicant.h new file mode 100644 index 000000000..46a9e86ce --- /dev/null +++ b/nexus/Supplicant.h @@ -0,0 +1,72 @@ +/* + * 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. + */ +#ifndef _SUPPLICANT_H +#define _SUPPLICANT_H + +struct wpa_ctrl; +class SupplicantListener; +class SupplicantEvent; + +#include + +#include "ScanResult.h" + +class Supplicant { +private: + struct wpa_ctrl *mCtrl; + struct wpa_ctrl *mMonitor; + SupplicantListener *mListener; + int mState; + + ScanResultCollection *mLatestScanResults; + pthread_mutex_t mLatestScanResultsLock; + +public: + Supplicant(); + virtual ~Supplicant() {} + + virtual int start(); + virtual int stop(); + virtual bool isStarted(); + + virtual int triggerScan(bool active); + + int getState() { return mState; } + + const ScanResultCollection *getLatestScanResults(); + +// XXX: Extract these into an interface +public: + virtual int onConnectedEvent(SupplicantEvent *evt); + virtual int onDisconnectedEvent(SupplicantEvent *evt); + virtual int onTerminatingEvent(SupplicantEvent *evt); + virtual int onPasswordChangedEvent(SupplicantEvent *evt); + virtual int onEapNotificationEvent(SupplicantEvent *evt); + virtual int onEapStartedEvent(SupplicantEvent *evt); + virtual int onEapMethodEvent(SupplicantEvent *evt); + virtual int onEapSuccessEvent(SupplicantEvent *evt); + virtual int onEapFailureEvent(SupplicantEvent *evt); + virtual int onScanResultsEvent(SupplicantEvent *evt); + virtual int onStateChangeEvent(SupplicantEvent *evt); + virtual int onLinkSpeedEvent(SupplicantEvent *evt); + virtual int onDriverStateEvent(SupplicantEvent *evt); + +private: + int connectToSupplicant(); + int sendCommand(const char *cmd, char *reply, size_t *reply_len); +}; + +#endif diff --git a/nexus/SupplicantEvent.cpp b/nexus/SupplicantEvent.cpp new file mode 100644 index 000000000..5c0944a7f --- /dev/null +++ b/nexus/SupplicantEvent.cpp @@ -0,0 +1,95 @@ +/* + * 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 + +#define LOG_TAG "SupplicantEvent" +#include + +#include "SupplicantEvent.h" + +#include "libwpa_client/wpa_ctrl.h" + +SupplicantEvent::SupplicantEvent(char *event, size_t len) { + + if (event[0] == '<') { + char *match = strchr(event, '>'); + if (match) { + char tmp[16]; + + strncpy(tmp, &event[1], (match - event)); + mLevel = atoi(tmp); + event += (match - event) + 1; + } else + LOGW("Unclosed level brace in event"); + } else + LOGW("No level specified in event"); + + /* + * CTRL-EVENT-XXX + * ^ + * +---- event + */ + + if (!strncmp(event, WPA_EVENT_CONNECTED, strlen(WPA_EVENT_CONNECTED))) + mType = SupplicantEvent::EVENT_CONNECTED; + else if (!strncmp(event, WPA_EVENT_DISCONNECTED, strlen(WPA_EVENT_DISCONNECTED))) + mType = SupplicantEvent::EVENT_DISCONNECTED; + else if (!strncmp(event, WPA_EVENT_TERMINATING, strlen(WPA_EVENT_TERMINATING))) + mType = SupplicantEvent::EVENT_TERMINATING; + else if (!strncmp(event, WPA_EVENT_PASSWORD_CHANGED, strlen(WPA_EVENT_PASSWORD_CHANGED))) + mType = SupplicantEvent::EVENT_PASSWORD_CHANGED; + else if (!strncmp(event, WPA_EVENT_EAP_NOTIFICATION, strlen(WPA_EVENT_EAP_NOTIFICATION))) + mType = SupplicantEvent::EVENT_EAP_NOTIFICATION; + else if (!strncmp(event, WPA_EVENT_EAP_STARTED, strlen(WPA_EVENT_EAP_STARTED))) + mType = SupplicantEvent::EVENT_EAP_STARTED; + else if (!strncmp(event, WPA_EVENT_EAP_METHOD, strlen(WPA_EVENT_EAP_METHOD))) + mType = SupplicantEvent::EVENT_EAP_METHOD; + else if (!strncmp(event, WPA_EVENT_EAP_SUCCESS, strlen(WPA_EVENT_EAP_SUCCESS))) + mType = SupplicantEvent::EVENT_EAP_SUCCESS; + else if (!strncmp(event, WPA_EVENT_EAP_FAILURE, strlen(WPA_EVENT_EAP_FAILURE))) + mType = SupplicantEvent::EVENT_EAP_FAILURE; + else if (!strncmp(event, WPA_EVENT_SCAN_RESULTS, strlen(WPA_EVENT_SCAN_RESULTS))) + mType = SupplicantEvent::EVENT_SCAN_RESULTS; + else if (!strncmp(event, WPA_EVENT_STATE_CHANGE, strlen(WPA_EVENT_STATE_CHANGE))) + mType = SupplicantEvent::EVENT_STATE_CHANGE; + else if (!strncmp(event, WPA_EVENT_LINK_SPEED, strlen(WPA_EVENT_LINK_SPEED))) + mType = SupplicantEvent::EVENT_LINK_SPEED; + else if (!strncmp(event, WPA_EVENT_DRIVER_STATE, strlen(WPA_EVENT_DRIVER_STATE))) + mType = SupplicantEvent::EVENT_DRIVER_STATE; + else { + LOGW("Unknown supplicant event '%s'", event); + mType = SupplicantEvent::EVENT_UNKNOWN; + } + + for (event; *event != ' '; event++); + event++; + + /* + * CTRL-EVENT-XXX YYYY + * ^ + * +---- event + */ + + for (event; *event == ' '; event++); + + mEvent = strdup(event); + mLen = len; +} + +SupplicantEvent::~SupplicantEvent() { + if (mEvent) + free(mEvent); +} diff --git a/nexus/SupplicantEvent.h b/nexus/SupplicantEvent.h new file mode 100644 index 000000000..86ce8cb44 --- /dev/null +++ b/nexus/SupplicantEvent.h @@ -0,0 +1,54 @@ +/* + * 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. + */ +#ifndef _SUPPLICANT_EVENT_H +#define _SUPPLICANT_EVENT_H + +#include + +class SupplicantEvent { +private: + int mType; + char *mEvent; + size_t mLen; + int mLevel; + +public: + static const int EVENT_UNKNOWN = 0; + static const int EVENT_CONNECTED = 1; + static const int EVENT_DISCONNECTED = 2; + static const int EVENT_TERMINATING = 3; + static const int EVENT_PASSWORD_CHANGED = 4; + static const int EVENT_EAP_NOTIFICATION = 5; + static const int EVENT_EAP_STARTED = 6; + static const int EVENT_EAP_METHOD = 7; + static const int EVENT_EAP_SUCCESS = 8; + static const int EVENT_EAP_FAILURE = 9; + static const int EVENT_SCAN_RESULTS = 10; + static const int EVENT_STATE_CHANGE = 11; + static const int EVENT_LINK_SPEED = 12; + static const int EVENT_DRIVER_STATE = 13; + +public: + SupplicantEvent(char *event, size_t len); + virtual ~SupplicantEvent(); + + int getType() { return mType; } + const char *getEvent() { return mEvent; } + int getLen() { return mLen; } + int getLevel() { return mLevel; } +}; + +#endif diff --git a/nexus/SupplicantListener.cpp b/nexus/SupplicantListener.cpp new file mode 100644 index 000000000..16306b5b6 --- /dev/null +++ b/nexus/SupplicantListener.cpp @@ -0,0 +1,114 @@ +/* + * 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 +#include +#include + +#define LOG_TAG "SupplicantListener" +#include + +#include "libwpa_client/wpa_ctrl.h" + +#include "Supplicant.h" +#include "SupplicantListener.h" +#include "SupplicantEvent.h" + +SupplicantListener::SupplicantListener(Supplicant *supplicant, struct wpa_ctrl *monitor) : + SocketListener(wpa_ctrl_get_fd(monitor), false) { + mSupplicant = supplicant; + mMonitor = monitor; + mThread = NULL; +} + +int SupplicantListener::startListener() { + LOGD("startListener()"); + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + return pthread_create(&mThread, &attr, &SupplicantListener::threadStart, this); +} + +int SupplicantListener::stopListener() { + errno = -ENOSYS; + return -1; +} + +void *SupplicantListener::threadStart(void *obj) { + LOGD("threadStart(): Worker thread started"); + reinterpret_cast(obj)->run(); + LOGD("threadStart(): Worker thread exited"); + return NULL; +} + +bool SupplicantListener::onDataAvailable(int socket) { + char buf[255]; + size_t buflen = sizeof(buf); + int rc; + size_t nread = buflen - 1; + + if ((rc = wpa_ctrl_recv(mMonitor, buf, &nread))) { + LOGE("wpa_ctrl_recv failed (%s)", strerror(errno)); + return -errno; + } + + buf[nread] = '\0'; + if (!rc && !nread) { + LOGD("Received EOF on supplicant socket\n"); + strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1); + buf[buflen-1] = '\0'; + return false; + } + + SupplicantEvent *evt = new SupplicantEvent(buf, nread); + + // XXX: Make this a factory + // XXX: Instead of calling Supplicant directly + // extract an Interface and use that instead + if (evt->getType() == SupplicantEvent::EVENT_CONNECTED) + rc = mSupplicant->onConnectedEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_DISCONNECTED) + rc = mSupplicant->onDisconnectedEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_TERMINATING) + rc = mSupplicant->onTerminatingEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_PASSWORD_CHANGED) + rc = mSupplicant->onPasswordChangedEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_EAP_NOTIFICATION) + rc = mSupplicant->onEapNotificationEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_EAP_STARTED) + rc = mSupplicant->onEapStartedEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_EAP_SUCCESS) + rc = mSupplicant->onEapSuccessEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_EAP_FAILURE) + rc = mSupplicant->onEapFailureEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_SCAN_RESULTS) + rc = mSupplicant->onScanResultsEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_STATE_CHANGE) + rc = mSupplicant->onStateChangeEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_LINK_SPEED) + rc = mSupplicant->onLinkSpeedEvent(evt); + else if (evt->getType() == SupplicantEvent::EVENT_DRIVER_STATE) + rc = mSupplicant->onDriverStateEvent(evt); + else { + LOGW("Ignoring unknown event"); + } + + delete evt; + + if (rc) + return false; + return true; +} diff --git a/nexus/SupplicantListener.h b/nexus/SupplicantListener.h new file mode 100644 index 000000000..3d27a6810 --- /dev/null +++ b/nexus/SupplicantListener.h @@ -0,0 +1,48 @@ +/* + * 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. + */ +#ifndef _SUPPLICANTLISTENER_H__ +#define _SUPPLICANTLISTENER_H__ + +#include + +#include + +struct wpa_ctrl; +class Supplicant; + +class SupplicantListener: public SocketListener { +private: + struct wpa_ctrl *mMonitor; + Supplicant *mSupplicant; + pthread_t mThread; + +public: + SupplicantListener(Supplicant *supplicant, struct wpa_ctrl *monitor); + virtual ~SupplicantListener() {} + int startListener(); + int stopListener(); + + struct wpa_ctrl *getMonitor() { return mMonitor; } + Supplicant *getSupplicant() { return mSupplicant; } + +protected: + virtual bool onDataAvailable(int socket); + +private: + static void *threadStart(void *obj); +}; + +#endif diff --git a/nexus/SupplicantState.h b/nexus/SupplicantState.h new file mode 100644 index 000000000..f2cf6039c --- /dev/null +++ b/nexus/SupplicantState.h @@ -0,0 +1,33 @@ +/* + * 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. + */ +#ifndef _SUPPLICANT_STATE_H +#define _SUPPLICANT_STATE_H + +class SupplicantState { +public: + static const int UNKNOWN = 0; + static const int DISCONNECTED = 1; + static const int INACTIVE = 2; + static const int SCANNING = 3; + static const int ASSOCIATING = 4; + static const int ASSOCIATED = 5; + static const int FOURWAY_HANDSHAKE = 6; + static const int GROUP_HANDSHAKE = 7; + static const int COMPLETED = 8; + static const int IDLE = 9; +}; + +#endif diff --git a/nexus/TiwlanWifiController.cpp b/nexus/TiwlanWifiController.cpp new file mode 100644 index 000000000..ec83825b8 --- /dev/null +++ b/nexus/TiwlanWifiController.cpp @@ -0,0 +1,67 @@ +/* + * 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 +#include +#include +#include + +#include +#define LOG_TAG "TiwlanWifiController" +#include + +#include "TiwlanWifiController.h" + +#define DRIVER_PROP_NAME "wlan.driver.status" + +extern "C" int sched_yield(void); + +TiwlanWifiController::TiwlanWifiController(char *modpath, char *modname, char *modargs) : + WifiController(modpath, modname, modargs) { +} + +int TiwlanWifiController::powerUp() { + return 0; // Powerup is currently done when the driver is loaded +} + +int TiwlanWifiController::powerDown() { + return 0; // Powerdown is currently done when the driver is unloaded +} + +bool TiwlanWifiController::isPoweredUp() { + return isKernelModuleLoaded(getModuleName()); +} + +int TiwlanWifiController::loadFirmware() { + char driver_status[PROPERTY_VALUE_MAX]; + int count = 100; + + LOGD("loadFirmware()"); + property_set("ctl.start", "wlan_loader"); + sched_yield(); + + // Wait for driver to be ready + while (count-- > 0) { + if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) { + if (strcmp(driver_status, "ok") == 0) + return 0; + else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) + return -1; + } + usleep(200000); + } + property_set(DRIVER_PROP_NAME, "timeout"); + return -1; +} diff --git a/nexus/TiwlanWifiController.h b/nexus/TiwlanWifiController.h new file mode 100644 index 000000000..a93d61004 --- /dev/null +++ b/nexus/TiwlanWifiController.h @@ -0,0 +1,31 @@ +/* + * 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. + */ +#ifndef _TIWLAN_WIFI_CONTROLLER_H +#define _TIWLAN_WIFI_CONTROLLER_H + +#include "WifiController.h" + +class TiwlanWifiController : public WifiController { +public: + TiwlanWifiController(char *modpath, char *modname, char *modargs); + virtual ~TiwlanWifiController() {} + + virtual int powerUp(); + virtual int powerDown(); + virtual bool isPoweredUp(); + virtual int loadFirmware(); +}; +#endif diff --git a/nexus/VpnController.cpp b/nexus/VpnController.cpp new file mode 100644 index 000000000..2d3db852b --- /dev/null +++ b/nexus/VpnController.cpp @@ -0,0 +1,44 @@ +/* + * 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 +#include "VpnController.h" + +VpnController::VpnController() : + Controller("VPN") { +} + +int VpnController::start() { + errno = -ENOSYS; + return -1; +} + +int VpnController::stop() { + errno = -ENOSYS; + return -1; +} + +int VpnController::enable() { + + // Load modules + // Start daemons + errno = -ENOSYS; + return -1; +} + +int VpnController::disable() { + errno = -ENOSYS; + return -1; +} diff --git a/nexus/VpnController.h b/nexus/VpnController.h new file mode 100644 index 000000000..f792ce3bc --- /dev/null +++ b/nexus/VpnController.h @@ -0,0 +1,38 @@ +/* + * 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. + */ +#ifndef _VPN_CONTROLLER_H +#define _VPN_CONTROLLER_H + +#include "Controller.h" + +class VpnController : public Controller { + +public: + VpnController(); + virtual ~VpnController() {} + + virtual int start(); + virtual int stop(); + + virtual int enable(); + virtual int disable(); + +protected: + +private: +}; + +#endif diff --git a/nexus/WifiController.cpp b/nexus/WifiController.cpp new file mode 100644 index 000000000..8a7e33f9e --- /dev/null +++ b/nexus/WifiController.cpp @@ -0,0 +1,134 @@ +/* + * 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 +#include + +#define LOG_TAG "WifiController" +#include + +#include "Supplicant.h" +#include "WifiController.h" + +WifiController::WifiController(char *modpath, char *modname, char *modargs) : + Controller("WIFI") { + strncpy(mModulePath, modpath, sizeof(mModulePath)); + strncpy(mModuleName, modname, sizeof(mModuleName)); + strncpy(mModuleArgs, modargs, sizeof(mModuleArgs)); + + mSupplicant = new Supplicant(); + mCurrentScanMode = 0; +} + +int WifiController::start() { + return 0; +} + +int WifiController::stop() { + errno = ENOSYS; + return -1; +} + +int WifiController::enable() { + if (!isPoweredUp() && powerUp()) { + LOGE("Powerup failed (%s)", strerror(errno)); + return -1; + } + + if (mModuleName[0] != '\0' && !isKernelModuleLoaded(mModuleName)) { + if (loadKernelModule(mModulePath, mModuleArgs)) { + LOGE("Kernel module load failed (%s)", strerror(errno)); + goto out_powerdown; + } + } + + if (loadFirmware()) { + LOGE("Firmware load failed (%s)", strerror(errno)); + goto out_powerdown; + } + + if (!mSupplicant->isStarted() && mSupplicant->start()) { + LOGE("Supplicant start failed (%s)", strerror(errno)); + goto out_unloadmodule; + } + + 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; +} + +int WifiController::disable() { + LOGD("disable()"); + + if (mSupplicant->isStarted() && mSupplicant->stop()) { + LOGE("Supplicant stop failed (%s)", strerror(errno)); + return -1; + } + + if (mModuleName[0] != '\0' && isKernelModuleLoaded(mModuleName)) { + if (unloadKernelModule(mModuleName)) { + LOGE("Unable to unload module (%s)", strerror(errno)); + return -1; + } + } + + if (isPoweredUp() && powerDown()) { + LOGE("Powerdown failed (%s)", strerror(errno)); + return -1; + } + return 0; +} + +int WifiController::loadFirmware() { + return 0; +} + +int WifiController::setScanMode(int mode) { + int rc = 0; + + if (mCurrentScanMode == mode) + return 0; + + if (!(mode & SCAN_ENABLE_MASK)) { + if (mCurrentScanMode & SCAN_REPEAT_MASK) + stopPeriodicScan(); + } else if (mode & SCAN_REPEAT_MASK) + rc = startPeriodicScan(); + else + rc = mSupplicant->triggerScan(mode & SCAN_ACTIVE_MASK); + + return rc; +} + +int WifiController::startPeriodicScan() { + errno = -ENOSYS; + return -1; +} + +int WifiController::stopPeriodicScan() { + errno = -ENOSYS; + return -1; +} diff --git a/nexus/WifiController.h b/nexus/WifiController.h new file mode 100644 index 000000000..6d0051323 --- /dev/null +++ b/nexus/WifiController.h @@ -0,0 +1,78 @@ +/* + * 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. + */ +#ifndef _WIFI_CONTROLLER_H +#define _WIFI_CONTROLLER_H + +#include + +#include "Controller.h" + +class NetInterface; +class Supplicant; + +class WifiController : public Controller { +public: + static const uint32_t SCAN_ENABLE_MASK = 0x01; + static const uint32_t SCAN_ACTIVE_MASK = 0x02; + static const uint32_t SCAN_REPEAT_MASK = 0x04; + + static const uint32_t SCANMODE_NONE = 0; + static const uint32_t SCANMODE_PASSIVE_ONESHOT = SCAN_ENABLE_MASK; + static const uint32_t SCANMODE_PASSIVE_CONTINUOUS = SCAN_ENABLE_MASK | SCAN_REPEAT_MASK; + static const uint32_t SCANMODE_ACTIVE_ONESHOT = SCAN_ENABLE_MASK | SCAN_ACTIVE_MASK; + static const uint32_t SCANMODE_ACTIVE_CONTINUOUS = SCAN_ENABLE_MASK | SCAN_ACTIVE_MASK | SCAN_REPEAT_MASK; + +private: + Supplicant *mSupplicant; + char mModulePath[255]; + char mModuleName[64]; + char mModuleArgs[255]; + int mCurrentScanMode; + + +public: + WifiController(char *modpath, char *modname, char *modargs); + virtual ~WifiController() {} + + int start(); + int stop(); + + int enable(); + int disable(); + + int getType(); + + char *getModulePath() { return mModulePath; } + char *getModuleName() { return mModuleName; } + char *getModuleArgs() { return mModuleArgs; } + + Supplicant *getSupplicant() { return mSupplicant; } + + int getScanMode() { return mCurrentScanMode; } + int setScanMode(int mode); + +protected: + virtual int powerUp() = 0; + virtual int powerDown() = 0; + virtual int loadFirmware(); + virtual bool isPoweredUp() = 0; + +private: + int startPeriodicScan(); + int stopPeriodicScan(); +}; + +#endif diff --git a/nexus/main.cpp b/nexus/main.cpp new file mode 100644 index 000000000..a26a14d37 --- /dev/null +++ b/nexus/main.cpp @@ -0,0 +1,41 @@ +/* + * 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 +#include + +#define LOG_TAG "Nexus" + +#include "cutils/log.h" +#include "NetworkManager.h" + +int main() { + NetworkManager *nm; + + LOGI("Nexus version 0.1 firing up"); + + if (!(nm = new NetworkManager())) { + LOGE("Unable to create NetworkManager"); + exit (-1); + }; + + if (nm->run()) { + LOGE("Unable to Run NetworkManager (%s)", strerror(errno)); + exit (1); + } + + LOGI("Nexus exiting"); + exit(0); +} diff --git a/nexus/nexctl.c b/nexus/nexctl.c new file mode 100644 index 000000000..6d117c778 --- /dev/null +++ b/nexus/nexctl.c @@ -0,0 +1,104 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +static void signal_handler(int sig) { + fprintf(stdout, "{ interrupt! }\n"); +} + +int main(int argc, char **argv) { + int sock; + + if ((sock = socket_local_client("nexus", + ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM)) < 0) { + fprintf(stderr, "Error connecting (%s)\n", strerror(errno)); + exit(1); + } + + printf("Connected to nexus\n"); + + while(1) { + fd_set read_fds; + struct timeval to; + int rc = 0; + + signal(SIGINT, SIG_DFL); + + printf("-> "); + fflush(stdout); + + char buffer[255]; + if (!fgets(buffer, sizeof(buffer) -1, stdin)) { + printf("Exiting...\n"); + exit(0); + } + + buffer[strlen(buffer) -1] = 0; + + printf("sending '%s'\n", buffer); + if (write(sock, buffer, strlen(buffer) +1) < 0) { + fprintf(stderr, "Error writing data (%s)\n", strerror(errno)); + exit(2); + } + +wait: + to.tv_sec = 5; + to.tv_usec = 0; + FD_ZERO(&read_fds); + FD_SET(sock, &read_fds); + + signal(SIGINT, signal_handler); + + if ((rc = select(sock +1, &read_fds, NULL, NULL, &to)) < 0) { + if (errno == EINTR) + continue; + fprintf(stderr, "Error in select (%s)\n", strerror(errno)); + exit(2); + } else if (!rc) { + printf("{response timeout}\n"); + continue; + } else if (FD_ISSET(sock, &read_fds)) { +printf("got data!\n"); + if ((rc = read(sock, buffer, sizeof(buffer)-1)) < 0) { + fprintf(stderr, "Error reading response (%s)\n", strerror(errno)); + exit(2); + } + printf(" |%s|\n", buffer); + goto wait; + } + } + + + exit(0); + +} diff --git a/rootdir/init.rc b/rootdir/init.rc index e1f1e8afd..c20eeaa8f 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -217,6 +217,10 @@ service servicemanager /system/bin/servicemanager service vold /system/bin/vold socket vold stream 0660 root mount +service nexus /system/bin/nexus + socket nexus stream 0660 root system + disabled + #service mountd /system/bin/mountd # socket mountd stream 0660 root mount