Browse Source

qcacmn: Add 80211W support to P2P component

Newly designed P2P component doesn't contain
80211W PMF related information which is one
of the mandatory requirement to make PMF work
for P2P.

Provide PMF support to P2P component by adding
necessary callbacks to protocol stack to get
11W related information.

Change-Id: I399f0d296f9461239ac9d720905b196e87983f29
CRs-Fixed: 2175898
Liangwei Dong 7 years ago
parent
commit
bc685e88f1

+ 4 - 0
umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h

@@ -25,6 +25,10 @@
 #include <qdf_types.h>
 #include <osdep.h>
 
+#define IEEE80211_CCMP_HEADERLEN    8
+#define IEEE80211_CCMP_MICLEN       8
+#define IEEE80211_FC1_WEP           0x40
+
 #define WLAN_SEQ_SEQ_SHIFT 4
 
 #define P2P_WFA_OUI {0x50, 0x6f, 0x9a}

+ 11 - 4
umac/cmn_services/mgmt_txrx/dispatcher/src/wlan_mgmt_txrx_tgt_api.c

@@ -869,17 +869,24 @@ QDF_STATUS tgt_mgmt_txrx_rx_frame_handler(
 	/* mpdu_data_ptr is pointer to action header */
 	mpdu_data_ptr = (uint8_t *)qdf_nbuf_data(buf) +
 			sizeof(struct ieee80211_frame);
+	if ((wh->i_fc[1] & IEEE80211_FC1_WEP) &&
+	    (mgmt_subtype == MGMT_SUBTYPE_ACTION) &&
+	    !qdf_is_macaddr_group((struct qdf_mac_addr *)wh->i_addr1) &&
+	    !qdf_is_macaddr_broadcast((struct qdf_mac_addr *)wh->i_addr1))
+		mpdu_data_ptr += IEEE80211_CCMP_HEADERLEN;
+
 	frm_type = mgmt_txrx_get_frm_type(mgmt_subtype, mpdu_data_ptr);
 	if (frm_type == MGMT_FRM_UNSPECIFIED) {
-		mgmt_txrx_err("Unspecified mgmt frame type");
+		mgmt_txrx_err("Unspecified mgmt frame type fc: %x %x",
+			      wh->i_fc[0], wh->i_fc[1]);
 		qdf_nbuf_free(buf);
 		status = QDF_STATUS_E_FAILURE;
 		goto dec_peer_ref_cnt;
 	}
 
-	mgmt_txrx_info("Rcvd mgmt frame, mgmt txrx frm type: %u"
-			"seq. no.: %u, peer: %pK",
-			frm_type, *(uint16_t *)wh->i_seq, peer);
+	mgmt_txrx_info("Rcvd mgmt frame, mgmt txrx frm type: %u seq. no.: %u, peer: %pK fc: %x %x",
+		       frm_type, *(uint16_t *)wh->i_seq, peer, wh->i_fc[0],
+		       wh->i_fc[1]);
 
 	mgmt_txrx_psoc_ctx = (struct mgmt_txrx_priv_psoc_context *)
 			wlan_objmgr_psoc_get_comp_private_obj(psoc,

+ 3 - 1
umac/p2p/core/src/wlan_p2p_main.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -166,6 +166,7 @@ enum p2p_connection_status {
  *                    data to HDD
  * @cancel_roc_done:  Cancel roc done event
  * @roc_runtime_lock: Runtime lock for roc request
+ * @p2p_cb: Callbacks to protocol stack
  * @connection_status:Global P2P connection status
  */
 struct p2p_soc_priv_obj {
@@ -177,6 +178,7 @@ struct p2p_soc_priv_obj {
 	struct p2p_start_param *start_param;
 	qdf_event_t cancel_roc_done;
 	qdf_runtime_lock_t roc_runtime_lock;
+	struct p2p_protocol_callbacks p2p_cb;
 #ifdef WLAN_FEATURE_P2P_DEBUG
 	enum p2p_connection_status connection_status;
 #endif

+ 125 - 21
umac/p2p/core/src/wlan_p2p_off_chan_tx.c

@@ -494,21 +494,6 @@ static QDF_STATUS p2p_populate_mac_header(
 	return QDF_STATUS_SUCCESS;
 }
 
-/**
- * p2p_set_protected_bit() - set protected bit
- * @tx_ctx:     tx context
- * @frame:      pointer to frame
- *
- * This function sets protected bit of this mgmt frame
- *
- * Return: QDF_STATUS_SUCCESS - in case of success
- */
-static QDF_STATUS p2p_set_protected_bit(
-	struct tx_action_context *tx_ctx, void *frame)
-{
-	return QDF_STATUS_E_INVAL;
-}
-
 /**
  * p2p_get_frame_type_str() - parse frame type to string
  * @frame_info: frame information
@@ -799,7 +784,7 @@ static QDF_STATUS p2p_rx_update_connection_status(
  * Return: QDF_STATUS_SUCCESS - in case of success
  */
 static QDF_STATUS p2p_packet_alloc(uint16_t size, void **data,
-	void **ppPacket)
+	qdf_nbuf_t *ppPacket)
 {
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	qdf_nbuf_t nbuf;
@@ -882,7 +867,7 @@ static QDF_STATUS p2p_send_tx_conf(struct tx_action_context *tx_ctx,
  * Return: QDF_STATUS_SUCCESS - in case of success
  */
 static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx,
-	uint32_t buf_len, void *packet, uint8_t *frame)
+	uint32_t buf_len, qdf_nbuf_t packet, uint8_t *frame)
 {
 	QDF_STATUS status;
 	mgmt_tx_download_comp_cb tx_comp_cb;
@@ -935,7 +920,7 @@ static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx,
 	tx_ctx->nbuf = packet;
 
 	status = wlan_mgmt_txrx_mgmt_frame_tx(peer, tx_ctx->p2p_soc_obj,
-			(qdf_nbuf_t)packet, tx_comp_cb, tx_ota_comp_cb,
+			packet, tx_comp_cb, tx_ota_comp_cb,
 			WLAN_UMAC_COMP_P2P, &mgmt_param);
 
 	wlan_objmgr_peer_release_ref(peer, WLAN_P2P_ID);
@@ -1352,6 +1337,120 @@ static QDF_STATUS p2p_disable_tx_timer(struct tx_action_context *tx_ctx)
 	return status;
 }
 
+/**
+ * is_rmf_mgmt_action_frame() - check RMF action frame by category
+ * @action_category: action frame actegory
+ *
+ * This function check the frame is robust mgmt action frame or not
+ *
+ * Return: true - if category is robust mgmt type
+ */
+static bool is_rmf_mgmt_action_frame(uint8_t action_category)
+{
+	switch (action_category) {
+	case ACTION_CATEGORY_SPECTRUM_MGMT:
+	case ACTION_CATEGORY_QOS:
+	case ACTION_CATEGORY_DLS:
+	case ACTION_CATEGORY_BACK:
+	case ACTION_CATEGORY_RRM:
+	case ACTION_FAST_BSS_TRNST:
+	case ACTION_CATEGORY_SA_QUERY:
+	case ACTION_CATEGORY_PROTECTED_DUAL_OF_PUBLIC_ACTION:
+	case ACTION_CATEGORY_WNM:
+	case ACTION_CATEGORY_MESH_ACTION:
+	case ACTION_CATEGORY_MULTIHOP_ACTION:
+	case ACTION_CATEGORY_DMG:
+	case ACTION_CATEGORY_FST:
+	case ACTION_CATEGORY_VENDOR_SPECIFIC_PROTECTED:
+		return true;
+	default:
+		break;
+	}
+	return false;
+}
+
+/**
+ * p2p_populate_rmf_field() - populate unicast rmf frame
+ * @tx_ctx: tx_action_context
+ * @size: input size of frame, and output new size
+ * @ppbuf: input frame ptr, and output new frame
+ * @ppkt: input pkt, output new pkt.
+ *
+ * This function allocates new pkt for rmf frame. The
+ * new frame has extra space for ccmp field.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_populate_rmf_field(struct tx_action_context *tx_ctx,
+	uint32_t *size, uint8_t **ppbuf, qdf_nbuf_t *ppkt)
+{
+	struct wlan_frame_hdr *wh, *rmf_wh;
+	struct action_frm_hdr *action_hdr;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	qdf_nbuf_t pkt = NULL;
+	uint8_t *frame;
+	uint32_t frame_len;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	p2p_soc_obj = tx_ctx->p2p_soc_obj;
+
+	if (tx_ctx->frame_info.sub_type != P2P_MGMT_ACTION ||
+	    !p2p_soc_obj->p2p_cb.is_mgmt_protected)
+		return QDF_STATUS_SUCCESS;
+	if (*size < (sizeof(struct wlan_frame_hdr) +
+	    sizeof(struct action_frm_hdr))) {
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wh = (struct wlan_frame_hdr *)(*ppbuf);
+	action_hdr = (struct action_frm_hdr *)(*ppbuf + sizeof(*wh));
+
+	if (!is_rmf_mgmt_action_frame(action_hdr->action_category)) {
+		p2p_debug("non rmf act frame 0x%x cat %x",
+			  tx_ctx->frame_info.sub_type,
+			  action_hdr->action_category);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if (!p2p_soc_obj->p2p_cb.is_mgmt_protected(
+		tx_ctx->vdev_id, wh->i_addr1)) {
+		p2p_debug("non rmf connection vdev %d "QDF_MAC_ADDR_STR,
+			  tx_ctx->vdev_id, QDF_MAC_ADDR_ARRAY(wh->i_addr1));
+		return QDF_STATUS_SUCCESS;
+	}
+	if (!qdf_is_macaddr_group((struct qdf_mac_addr *)wh->i_addr1) &&
+	    !qdf_is_macaddr_broadcast((struct qdf_mac_addr *)wh->i_addr1)) {
+
+		frame_len = *size + IEEE80211_CCMP_HEADERLEN +
+			    IEEE80211_CCMP_MICLEN;
+		status = p2p_packet_alloc((uint16_t)frame_len, (void **)&frame,
+			 &pkt);
+		if (status != QDF_STATUS_SUCCESS) {
+			p2p_err("Failed to allocate %d bytes for rmf frame.",
+				frame_len);
+			return QDF_STATUS_E_NOMEM;
+		}
+
+		qdf_mem_copy(frame, wh, sizeof(*wh));
+		qdf_mem_copy(frame + sizeof(*wh) + IEEE80211_CCMP_HEADERLEN,
+			     *ppbuf + sizeof(*wh),
+			     *size - sizeof(*wh));
+		rmf_wh = (struct wlan_frame_hdr *)frame;
+		(rmf_wh)->i_fc[1] |= IEEE80211_FC1_WEP;
+		p2p_debug("set protection 0x%x cat %d "QDF_MAC_ADDR_STR,
+			  tx_ctx->frame_info.sub_type,
+			  action_hdr->action_category,
+			  QDF_MAC_ADDR_ARRAY(wh->i_addr1));
+
+		qdf_nbuf_free(*ppkt);
+		*ppbuf = frame;
+		*ppkt = pkt;
+		*size = frame_len;
+	}
+
+	return status;
+}
+
 /**
  * p2p_execute_tx_action_frame() - execute tx action frame
  * @tx_ctx:        tx context
@@ -1364,7 +1463,7 @@ static QDF_STATUS p2p_execute_tx_action_frame(
 	struct tx_action_context *tx_ctx)
 {
 	uint8_t *frame;
-	void *packet;
+	qdf_nbuf_t packet;
 	QDF_STATUS status;
 	uint8_t noa_len = 0;
 	uint8_t noa_stream[P2P_NOA_STREAM_ARR_SIZE];
@@ -1411,7 +1510,7 @@ static QDF_STATUS p2p_execute_tx_action_frame(
 
 		/* Ok-- try to allocate some memory: */
 	status = p2p_packet_alloc((uint16_t) buf_len, (void **)&frame,
-			(void **)&packet);
+			&packet);
 	if (status != QDF_STATUS_SUCCESS) {
 		p2p_err("Failed to allocate %d bytes for a Probe Request.",
 			buf_len);
@@ -1439,7 +1538,12 @@ static QDF_STATUS p2p_execute_tx_action_frame(
 		qdf_mem_copy(frame, tx_ctx->buf, buf_len);
 	}
 
-	p2p_set_protected_bit(tx_ctx, frame);
+	status = p2p_populate_rmf_field(tx_ctx, &buf_len, &frame, &packet);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to populate rmf frame");
+		qdf_nbuf_free(packet);
+		return status;
+	}
 	status = p2p_mgmt_tx(tx_ctx, buf_len, packet, frame);
 	if (status == QDF_STATUS_SUCCESS) {
 		if (tx_ctx->no_ack) {

+ 2 - 2
umac/p2p/core/src/wlan_p2p_off_chan_tx.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -173,7 +173,7 @@ struct tx_action_context {
 	uint32_t duration;
 	qdf_mc_timer_t tx_timer;
 	struct p2p_frame_info frame_info;
-	void *nbuf;
+	qdf_nbuf_t nbuf;
 };
 
 /**

+ 9 - 1
umac/p2p/dispatcher/inc/wlan_p2p_public_struct.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -215,4 +215,12 @@ struct p2p_noa_info {
 	struct noa_descriptor noa_desc[P2P_MAX_NOA_DESC];
 };
 
+/**
+ * struct p2p_protocol_callbacks - callback to non-converged driver
+ * @is_mgmt_protected: func to get 11w mgmt protection status
+ */
+struct p2p_protocol_callbacks {
+	bool (*is_mgmt_protected)(uint32_t vdev_id, const uint8_t *peer_addr);
+};
+
 #endif /* _WLAN_P2P_PUBLIC_STRUCT_H_ */

+ 14 - 1
umac/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -297,6 +297,19 @@ void p2p_peer_authorized(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr);
 QDF_STATUS ucfg_p2p_set_noa(struct wlan_objmgr_psoc *soc,
 	uint32_t vdev_id, bool disable_noa);
 
+/**
+ * ucfg_p2p_register_callbacks() - register p2p callbacks
+ * @soc: soc context
+ * @cb_obj: p2p_protocol_callbacks struct
+ *
+ * This function registers lim callbacks to p2p components to provide
+ * protocol information.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_register_callbacks(struct wlan_objmgr_psoc *soc,
+	    struct p2p_protocol_callbacks *cb_obj);
+
 /**
  * ucfg_p2p_status_scan() - Show P2P connection status when scanning
  * @vdev: vdev context

+ 24 - 2
umac/p2p/dispatcher/src/wlan_p2p_ucfg_api.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -23,8 +23,8 @@
 #include <wmi_unified_api.h>
 #include <wlan_objmgr_psoc_obj.h>
 #include <scheduler_api.h>
-#include "wlan_p2p_ucfg_api.h"
 #include "wlan_p2p_public_struct.h"
+#include "wlan_p2p_ucfg_api.h"
 #include "../../core/src/wlan_p2p_main.h"
 #include "../../core/src/wlan_p2p_roc.h"
 #include "../../core/src/wlan_p2p_off_chan_tx.h"
@@ -423,6 +423,28 @@ QDF_STATUS  ucfg_p2p_set_noa(struct wlan_objmgr_psoc *soc,
 	return status;
 }
 
+QDF_STATUS ucfg_p2p_register_callbacks(struct wlan_objmgr_psoc *soc,
+	    struct p2p_protocol_callbacks *cb_obj)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	if (!soc || !cb_obj) {
+		p2p_err("psoc %pM cb_obj %pM context passed is NULL", soc,
+			cb_obj);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+		      WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc private object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	p2p_soc_obj->p2p_cb = *cb_obj;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS ucfg_p2p_status_scan(struct wlan_objmgr_vdev *vdev)
 {
 	if (!vdev) {