From f1a5a34d8e5554d4286842f91797d811a713a5fc Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 16 Feb 2016 16:40:06 -0800 Subject: [PATCH] binder: Implement interface add/remove methods 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 --- wpa_supplicant/binder/binder.cpp | 28 +++++ wpa_supplicant/binder/binder.h | 14 +++ wpa_supplicant/binder/binder_manager.cpp | 54 +++++++++ wpa_supplicant/binder/binder_manager.h | 5 + .../fi/w1/wpa_supplicant/ISupplicant.aidl | 40 +++++++ wpa_supplicant/binder/supplicant.cpp | 106 ++++++++++++++++++ wpa_supplicant/binder/supplicant.h | 12 ++ wpa_supplicant/wpa_supplicant_i.h | 3 + 8 files changed, 262 insertions(+) diff --git a/wpa_supplicant/binder/binder.cpp b/wpa_supplicant/binder/binder.cpp index 59ee9a575..28f7a2bf6 100644 --- a/wpa_supplicant/binder/binder.cpp +++ b/wpa_supplicant/binder/binder.cpp @@ -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); +} diff --git a/wpa_supplicant/binder/binder.h b/wpa_supplicant/binder/binder.h index 6406f096b..a16507495 100644 --- a/wpa_supplicant/binder/binder.h +++ b/wpa_supplicant/binder/binder.h @@ -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 */ diff --git a/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant/binder/binder_manager.cpp index 9c35b233e..728f4b7e1 100644 --- a/wpa_supplicant/binder/binder_manager.cpp +++ b/wpa_supplicant/binder/binder_manager.cpp @@ -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 *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 */ diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h index 011fa3edd..687e74044 100644 --- a/wpa_supplicant/binder/binder_manager.h +++ b/wpa_supplicant/binder/binder_manager.h @@ -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 *iface_object); private: BinderManager() = default; diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl index 5be23911f..1cbee20a6 100644 --- a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl +++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl @@ -10,10 +10,50 @@ 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); } diff --git a/wpa_supplicant/binder/supplicant.cpp b/wpa_supplicant/binder/supplicant.cpp index 053f329c8..6844e5a3c 100644 --- a/wpa_supplicant/binder/supplicant.cpp +++ b/wpa_supplicant/binder/supplicant.cpp @@ -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 ¶ms, + android::sp *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 *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 */ diff --git a/wpa_supplicant/binder/supplicant.h b/wpa_supplicant/binder/supplicant.h index 02b59188a..b96f4e6a0 100644 --- a/wpa_supplicant/binder/supplicant.h +++ b/wpa_supplicant/binder/supplicant.h @@ -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 ¶ms, + android::sp *aidl_return) + override; + android::binder::Status RemoveInterface( + const std::string &ifname) override; + android::binder::Status GetInterface( + const std::string &ifname, + android::sp *aidl_return) + override; + private: /* Raw pointer to the global structure maintained by the core. */ struct wpa_global *wpa_global_; diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 255dcc3e0..c48589171 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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;