diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index b7fe0af..9511f73 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -809,7 +809,8 @@ void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
 	} else if (vif->sme_state == SME_CONNECTED) {
 		/* inform roam event to cfg80211 */
 		cfg80211_roamed_bss(vif->ndev, bss, assoc_req_ie, assoc_req_len,
-				    assoc_resp_ie, assoc_resp_len, GFP_KERNEL);
+				    assoc_resp_ie, assoc_resp_len, GFP_KERNEL,
+				    NULL, NULL, NULL, 0);
 	}
 }
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 748eaa6..5934b77 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5450,7 +5450,8 @@ done:
 	kfree(buf);
 	cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
 			conn_info->req_ie, conn_info->req_ie_len,
-			conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
+			conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL,
+			NULL, NULL, NULL, 0);
 	brcmf_dbg(CONN, "Report roaming result\n");
 
 	set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 603c904..ad9535f 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2838,7 +2838,8 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
 			cfg80211_roamed(usbdev->net,
 					get_current_channel(usbdev, NULL),
 					bssid, req_ie, req_ie_len,
-					resp_ie, resp_ie_len, GFP_KERNEL);
+					resp_ie, resp_ie_len, GFP_KERNEL,
+					NULL, NULL, NULL, 0);
 	} else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
 		cfg80211_ibss_joined(usbdev->net, bssid,
 				     get_current_channel(usbdev, NULL),
diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
index d0ba377..e74216a 100644
--- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
@@ -341,7 +341,7 @@ void rtw_cfg80211_indicate_connect(struct rtw_adapter *padapter)
 				sizeof(struct ieee80211_hdr_3addr) + 6,
 				pmlmepriv->assoc_rsp_len -
 				sizeof(struct ieee80211_hdr_3addr) - 6,
-				GFP_ATOMIC);
+				GFP_ATOMIC, NULL, NULL, NULL, 0);
 	} else {
 		cfg80211_connect_result(padapter->pnetdev,
 					cur_network->network.MacAddress,
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index f46dfe6..178d955 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -722,7 +722,7 @@ void prism2_disconnected(wlandevice_t *wlandev)
 void prism2_roamed(wlandevice_t *wlandev)
 {
 	cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid,
-		NULL, 0, NULL, 0, GFP_KERNEL);
+		NULL, 0, NULL, 0, GFP_KERNEL, NULL, NULL, NULL, 0);
 }
 
 /* Structures for declaring wiphy interface */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index a80516f..8cf3535 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2312,6 +2312,9 @@ enum ieee80211_sa_query_action {
 #define WLAN_CIPHER_SUITE_BIP_CMAC_256	0x000FAC0D
 
 #define WLAN_CIPHER_SUITE_SMS4		0x00147201
+#define WLAN_CIPHER_SUITE_PMK           0x00147202
+#define WLAN_CIPHER_SUITE_PMK_R0        0x00147203
+#define WLAN_CIPHER_SUITE_PMK_R0_NAME   0x00147204
 
 /* AKM suite selectors */
 #define WLAN_AKM_SUITE_8021X		0x000FAC01
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ed37304..817df07 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4865,7 +4865,9 @@ void cfg80211_roamed(struct net_device *dev,
 		     struct ieee80211_channel *channel,
 		     const u8 *bssid,
 		     const u8 *req_ie, size_t req_ie_len,
-		     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+		     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp,
+		     const u8 *key_replay_ctr, const u8 *ptk_kck,
+		     const u8 *ptk_kek, const u8 authorized);
 
 /**
  * cfg80211_roamed_bss - notify cfg80211 of roaming
@@ -4891,7 +4893,9 @@ void cfg80211_roamed(struct net_device *dev,
  */
 void cfg80211_roamed_bss(struct net_device *dev, struct cfg80211_bss *bss,
 			 const u8 *req_ie, size_t req_ie_len,
-			 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+			 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp,
+			 const u8 *key_replay_ctr, const u8 *ptk_kck,
+			 const u8 *ptk_kek, const u8 authorized);
 
 /**
  * cfg80211_disconnected - notify cfg80211 that connection was dropped
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index ec10d1b..c56df53 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1873,6 +1873,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_MESH_PEER_AID: Association ID for the mesh peer (u16). This is
  *	used to pull the stored data for mesh peer in power save state.
  *
+ * @NL80211_ATTR_AUTHORIZED: flag attribute, if set indicates that the
+ *      connection is authorized.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2267,6 +2270,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_MESH_PEER_AID,
 
+	NL80211_ATTR_AUTHORIZED,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -3687,6 +3692,9 @@ enum nl80211_key_attributes {
 	NL80211_KEY_DEFAULT_MGMT,
 	NL80211_KEY_TYPE,
 	NL80211_KEY_DEFAULT_TYPES,
+	NL80211_KEY_REPLAY_CTR,
+	NL80211_KEY_KCK,
+	NL80211_KEY_KEK,
 
 	/* keep last */
 	__NL80211_KEY_AFTER_LAST,
@@ -4563,6 +4571,8 @@ enum nl80211_feature_flags {
  *	configuration (AP/mesh) with HT rates.
  * @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate
  *	configuration (AP/mesh) with VHT rates.
+ * @NL80211_EXT_FEATURE_KEY_MGMT_OFFLOAD: This driver supports key management
+ *	auth offload.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4577,6 +4587,7 @@ enum nl80211_ext_feature_index {
 	NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
 	NL80211_EXT_FEATURE_BEACON_RATE_HT,
 	NL80211_EXT_FEATURE_BEACON_RATE_VHT,
+	NL80211_EXT_FEATURE_KEY_MGMT_OFFLOAD,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 5555e3c..bd9914b2 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -231,8 +231,12 @@ struct cfg80211_event {
 		struct {
 			const u8 *req_ie;
 			const u8 *resp_ie;
+			const u8 *key_replay_ctr;
+			const u8 *key_kck;
+			const u8 *key_kek;
 			size_t req_ie_len;
 			size_t resp_ie_len;
+			u8 authorized;
 			struct cfg80211_bss *bss;
 		} rm;
 		struct {
@@ -396,7 +400,9 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 void __cfg80211_roamed(struct wireless_dev *wdev,
 		       struct cfg80211_bss *bss,
 		       const u8 *req_ie, size_t req_ie_len,
-		       const u8 *resp_ie, size_t resp_ie_len);
+		       const u8 *resp_ie, size_t resp_ie_len,
+		       const u8 authorized, const u8 *key_replay_ctr,
+		       const u8 *key_kck, const u8 *key_kek);
 int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
 			      struct wireless_dev *wdev);
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
old mode 100644
new mode 100755
index b8441e6..06754f9
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -928,7 +928,9 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
 	case NL80211_IFTYPE_ADHOC:
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_P2P_CLIENT:
-		if (!wdev->current_bss)
+		if (!wdev->current_bss &&
+		    !wiphy_ext_feature_isset(wdev->wiphy,
+		    NL80211_EXT_FEATURE_KEY_MGMT_OFFLOAD))
 			return -ENOLINK;
 		break;
 	case NL80211_IFTYPE_UNSPECIFIED:
@@ -12481,7 +12483,9 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
 void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
 			 struct net_device *netdev, const u8 *bssid,
 			 const u8 *req_ie, size_t req_ie_len,
-			 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
+			 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp,
+			 const u8 authorized, const u8 *key_replay_ctr,
+			 const u8 *key_kck, const u8 *key_kek)
 {
 	struct sk_buff *msg;
 	void *hdr;
@@ -12505,6 +12509,17 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
 	     nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
 		goto nla_put_failure;
 
+	if (wiphy_ext_feature_isset(&rdev->wiphy,
+				    NL80211_EXT_FEATURE_KEY_MGMT_OFFLOAD) &&
+	    (nla_put_u8(msg, NL80211_ATTR_AUTHORIZED, authorized) ||
+	    (key_replay_ctr && nla_put(msg, NL80211_KEY_REPLAY_CTR,
+	     NL80211_REPLAY_CTR_LEN, key_replay_ctr)) ||
+	    (key_kck &&
+	     nla_put(msg, NL80211_KEY_KCK, NL80211_KCK_LEN, key_kck)) ||
+	    (key_kek &&
+	     nla_put(msg, NL80211_KEY_KEK, NL80211_KEK_LEN, key_kek))))
+		goto nla_put_failure;
+
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 7e3821d..5d2fe3a 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -62,7 +62,9 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
 void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
 			 struct net_device *netdev, const u8 *bssid,
 			 const u8 *req_ie, size_t req_ie_len,
-			 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
+			 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp,
+			 const u8 authorized, const u8 *key_replay_ctr,
+			 const u8 *key_kck, const u8 *key_kek);
 void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
 			       struct net_device *netdev, u16 reason,
 			       const u8 *ie, size_t ie_len, bool from_ap);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index c08a3b5..a6ddbb4 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -807,7 +807,9 @@ EXPORT_SYMBOL(cfg80211_connect_bss);
 void __cfg80211_roamed(struct wireless_dev *wdev,
 		       struct cfg80211_bss *bss,
 		       const u8 *req_ie, size_t req_ie_len,
-		       const u8 *resp_ie, size_t resp_ie_len)
+		       const u8 *resp_ie, size_t resp_ie_len,
+		       const u8 authorized, const u8 *key_replay_ctr,
+		       const u8 *key_kck, const u8 *key_kek)
 {
 #ifdef CONFIG_CFG80211_WEXT
 	union iwreq_data wrqu;
@@ -831,7 +833,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
 	nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
 			    wdev->netdev, bss->bssid,
 			    req_ie, req_ie_len, resp_ie, resp_ie_len,
-			    GFP_KERNEL);
+			    GFP_KERNEL, authorized, key_replay_ctr,
+			    key_kck, key_kek);
 
 #ifdef CONFIG_CFG80211_WEXT
 	if (req_ie) {
@@ -865,7 +868,9 @@ void cfg80211_roamed(struct net_device *dev,
 		     struct ieee80211_channel *channel,
 		     const u8 *bssid,
 		     const u8 *req_ie, size_t req_ie_len,
-		     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
+		     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp,
+		     const u8 *key_replay_ctr, const u8 *ptk_kck,
+		     const u8 *ptk_kek, const u8 authorized)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_bss *bss;
@@ -877,7 +882,8 @@ void cfg80211_roamed(struct net_device *dev,
 		return;
 
 	cfg80211_roamed_bss(dev, bss, req_ie, req_ie_len, resp_ie,
-			    resp_ie_len, gfp);
+			    resp_ie_len, gfp, key_replay_ctr, ptk_kck,
+			    ptk_kek, authorized);
 }
 EXPORT_SYMBOL(cfg80211_roamed);
 
@@ -885,7 +891,9 @@ EXPORT_SYMBOL(cfg80211_roamed);
 void cfg80211_roamed_bss(struct net_device *dev,
 			 struct cfg80211_bss *bss, const u8 *req_ie,
 			 size_t req_ie_len, const u8 *resp_ie,
-			 size_t resp_ie_len, gfp_t gfp)
+			 size_t resp_ie_len, gfp_t gfp,
+			 const u8 *key_replay_ctr, const u8 *ptk_kck,
+			 const u8 *ptk_kek, const u8 authorized)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
@@ -908,6 +916,14 @@ void cfg80211_roamed_bss(struct net_device *dev,
 	ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
 	ev->rm.resp_ie_len = resp_ie_len;
 	memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len);
+	ev->rm.key_replay_ctr = ((u8 *)ev) + sizeof(*ev) + resp_ie_len;
+	memcpy((void *)ev->rm.key_replay_ctr, key_replay_ctr,
+	       NL80211_REPLAY_CTR_LEN);
+	ev->rm.key_kck = ((u8 *)ev) + sizeof(*ev) + NL80211_REPLAY_CTR_LEN;
+	memcpy((void *)ev->rm.key_kck, ptk_kck, NL80211_KCK_LEN);
+	ev->rm.key_kek = ((u8 *)ev) + sizeof(*ev) + NL80211_KCK_LEN;
+	memcpy((void *)ev->rm.key_kek, ptk_kek, NL80211_KEK_LEN);
+	ev->rm.authorized = authorized;
 	ev->rm.bss = bss;
 
 	spin_lock_irqsave(&wdev->event_lock, flags);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 9e6e2aa..30c4628 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -960,7 +960,9 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
 		case EVENT_ROAMED:
 			__cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie,
 					  ev->rm.req_ie_len, ev->rm.resp_ie,
-					  ev->rm.resp_ie_len);
+					  ev->rm.resp_ie_len, ev->rm.authorized,
+					  ev->rm.key_replay_ctr, ev->rm.key_kck,
+					  ev->rm.key_kek);
 			break;
 		case EVENT_DISCONNECTED:
 			__cfg80211_disconnected(wdev->netdev,
