Merge changes from topic "wifi-p2p-api-create-group"

* changes:
  p2p: implementation for addGroup_1_2
  p2p: support using pre-defined passphrase for adding a new P2P group
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index b4660c4..585b4a0 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1797,7 +1797,12 @@
 	}
 	p2p->ssid_set = 0;
 
-	p2p_random(params->passphrase, p2p->cfg->passphrase_len);
+	if (p2p->passphrase_set) {
+		os_memcpy(params->passphrase, p2p->passphrase, os_strlen(p2p->passphrase));
+	} else {
+		p2p_random(params->passphrase, p2p->cfg->passphrase_len);
+	}
+	p2p->passphrase_set = 0;
 	return 0;
 }
 
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 6a4d751..a73d99e 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -11,6 +11,7 @@
 
 #include "utils/list.h"
 #include "p2p.h"
+#include "ap/ap_config.h"
 
 #define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1
 
@@ -358,6 +359,16 @@
 	int ssid_set;
 
 	/**
+	 * passphrase - WPA2-Personal passphrase for GO Negotiation (if local end will be GO)
+	 */
+	char passphrase[MAX_PASSPHRASE_LEN + 1];
+
+	/**
+	 * passphrase_set - Whether passphrase is already set for GO Negotiation
+	 */
+	int passphrase_set;
+
+	/**
 	 * Regulatory class for own operational channel
 	 */
 	u8 op_reg_class;
diff --git a/wpa_supplicant/hidl/1.2/hidl_manager.h b/wpa_supplicant/hidl/1.2/hidl_manager.h
index 67c2b3b..47b6e7d 100644
--- a/wpa_supplicant/hidl/1.2/hidl_manager.h
+++ b/wpa_supplicant/hidl/1.2/hidl_manager.h
@@ -40,6 +40,7 @@
 namespace V1_2 {
 namespace implementation {
 using namespace android::hardware::wifi::supplicant::V1_2;
+using V1_0::ISupplicantP2pIface;
 using V1_0::ISupplicantStaIfaceCallback;
 using V1_1::ISupplicant;
 using V1_1::ISupplicantStaIface;
diff --git a/wpa_supplicant/hidl/1.2/p2p_iface.cpp b/wpa_supplicant/hidl/1.2/p2p_iface.cpp
index a408b38..80c0205 100644
--- a/wpa_supplicant/hidl/1.2/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/1.2/p2p_iface.cpp
@@ -13,6 +13,7 @@
 #include "iface_config_utils.h"
 #include "misc_utils.h"
 #include "p2p_iface.h"
+#include "sta_network.h"
 
 extern "C"
 {
@@ -30,6 +31,7 @@
 constexpr char kWfdDeviceInfoSubelemLenHexStr[] = "0006";
 
 using android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
+using android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
 uint8_t convertHidlMiracastModeToInternal(
     ISupplicantP2pIface::MiracastMode mode)
 {
@@ -43,6 +45,43 @@
 	};
 	WPA_ASSERT(false);
 }
+
+/**
+ * Check if the provided ssid is valid or not.
+ *
+ * Returns 1 if valid, 0 otherwise.
+ */
+int isSsidValid(const std::vector<uint8_t>& ssid)
+{
+	if (ssid.size() == 0 ||
+	    ssid.size() >
+		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+					  SSID_MAX_LEN_IN_BYTES)) {
+		return 0;
+	}
+	return 1;
+}
+
+/**
+ * Check if the provided psk passhrase is valid or not.
+ *
+ * Returns 1 if valid, 0 otherwise.
+ */
+int isPskPassphraseValid(const std::string &psk)
+{
+	if (psk.size() <
+		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+					  PSK_PASSPHRASE_MIN_LEN_IN_BYTES) ||
+	    psk.size() >
+		static_cast<uint32_t>(ISupplicantStaNetwork::ParamSizeLimits::
+					  PSK_PASSPHRASE_MAX_LEN_IN_BYTES)) {
+		return 0;
+	}
+	if (has_ctrl_char((u8 *)psk.c_str(), psk.size())) {
+		return 0;
+	}
+	return 1;
+}
 }  // namespace
 
 namespace android {
@@ -505,6 +544,17 @@
 	    &P2pIface::saveConfigInternal, _hidl_cb);
 }
 
+Return<void> P2pIface::addGroup_1_2(
+    const hidl_vec<uint8_t>& ssid, const hidl_string& passphrase,
+    bool persistent, uint32_t freq, const hidl_array<uint8_t, 6>& peer_address,
+    bool join, addGroup_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &P2pIface::addGroup_1_2Internal, _hidl_cb,
+	    ssid, passphrase, persistent, freq, peer_address, join);
+}
+
 std::pair<SupplicantStatus, std::string> P2pIface::getNameInternal()
 {
 	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
@@ -1257,6 +1307,77 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+SupplicantStatus P2pIface::addGroup_1_2Internal(
+    const std::vector<uint8_t>& ssid, const std::string& passphrase,
+    bool persistent, uint32_t freq, const std::array<uint8_t, 6>& peer_address,
+    bool joinExistingGroup)
+{
+	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	int vht = wpa_s->conf->p2p_go_vht;
+	int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+
+	if (!isSsidValid(ssid)) {
+		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, "SSID is invalid."};
+	}
+
+	if (!isPskPassphraseValid(passphrase)) {
+		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, "passphrase is invalid."};
+	}
+
+	if (joinExistingGroup) {
+		struct wpa_bss *bss = findBssBySsid(
+		    wpa_s, peer_address.data(),
+		    ssid.data(), ssid.size());
+		if (bss == NULL) {
+			return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN,
+			    "No matched BSS found."};
+		}
+
+		// Construct a network for adding group.
+		// Group client follows the persistent attribute of Group Owner.
+		// If joined group is persistent, it adds a persistent network on GroupStarted.
+		struct wpa_ssid *wpa_network = addGroupClientNetwork(
+		    wpa_s, bss->bssid, ssid, passphrase);
+		if (wpa_network == NULL) {
+			return {SupplicantStatusCode::FAILURE_UNKNOWN,
+			    "Cannot construct P2P network."};
+		}
+
+		// this is temporary network only for establishing the connection.
+		wpa_network->temporary = 1;
+
+		if (wpas_p2p_group_add_persistent(
+			wpa_s, wpa_network, 0, 0, 0, 0, ht40, vht,
+			VHT_CHANWIDTH_USE_HT, NULL, 0, 1)) {
+			wpa_config_remove_network(wpa_s->conf, wpa_network->id);
+			return {SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN, ""};
+		}
+
+		// Always remove this temporary network at the end.
+		wpa_config_remove_network(wpa_s->conf, wpa_network->id);
+	} else {
+		if (wpa_s->global->p2p == NULL) {
+			return {SupplicantStatusCode::FAILURE_IFACE_DISABLED, ""};
+		}
+
+		struct p2p_data *p2p = wpa_s->global->p2p;
+		os_memcpy(p2p->ssid, ssid.data(), ssid.size());
+		p2p->ssid_len = ssid.size();
+		p2p->ssid_set = 1;
+
+		os_memset(p2p->passphrase, 0, sizeof(p2p->passphrase));
+		os_memcpy(p2p->passphrase, passphrase.c_str(), passphrase.length());
+		p2p->passphrase_set = 1;
+
+		if (wpas_p2p_group_add(
+			wpa_s, persistent, freq, 0, ht40, vht,
+			VHT_CHANWIDTH_USE_HT)) {
+			return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+		}
+	}
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
 /**
  * Retrieve the underlying |wpa_supplicant| struct
  * pointer for this iface.
@@ -1277,6 +1398,77 @@
 	return wpa_supplicant_get_iface(wpa_global_, group_ifname.c_str());
 }
 
+struct wpa_ssid* P2pIface::addGroupClientNetwork(
+    struct wpa_supplicant* wpa_s,
+    uint8_t *group_owner_bssid,
+    const std::vector<uint8_t>& ssid,
+    const std::string& passphrase)
+{
+	struct wpa_ssid* wpa_network = wpa_config_add_network(wpa_s->conf);
+	if (!wpa_network) {
+		return NULL;
+	}
+	// set general network defaults
+	wpa_config_set_network_defaults(wpa_network);
+
+	// set P2p network defaults
+	wpa_network->p2p_group = 1;
+	wpa_network->mode = wpa_ssid::wpas_mode::WPAS_MODE_INFRA;
+
+	wpa_network->auth_alg = WPA_AUTH_ALG_OPEN;
+	wpa_network->key_mgmt = WPA_KEY_MGMT_PSK;
+	wpa_network->proto = WPA_PROTO_RSN;
+	wpa_network->pairwise_cipher = WPA_CIPHER_CCMP;
+	wpa_network->group_cipher = WPA_CIPHER_CCMP;
+	wpa_network->disabled = 2;
+
+	// set necessary fields
+	os_memcpy(wpa_network->bssid, group_owner_bssid, ETH_ALEN);
+	wpa_network->bssid_set = 1;
+
+	wpa_network->ssid = (uint8_t *)os_malloc(ssid.size());
+	if (wpa_network->ssid == NULL) {
+		wpa_config_remove_network(wpa_s->conf, wpa_network->id);
+		return  NULL;
+	}
+	memcpy(wpa_network->ssid, ssid.data(), ssid.size());
+	wpa_network->ssid_len = ssid.size();
+
+	wpa_network->psk_set = 0;
+	wpa_network->passphrase = dup_binstr(passphrase.c_str(), passphrase.length());
+	if (wpa_network->passphrase == NULL) {
+		wpa_config_remove_network(wpa_s->conf, wpa_network->id);
+		return  NULL;
+	}
+	wpa_config_update_psk(wpa_network);
+
+	return wpa_network;
+
+}
+
+/**
+ * findBssBySsid - Fetch a BSS table entry based on SSID and optional BSSID.
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID, zero addr matches any bssid
+ * @ssid: SSID
+ * @ssid_len: Length of @ssid
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss* P2pIface::findBssBySsid(
+    struct wpa_supplicant *wpa_s, const u8 *bssid,
+    const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_bss *bss;
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if ((is_zero_ether_addr(bssid) ||
+		    os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) &&
+		    bss->ssid_len == ssid_len &&
+		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
+			return bss;
+	}
+	return NULL;
+}
+
 }  // namespace implementation
 }  // namespace V1_2
 }  // namespace supplicant
diff --git a/wpa_supplicant/hidl/1.2/p2p_iface.h b/wpa_supplicant/hidl/1.2/p2p_iface.h
index 6842363..a3ccdde 100644
--- a/wpa_supplicant/hidl/1.2/p2p_iface.h
+++ b/wpa_supplicant/hidl/1.2/p2p_iface.h
@@ -15,7 +15,7 @@
 
 #include <android-base/macros.h>
 
-#include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIface.h>
+#include <android/hardware/wifi/supplicant/1.2/ISupplicantP2pIface.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pIfaceCallback.h>
 #include <android/hardware/wifi/supplicant/1.0/ISupplicantP2pNetwork.h>
 
@@ -44,7 +44,7 @@
  * object is used for control operations on a specific interface
  * controlled by wpa_supplicant.
  */
-class P2pIface : public ISupplicantP2pIface
+class P2pIface : public V1_2::ISupplicantP2pIface
 {
 public:
 	P2pIface(struct wpa_global* wpa_global, const char ifname[]);
@@ -187,6 +187,10 @@
 	    const hidl_vec<uint8_t>& select,
 	    reportNfcHandoverInitiation_cb _hidl_cb) override;
 	Return<void> saveConfig(saveConfig_cb _hidl_cb) override;
+	Return<void> addGroup_1_2(
+	    const hidl_vec<uint8_t>& ssid, const hidl_string& passphrase,
+	    bool persistent, uint32_t freq, const hidl_array<uint8_t, 6>& peer_address,
+	    bool joinExistingGroup, addGroup_1_2_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
@@ -291,10 +295,22 @@
 	SupplicantStatus reportNfcHandoverInitiationInternal(
 	    const std::vector<uint8_t>& select);
 	SupplicantStatus saveConfigInternal();
+	SupplicantStatus addGroup_1_2Internal(
+	    const std::vector<uint8_t>& ssid, const std::string& passphrase,
+	    bool persistent, uint32_t freq, const std::array<uint8_t, 6>& peer_address,
+	    bool joinExistingGroup);
 
 	struct wpa_supplicant* retrieveIfacePtr();
 	struct wpa_supplicant* retrieveGroupIfacePtr(
 	    const std::string& group_ifname);
+	struct wpa_ssid* addGroupClientNetwork(
+	    struct wpa_supplicant* wpa_s,
+	    uint8_t *group_owner_bssid,
+	    const std::vector<uint8_t>& ssid,
+	    const std::string& passphrase);
+	struct wpa_bss* findBssBySsid(
+	    struct wpa_supplicant *wpa_s, const u8 *bssid,
+	    const u8 *ssid, size_t ssid_len);
 
 	// Reference to the global wpa_struct. This is assumed to be valid for
 	// the lifetime of the process.