binder: Implement |OnStateChanged| callback
Add state change callbacks. This is used by clients to monitor wpa_supplicant's
connection status, etc.
BUG: 30093041
TEST: Ran a simple connect/disconnect integration test gtest.
Change-Id: I35238f0f95b0a0a4723cb315ddaba30dd19d7dab
Signed-off-by: Roshan Pius <rpius@google.com>
diff --git a/wpa_supplicant/binder/binder.cpp b/wpa_supplicant/binder/binder.cpp
index 704b1c3..d174f2b 100644
--- a/wpa_supplicant/binder/binder.cpp
+++ b/wpa_supplicant/binder/binder.cpp
@@ -85,7 +85,7 @@
int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
{
- if (!wpa_s->global->binder || !wpa_s)
+ if (!wpa_s || !wpa_s->global->binder)
return 1;
wpa_printf(
@@ -102,7 +102,7 @@
int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
{
- if (!wpa_s->global->binder || !wpa_s)
+ if (!wpa_s || !wpa_s->global->binder)
return 1;
wpa_printf(
@@ -120,7 +120,7 @@
int wpas_binder_register_network(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
- if (!wpa_s->global->binder || !wpa_s || !ssid)
+ if (!wpa_s || !wpa_s->global->binder || !ssid)
return 1;
wpa_printf(
@@ -137,7 +137,7 @@
int wpas_binder_unregister_network(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
- if (!wpa_s->global->binder || !wpa_s || !ssid)
+ if (!wpa_s || !wpa_s->global->binder || !ssid)
return 1;
wpa_printf(
@@ -151,3 +151,20 @@
return binder_manager->unregisterNetwork(wpa_s, ssid);
}
+
+int wpas_binder_notify_state_changed(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s || !wpa_s->global->binder || !ssid)
+ return 1;
+
+ wpa_printf(
+ MSG_DEBUG, "Notifying state change event to binder control: %d",
+ wpa_s->wpa_state);
+
+ wpa_supplicant_binder::BinderManager *binder_manager =
+ wpa_supplicant_binder::BinderManager::getInstance();
+ if (!binder_manager)
+ return 1;
+
+ return binder_manager->notifyStateChange(wpa_s);
+}
diff --git a/wpa_supplicant/binder/binder.h b/wpa_supplicant/binder/binder.h
index 4ca2c86..7afc6ef 100644
--- a/wpa_supplicant/binder/binder.h
+++ b/wpa_supplicant/binder/binder.h
@@ -32,6 +32,7 @@
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpas_binder_unregister_network(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_binder_notify_state_changed(struct wpa_supplicant *wpa_s);
#else /* CONFIG_CTRL_IFACE_BINDER */
static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
{
@@ -51,6 +52,10 @@
{
return 0;
}
+static inline int wpas_binder_notify_state_changed(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
#endif /* CONFIG_CTRL_IFACE_BINDER */
#ifdef _cplusplus
diff --git a/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant/binder/binder_manager.cpp
index d5a502c..ab79f91 100644
--- a/wpa_supplicant/binder/binder_manager.cpp
+++ b/wpa_supplicant/binder/binder_manager.cpp
@@ -216,8 +216,45 @@
wpa_s->ifname,
std::bind(
&fi::w1::wpa_supplicant::IIfaceCallback::OnNetworkRemoved,
- std::placeholders::_1,
- ssid->id));
+ std::placeholders::_1, ssid->id));
+ return 0;
+}
+
+/**
+ * Notify all listeners about any state changes on a particular interface.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the state change event occured.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+int BinderManager::notifyStateChange(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s)
+ return 1;
+
+ const std::string ifname(wpa_s->ifname);
+
+ if (iface_object_map_.find(ifname) == iface_object_map_.end())
+ return 1;
+
+ // Invoke the |OnStateChanged| method on all registered callbacks.
+ int state = wpa_s->wpa_state;
+ std::vector<uint8_t> bssid(wpa_s->bssid, wpa_s->bssid + ETH_ALEN);
+ int network_id =
+ fi::w1::wpa_supplicant::IIfaceCallback::NETWORK_ID_INVALID;
+ std::vector<uint8_t> ssid;
+ if (wpa_s->current_ssid) {
+ network_id = wpa_s->current_ssid->id;
+ ssid.assign(
+ wpa_s->current_ssid->ssid,
+ wpa_s->current_ssid->ssid + wpa_s->current_ssid->ssid_len);
+ }
+ callWithEachIfaceCallback(
+ wpa_s->ifname,
+ std::bind(
+ &fi::w1::wpa_supplicant::IIfaceCallback::OnStateChanged,
+ std::placeholders::_1, state, bssid, network_id, ssid));
return 0;
}
diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h
index 01ff2fc..200d7e6 100644
--- a/wpa_supplicant/binder/binder_manager.h
+++ b/wpa_supplicant/binder/binder_manager.h
@@ -46,6 +46,7 @@
registerNetwork(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int
unregisterNetwork(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+ int notifyStateChange(struct wpa_supplicant *wpa_s);
// Methods called from binder objects.
int getIfaceBinderObjectByIfname(
@@ -235,5 +236,12 @@
WPA_CIPHER_CCMP,
"PairwiseCipher value mismatch");
+static_assert(
+ WPA_DISCONNECTED ==
+ fi::w1::wpa_supplicant::IIfaceCallback::STATE_DISCONNECTED,
+ "State value mismatch");
+static_assert(
+ WPA_COMPLETED == fi::w1::wpa_supplicant::IIfaceCallback::STATE_COMPLETED,
+ "State value mismatch");
} // namespace wpa_supplicant_binder
#endif // WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIfaceCallback.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIfaceCallback.aidl
index f740b94..18ff513 100644
--- a/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIfaceCallback.aidl
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIfaceCallback.aidl
@@ -19,6 +19,106 @@
*/
@utf8InCpp
interface IIfaceCallback {
+ /** Used to indicate a non specific network event via |OnStateChanged|.*/
+ const int NETWORK_ID_INVALID = -1;
+
+ /** Various states of the interface reported by |OnStateChanged|.*/
+ /**
+ * STATE_DISCONNECTED - Disconnected state
+ *
+ * This state indicates that client is not associated, but is likely to
+ * start looking for an access point. This state is entered when a
+ * connection is lost.
+ */
+ const int STATE_DISCONNECTED = 0;
+ /**
+ * STATE_INTERFACE_DISABLED - Interface disabled
+ *
+ * This state is entered if the network interface is disabled, e.g.,
+ * due to rfkill. wpa_supplicant refuses any new operations that would
+ * use the radio until the interface has been enabled.
+ */
+ const int STATE_INTERFACE_DISABLED = 1;
+ /**
+ * STATE_INACTIVE - Inactive state (wpa_supplicant disabled)
+ *
+ * This state is entered if there are no enabled networks in the
+ * configuration. wpa_supplicant is not trying to associate with a new
+ * network and external interaction (e.g., ctrl_iface call to add or
+ * enable a network) is needed to start association.
+ */
+ const int STATE_INACTIVE = 2;
+ /**
+ * STATE_SCANNING - Scanning for a network
+ *
+ * This state is entered when wpa_supplicant starts scanning for a
+ * network.
+ */
+ const int STATE_SCANNING = 3;
+ /**
+ * STATE_AUTHENTICATING - Trying to authenticate with a BSS/SSID
+ *
+ * This state is entered when wpa_supplicant has found a suitable BSS
+ * to authenticate with and the driver is configured to try to
+ * authenticate with this BSS. This state is used only with drivers
+ * that use wpa_supplicant as the SME.
+ */
+ const int STATE_AUTHENTICATING = 4;
+ /**
+ * STATE_ASSOCIATING - Trying to associate with a BSS/SSID
+ *
+ * This state is entered when wpa_supplicant has found a suitable BSS
+ * to associate with and the driver is configured to try to associate
+ * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
+ * state is entered when the driver is configured to try to associate
+ * with a network using the configured SSID and security policy.
+ */
+ const int STATE_ASSOCIATING = 5;
+ /**
+ * STATE_ASSOCIATED - Association completed
+ *
+ * This state is entered when the driver reports that association has
+ * been successfully completed with an AP. If IEEE 802.1X is used
+ * (with or without WPA/WPA2), wpa_supplicant remains in this state
+ * until the IEEE 802.1X/EAPOL authentication has been completed.
+ */
+ const int STATE_ASSOCIATED = 6;
+ /**
+ * STATE_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
+ *
+ * This state is entered when WPA/WPA2 4-Way Handshake is started. In
+ * case of WPA-PSK, this happens when receiving the first EAPOL-Key
+ * frame after association. In case of WPA-EAP, this state is entered
+ * when the IEEE 802.1X/EAPOL authentication has been completed.
+ */
+ const int STATE_4WAY_HANDSHAKE = 7;
+ /**
+ * STATE_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
+ *
+ * This state is entered when 4-Way Key Handshake has been completed
+ * (i.e., when the supplicant sends out message 4/4) and when Group
+ * Key rekeying is started by the AP (i.e., when supplicant receives
+ * message 1/2).
+ */
+ const int STATE_GROUP_HANDSHAKE = 8;
+ /**
+ * STATE_COMPLETED - All authentication completed
+ *
+ * This state is entered when the full authentication process is
+ * completed. In case of WPA2, this happens when the 4-Way Handshake is
+ * successfully completed. With WPA, this state is entered after the
+ * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
+ * completed after dynamic keys are received (or if not used, after
+ * the EAP authentication has been completed). With static WEP keys and
+ * plaintext connections, this state is entered when an association
+ * has been completed.
+ *
+ * This state indicates that the supplicant has completed its
+ * processing for the association phase and that data connection is
+ * fully configured.
+ */
+ const int STATE_COMPLETED = 9;
+
/**
* Used to indicate that a new network has been added.
*
@@ -31,5 +131,26 @@
*
* @param id Network ID allocated to the corresponding network.
*/
- oneway void OnNetworkRemoved(int network_id);
+ oneway void OnNetworkRemoved(int id);
+
+ /**
+ * Used to indicate a state change event on this particular iface. This
+ * event may be triggered by a particular network in which case the
+ * |network_id|, |ssid|, |bssid| parameters will indicate the parameters
+ * of the network/AP which cased this state transition.
+ *
+ * @param new_state New State of the interface. This will be one of
+ * the |STATE_|* values above.
+ * @param bssid BSSID of the corresponding AP which caused this state
+ * change event. This will be empty if this event is not specific
+ * to a particular network.
+ * @param network_id ID of the corresponding network which caused this
+ * state change event. This will be |INVALID_NETWORK_ID| if this
+ * event is not specific to a particular network.
+ * @param ssid SSID of the corresponding network which caused this state
+ * change event. This will be empty if this event is not specific
+ * to a particular network.
+ */
+ oneway void OnStateChanged(
+ int new_state, in byte[] bssid, int network_id, in byte[] ssid);
}
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index b2b4225..61469dc 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -133,6 +133,8 @@
wpa_ssid_txt(wpa_s->current_ssid->ssid,
wpa_s->current_ssid->ssid_len) : "");
#endif /* ANDROID */
+
+ wpas_binder_notify_state_changed(wpa_s);
}