Merge "Fix idletimer iptable rules."
diff --git a/Android.mk b/Android.mk
index 4e6c6f3..811e875 100644
--- a/Android.mk
+++ b/Android.mk
@@ -8,6 +8,7 @@
                   DnsProxyListener.cpp                 \
                   FirewallController.cpp               \
                   IdletimerController.cpp              \
+                  InterfaceController.cpp              \
                   MDnsSdListener.cpp                   \
                   NatController.cpp                    \
                   NetdCommand.cpp                      \
diff --git a/CommandListener.cpp b/CommandListener.cpp
index e0cbca0..969fa65 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -50,6 +50,7 @@
 SoftapController *CommandListener::sSoftapCtrl = NULL;
 BandwidthController * CommandListener::sBandwidthCtrl = NULL;
 IdletimerController * CommandListener::sIdletimerCtrl = NULL;
+InterfaceController *CommandListener::sInterfaceCtrl = NULL;
 ResolverController *CommandListener::sResolverCtrl = NULL;
 SecondaryTableController *CommandListener::sSecondaryTableCtrl = NULL;
 FirewallController *CommandListener::sFirewallCtrl = NULL;
@@ -158,6 +159,8 @@
         sResolverCtrl = new ResolverController();
     if (!sFirewallCtrl)
         sFirewallCtrl = new FirewallController();
+    if (!sInterfaceCtrl)
+        sInterfaceCtrl = new InterfaceController();
 
     /*
      * This is the only time we touch top-level chains in iptables; controllers
@@ -317,6 +320,22 @@
             cli->sendMsg(ResponseCode::CommandOkay, "Interface throttling set", false);
         }
         return 0;
+    } else if (!strcmp(argv[1], "driver")) {
+        int rc;
+        char *rbuf;
+
+        if (argc < 4) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                    "Usage: interface driver <interface> <cmd> <args>", false);
+            return 0;
+        }
+        rc = sInterfaceCtrl->interfaceCommand(argc, argv, &rbuf);
+        if (rc) {
+            cli->sendMsg(ResponseCode::OperationFailed, "Failed to execute command", true);
+        } else {
+            cli->sendMsg(ResponseCode::CommandOkay, rbuf, false);
+        }
+        return 0;
     } else {
         /*
          * These commands take a minimum of 3 arguments
diff --git a/CommandListener.h b/CommandListener.h
index e52b440..faf0c21 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -27,6 +27,7 @@
 #include "SoftapController.h"
 #include "BandwidthController.h"
 #include "IdletimerController.h"
+#include "InterfaceController.h"
 #include "ResolverController.h"
 #include "SecondaryTableController.h"
 #include "FirewallController.h"
@@ -39,6 +40,7 @@
     static SoftapController *sSoftapCtrl;
     static BandwidthController *sBandwidthCtrl;
     static IdletimerController *sIdletimerCtrl;
+    static InterfaceController *sInterfaceCtrl;
     static ResolverController *sResolverCtrl;
     static SecondaryTableController *sSecondaryTableCtrl;
     static FirewallController *sFirewallCtrl;
diff --git a/InterfaceController.cpp b/InterfaceController.cpp
new file mode 100644
index 0000000..a20b13f
--- /dev/null
+++ b/InterfaceController.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 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 <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define LOG_TAG "InterfaceController"
+#include <cutils/log.h>
+#include <netutils/ifc.h>
+#include <private/android_filesystem_config.h>
+
+#include "InterfaceController.h"
+
+InterfaceController::InterfaceController() {
+    iSock = socket(AF_INET, SOCK_DGRAM, 0);
+    if (iSock < 0)
+        ALOGE("Failed to open socket");
+    iBuf = (char *)malloc(INTERFACE_MAX_BUFFER_SIZE);
+    if (!iBuf)
+        ALOGE("Failed to allocate buffer");
+}
+
+InterfaceController::~InterfaceController() {
+    if (iSock >= 0)
+        close(iSock);
+    if (iBuf)
+        free(iBuf);
+}
+
+int InterfaceController::sendCommand(char *iface, char *cmd, char *buf, int buf_len) {
+    struct ifreq ifr;
+    android_wifi_priv_cmd priv_cmd;
+    int ret;
+
+    if (!iface || !cmd)
+        return -1;
+
+    memset(&ifr, 0, sizeof(ifr));
+    memset(&priv_cmd, 0, sizeof(priv_cmd));
+    strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+    memcpy(buf, cmd, strlen(cmd) + 1);
+
+    priv_cmd.buf = buf;
+    priv_cmd.used_len = buf_len;
+    priv_cmd.total_len = buf_len;
+    ifr.ifr_data = &priv_cmd;
+
+    if ((ret = ioctl(iSock, SIOCDEVPRIVATE + 1, &ifr)) < 0) {
+        ALOGE("Failed to execute command: %s", cmd);
+    } else {
+        if (buf[0] == '\0') {
+            snprintf(buf, buf_len, "OK");
+        }
+    }
+    return ret;
+}
+
+/*
+ * Arguments:
+ *      argv[2] - wlan interface
+ *      argv[3] - command
+ *      argv[4] - argument
+ *      rbuf    - returned buffer
+ */
+int InterfaceController::interfaceCommand(int argc, char *argv[], char **rbuf) {
+    char cmd[INTERFACE_MAX_BUFFER_SIZE];
+    unsigned int bc = 0;
+    int ret;
+    int i;
+
+    if ((iSock < 0) || !iBuf || (argc < 4))
+        return -1;
+
+    for (i=3; i < argc; i++) {
+        bc += snprintf(&cmd[bc], sizeof(cmd) - bc, "%s ", argv[i]);
+    }
+    if (bc >= sizeof(cmd))
+        bc = sizeof(cmd) - 1;
+    cmd[bc] = '\0';
+    ret = sendCommand(argv[2], cmd, iBuf, INTERFACE_MAX_BUFFER_SIZE);
+    if (rbuf)
+        *rbuf = iBuf;
+    return ret;
+}
diff --git a/InterfaceController.h b/InterfaceController.h
new file mode 100644
index 0000000..dbedc13
--- /dev/null
+++ b/InterfaceController.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 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 _INTERFACE_CONTROLLER_H
+#define _INTERFACE_CONTROLLER_H
+
+#include <linux/in.h>
+#include <net/if.h>
+
+typedef struct android_wifi_priv_cmd {
+    char *buf;
+    int used_len;
+    int total_len;
+} android_wifi_priv_cmd;
+
+#define INTERFACE_MAX_BUFFER_SIZE	256
+
+class InterfaceController {
+    int iSock;
+    char *iBuf;
+
+    int sendCommand(char *iface, char *cmd, char *buf, int buf_len);
+public:
+    InterfaceController();
+    virtual ~InterfaceController();
+
+    int interfaceCommand(int argc, char *argv[], char **rbuf);
+};
+
+#endif