Kaynağa Gözat

qcacmn: Add os_if changes for tdls management

Add os interface changes to send tdls management
frames to tdls component

Change-Id: Ib675e4b089a88ad618f918d9992a777c7221b34c
CRs-Fixed: 2034220
Kabilan Kannan 8 yıl önce
ebeveyn
işleme
84ddd1f699
2 değiştirilmiş dosya ile 300 ekleme ve 0 silme
  1. 68 0
      inc/wlan_cfg80211_tdls.h
  2. 232 0
      src/wlan_cfg80211_tdls.c

+ 68 - 0
inc/wlan_cfg80211_tdls.h

@@ -33,6 +33,9 @@
 #include <qdf_types.h>
 #include <wlan_tdls_ucfg_api.h>
 
+
+#define TDLS_VDEV_MAGIC 0x54444c53       /* "TDLS" */
+
 /**
  * struct osif_tdls_vdev - OS tdls vdev private structure
  * @tdls_add_peer_comp: Completion to add tdls peer
@@ -52,6 +55,26 @@ struct osif_tdls_vdev {
 	uint32_t mgmt_tx_completion_status;
 };
 
+/**
+ * enum qca_wlan_vendor_tdls_trigger_mode_vdev_map: Maps the user space TDLS
+ *	trigger mode in the host driver.
+ * @WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: TDLS Connection and
+ *	disconnection handled by user space.
+ * @WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: TDLS connection and
+ *	disconnection controlled by host driver based on data traffic.
+ * @WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: TDLS connection and
+ *	disconnection jointly controlled by user space and host driver.
+ */
+enum qca_wlan_vendor_tdls_trigger_mode_vdev_map {
+	WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT =
+		QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT,
+	WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT =
+		QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT,
+	WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL =
+		((QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT |
+		  QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT) << 1),
+};
+
 /**
  * wlan_cfg80211_tdls_priv_init() - API to initialize tdls os private
  * @osif_priv: vdev os private
@@ -96,6 +119,17 @@ int wlan_cfg80211_tdls_update_peer(struct wlan_objmgr_pdev *pdev,
 				   struct net_device *dev,
 				   const uint8_t *mac,
 				   struct station_parameters *params);
+
+/**
+ * wlan_cfg80211_tdls_configure_mode() - configure tdls mode
+ * @vdev: vdev obj manager
+ * @trigger_mode: tdls trgger mode
+ *
+ * Return: 0 for success; negative errno otherwise
+ */
+int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev,
+						uint32_t trigger_mode);
+
 /**
  * wlan_cfg80211_tdls_oper() - process cfg80211 operation on an TDLS peer
  * @pdev: pdev object
@@ -110,6 +144,27 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_pdev *pdev,
 			    const uint8_t *peer,
 			    enum nl80211_tdls_operation oper);
 
+/**
+ * wlan_cfg80211_tdls_mgmt() - process tdls management frames from the supplicant
+ * @pdev: pdev object
+ * @dev: net device
+ * @peer: MAC address of the TDLS peer
+ * @action_code: type of TDLS mgmt frame to be sent
+ * @dialog_token: dialog token used in the frame
+ * @status_code: status to be incuded in the frame
+ * @peer_capability: peer capability information
+ * @buf: additional IEs to be included
+ * @len: lenght of additional Ies
+ * @oper: cfg80211 TDLS operation
+ *
+ * Return: 0 on success; negative errno otherwise
+ */
+int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_pdev *pdev,
+				struct net_device *dev, const uint8_t *peer,
+				uint8_t action_code, uint8_t dialog_token,
+				uint16_t status_code, uint32_t peer_capability,
+				const uint8_t *buf, size_t len);
+
 /**
  * wlan_cfg80211_tdls_event_callback() - callback for tdls module
  * @userdata: user data
@@ -123,4 +178,17 @@ int wlan_cfg80211_tdls_oper(struct wlan_objmgr_pdev *pdev,
 void wlan_cfg80211_tdls_event_callback(void *userdata,
 				       enum tdls_event_type type,
 				       struct tdls_osif_indication *param);
+
+/**
+ * wlan_cfg80211_tdls_rx_callback() - Callback for rx mgmt frame
+ * @user_data: pointer to soc object
+ * @rx_frame: RX mgmt frame information
+ *
+ * This callback will be used to rx frames in os interface.
+ *
+ * Return: None
+ */
+void wlan_cfg80211_tdls_rx_callback(void *user_data,
+	struct tdls_rx_mgmt_frame *rx_frame);
+
 #endif

+ 232 - 0
src/wlan_cfg80211_tdls.c

@@ -36,6 +36,9 @@
 
 #define MAX_CHANNEL (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS)
 
+
+#define TDLS_MAX_NO_OF_2_4_CHANNELS 14
+
 QDF_STATUS wlan_cfg80211_tdls_priv_init(struct vdev_osif_priv *osif_priv)
 {
 	struct osif_tdls_vdev *tdls_priv;
@@ -370,6 +373,41 @@ static enum tdls_command_type tdls_oper_to_cmd(enum nl80211_tdls_operation oper)
 		return 0;
 }
 
+int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev,
+						uint32_t trigger_mode)
+{
+	enum tdls_feature_mode tdls_mode;
+	struct tdls_set_mode_params set_mode_params;
+	int status;
+
+	if (!vdev)
+		return -EINVAL;
+
+	switch (trigger_mode) {
+	case WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT:
+		tdls_mode = TDLS_SUPPORT_IMP_MODE;
+		break;
+	case WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL:
+		tdls_mode = TDLS_SUPPORT_EXT_CONTROL;
+		break;
+	case WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT:
+		tdls_mode = TDLS_SUPPORT_IMP_MODE;
+		break;
+	default:
+		cfg80211_err("Invalid TDLS trigger mode");
+		return -EINVAL;
+	}
+
+	cfg80211_notice("cfg80211 tdls trigger mode %d", trigger_mode);
+	set_mode_params.source = TDLS_SET_MODE_SOURCE_USER;
+	set_mode_params.tdls_mode = tdls_mode;
+	set_mode_params.update_last = false;
+	set_mode_params.vdev = vdev;
+
+	status = ucfg_tdls_set_operating_mode(&set_mode_params);
+	return status;
+}
+
 int wlan_cfg80211_tdls_oper(struct wlan_objmgr_pdev *pdev,
 			    struct net_device *dev,
 			    const uint8_t *peer,
@@ -442,6 +480,196 @@ error:
 	return status;
 }
 
+void wlan_cfg80211_tdls_rx_callback(void *user_data,
+	struct tdls_rx_mgmt_frame *rx_frame)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_vdev *vdev;
+	struct vdev_osif_priv *osif_priv;
+	struct wireless_dev *wdev;
+	uint16_t freq;
+
+	cfg80211_debug("user data:%p, vdev id:%d, rssi:%d, buf:%p, len:%d",
+		user_data, rx_frame->vdev_id, rx_frame->rx_rssi,
+		rx_frame->buf, rx_frame->frame_len);
+
+	psoc = user_data;
+	if (!psoc) {
+		cfg80211_err("psoc is null");
+		return;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+		rx_frame->vdev_id, WLAN_TDLS_NB_ID);
+	if (!vdev) {
+		cfg80211_err("vdev is null");
+		return;
+	}
+
+	wlan_vdev_obj_lock(vdev);
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	wlan_vdev_obj_unlock(vdev);
+	if (!osif_priv) {
+		cfg80211_err("osif_priv is null");
+		goto fail;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		cfg80211_err("wdev is null");
+		goto fail;
+	}
+
+	if (rx_frame->rx_chan <= TDLS_MAX_NO_OF_2_4_CHANNELS)
+		freq = ieee80211_channel_to_frequency(
+			rx_frame->rx_chan, NL80211_BAND_2GHZ);
+	else
+		freq = ieee80211_channel_to_frequency(
+			rx_frame->rx_chan, NL80211_BAND_5GHZ);
+
+	cfg80211_notice("Indicate frame over nl80211, vdev id:%d, idx:%d",
+		   rx_frame->vdev_id, wdev->netdev->ifindex);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len,
+		NL80211_RXMGMT_FLAG_ANSWERED);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len,
+		NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC);
+#else
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len, GFP_ATOMIC);
+#endif /* LINUX_VERSION_CODE */
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+}
+
+int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_pdev *pdev,
+				struct net_device *dev, const uint8_t *peer_mac,
+				uint8_t action_code, uint8_t dialog_token,
+				uint16_t status_code, uint32_t peer_capability,
+				const uint8_t *buf, size_t len)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_action_frame_request mgmt_req;
+	struct vdev_osif_priv *osif_priv;
+	struct osif_tdls_vdev *tdls_priv;
+	int status;
+	unsigned long rc;
+	int max_sta_failed = 0;
+	struct tdls_validate_action_req chk_frame;
+	struct tdls_set_responder_req set_responder;
+
+	vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(pdev,
+							 dev->dev_addr,
+							 WLAN_OSIF_ID);
+	if (vdev == NULL) {
+		cfg80211_err("vdev object is NULL");
+		return -EIO;
+	}
+
+	wlan_vdev_obj_lock(vdev);
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	wlan_vdev_obj_unlock(vdev);
+
+	tdls_priv = osif_priv->osif_tdls;
+
+	/* make sure doesn't call send_mgmt() while it is pending */
+	if (TDLS_VDEV_MAGIC == tdls_priv->mgmt_tx_completion_status) {
+		cfg80211_err(QDF_MAC_ADDRESS_STR " action %d couldn't sent, as one is pending. return EBUSY",
+			     QDF_MAC_ADDR_ARRAY(peer_mac), action_code);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
+		return -EBUSY;
+	}
+
+	/* Reset TDLS VDEV magic */
+	tdls_priv->mgmt_tx_completion_status = TDLS_VDEV_MAGIC;
+
+
+	/*prepare the request */
+
+	/* Validate the management Request */
+	chk_frame.vdev = vdev;
+	chk_frame.action_code = action_code;
+	qdf_mem_copy(chk_frame.peer_mac, peer_mac, QDF_MAC_ADDR_SIZE);
+	chk_frame.dialog_token = dialog_token;
+	chk_frame.action_code = action_code;
+	chk_frame.status_code = status_code;
+	chk_frame.len = len;
+	chk_frame.max_sta_failed = max_sta_failed;
+
+	mgmt_req.chk_frame = &chk_frame;
+
+	mgmt_req.vdev = vdev;
+	mgmt_req.vdev_id = wlan_vdev_get_id(vdev);
+	mgmt_req.session_id = mgmt_req.vdev_id;
+	/* populate management req params */
+	qdf_mem_copy(mgmt_req.tdls_mgmt.peer_mac.bytes,
+		     peer_mac, QDF_MAC_ADDR_SIZE);
+	mgmt_req.tdls_mgmt.dialog = dialog_token;
+	mgmt_req.tdls_mgmt.frame_type = action_code;
+	mgmt_req.tdls_mgmt.len = len;
+	mgmt_req.tdls_mgmt.peer_capability = peer_capability;
+	mgmt_req.tdls_mgmt.status_code = chk_frame.status_code;
+
+	/*populate the additional IE's */
+	mgmt_req.cmd_buf = buf;
+	mgmt_req.len = len;
+
+	reinit_completion(&tdls_priv->tdls_mgmt_comp);
+	status = ucfg_tdls_send_mgmt_frame(&mgmt_req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cfg80211_err("ucfg_tdls_send_mgmt failed err %d", status);
+		status = -EIO;
+		tdls_priv->mgmt_tx_completion_status = false;
+		goto error_mgmt_req;
+	}
+
+	cfg80211_info("Wait for tdls_mgmt_comp. Timeout %u ms",
+		WAIT_TIME_FOR_TDLS_MGMT);
+
+	rc = wait_for_completion_timeout(
+		&tdls_priv->tdls_mgmt_comp,
+		msecs_to_jiffies(WAIT_TIME_FOR_TDLS_MGMT));
+
+	if ((0 == rc) || (true != tdls_priv->mgmt_tx_completion_status)) {
+		cfg80211_err("%s rc %ld mgmtTxCompletionStatus %u",
+			     !rc ? "Mgmt Tx Completion timed out" :
+			     "Mgmt Tx Completion failed",
+			     rc, tdls_priv->mgmt_tx_completion_status);
+
+		tdls_priv->mgmt_tx_completion_status = false;
+		status = -EINVAL;
+		goto error_mgmt_req;
+	}
+
+	cfg80211_info("Mgmt Tx Completion status %ld TxCompletion %u",
+		rc, tdls_priv->mgmt_tx_completion_status);
+
+	if (chk_frame.max_sta_failed) {
+		status = max_sta_failed;
+		goto error_mgmt_req;
+	}
+
+	if (TDLS_SETUP_RESPONSE == action_code ||
+	    TDLS_SETUP_CONFIRM == action_code) {
+		qdf_mem_copy(set_responder.peer_mac, peer_mac,
+			     QDF_MAC_ADDR_SIZE);
+		set_responder.vdev = vdev;
+		if (TDLS_SETUP_RESPONSE == action_code)
+			set_responder.responder = false;
+		if (TDLS_SETUP_CONFIRM == action_code)
+			set_responder.responder = true;
+		ucfg_tdls_responder(&set_responder);
+	}
+
+error_mgmt_req:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID);
+	return status;
+}
+
 static void
 wlan_cfg80211_tdls_indicate_discovery(struct tdls_osif_indication *ind)
 {
@@ -504,6 +732,10 @@ void wlan_cfg80211_tdls_event_callback(void *user_data,
 	wlan_vdev_obj_unlock(ind->vdev);
 
 	switch (type) {
+	case TDLS_EVENT_MGMT_TX_ACK_CNF:
+		tdls_priv->mgmt_tx_completion_status = ind->status;
+		complete(&tdls_priv->tdls_mgmt_comp);
+		break;
 	case TDLS_EVENT_ADD_PEER:
 		tdls_priv->tdls_add_peer_status = ind->status;
 		complete(&tdls_priv->tdls_add_peer_comp);