binder: Add network request/response interface

1. Add a callback function in |INetworkCallback| to make
any control requests on the corresponding network to registered
callback clients.
2. Add a function in |INetwork| to send responses to the above
request from the clients.

These are used when there is a need to perform external
SIM authentication for example.

While there, fix a nit:
Network.SetSSID() is setting a regular byte array field and
not a key field.

BUG: 30815238
TEST: This will have to wait for wificond integration for testing.

Change-Id: I8bfb9c381159373697ae8d1a0d7b999fca19b3a9
Signed-off-by: Roshan Pius <rpius@google.com>
diff --git a/wpa_supplicant/binder/binder.cpp b/wpa_supplicant/binder/binder.cpp
index c93b9bc..6a45754 100644
--- a/wpa_supplicant/binder/binder.cpp
+++ b/wpa_supplicant/binder/binder.cpp
@@ -167,3 +167,23 @@
 
 	return binder_manager->notifyStateChange(wpa_s);
 }
+
+int wpas_binder_notify_network_request(
+    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+    enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+	if (!wpa_s || !wpa_s->global->binder || !ssid)
+		return 1;
+
+	wpa_printf(
+	    MSG_DEBUG, "Notifying network request to binder control: %d",
+	    ssid->id);
+
+	wpa_supplicant_binder::BinderManager *binder_manager =
+	    wpa_supplicant_binder::BinderManager::getInstance();
+	if (!binder_manager)
+		return 1;
+
+	return binder_manager->notifyNetworkRequest(
+	    wpa_s, ssid, rtype, default_txt);
+}
diff --git a/wpa_supplicant/binder/binder.h b/wpa_supplicant/binder/binder.h
index 7afc6ef..045a4fa 100644
--- a/wpa_supplicant/binder/binder.h
+++ b/wpa_supplicant/binder/binder.h
@@ -33,6 +33,9 @@
 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);
+int wpas_binder_notify_network_request(
+    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+    enum wpa_ctrl_req_type rtype, const char *default_txt);
 #else  /* CONFIG_CTRL_IFACE_BINDER */
 static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
 {
@@ -56,6 +59,12 @@
 {
 	return 0;
 }
+static inline int wpas_binder_notify_network_request(
+    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+    enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+	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 ef96f3a..5d16355 100644
--- a/wpa_supplicant/binder/binder_manager.cpp
+++ b/wpa_supplicant/binder/binder_manager.cpp
@@ -223,8 +223,6 @@
  *
  * @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)
 {
@@ -232,7 +230,6 @@
 		return 1;
 
 	const std::string ifname(wpa_s->ifname);
-
 	if (iface_object_map_.find(ifname) == iface_object_map_.end())
 		return 1;
 
@@ -257,6 +254,35 @@
 }
 
 /**
+ * Notify all listeners about a request on a particular network.
+ *
+ * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
+ * the network is present.
+ * @param ssid |wpa_ssid| struct corresponding to the network.
+ * @param type type of request.
+ * @param param addition params associated with the request.
+ */
+int BinderManager::notifyNetworkRequest(
+    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int type,
+    const char *param)
+{
+	if (!wpa_s || !ssid)
+		return 1;
+
+	const std::string network_key =
+	    getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
+	if (network_object_map_.find(network_key) == network_object_map_.end())
+		return 1;
+
+	callWithEachNetworkCallback(
+	    wpa_s->ifname, ssid->id,
+	    std::bind(
+		&fi::w1::wpa_supplicant::INetworkCallback::OnNetworkRequest,
+		std::placeholders::_1, type, param));
+	return 0;
+}
+
+/**
  * Retrieve the |IIface| binder object reference using the provided
  * ifname.
  *
diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h
index 5e81078..0cb4999 100644
--- a/wpa_supplicant/binder/binder_manager.h
+++ b/wpa_supplicant/binder/binder_manager.h
@@ -47,6 +47,9 @@
 	int unregisterNetwork(
 	    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
 	int notifyStateChange(struct wpa_supplicant *wpa_s);
+	int notifyNetworkRequest(
+	    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int type,
+	    const char *param);
 
 	// Methods called from binder objects.
 	int getIfaceBinderObjectByIfname(
@@ -243,5 +246,22 @@
 static_assert(
     WPA_COMPLETED == fi::w1::wpa_supplicant::IIfaceCallback::STATE_COMPLETED,
     "State value mismatch");
+
+static_assert(
+    WPA_CTRL_REQ_UNKNOWN ==
+	fi::w1::wpa_supplicant::INetwork::NETWORK_RSP_UNKNOWN,
+    "Network Rsp value mismatch");
+static_assert(
+    WPA_CTRL_REQ_EXT_CERT_CHECK ==
+	fi::w1::wpa_supplicant::INetwork::NETWORK_RSP_EXT_CERT_CHECK,
+    "Network Rsp value mismatch");
+static_assert(
+    WPA_CTRL_REQ_UNKNOWN ==
+	fi::w1::wpa_supplicant::INetworkCallback::NETWORK_REQ_UNKNOWN,
+    "Network Req value mismatch");
+static_assert(
+    WPA_CTRL_REQ_EXT_CERT_CHECK ==
+	fi::w1::wpa_supplicant::INetworkCallback::NETWORK_REQ_EXT_CERT_CHECK,
+    "Network Req value mismatch");
 }  // namespace wpa_supplicant_binder
 #endif  // WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/INetwork.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/INetwork.aidl
index 9bc84e2..154d0a5 100644
--- a/wpa_supplicant/binder/fi/w1/wpa_supplicant/INetwork.aidl
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/INetwork.aidl
@@ -92,6 +92,21 @@
 	const int EAP_PHASE2_METHOD_GTC = 4;
 
 	/**
+	 * Various response types to be sent for the network using
+	 * |SendNetworkResponse|.
+	 */
+	const int NETWORK_RSP_UNKNOWN = 0;
+	const int NETWORK_RSP_EAP_IDENTITY = 1;
+	const int NETWORK_RSP_EAP_PASSWORD = 2;
+	const int NETWORK_RSP_EAP_NEW_PASSWORD = 3;
+	const int NETWORK_RSP_EAP_PIN = 4;
+	const int NETWORK_RSP_EAP_OTP = 5;
+	const int NETWORK_RSP_EAP_PASSPHRASE = 6;
+	const int NETWORK_RSP_SIM = 7;
+	const int NETWORK_RSP_PSK_PASSPHRASE = 8;
+	const int NETWORK_RSP_EXT_CERT_CHECK = 9;
+
+	/**
 	 * Retrieves the ID allocated to this network by wpa_supplicant.
 	 *
 	 * This is not the |SSID| of the network, but an internal identifier for
@@ -353,4 +368,21 @@
 	 * Initiate connection to this network.
 	 */
 	void Select();
+
+	/**
+	 * Used to send a response to the request received on this particular network.
+	 * The type of response is one of the |NETWORK_RSP_| values above and depending on
+	 * the request type may include additional params.
+	 *
+	 * The request for the response must have been triggered via the corresponding
+	 * |INetworkCallback.OnNetworkRequest| call.
+	 *
+	 * @param type Type of response. This will be one of the |NETWORK_RSP_|*
+	 *        values above.
+	 * @param param Additional param associated with the response.
+	 *        For ex: NETWORK_RSP_SIM request type may contain either
+	 *        "GSM-FAIL" or "UMTS-FAIL" param to indicate the failure for
+	 *        external GSM or 3G authentication.
+	 */
+	void SendNetworkResponse(int type, String param);
 }
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/INetworkCallback.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/INetworkCallback.aidl
index 147f0a6..444210c 100644
--- a/wpa_supplicant/binder/fi/w1/wpa_supplicant/INetworkCallback.aidl
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/INetworkCallback.aidl
@@ -19,4 +19,32 @@
  */
 @utf8InCpp
 interface INetworkCallback {
+	/** Various request types received for the network from |OnNetworkRequest|.*/
+	const int NETWORK_REQ_UNKNOWN = 0;
+	const int NETWORK_REQ_EAP_IDENTITY = 1;
+	const int NETWORK_REQ_EAP_PASSWORD = 2;
+	const int NETWORK_REQ_EAP_NEW_PASSWORD = 3;
+	const int NETWORK_REQ_EAP_PIN = 4;
+	const int NETWORK_REQ_EAP_OTP = 5;
+	const int NETWORK_REQ_EAP_PASSPHRASE = 6;
+	const int NETWORK_REQ_SIM = 7;
+	const int NETWORK_REQ_PSK_PASSPHRASE = 8;
+	const int NETWORK_REQ_EXT_CERT_CHECK = 9;
+
+	/**
+	 * Used to indicate a request on this particular network. The type of
+	 * request is one of the |NETWORK_REQ_| values above and depending on
+	 * the request type may include additional params.
+	 *
+	 * The response for the request must be sent using the corresponding
+	 * |INetwork.SendNetworkResponse| call.
+	 *
+	 * @param type Type of request. This will be one of the |NETWORK_REQ_|*
+	 *        values above.
+	 * @param param Additional param associated with the request.
+	 *        For ex: NETWORK_REQ_SIM request type may contain either
+	 *        "GSM-AUTH" or "UMTS-AUTH" param to indicate the need for
+	 *        external GSM or 3G authentication.
+	 */
+	oneway void OnNetworkRequest(int type, String param);
 }
diff --git a/wpa_supplicant/binder/network.cpp b/wpa_supplicant/binder/network.cpp
index 8bd745b..e4dcbd4 100644
--- a/wpa_supplicant/binder/network.cpp
+++ b/wpa_supplicant/binder/network.cpp
@@ -108,8 +108,7 @@
 		    android::binder::Status::EX_ILLEGAL_ARGUMENT,
 		    error_msg.c_str());
 	}
-
-	android::binder::Status status = setByteArrayKeyFieldAndResetState(
+	android::binder::Status status = setByteArrayFieldAndResetState(
 	    ssid.data(), ssid.size(), &(wpa_ssid->ssid), &(wpa_ssid->ssid_len),
 	    "ssid");
 	if (status.isOk() && wpa_ssid->passphrase) {
@@ -725,6 +724,38 @@
 	return android::binder::Status::ok();
 }
 
+android::binder::Status Network::SendNetworkResponse(
+    int type, const std::string &param)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	RETURN_IF_NETWORK_INVALID(wpa_ssid);
+
+	if (type < NETWORK_RSP_UNKNOWN || type > NETWORK_RSP_EXT_CERT_CHECK) {
+		const std::string error_msg =
+		    "Invalid network response type: " + std::to_string(type) +
+		    ".";
+		return android::binder::Status::fromExceptionCode(
+		    android::binder::Status::EX_ILLEGAL_ARGUMENT,
+		    error_msg.c_str());
+	}
+
+	enum wpa_ctrl_req_type rtype = (enum wpa_ctrl_req_type)type;
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	if (wpa_supplicant_ctrl_rsp_handle(
+		wpa_s, wpa_ssid, rtype, param.c_str())) {
+		const std::string error_msg =
+		    "Failed handling network response: " +
+		    std::to_string(type) + ".";
+		return android::binder::Status::fromServiceSpecificError(
+		    ERROR_GENERIC, error_msg.c_str());
+	}
+	eapol_sm_notify_ctrl_response(wpa_s->eapol);
+	wpa_hexdump_ascii(
+	    MSG_DEBUG, "network response param", (const u8 *)param.c_str(),
+	    param.size());
+	return android::binder::Status::ok();
+}
+
 /**
  * Retrieve the underlying |wpa_ssid| struct pointer for
  * this network.
diff --git a/wpa_supplicant/binder/network.h b/wpa_supplicant/binder/network.h
index 6302aa7..34418ec 100644
--- a/wpa_supplicant/binder/network.h
+++ b/wpa_supplicant/binder/network.h
@@ -105,6 +105,8 @@
 	android::binder::Status Enable(bool no_connect) override;
 	android::binder::Status Disable() override;
 	android::binder::Status Select() override;
+	android::binder::Status SendNetworkResponse(
+	    int type, const std::string &param) override;
 
 private:
 	struct wpa_ssid *retrieveNetworkPtr();
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 61469dc..393d7d6 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -221,6 +221,8 @@
 		return;
 
 	wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt);
+
+	wpas_binder_notify_network_request(wpa_s, ssid, rtype, default_txt);
 }