am a0eece26: am 6b858eb3: Keep IP forwarding enabled in tools mode.
* commit 'a0eece268a7dbd837f73c80ad97cbea81abebf11':
Keep IP forwarding enabled in tools mode.
diff --git a/Android.mk b/Android.mk
index c6deaab..8045ad7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -10,28 +10,31 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- main.cpp \
+ BandwidthController.cpp \
CommandListener.cpp \
DnsProxyListener.cpp \
- NetdCommand.cpp \
- NetlinkManager.cpp \
- NetlinkHandler.cpp \
- logwrapper.c \
- TetherController.cpp \
NatController.cpp \
- PppController.cpp \
+ NetdCommand.cpp \
+ NetlinkHandler.cpp \
+ NetlinkManager.cpp \
PanController.cpp \
+ PppController.cpp \
+ ResolverController.cpp \
SoftapController.cpp \
- UsbController.cpp \
+ TetherController.cpp \
ThrottleController.cpp \
- ResolverController.cpp
+ logwrapper.c \
+ main.cpp \
+
LOCAL_MODULE:= netd
LOCAL_C_INCLUDES := $(KERNEL_HEADERS) \
$(LOCAL_PATH)/../bluetooth/bluedroid/include \
$(LOCAL_PATH)/../bluetooth/bluez-clean-headers \
- external/openssl/include
+ external/openssl/include \
+ external/stlport/stlport \
+ bionic
LOCAL_CFLAGS :=
ifdef WIFI_DRIVER_FW_STA_PATH
@@ -41,7 +44,7 @@
LOCAL_CFLAGS += -DWIFI_DRIVER_FW_AP_PATH=\"$(WIFI_DRIVER_FW_AP_PATH)\"
endif
-LOCAL_SHARED_LIBRARIES := libsysutils libcutils libnetutils libcrypto
+LOCAL_SHARED_LIBRARIES := libstlport libsysutils libcutils libnetutils libcrypto
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES) libbluedroid
diff --git a/BandwidthController.cpp b/BandwidthController.cpp
new file mode 100644
index 0000000..50db1ec
--- /dev/null
+++ b/BandwidthController.cpp
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2011 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 <fcntl.h>
+#include <string.h>
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/pkt_sched.h>
+
+#define LOG_TAG "BandwidthController"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+extern "C" int logwrap(int argc, const char **argv, int background);
+
+#include "BandwidthController.h"
+
+const int BandwidthController::MAX_CMD_LEN = 1024;
+const int BandwidthController::MAX_IFACENAME_LEN = 64;
+const int BandwidthController::MAX_CMD_ARGS = 32;
+const char BandwidthController::IPTABLES_PATH[] = "/system/bin/iptables";
+const char BandwidthController::IP6TABLES_PATH[] = "/system/bin/ip6tables";
+
+/**
+ * Some comments about the rules:
+ * * Ordering
+ * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
+ * E.g. "-I INPUT -i rmnet0 --goto costly"
+ * - quota'd rules in the costly chain should be before penalty_box lookups.
+ *
+ * * global quota vs per interface quota
+ * - global quota for all costly interfaces uses a single costly chain:
+ * . initial rules
+ * iptables -N costly
+ * iptables -I INPUT -i iface0 --goto costly
+ * iptables -I OUTPUT -o iface0 --goto costly
+ * iptables -I costly -m quota \! --quota 500000 --jump REJECT --reject-with icmp-net-prohibited
+ * iptables -A costly --jump penalty_box
+ * iptables -A costly -m owner --socket-exists
+ * . adding a new iface to this, E.g.:
+ * iptables -I INPUT -i iface1 --goto costly
+ * iptables -I OUTPUT -o iface1 --goto costly
+ *
+ * - quota per interface. This is achieve by having "costly" chains per quota.
+ * E.g. adding a new costly interface iface0 with its own quota:
+ * iptables -N costly_iface0
+ * iptables -I INPUT -i iface0 --goto costly_iface0
+ * iptables -I OUTPUT -o iface0 --goto costly_iface0
+ * iptables -A costly_iface0 -m quota \! --quota 500000 --jump REJECT --reject-with icmp-net-prohibited
+ * iptables -A costly_iface0 --jump penalty_box
+ * iptables -A costly_iface0 -m owner --socket-exists
+ *
+ * * penalty_box handling:
+ * - only one penalty_box for all interfaces
+ * E.g Adding an app:
+ * iptables -A penalty_box -m owner --uid-owner app_3 --jump REJECT --reject-with icmp-net-prohibited
+ */
+const char *BandwidthController::cleanupCommands[] = {
+ /* Cleanup rules. */
+ "-F",
+ "-t raw -F",
+ "-X costly",
+ "-X penalty_box",
+};
+
+const char *BandwidthController::setupCommands[] = {
+ /* Created needed chains. */
+ "-N costly",
+ "-N penalty_box",
+};
+
+const char *BandwidthController::basicAccountingCommands[] = {
+ "-F INPUT",
+ "-A INPUT -i lo --jump ACCEPT",
+ "-A INPUT -m owner --socket-exists", /* This is a tracking rule. */
+
+ "-F OUTPUT",
+ "-A OUTPUT -o lo --jump ACCEPT",
+ "-A OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
+
+ "-F costly",
+ "-A costly --jump penalty_box",
+ "-A costly -m owner --socket-exists", /* This is a tracking rule. */
+ /* TODO(jpa): Figure out why iptables doesn't correctly return from this
+ * chain. For now, hack the chain exit with an ACCEPT.
+ */
+ "-A costly --jump ACCEPT",
+};
+
+BandwidthController::BandwidthController(void) {
+
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("persist.bandwidth.enable", value, "0");
+ if (!strcmp(value, "1")) {
+ enableBandwidthControl();
+ }
+
+}
+
+int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling) {
+ int res = 0;
+ LOGD("runIpxtablesCmd(cmd=%s)", cmd);
+ res |= runIptablesCmd(cmd, rejectHandling, IptIpV4);
+ res |= runIptablesCmd(cmd, rejectHandling, IptIpV6);
+ return res;
+}
+
+int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
+
+ memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
+ strncpy(buffer, src, buffSize);
+ return buffer[buffSize - 1];
+}
+
+int BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling, IptIpVer iptVer) {
+ char buffer[MAX_CMD_LEN];
+ const char *argv[MAX_CMD_ARGS];
+ int argc = 0;
+ char *next = buffer;
+ char *tmp;
+
+ std::string fullCmd = cmd;
+
+ if (rejectHandling == IptRejectAdd) {
+ fullCmd += " --jump REJECT --reject-with";
+ switch (iptVer) {
+ case IptIpV4:
+ fullCmd += " icmp-net-prohibited";
+ break;
+ case IptIpV6:
+ fullCmd += " icmp6-adm-prohibited";
+ break;
+ }
+ }
+
+ argc = 0;
+ argv[argc++] = iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH;
+ LOGD("About to run: %s %s", argv[0], fullCmd.c_str());
+
+ LOGD("runIpxtablesCmd(): fullCmd.c_str()=%s buffSize=%d", fullCmd.c_str(), sizeof(buffer));
+ if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
+ LOGE("iptables command too long");
+ return -1;
+ }
+
+ while ((tmp = strsep(&next, " "))) {
+ argv[argc++] = tmp;
+ if (argc >= MAX_CMD_ARGS) {
+ LOGE("iptables argument overflow");
+ return -1;
+ }
+ }
+
+ argv[argc] = NULL;
+ LOGD("runIpxtablesCmd(): argc=%d, argv[argc]=%p", argc, argv[argc]);
+ /* TODO(jpa): Once this stabilizes, remove logwrap() as it tends to wedge netd
+ * Then just talk directly to the kernel via rtnetlink.
+ */
+ for (int i = 0 ; i < argc; i++) {
+ LOGD("runIpxtablesCmd(): argv[%d]=%p:%s", i, argv[i], argv[i]?:"null");
+ }
+ return logwrap(argc, argv, 0);
+}
+
+int BandwidthController::enableBandwidthControl(void) {
+ int res;
+ /* Some of the initialCommands are allowed to fail */
+ runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, RunCmdFailureOk);
+ runCommands(sizeof(setupCommands) / sizeof(char*), setupCommands, RunCmdFailureOk);
+ res = runCommands(sizeof(basicAccountingCommands) / sizeof(char*), basicAccountingCommands, RunCmdFailureBad);
+ return res;
+
+}
+
+int BandwidthController::disableBandwidthControl(void) {
+ /* The cleanupCommands are allowed to fail. */
+ runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, RunCmdFailureOk);
+ return 0;
+}
+
+int BandwidthController::runCommands(int numCommands, const char *commands[], RunCmdErrHandling cmdErrHandling) {
+ int res = 0;
+ LOGD("runCommands(): %d commands", numCommands);
+ for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
+ res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd);
+ if (res && cmdErrHandling != RunCmdFailureBad)
+ return res;
+ }
+ return cmdErrHandling == RunCmdFailureBad ? res : 0;
+}
+
+std::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
+ std::string res;
+ char *convBuff;
+
+ switch (op) {
+ case IptOpInsert:
+ res = "-I";
+ break;
+ case IptOpReplace:
+ res = "-R";
+ break;
+ default:
+ case IptOpDelete:
+ res = "-D";
+ break;
+ }
+ res += " penalty_box";
+ asprintf(&convBuff, "%d", uid);
+ res += " -m owner --uid-owner ";
+ res += convBuff;
+ free(convBuff);
+ LOGD("makeIptablesNaughtyCmd() res=%s", res.c_str());
+ return res;
+}
+
+int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
+ return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpAdd);
+}
+
+int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
+ return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpRemove);
+}
+
+int BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp) {
+ char cmd[MAX_CMD_LEN];
+ int uidNum;
+ const char *failLogTemplate;
+ IptOp op;
+ int appUids[numUids];
+ std::string naughtyCmd;
+ LOGD("manipulateNaughtyApps()");
+ switch (appOp) {
+ case NaughtyAppOpAdd:
+ op = IptOpInsert;
+ failLogTemplate = "Failed to add app uid %d to penalty box.";
+ break;
+ case NaughtyAppOpRemove:
+ op = IptOpDelete;
+ failLogTemplate = "Failed to delete app uid %d from penalty box.";
+ break;
+ }
+
+ for (uidNum = 0; uidNum < numUids; uidNum++) {
+ appUids[uidNum] = atol(appStrUids[uidNum]);
+ if (appUids[uidNum] == 0) {
+ LOGE(failLogTemplate, appUids[uidNum]);
+ goto fail_parse;
+ }
+ }
+ LOGD("manipulateNaughtyApps() got the appUids");
+
+ for (uidNum = 0; uidNum < numUids; uidNum++) {
+ naughtyCmd = makeIptablesNaughtyCmd(op, appUids[uidNum]);
+ if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
+ LOGE(failLogTemplate, appUids[uidNum]);
+ goto fail_with_uidNum;
+ }
+ }
+ return 0;
+
+fail_with_uidNum:
+ /* Try to remove the uid that failed in any case*/
+ naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]);
+ runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd);
+fail_parse:
+ return -1;
+}
+
+std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
+ std::string res;
+ char convBuff[21]; // log10(2^64) ~ 20
+
+ LOGD("makeIptablesQuotaCmd(%d, %llu)", op, quota);
+
+ switch (op) {
+ case IptOpInsert:
+ res = "-I";
+ break;
+ case IptOpReplace:
+ res = "-R";
+ break;
+ default:
+ case IptOpDelete:
+ res = "-D";
+ break;
+ }
+ res += " costly";
+ if (costName) {
+ res += "_";
+ res += costName;
+ }
+ sprintf(convBuff, "%lld", quota);
+ /* TODO(jpa): Use -m quota2 --name " + costName + " ! --quota "
+ * once available.
+ */
+ res += " -m quota ! --quota ";
+ res += convBuff;
+ ;
+ // The requried --jump REJECT ... will be added later.
+ return res;
+}
+
+int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
+ char cmd[MAX_CMD_LEN];
+ int res = 0;
+ std::string costString;
+ const char *costCString;
+
+ costString = "costly";
+ /* The "-N costly" is created upfront, no need to handle it here. */
+ switch (quotaType) {
+ case QuotaUnique:
+ costString += "_";
+ costString += ifn;
+ costCString = costString.c_str();
+ snprintf(cmd, sizeof(cmd), "-N %s", costCString);
+ res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
+ snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
+ res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
+ snprintf(cmd, sizeof(cmd), "-A %s -m owner --socket-exists", costCString);
+ res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
+ /* TODO(jpa): Figure out why iptables doesn't correctly return from this
+ * chain. For now, hack the chain exit with an ACCEPT.
+ */
+ snprintf(cmd, sizeof(cmd), "-A %s --jump ACCEPT", costCString);
+ res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
+ break;
+ case QuotaShared:
+ costCString = costString.c_str();
+ break;
+ }
+
+ snprintf(cmd, sizeof(cmd), "-I INPUT -i %s --goto %s", ifn, costCString);
+ res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
+ snprintf(cmd, sizeof(cmd), "-I OUTPUT -o %s --goto %s", ifn, costCString);
+ res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
+ return res;
+}
+
+int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
+ char cmd[MAX_CMD_LEN];
+ int res = 0;
+ std::string costString;
+ const char *costCString;
+
+ costString = "costly";
+ switch (quotaType) {
+ case QuotaUnique:
+ costString += "_";
+ costString += ifn;
+ costCString = costString.c_str();
+ break;
+ case QuotaShared:
+ costCString = costString.c_str();
+ break;
+ }
+
+ snprintf(cmd, sizeof(cmd), "-D INPUT -i %s --goto %s", ifn, costCString);
+ res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
+ snprintf(cmd, sizeof(cmd), "-D OUTPUT -o %s --goto %s", ifn, costCString);
+ res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
+
+ /* The "-N costly" is created upfront, no need to handle it here. */
+ if (quotaType == QuotaUnique) {
+ snprintf(cmd, sizeof(cmd), "-F %s", costCString);
+ res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
+ }
+ return res;
+}
+
+int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
+ char cmd[MAX_CMD_LEN];
+ char ifn[MAX_IFACENAME_LEN];
+ int res = 0;
+ std::string quotaCmd;
+ std::string ifaceName;;
+ const char *costName = NULL; /* Shared quota */
+ std::list<std::string>::iterator it;
+
+ if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
+ LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
+ return -1;
+ }
+ ifaceName = ifn;
+
+ if (maxBytes == -1) {
+ return removeInterfaceSharedQuota(ifn);
+ }
+
+ /* Insert ingress quota. */
+ for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
+ if (*it == ifaceName)
+ break;
+ }
+
+ if (it == sharedQuotaIfaces.end()) {
+ res |= prepCostlyIface(ifn, QuotaShared);
+ if (sharedQuotaIfaces.empty()) {
+ quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
+ res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
+ if (res) {
+ LOGE("Failed set quota rule.");
+ goto fail;
+ }
+ sharedQuotaBytes = maxBytes;
+ }
+ sharedQuotaIfaces.push_front(ifaceName);
+
+ }
+
+ if (maxBytes != sharedQuotaBytes) {
+ /* Instead of replacing, which requires being aware of the rules in
+ * the kernel, we just add a new one, then delete the older one.
+ */
+
+ quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
+ res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
+
+ quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
+ res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
+
+ if (res) {
+ LOGE("Failed replace quota rule.");
+ goto fail;
+ }
+ sharedQuotaBytes = maxBytes;
+ }
+ return 0;
+
+ fail:
+ /*
+ * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
+ * rules in the kernel to see which ones need cleaning up.
+ * For now callers needs to choose if they want to "ndc bandwidth enable"
+ * which resets everything.
+ */
+ removeInterfaceSharedQuota(ifn);
+ return -1;
+}
+
+int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
+ char ifn[MAX_IFACENAME_LEN];
+ int res = 0;
+ std::string ifaceName;
+ std::list<std::string>::iterator it;
+
+ if(StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
+ LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
+ return -1;
+ }
+ ifaceName =ifn;
+
+ for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
+ if (*it == ifaceName)
+ break;
+ }
+ if (it == sharedQuotaIfaces.end()) {
+ LOGE("No such iface %s to delete.", ifn);
+ return -1;
+ }
+
+ res |= cleanupCostlyIface(ifn, QuotaShared);
+ sharedQuotaIfaces.erase(it);
+
+ if (sharedQuotaIfaces.empty()) {
+ std::string quotaCmd;
+ quotaCmd = makeIptablesQuotaCmd(IptOpDelete, NULL, sharedQuotaBytes);
+ res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
+ sharedQuotaBytes = -1;
+ }
+
+ return res;
+}
+
+int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
+ char ifn[MAX_IFACENAME_LEN];
+ int res = 0;
+ std::string ifaceName;
+ const char *costName;
+ std::list<QuotaInfo>::iterator it;
+ std::string quotaCmd;
+
+ if (maxBytes == -1) {
+ return removeInterfaceQuota(iface);
+ }
+
+ if(StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
+ LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
+ return -1;
+ }
+ ifaceName = ifn;
+ costName = iface;
+
+
+ /* Insert ingress quota. */
+ for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
+ if (it->first == ifaceName)
+ break;
+ }
+
+ if (it == quotaIfaces.end()) {
+ res |= prepCostlyIface(ifn, QuotaUnique);
+ quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
+ res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
+ if (res) {
+ LOGE("Failed set quota rule.");
+ goto fail;
+ }
+
+ quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes));
+
+ } else {
+ /* Instead of replacing, which requires being aware of the rules in
+ * the kernel, we just add a new one, then delete the older one.
+ */
+ quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
+ res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
+
+ quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, it->second);
+ res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
+
+ if (res) {
+ LOGE("Failed replace quota rule.");
+ goto fail;
+ }
+ it->second = maxBytes;
+ }
+ return 0;
+
+ fail:
+ /*
+ * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
+ * rules in the kernel to see which ones need cleaning up.
+ * For now callers needs to choose if they want to "ndc bandwidth enable"
+ * which resets everything.
+ */
+ removeInterfaceSharedQuota(ifn);
+ return -1;
+}
+
+int BandwidthController::removeInterfaceQuota(const char *iface) {
+
+ char ifn[MAX_IFACENAME_LEN];
+ int res = 0;
+ std::string ifaceName;
+ const char *costName;
+ std::list<QuotaInfo>::iterator it;
+
+ if(StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
+ LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
+ return -1;
+ }
+ ifaceName = ifn;
+ costName = iface;
+
+ for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
+ if (it->first == ifaceName)
+ break;
+ }
+
+ if (it == quotaIfaces.end()) {
+ LOGE("No such iface %s to delete.", ifn);
+ return -1;
+ }
+
+ /* This also removes the quota command of CostlyIface chain. */
+ res |= cleanupCostlyIface(ifn, QuotaUnique);
+
+ quotaIfaces.erase(it);
+
+ return res;
+}
diff --git a/BandwidthController.h b/BandwidthController.h
new file mode 100644
index 0000000..f4fce50
--- /dev/null
+++ b/BandwidthController.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 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 _BANDWIDTH_CONTROLLER_H
+#define _BANDWIDTH_CONTROLLER_H
+
+#include <list>
+#include <string>
+#include <utility> // for pair
+class BandwidthController {
+public:
+ BandwidthController();
+ int enableBandwidthControl(void);
+ int disableBandwidthControl(void);
+
+ int setInterfaceSharedQuota(const char *iface, int64_t bytes);
+ int removeInterfaceSharedQuota(const char *iface);
+
+ int setInterfaceQuota(const char *iface, int64_t bytes);
+ int removeInterfaceQuota(const char *iface);
+
+ int addNaughtyApps(int numUids, char *appUids[]);
+ int removeNaughtyApps(int numUids, char *appUids[]);
+
+
+protected:
+ typedef std::pair<std::string /*ifaceName*/, int64_t /*quota*/> QuotaInfo;
+ enum IptIpVer { IptIpV4, IptIpV6 };
+ enum IptOp { IptOpInsert, IptOpReplace, IptOpDelete };
+ enum IptRejectOp { IptRejectAdd, IptRejectNoAdd };
+ enum NaughtyAppOp { NaughtyAppOpAdd, NaughtyAppOpRemove };
+ enum QuotaType { QuotaUnique, QuotaShared };
+ enum RunCmdErrHandling { RunCmdFailureBad, RunCmdFailureOk };
+
+ int64_t sharedQuotaBytes;
+ std::list<std::string> sharedQuotaIfaces;
+
+ std::list<QuotaInfo> quotaIfaces;
+
+ std::list<int /*appUid*/> naughtyAppUids;
+ int maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp);
+
+ int prepCostlyIface(const char *ifn, QuotaType quotaType);
+ int cleanupCostlyIface(const char *ifn, QuotaType quotaType);
+
+ std::string makeIptablesNaughtyCmd(IptOp op, int uid);
+ std::string makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota);
+
+ /* Runs for both ipv4 and ipv6 iptables */
+ int runCommands(int numCommands, const char *commands[], RunCmdErrHandling cmdErrHandling);
+ /* Runs for both ipv4 and ipv6 iptables, appends -j REJECT --reject-with ... */
+ static int runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling);
+ static int runIptablesCmd(const char *cmd, IptRejectOp rejectHandling, IptIpVer iptIpVer);
+
+ // Provides strncpy() + check overflow.
+ static int StrncpyAndCheck(char *buffer, const char *src, size_t buffSize);
+
+private:
+ static const char *cleanupCommands[];
+ static const char *setupCommands[];
+ static const char *basicAccountingCommands[];
+ static const int MAX_CMD_LEN;
+ static const int MAX_IFACENAME_LEN;
+ static const int MAX_CMD_ARGS;
+ static const char IPTABLES_PATH[];
+ static const char IP6TABLES_PATH[];
+
+};
+
+#endif
diff --git a/CommandListener.cpp b/CommandListener.cpp
index c6faea4..9236605 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -33,11 +33,14 @@
#include "CommandListener.h"
#include "ResponseCode.h"
#include "ThrottleController.h"
+#include "BandwidthController.h"
extern "C" int ifc_init(void);
+extern "C" int ifc_close(void);
extern "C" int ifc_get_hwaddr(const char *name, void *ptr);
extern "C" int ifc_get_info(const char *name, in_addr_t *addr, int *prefixLength, unsigned *flags);
+extern "C" int ifc_get_addr(const char *name, in_addr_t *addr);
extern "C" int ifc_set_addr(const char *name, in_addr_t addr);
extern "C" int ifc_set_prefixLength(const char *name, int prefixLength);
extern "C" int ifc_up(const char *name);
@@ -50,7 +53,7 @@
PppController *CommandListener::sPppCtrl = NULL;
PanController *CommandListener::sPanCtrl = NULL;
SoftapController *CommandListener::sSoftapCtrl = NULL;
-UsbController *CommandListener::sUsbCtrl = NULL;
+BandwidthController * CommandListener::sBandwidthCtrl = NULL;
ResolverController *CommandListener::sResolverCtrl = NULL;
CommandListener::CommandListener() :
@@ -63,7 +66,7 @@
registerCmd(new PppdCmd());
registerCmd(new PanCmd());
registerCmd(new SoftapCmd());
- registerCmd(new UsbCmd());
+ registerCmd(new BandwidthControlCmd());
registerCmd(new ResolverCmd());
if (!sTetherCtrl)
@@ -76,8 +79,8 @@
sPanCtrl = new PanController();
if (!sSoftapCtrl)
sSoftapCtrl = new SoftapController();
- if (!sUsbCtrl)
- sUsbCtrl = new UsbController();
+ if (!sBandwidthCtrl)
+ sBandwidthCtrl = new BandwidthController();
if (!sResolverCtrl)
sResolverCtrl = new ResolverController();
}
@@ -231,6 +234,7 @@
if (ifc_get_info(argv[2], &addr.s_addr, &prefixLength, &flags)) {
cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
+ ifc_close();
return 0;
}
@@ -262,6 +266,8 @@
free(addr_s);
free(flag_s);
free(msg);
+
+ ifc_close();
return 0;
} else if (!strcmp(argv[1], "setcfg")) {
// arglist: iface addr prefixLength [flags]
@@ -282,11 +288,13 @@
ifc_init();
if (ifc_set_addr(argv[2], addr.s_addr)) {
cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
+ ifc_close();
return 0;
}
if (ifc_set_prefixLength(argv[2], atoi(argv[4]))) {
cli->sendMsg(ResponseCode::OperationFailed, "Failed to set prefixLength", true);
+ ifc_close();
return 0;
}
@@ -313,6 +321,7 @@
if (ifc_up(argv[2])) {
LOGE("Error upping interface");
cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
+ ifc_close();
return 0;
}
} else if (!strcmp(flag, "down")) {
@@ -320,6 +329,7 @@
if (ifc_down(argv[2])) {
LOGE("Error downing interface");
cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
+ ifc_close();
return 0;
}
} else if (!strcmp(flag, "broadcast")) {
@@ -328,10 +338,30 @@
LOGD("multicast flag ignored");
} else {
cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
+ ifc_close();
return 0;
}
}
+
cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
+ ifc_close();
+ return 0;
+ } else if (!strcmp(argv[1], "clearaddrs")) {
+ // arglist: iface
+ unsigned count, addr;
+
+ //IPv4 only right now
+ LOGD("Clearing all IP addresses on %s", argv[2]);
+
+ ifc_init();
+ for (count=0, addr=1;((addr != 0) && (count < 255)); count++) {
+ if (ifc_get_addr(argv[2], &addr) < 0)
+ break;
+ if (addr)
+ ifc_set_addr(argv[2], 0);
+ }
+ ifc_close();
+ cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false);
return 0;
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
@@ -341,6 +371,7 @@
return 0;
}
+
CommandListener::ListTtysCmd::ListTtysCmd() :
NetdCommand("list_ttys") {
}
@@ -623,6 +654,7 @@
int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
int rc = 0, flag = 0;
+ char *retbuf = NULL;
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false);
@@ -639,13 +671,18 @@
rc = sSoftapCtrl->stopSoftap();
} else if (!strcmp(argv[1], "fwreload")) {
rc = sSoftapCtrl->fwReloadSoftap(argc, argv);
+ } else if (!strcmp(argv[1], "clients")) {
+ rc = sSoftapCtrl->clientsSoftap(&retbuf);
+ if (!rc) {
+ cli->sendMsg(ResponseCode::CommandOkay, retbuf, false);
+ free(retbuf);
+ return 0;
+ }
} else if (!strcmp(argv[1], "status")) {
- char *tmp = NULL;
-
- asprintf(&tmp, "Softap service %s",
+ asprintf(&retbuf, "Softap service %s",
(sSoftapCtrl->isSoftapStarted() ? "started" : "stopped"));
- cli->sendMsg(ResponseCode::SoftapStatusResult, tmp, false);
- free(tmp);
+ cli->sendMsg(ResponseCode::SoftapStatusResult, retbuf, false);
+ free(retbuf);
return 0;
} else if (!strcmp(argv[1], "set")) {
rc = sSoftapCtrl->setSoftap(argc, argv);
@@ -663,44 +700,6 @@
return 0;
}
-CommandListener::UsbCmd::UsbCmd() :
- NetdCommand("usb") {
-}
-
-int CommandListener::UsbCmd::runCommand(SocketClient *cli, int argc, char **argv) {
- int rc = 0;
-
- if (argc < 2) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usb Missing argument", false);
- return 0;
- }
-
- if (!strcmp(argv[1], "startrndis")) {
- rc = sUsbCtrl->startRNDIS();
- } else if (!strcmp(argv[1], "stoprndis")) {
- rc = sUsbCtrl->stopRNDIS();
- } else if (!strcmp(argv[1], "rndisstatus")) {
- char *tmp = NULL;
-
- asprintf(&tmp, "Usb RNDIS %s",
- (sUsbCtrl->isRNDISStarted() ? "started" : "stopped"));
- cli->sendMsg(ResponseCode::UsbRNDISStatusResult, tmp, false);
- free(tmp);
- return 0;
- } else {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Usb Unknown cmd", false);
- return 0;
- }
-
- if (!rc) {
- cli->sendMsg(ResponseCode::CommandOkay, "Usb operation succeeded", false);
- } else {
- cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
- }
-
- return 0;
-}
-
CommandListener::ResolverCmd::ResolverCmd() :
NetdCommand("resolver") {
}
@@ -810,3 +809,117 @@
*tx = 0;
return 0;
}
+
+CommandListener::BandwidthControlCmd::BandwidthControlCmd() :
+ NetdCommand("bandwidth") {
+}
+
+int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
+ int rc = 0;
+ LOGD("bwctrlcmd: argc=%d argv[0]=%s", argc, argv[0]);
+ if (argc < 2) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ return 0;
+ }
+
+ if (!strcmp(argv[1], "enable")) {
+ rc = sBandwidthCtrl->enableBandwidthControl();
+ } else if (!strcmp(argv[1], "disable")) {
+ rc = sBandwidthCtrl->disableBandwidthControl();
+
+ } else if (!strcmp(argv[1], "removequota") || !strcmp(argv[1], "rq")) {
+ if (argc != 3) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: bandwidth removequota <interface>", false);
+ return 0;
+ }
+ rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[2]);
+
+ } else if (!strcmp(argv[1], "setquota") || !strcmp(argv[1], "sq")) {
+ if (argc != 4) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: bandwidth setquota <interface> <bytes>", false);
+ return 0;
+ }
+ rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[2], atoll(argv[3]));
+
+ } else if (!strcmp(argv[1], "setquotas") || !strcmp(argv[1], "sqs")) {
+ if (argc < 4) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: bandwidth setquotas <bytes> <interface> ...", false);
+ return 0;
+ }
+ for (int q=3; argc >= 4; q++, argc--) {
+ rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[q], atoll(argv[2]));
+ if (rc) {
+ char *msg;
+ asprintf(&msg, "bandwidth setquotas %s %s failed", argv[2], argv[q]);
+ cli->sendMsg(ResponseCode::OperationFailed,
+ msg, false);
+ free(msg);
+ break;
+ }
+ }
+
+ } else if (!strcmp(argv[1], "removequotas") || !strcmp(argv[1], "rqs")) {
+ if (argc < 3) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: bandwidth removequotas <interface> ...", false);
+ return 0;
+ }
+ for (int q=2; argc >= 3; q++, argc--) {
+ rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[q]);
+ if (rc) {
+ char *msg;
+ asprintf(&msg, "bandwidth removequotas %s failed", argv[q]);
+ cli->sendMsg(ResponseCode::OperationFailed,
+ msg, false);
+ free(msg);
+ break;
+ }
+ }
+
+ } else if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
+ if (argc != 3) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: bandwidth removeiquota <interface>", false);
+ return 0;
+ }
+ rc = sBandwidthCtrl->removeInterfaceQuota(argv[2]);
+
+ } else if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
+ if (argc != 4) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: bandwidth setiquota <interface> <bytes>", false);
+ return 0;
+ }
+ rc = sBandwidthCtrl->setInterfaceQuota(argv[2], atoll(argv[3]));
+
+ } else if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
+ if (argc < 3) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: bandwidth addnaughtyapps <appUid> ...", false);
+ return 0;
+ }
+ rc = sBandwidthCtrl->addNaughtyApps(argc - 2, argv + 2);
+
+ } else if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) {
+ if (argc < 3) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: bandwidth remnaughtyapps <appUid> ...", false);
+ return 0;
+ }
+ rc = sBandwidthCtrl->removeNaughtyApps(argc - 2, argv + 2);
+
+ } else {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
+ return 0;
+ }
+
+ if (!rc) {
+ cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
+ } else {
+ cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", true);
+ }
+ return 0;
+}
diff --git a/CommandListener.h b/CommandListener.h
index d60069e..05e990e 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -25,7 +25,7 @@
#include "PppController.h"
#include "PanController.h"
#include "SoftapController.h"
-#include "UsbController.h"
+#include "BandwidthController.h"
#include "ResolverController.h"
class CommandListener : public FrameworkListener {
@@ -34,7 +34,7 @@
static PppController *sPppCtrl;
static PanController *sPanCtrl;
static SoftapController *sSoftapCtrl;
- static UsbController *sUsbCtrl;
+ static BandwidthController *sBandwidthCtrl;
static ResolverController *sResolverCtrl;
public:
@@ -45,13 +45,6 @@
static int readInterfaceCounters(const char *iface, unsigned long *rx, unsigned long *tx);
- class UsbCmd : public NetdCommand {
- public:
- UsbCmd();
- virtual ~UsbCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
-
class SoftapCmd : public NetdCommand {
public:
SoftapCmd();
@@ -108,6 +101,13 @@
int runCommand(SocketClient *c, int argc, char ** argv);
};
+ class BandwidthControlCmd : public NetdCommand {
+ public:
+ BandwidthControlCmd();
+ virtual ~BandwidthControlCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
class ResolverCmd : public NetdCommand {
public:
ResolverCmd();
diff --git a/DnsProxyListener.cpp b/DnsProxyListener.cpp
index 2546b82..bcb961e 100644
--- a/DnsProxyListener.cpp
+++ b/DnsProxyListener.cpp
@@ -92,6 +92,7 @@
if (!success) {
LOGW("Error writing DNS result to client");
}
+ mClient->decRef();
}
DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd() :
@@ -145,11 +146,11 @@
service ? service : "[nullservice]");
}
+ cli->incRef();
DnsProxyListener::GetAddrInfoHandler* handler =
new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints);
handler->start();
-
return 0;
}
@@ -187,6 +188,7 @@
return -1;
}
+ cli->incRef();
DnsProxyListener::GetHostByAddrHandler* handler =
new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily);
handler->start();
@@ -234,4 +236,5 @@
if (!success) {
LOGW("GetHostByAddrHandler: Error writing DNS result to client\n");
}
+ mClient->decRef();
}
diff --git a/DnsProxyListener.h b/DnsProxyListener.h
index 915f86d..1e24ebd 100644
--- a/DnsProxyListener.h
+++ b/DnsProxyListener.h
@@ -54,7 +54,7 @@
private:
void run();
pthread_t mThread;
- SocketClient* mClient; // not owned
+ SocketClient* mClient; // ref counted
char* mHost; // owned
char* mService; // owned
struct addrinfo* mHints; // owned
@@ -86,7 +86,7 @@
private:
void run();
pthread_t mThread;
- SocketClient* mClient; // not owned
+ SocketClient* mClient; // ref counted
void* mAddress; // address to lookup; owned
int mAddressLen; // length of address to look up
int mAddressFamily; // address family
diff --git a/NatController.cpp b/NatController.cpp
index ddb0499..8c719eb 100644
--- a/NatController.cpp
+++ b/NatController.cpp
@@ -70,12 +70,8 @@
if (runIptablesCmd("-P INPUT ACCEPT"))
return -1;
- if (runIptablesCmd("-F INPUT"))
- return -1;
if (runIptablesCmd("-P OUTPUT ACCEPT"))
return -1;
- if (runIptablesCmd("-F OUTPUT"))
- return -1;
if (runIptablesCmd("-P FORWARD DROP"))
return -1;
if (runIptablesCmd("-F FORWARD"))
diff --git a/NetlinkHandler.cpp b/NetlinkHandler.cpp
index 800c86c..874e03f 100644
--- a/NetlinkHandler.cpp
+++ b/NetlinkHandler.cpp
@@ -28,8 +28,9 @@
#include "NetlinkManager.h"
#include "ResponseCode.h"
-NetlinkHandler::NetlinkHandler(NetlinkManager *nm, int listenerSocket) :
- NetlinkListener(listenerSocket) {
+NetlinkHandler::NetlinkHandler(NetlinkManager *nm, int listenerSocket,
+ int format) :
+ NetlinkListener(listenerSocket, format) {
mNm = nm;
}
@@ -50,18 +51,22 @@
LOGW("No subsystem found in netlink event");
return;
}
+
if (!strcmp(subsys, "net")) {
int action = evt->getAction();
+ const char *iface = evt->findParam("INTERFACE");
+
if (action == evt->NlActionAdd) {
- const char *iface = evt->findParam("INTERFACE");
notifyInterfaceAdded(iface);
} else if (action == evt->NlActionRemove) {
- const char *iface = evt->findParam("INTERFACE");
notifyInterfaceRemoved(iface);
} else if (action == evt->NlActionChange) {
evt->dump();
- const char *iface = evt->findParam("INTERFACE");
notifyInterfaceChanged("nana", true);
+ } else if (action == evt->NlActionLinkUp) {
+ notifyInterfaceLinkChanged(iface, true);
+ } else if (action == evt->NlActionLinkDown) {
+ notifyInterfaceLinkChanged(iface, false);
}
}
}
@@ -84,7 +89,17 @@
void NetlinkHandler::notifyInterfaceChanged(const char *name, bool isUp) {
char msg[255];
- snprintf(msg, sizeof(msg), "Iface is %s %s", (isUp ? "up" : "down"), name);
+ snprintf(msg, sizeof(msg), "Iface changed %s %s", name,
+ (isUp ? "up" : "down"));
+
+ mNm->getBroadcaster()->sendBroadcast(ResponseCode::InterfaceChange,
+ msg, false);
+}
+
+void NetlinkHandler::notifyInterfaceLinkChanged(const char *name, bool isUp) {
+ char msg[255];
+ snprintf(msg, sizeof(msg), "Iface linkstate %s %s", name,
+ (isUp ? "up" : "down"));
mNm->getBroadcaster()->sendBroadcast(ResponseCode::InterfaceChange,
msg, false);
diff --git a/NetlinkHandler.h b/NetlinkHandler.h
index 8b2498f..492d6b1 100644
--- a/NetlinkHandler.h
+++ b/NetlinkHandler.h
@@ -24,7 +24,7 @@
NetlinkManager *mNm;
public:
- NetlinkHandler(NetlinkManager *nm, int listenerSocket);
+ NetlinkHandler(NetlinkManager *nm, int listenerSocket, int format);
virtual ~NetlinkHandler();
int start(void);
@@ -36,5 +36,6 @@
void notifyInterfaceAdded(const char *name);
void notifyInterfaceRemoved(const char *name);
void notifyInterfaceChanged(const char *name, bool isUp);
+ void notifyInterfaceLinkChanged(const char *name, bool isUp);
};
#endif
diff --git a/NetlinkManager.cpp b/NetlinkManager.cpp
index e7f0c7b..3e7a0a1 100644
--- a/NetlinkManager.cpp
+++ b/NetlinkManager.cpp
@@ -24,6 +24,7 @@
#include <sys/un.h>
#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
#define LOG_TAG "Netd"
@@ -47,7 +48,9 @@
NetlinkManager::~NetlinkManager() {
}
-int NetlinkManager::start() {
+NetlinkHandler *NetlinkManager::setupSocket(int *sock, int socketType,
+ int groups, int format) {
+
struct sockaddr_nl nladdr;
int sz = 64 * 1024;
int on = 1;
@@ -55,47 +58,78 @@
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = getpid();
- nladdr.nl_groups = 0xffffffff;
+ nladdr.nl_groups = groups;
- if ((mSock = socket(PF_NETLINK,
- SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {
- LOGE("Unable to create uevent socket: %s", strerror(errno));
- return -1;
+ if ((*sock = socket(PF_NETLINK, SOCK_DGRAM, socketType)) < 0) {
+ LOGE("Unable to create netlink socket: %s", strerror(errno));
+ return NULL;
}
- if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
+ if (setsockopt(*sock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
LOGE("Unable to set uevent socket SO_RCVBUFFORCE option: %s", strerror(errno));
- return -1;
+ close(*sock);
+ return NULL;
}
- if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
+ if (setsockopt(*sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
- return -1;
+ close(*sock);
+ return NULL;
}
- if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
- LOGE("Unable to bind uevent socket: %s", strerror(errno));
- return -1;
+ if (bind(*sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
+ LOGE("Unable to bind netlink socket: %s", strerror(errno));
+ close(*sock);
+ return NULL;
}
- mHandler = new NetlinkHandler(this, mSock);
- if (mHandler->start()) {
+ NetlinkHandler *handler = new NetlinkHandler(this, *sock, format);
+ if (handler->start()) {
LOGE("Unable to start NetlinkHandler: %s", strerror(errno));
+ close(*sock);
+ return NULL;
+ }
+
+ return handler;
+}
+
+int NetlinkManager::start() {
+ if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
+ 0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {
+ return -1;
+ }
+
+ if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE, RTMGRP_LINK,
+ NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
return -1;
}
return 0;
}
int NetlinkManager::stop() {
- if (mHandler->stop()) {
- LOGE("Unable to stop NetlinkHandler: %s", strerror(errno));
- return -1;
+ int status = 0;
+
+ if (mUeventHandler->stop()) {
+ LOGE("Unable to stop uevent NetlinkHandler: %s", strerror(errno));
+ status = -1;
}
- delete mHandler;
- mHandler = NULL;
- close(mSock);
- mSock = -1;
+ delete mUeventHandler;
+ mUeventHandler = NULL;
- return 0;
+ close(mUeventSock);
+ mUeventSock = -1;
+
+ if (mRouteHandler->stop()) {
+ LOGE("Unable to stop route NetlinkHandler: %s", strerror(errno));
+ status = -1;
+ }
+
+ delete mRouteHandler;
+ mRouteHandler = NULL;
+
+ close(mRouteSock);
+ mRouteSock = -1;
+
+ return status;
}
diff --git a/NetlinkManager.h b/NetlinkManager.h
index 9c7ba11..ff646f4 100644
--- a/NetlinkManager.h
+++ b/NetlinkManager.h
@@ -28,8 +28,10 @@
private:
SocketListener *mBroadcaster;
- NetlinkHandler *mHandler;
- int mSock;
+ NetlinkHandler *mUeventHandler;
+ NetlinkHandler *mRouteHandler;
+ int mUeventSock;
+ int mRouteSock;
public:
virtual ~NetlinkManager();
@@ -44,5 +46,7 @@
private:
NetlinkManager();
+ NetlinkHandler* setupSocket(int *sock, int socketType, int groups,
+ int format);
};
#endif
diff --git a/SoftapController.cpp b/SoftapController.cpp
index 1f42214..6039761 100644
--- a/SoftapController.cpp
+++ b/SoftapController.cpp
@@ -51,7 +51,7 @@
close(mSock);
}
-int SoftapController::setCommand(char *iface, const char *fname) {
+int SoftapController::setCommand(char *iface, const char *fname, unsigned buflen) {
char tBuf[SOFTAP_MAX_BUFFER_SIZE];
struct iwreq wrq;
struct iw_priv_args *priv_ptr;
@@ -96,10 +96,10 @@
}
strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));
- if (*mBuf != 0)
+ if ((buflen == 0) && (*mBuf != 0))
wrq.u.data.length = strlen(mBuf) + 1;
else
- wrq.u.data.length = 0;
+ wrq.u.data.length = buflen;
wrq.u.data.pointer = mBuf;
wrq.u.data.flags = sub_cmd;
ret = ioctl(mSock, cmd, &wrq);
@@ -348,3 +348,22 @@
}
return ret;
}
+
+int SoftapController::clientsSoftap(char **retbuf)
+{
+ int ret;
+
+ if (mSock < 0) {
+ LOGE("Softap clients - failed to open socket");
+ return -1;
+ }
+ *mBuf = 0;
+ ret = setCommand(mIface, "AP_GET_STA_LIST", SOFTAP_MAX_BUFFER_SIZE);
+ if (ret) {
+ LOGE("Softap clients - failed: %d", ret);
+ } else {
+ asprintf(retbuf, "Softap clients:%s", mBuf);
+ LOGD("Softap clients:%s", mBuf);
+ }
+ return ret;
+}
diff --git a/SoftapController.h b/SoftapController.h
index 60236f8..7801577 100644
--- a/SoftapController.h
+++ b/SoftapController.h
@@ -34,7 +34,7 @@
int mSock;
int addParam(int pos, const char *cmd, const char *arg);
- int setCommand(char *iface, const char *fname);
+ int setCommand(char *iface, const char *fname, unsigned buflen=0);
public:
SoftapController();
virtual ~SoftapController();
@@ -46,6 +46,7 @@
bool isSoftapStarted();
int setSoftap(int argc, char *argv[]);
int fwReloadSoftap(int argc, char *argv[]);
+ int clientsSoftap(char **retbuf);
};
#endif
diff --git a/UsbController.cpp b/UsbController.cpp
deleted file mode 100644
index 16e5d6a..0000000
--- a/UsbController.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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 <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#define LOG_TAG "UsbController"
-#include <cutils/log.h>
-
-#include "UsbController.h"
-
-
-UsbController::UsbController() {
-}
-
-UsbController::~UsbController() {
-}
-
-int UsbController::startRNDIS() {
- LOGD("Usb RNDIS start");
- return enableRNDIS(true);
-}
-
-int UsbController::stopRNDIS() {
- LOGD("Usb RNDIS stop");
- return enableRNDIS(false);
-}
-
-int UsbController::enableRNDIS(bool enable) {
- char value[20];
- int fd = open("/sys/class/usb_composite/rndis/enable", O_RDWR);
- int count = snprintf(value, sizeof(value), "%d\n", (enable ? 1 : 0));
- write(fd, value, count);
- close(fd);
- return 0;
-}
-
-bool UsbController::isRNDISStarted() {
- char value=0;
- int fd = open("/sys/class/usb_composite/rndis/enable", O_RDWR);
- read(fd, &value, 1);
- close(fd);
- return (value == '1' ? true : false);
-}
diff --git a/UsbController.h b/UsbController.h
deleted file mode 100644
index 2de4bfa..0000000
--- a/UsbController.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 _USB_CONTROLLER_H
-#define _USB_CONTROLLER_H
-
-#include <linux/in.h>
-
-
-class UsbController {
-
-public:
- UsbController();
- virtual ~UsbController();
-
- int startRNDIS();
- int stopRNDIS();
- bool isRNDISStarted();
-
-private:
- int enableRNDIS(bool enable);
-};
-
-#endif