binder: Implement interface add/remove methods
authorRoshan Pius <rpius@google.com>
Wed, 17 Feb 2016 00:40:06 +0000 (16:40 -0800)
committerJouni Malinen <j@w1.fi>
Sat, 2 Apr 2016 14:35:28 +0000 (17:35 +0300)
This commit implements the methods defined in Supplicant service:
1. CreateInterface
2. RemoveInterface
3. GetInterface

The binder service returns the corresponding iface binder object
references which can be used by clients to control a specific
interface.

Signed-off-by: Roshan Pius <rpius@google.com>
wpa_supplicant/binder/binder.cpp
wpa_supplicant/binder/binder.h
wpa_supplicant/binder/binder_manager.cpp
wpa_supplicant/binder/binder_manager.h
wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
wpa_supplicant/binder/supplicant.cpp
wpa_supplicant/binder/supplicant.h
wpa_supplicant/wpa_supplicant_i.h

index 59ee9a5..28f7a2b 100644 (file)
@@ -78,3 +78,31 @@ void wpas_binder_deinit(struct wpas_binder_priv *priv)
        eloop_unregister_read_sock(priv->binder_fd);
        android::IPCThreadState::shutdown();
 }
+
+
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->global->binder)
+               return 1;
+
+       wpa_supplicant_binder::BinderManager *binder_manager =
+               wpa_supplicant_binder::BinderManager::getInstance();
+       if (!binder_manager)
+               return 1;
+
+       return binder_manager->registerInterface(wpa_s);
+}
+
+
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s->global->binder)
+               return 1;
+
+       wpa_supplicant_binder::BinderManager *binder_manager =
+               wpa_supplicant_binder::BinderManager::getInstance();
+       if (!binder_manager)
+               return 1;
+
+       return binder_manager->unregisterInterface(wpa_s);
+}
index 6406f09..a165074 100644 (file)
@@ -25,6 +25,20 @@ struct wpa_global;
 struct wpas_binder_priv * wpas_binder_init(struct wpa_global *global);
 void wpas_binder_deinit(struct wpas_binder_priv *priv);
 
+#ifdef CONFIG_CTRL_IFACE_BINDER
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s);
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s);
+#else /* CONFIG_CTRL_IFACE_BINDER */
+static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+       return 0;
+}
+static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+       return 0;
+}
+#endif /* CONFIG_CTRL_IFACE_BINDER */
+
 #ifdef _cplusplus
 }
 #endif /* _cplusplus */
index 9c35b23..728f4b7 100644 (file)
@@ -50,4 +50,58 @@ int BinderManager::registerBinderService(struct wpa_global *global)
        return 0;
 }
 
+
+int BinderManager::registerInterface(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s)
+               return 1;
+
+       /* Using the corresponding wpa_supplicant pointer as key to our
+        * object map. */
+       const void *iface_key = wpa_s;
+
+       /* Return failure if we already have an object for that iface_key. */
+       if (iface_object_map_.find(iface_key) != iface_object_map_.end())
+               return 1;
+
+       iface_object_map_[iface_key] = new Iface(wpa_s);
+       if (!iface_object_map_[iface_key].get())
+               return 1;
+
+       wpa_s->binder_object_key = iface_key;
+
+       return 0;
+}
+
+
+int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s)
+{
+       if (!wpa_s || !wpa_s->binder_object_key)
+               return 1;
+
+       const void *iface_key = wpa_s;
+       if (iface_object_map_.find(iface_key) == iface_object_map_.end())
+               return 1;
+
+       /* Delete the corresponding iface object from our map. */
+       iface_object_map_.erase(iface_key);
+       wpa_s->binder_object_key = NULL;
+       return 0;
+}
+
+
+int BinderManager::getIfaceBinderObjectByKey(
+       const void *iface_object_key,
+       android::sp<fi::w1::wpa_supplicant::IIface> *iface_object)
+{
+       if (!iface_object_key || !iface_object)
+               return 1;
+
+       if (iface_object_map_.find(iface_object_key) == iface_object_map_.end())
+               return 1;
+
+       *iface_object = iface_object_map_[iface_object_key];
+       return 0;
+}
+
 } /* namespace wpa_supplicant_binder */
index 011fa3e..687e740 100644 (file)
@@ -34,6 +34,11 @@ public:
        static BinderManager * getInstance();
        static void destroyInstance();
        int registerBinderService(struct wpa_global *global);
+       int registerInterface(struct wpa_supplicant *wpa_s);
+       int unregisterInterface(struct wpa_supplicant *wpa_s);
+       int getIfaceBinderObjectByKey(
+               const void *iface_object_key,
+               android::sp<fi::w1::wpa_supplicant::IIface> *iface_object);
 
 private:
        BinderManager() = default;
index 5be2391..1cbee20 100644 (file)
 package fi.w1.wpa_supplicant;
 
 import android.os.PersistableBundle;
+import fi.w1.wpa_supplicant.IIface;
 
 /**
  * Interface exposed by the wpa_supplicant binder service registered
  * with the service manager with name: fi.w1.wpa_supplicant.
  */
 interface ISupplicant {
+       /* Error values returned by the service to RPC method calls. */
+       const int ERROR_INVALID_ARGS = 1;
+       const int ERROR_UNKNOWN = 2;
+       const int ERROR_IFACE_EXISTS = 3;
+       const int ERROR_IFACE_UNKNOWN = 4;
+
+       /**
+        * Registers a wireless interface in wpa_supplicant.
+        *
+        * @param args A dictionary with arguments used to add the interface to
+        *             wpa_supplicant.
+        * The dictionary may contain the following entries:
+        *   Ifname(String) Name of the network interface to control, e.g.,
+        *   wlan0.
+        *   BridgeIfname(String) Name of the bridge interface to control, e.g.,
+        *   br0.
+        *   Driver(String) Driver name which the interface uses, e.g., nl80211.
+        *   ConfigFile(String) Configuration file path.
+        *
+        * @return Binder object representing the interface.
+        */
+       IIface CreateInterface(in PersistableBundle args);
+
+       /**
+        * Deregisters a wireless interface from wpa_supplicant.
+        *
+        * @param ifname Name of the network interface, e.g., wlan0
+        */
+       void RemoveInterface(in @utf8InCpp String ifname);
+
+       /**
+        * Gets a binder object for the interface corresponding to ifname
+        * which wpa_supplicant already controls.
+        *
+        * @param ifname Name of the network interface, e.g., wlan0
+        *
+        * @return Binder object representing the interface.
+        */
+       IIface GetInterface(in @utf8InCpp String ifname);
 }
index 053f329..6844e5a 100644 (file)
@@ -7,6 +7,7 @@
  * See README for more details.
  */
 
+#include "binder_manager.h"
 #include "supplicant.h"
 
 namespace wpa_supplicant_binder {
@@ -16,4 +17,109 @@ Supplicant::Supplicant(struct wpa_global *global)
 {
 }
 
+
+android::binder::Status Supplicant::CreateInterface(
+       const android::os::PersistableBundle &params,
+       android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+       android::String16 driver, ifname, confname, bridge_ifname;
+
+       /* Check if required Ifname argument is missing */
+       if (!params.getString(android::String16("Ifname"), &ifname))
+               return android::binder::Status::fromServiceSpecificError(
+                       ERROR_INVALID_ARGS,
+                       android::String8("Ifname missing in params."));
+       /* Retrieve the remaining params from the dictionary */
+       params.getString(android::String16("Driver"), &driver);
+       params.getString(android::String16("ConfigFile"), &confname);
+       params.getString(android::String16("BridgeIfname"), &bridge_ifname);
+
+       /*
+        * Try to get the wpa_supplicant record for this iface, return
+        * an error if we already control it.
+        */
+       if (wpa_supplicant_get_iface(wpa_global_,
+                                    android::String8(ifname).string()) != NULL)
+               return android::binder::Status::fromServiceSpecificError(
+                       ERROR_IFACE_EXISTS,
+                       android::String8("wpa_supplicant already controls this interface."));
+
+       android::binder::Status status;
+       struct wpa_supplicant *wpa_s = NULL;
+       struct wpa_interface iface;
+
+       os_memset(&iface, 0, sizeof(iface));
+       iface.driver = os_strdup(android::String8(driver).string());
+       iface.ifname = os_strdup(android::String8(ifname).string());
+       iface.confname = os_strdup(android::String8(confname).string());
+       iface.bridge_ifname = os_strdup(
+               android::String8(bridge_ifname).string());
+       /* Otherwise, have wpa_supplicant attach to it. */
+       wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL);
+       /* The supplicant core creates a corresponding binder object via
+        * BinderManager when |wpa_supplicant_add_iface| is called. */
+       if (!wpa_s || !wpa_s->binder_object_key) {
+               status = android::binder::Status::fromServiceSpecificError(
+                       ERROR_UNKNOWN,
+                       android::String8("wpa_supplicant couldn't grab this interface."));
+       } else {
+               BinderManager *binder_manager = BinderManager::getInstance();
+
+               if (!binder_manager ||
+                   binder_manager->getIfaceBinderObjectByKey(
+                           wpa_s->binder_object_key, aidl_return))
+                       status = android::binder::Status::fromServiceSpecificError(
+                               ERROR_UNKNOWN,
+                               android::String8("wpa_supplicant encountered a binder error."));
+               else
+                       status = android::binder::Status::ok();
+       }
+       os_free((void *) iface.driver);
+       os_free((void *) iface.ifname);
+       os_free((void *) iface.confname);
+       os_free((void *) iface.bridge_ifname);
+       return status;
+}
+
+
+android::binder::Status Supplicant::RemoveInterface(const std::string &ifname)
+{
+       struct wpa_supplicant *wpa_s;
+
+       wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+       if (!wpa_s || !wpa_s->binder_object_key)
+               return android::binder::Status::fromServiceSpecificError(
+                       ERROR_IFACE_UNKNOWN,
+                       android::String8("wpa_supplicant does not control this interface."));
+       if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0))
+               return android::binder::Status::fromServiceSpecificError(
+                       ERROR_UNKNOWN,
+                       android::String8("wpa_supplicant couldn't remove this interface."));
+       return android::binder::Status::ok();
+}
+
+
+android::binder::Status Supplicant::GetInterface(
+       const std::string &ifname,
+       android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+       struct wpa_supplicant *wpa_s;
+
+       wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+       if (!wpa_s || !wpa_s->binder_object_key)
+               return android::binder::Status::fromServiceSpecificError(
+                       ERROR_IFACE_UNKNOWN,
+                       android::String8("wpa_supplicant does not control this interface."));
+
+       BinderManager *binder_manager = BinderManager::getInstance();
+       if (!binder_manager ||
+           binder_manager->getIfaceBinderObjectByKey(wpa_s->binder_object_key,
+                                                     aidl_return))
+               return android::binder::Status::fromServiceSpecificError(
+                       ERROR_UNKNOWN,
+                       android::String8("wpa_supplicant encountered a binder error."));
+
+       return android::binder::Status::ok();
+}
+
 } /* namespace wpa_supplicant_binder */
index 02b5918..b96f4e6 100644 (file)
@@ -11,6 +11,7 @@
 #define SUPPLICANT_H
 
 #include "fi/w1/wpa_supplicant/BnSupplicant.h"
+#include "fi/w1/wpa_supplicant/IIface.h"
 #include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h"
 
 extern "C" {
@@ -32,6 +33,17 @@ public:
        Supplicant(struct wpa_global *global);
        virtual ~Supplicant() = default;
 
+       android::binder::Status CreateInterface(
+               const android::os::PersistableBundle &params,
+               android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+               override;
+       android::binder::Status RemoveInterface(
+               const std::string &ifname) override;
+       android::binder::Status GetInterface(
+               const std::string &ifname,
+               android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+               override;
+
 private:
        /* Raw pointer to the global structure maintained by the core. */
        struct wpa_global *wpa_global_;
index 255dcc3..c485891 100644 (file)
@@ -484,6 +484,9 @@ struct wpa_supplicant {
        char *preq_notify_peer;
 #endif /* CONFIG_AP */
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+#ifdef CONFIG_CTRL_IFACE_BINDER
+       const void *binder_object_key;
+#endif /* CONFIG_CTRL_IFACE_BINDER */
        char bridge_ifname[16];
 
        char *confname;