Browse Source

qcacld-3.0: Add SAP twt teardown support to componentization

Add SAP twt teardown support to componentization.
i.e to terminate the TWT session.

Change-Id: Idc12c564f3fb078aee4ff11831008d06876047e6
CRs-Fixed: 3085562
Srinivas Girigowda 3 years ago
parent
commit
297fb98ed9
2 changed files with 424 additions and 9 deletions
  1. 364 8
      components/umac/twt/core/src/wlan_twt_main.c
  2. 60 1
      os_if/twt/src/osif_twt_ext_req.c

+ 364 - 8
components/umac/twt/core/src/wlan_twt_main.c

@@ -236,6 +236,48 @@ wlan_twt_set_wait_for_notify(struct wlan_objmgr_psoc *psoc, uint32_t vdev_id,
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * wlan_twt_util_cmd_in_progress() - for a given peer_priv, check if the
+ * given command is in progress
+ * @peer_priv: peer priv object
+ * @dialog_id: Dialog id
+ * @cmd: command
+ *
+ * Return: true if command is in progress, false otherwise
+ */
+static bool
+wlan_twt_util_cmd_in_progress(struct twt_peer_priv_obj *peer_priv,
+			      uint8_t dialog_id,
+			      enum wlan_twt_commands cmd)
+{
+	bool cmd_in_progress = false;
+	uint8_t i;
+	uint8_t num_sessions = peer_priv->num_twt_sessions;
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+	for (i = 0; i < num_sessions; i++) {
+		enum wlan_twt_commands active_cmd;
+		uint8_t existing_dialog_id;
+
+		active_cmd = peer_priv->session_info[i].active_cmd;
+		existing_dialog_id = peer_priv->session_info[i].dialog_id;
+
+		if (existing_dialog_id == dialog_id ||
+		    dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+			cmd_in_progress = (active_cmd == cmd);
+
+			if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID ||
+			    cmd_in_progress) {
+				qdf_mutex_release(&peer_priv->twt_peer_lock);
+				return cmd_in_progress;
+			}
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	return cmd_in_progress;
+}
+
 /**
  * wlan_twt_any_peer_cmd_in_progress() - Iterate through the list of peers
  * and check if the given command is in progress
@@ -255,7 +297,61 @@ wlan_twt_any_peer_cmd_in_progress(struct wlan_objmgr_psoc *psoc,
 				  uint8_t dialog_id,
 				  enum wlan_twt_commands cmd)
 {
-	return false;
+	qdf_list_t *peer_list;
+	struct wlan_objmgr_peer *peer, *peer_next;
+	struct wlan_objmgr_vdev *vdev;
+	struct twt_peer_priv_obj *peer_priv;
+	bool cmd_in_progress = false;
+
+	if (!psoc) {
+		twt_err("psoc is NULL, dialog_id: %d", dialog_id);
+		return false;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_TWT_ID);
+	if (!vdev) {
+		twt_err("vdev is NULL, vdev_id: %d dialog_id: %d",
+				vdev_id, dialog_id);
+		return false;
+	}
+
+	peer_list = &vdev->vdev_objmgr.wlan_peer_list;
+	if (!peer_list) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
+		twt_err("Peer list for vdev obj is NULL");
+		return false;
+	}
+
+	peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list,
+						    WLAN_TWT_ID);
+	while (peer) {
+		peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_TWT);
+		if (peer_priv) {
+			cmd_in_progress =
+				wlan_twt_util_cmd_in_progress(peer_priv,
+							      dialog_id, cmd);
+
+			if (cmd_in_progress) {
+				wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+				wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
+				return cmd_in_progress;
+			}
+		}
+
+		peer_next =
+			wlan_peer_get_next_active_peer_of_vdev(vdev,
+							       peer_list,
+							       peer,
+							       WLAN_TWT_ID);
+
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		peer = peer_next;
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
+	return cmd_in_progress;
 }
 
 /**
@@ -274,7 +370,51 @@ wlan_twt_sap_peer_is_cmd_in_progress(struct wlan_objmgr_psoc *psoc,
 				     uint8_t dialog_id,
 				     enum wlan_twt_commands cmd)
 {
-	return false;
+	struct wlan_objmgr_peer *peer;
+	struct twt_peer_priv_obj *peer_priv;
+	uint8_t i;
+	bool cmd_in_progress = false;
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes,
+					   WLAN_TWT_ID);
+	if (!peer) {
+		twt_err("Peer object not found");
+		return false;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_TWT);
+	if (!peer_priv) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		twt_err("twt peer component object is NULL");
+		return false;
+	}
+
+	qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
+		enum wlan_twt_commands active_cmd;
+		uint8_t existing_dialog_id;
+
+		active_cmd =
+			peer_priv->session_info[i].active_cmd;
+		existing_dialog_id =
+			peer_priv->session_info[i].dialog_id;
+
+		if (existing_dialog_id == dialog_id ||
+		    dialog_id == TWT_ALL_SESSIONS_DIALOG_ID ||
+		    existing_dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+			cmd_in_progress = (active_cmd == cmd);
+
+			if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID ||
+			    cmd_in_progress) {
+				break;
+			}
+		}
+	}
+	qdf_mutex_release(&peer_priv->twt_peer_lock);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+	return cmd_in_progress;
 }
 
 /**
@@ -368,6 +508,70 @@ wlan_twt_sap_set_all_peers_cmd_in_progress(struct wlan_objmgr_psoc *psoc,
 					   uint8_t dialog_id,
 					   enum wlan_twt_commands cmd)
 {
+	qdf_list_t *peer_list;
+	struct wlan_objmgr_peer *peer, *peer_next;
+	struct wlan_objmgr_vdev *vdev;
+	struct twt_peer_priv_obj *peer_priv;
+
+	if (!psoc) {
+		twt_err("psoc is NULL, dialog_id: %d", dialog_id);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_TWT_ID);
+	if (!vdev) {
+		twt_err("vdev is NULL, vdev_id: %d dialog_id: %d",
+			vdev_id, dialog_id);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	peer_list = &vdev->vdev_objmgr.wlan_peer_list;
+	if (!peer_list) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
+		twt_err("Peer list for vdev obj is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list,
+						    WLAN_TWT_ID);
+	while (peer) {
+		peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_TWT);
+		if (peer_priv) {
+			uint8_t i;
+			uint8_t num_sessions = peer_priv->num_twt_sessions;
+
+			qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+			for (i = 0; i < num_sessions; i++) {
+				uint8_t eid =
+					peer_priv->session_info[i].dialog_id;
+
+				if (eid == dialog_id ||
+				    dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+					peer_priv->session_info[i].active_cmd =
+									    cmd;
+
+					if (dialog_id !=
+					    TWT_ALL_SESSIONS_DIALOG_ID) {
+						break;
+					}
+				}
+			}
+			qdf_mutex_release(&peer_priv->twt_peer_lock);
+		}
+
+		peer_next =
+			wlan_peer_get_next_active_peer_of_vdev(vdev,
+							       peer_list,
+							       peer,
+							       WLAN_TWT_ID);
+
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		peer = peer_next;
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -431,6 +635,69 @@ wlan_twt_init_all_peers_context(struct wlan_objmgr_psoc *psoc,
 				uint8_t vdev_id,
 				uint8_t dialog_id)
 {
+	qdf_list_t *peer_list;
+	struct wlan_objmgr_peer *peer, *peer_next;
+	struct wlan_objmgr_vdev *vdev;
+	struct twt_peer_priv_obj *peer_priv;
+
+	if (!psoc) {
+		twt_err("psoc is NULL, dialog_id: %d", dialog_id);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_TWT_ID);
+	if (!vdev) {
+		twt_err("vdev is NULL, vdev_id: %d dialog_id: %d",
+			vdev_id, dialog_id);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	peer_list = &vdev->vdev_objmgr.wlan_peer_list;
+	if (!peer_list) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
+		twt_err("Peer list for vdev obj is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list,
+						    WLAN_TWT_ID);
+	while (peer) {
+		peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_TWT);
+		if (peer_priv) {
+			uint8_t i = 0;
+			uint8_t num_sessions = WLAN_MAX_TWT_SESSIONS_PER_PEER;
+
+			peer_priv->num_twt_sessions = num_sessions;
+			qdf_mutex_acquire(&peer_priv->twt_peer_lock);
+			for (i = 0; i < num_sessions; i++) {
+				uint8_t eid =
+					   peer_priv->session_info[i].dialog_id;
+
+				if (eid == dialog_id ||
+				    dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
+					peer_priv->session_info[i].setup_done =
+						false;
+					peer_priv->session_info[i].dialog_id =
+						TWT_ALL_SESSIONS_DIALOG_ID;
+				}
+			}
+			qdf_mutex_release(&peer_priv->twt_peer_lock);
+		}
+
+		peer_next =
+			wlan_peer_get_next_active_peer_of_vdev(vdev,
+							       peer_list,
+							       peer,
+							       WLAN_TWT_ID);
+
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		peer = peer_next;
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
+	twt_debug("init done");
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -466,7 +733,12 @@ wlan_twt_sap_init_context(struct wlan_objmgr_psoc *psoc,
 			  struct qdf_mac_addr *peer_mac,
 			  uint8_t dialog_id)
 {
-	return QDF_STATUS_SUCCESS;
+	if (qdf_is_macaddr_broadcast(peer_mac)) {
+		return wlan_twt_init_all_peers_context(psoc, vdev_id,
+						       dialog_id);
+	} else {
+		return wlan_twt_init_context(psoc, peer_mac, dialog_id);
+	}
 }
 
 /**
@@ -484,7 +756,43 @@ static bool
 wlan_is_vdev_connected_to_peer(struct wlan_objmgr_psoc *psoc, uint32_t vdev_id,
 			       struct qdf_mac_addr *peer_macaddr)
 {
-	return false;
+	uint8_t pdev_id;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_peer *peer;
+	bool connection_exists = false;
+
+	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id,
+						WLAN_TWT_ID);
+	if (pdev_id == WLAN_INVALID_PDEV_ID) {
+		twt_err("Invalid pdev id");
+		return connection_exists;
+	}
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID);
+	if (!pdev) {
+		twt_err("Invalid pdev");
+		return connection_exists;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id,
+						    WLAN_TWT_ID);
+	if (!vdev) {
+		twt_err("vdev object is NULL");
+		goto end;
+	}
+
+	peer = wlan_objmgr_vdev_find_peer_by_mac(vdev, peer_macaddr->bytes,
+						 WLAN_TWT_ID);
+	if (peer) {
+		wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
+		connection_exists = true;
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
+end:
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID);
+	return connection_exists;
 }
 
 /**
@@ -524,8 +832,7 @@ bool wlan_twt_is_setup_done(struct wlan_objmgr_psoc *psoc,
 	for (i = 0; i < peer_priv->num_twt_sessions; i++) {
 		if (peer_priv->session_info[i].dialog_id == dialog_id ||
 		    dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) {
-			is_setup_done =
-				peer_priv->session_info[i].setup_done;
+			is_setup_done = peer_priv->session_info[i].setup_done;
 
 			if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID ||
 			    is_setup_done)
@@ -578,7 +885,7 @@ bool wlan_twt_is_max_sessions_reached(struct wlan_objmgr_psoc *psoc,
 	wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID);
 
 	twt_debug("num_twt_sessions:%d max_twt_sessions:%d",
-			  num_twt_sessions, max_twt_sessions);
+		  num_twt_sessions, max_twt_sessions);
 	return num_twt_sessions == max_twt_sessions;
 }
 
@@ -931,7 +1238,56 @@ static QDF_STATUS
 wlan_twt_sap_teardown_req(struct wlan_objmgr_psoc *psoc,
 			  struct twt_del_dialog_param *req)
 {
-	return QDF_STATUS_SUCCESS;
+	bool is_twt_cmd_in_progress;
+	QDF_STATUS status;
+	bool connection_exists;
+
+	if (!qdf_is_macaddr_broadcast(&req->peer_macaddr)) {
+		connection_exists = wlan_is_vdev_connected_to_peer(psoc,
+							   req->vdev_id,
+							   &req->peer_macaddr);
+		if (!connection_exists) {
+			twt_warn("SAP doesn't have connection with this peer("QDF_MAC_ADDR_FMT")",
+				QDF_MAC_ADDR_REF(req->peer_macaddr.bytes));
+			/*
+			 * Return success, since STA is not associated and
+			 * there is no TWT session.
+			 */
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+
+	is_twt_cmd_in_progress =
+		wlan_twt_sap_is_command_in_progress(
+				psoc, req->vdev_id, &req->peer_macaddr,
+				req->dialog_id, WLAN_TWT_TERMINATE);
+	if (is_twt_cmd_in_progress) {
+		twt_debug("Already TWT teardown command is in progress");
+		return QDF_STATUS_E_PENDING;
+	}
+
+	/*
+	 * Add the dialog id to TWT context to drop back to back
+	 * commands
+	 */
+	wlan_twt_sap_add_session(psoc, req->vdev_id, &req->peer_macaddr,
+				 req->dialog_id);
+
+	wlan_twt_sap_set_command_in_progress(psoc, req->vdev_id,
+					     &req->peer_macaddr, req->dialog_id,
+					     WLAN_TWT_TERMINATE);
+
+	status = tgt_twt_teardown_req_send(psoc, req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		twt_err("tgt_twt_teardown_req_send failed (status=%d)", status);
+		wlan_twt_sap_set_command_in_progress(psoc, req->vdev_id,
+					&req->peer_macaddr, req->dialog_id,
+					WLAN_TWT_NONE);
+		wlan_twt_sap_init_context(psoc, req->vdev_id,
+					  &req->peer_macaddr, req->dialog_id);
+	}
+
+	return status;
 }
 
 QDF_STATUS

+ 60 - 1
os_if/twt/src/osif_twt_ext_req.c

@@ -756,7 +756,66 @@ end:
 int osif_twt_sap_teardown_req(struct wlan_objmgr_vdev *vdev,
 			      struct nlattr *twt_param_attr)
 {
-	return 0;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
+	struct wlan_objmgr_psoc *psoc;
+	int id, id1, ret = 0;
+	uint8_t vdev_id;
+	struct twt_del_dialog_param params = {0};
+	QDF_STATUS status;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		osif_err("NULL psoc");
+		return -EINVAL;
+	}
+
+	vdev_id = wlan_vdev_get_id(vdev);
+	params.vdev_id = vdev_id;
+
+	ret = wlan_cfg80211_nla_parse_nested(tb,
+					 QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
+					 twt_param_attr,
+					 qca_wlan_vendor_twt_add_dialog_policy);
+	if (ret)
+		return ret;
+
+	id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
+	id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
+	if (tb[id] && tb[id1]) {
+		params.dialog_id = nla_get_u8(tb[id]);
+		nla_memcpy(params.peer_macaddr.bytes, tb[id1],
+			   QDF_MAC_ADDR_SIZE);
+	} else if (!tb[id] && !tb[id1]) {
+		struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT;
+
+		params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
+		qdf_copy_macaddr(&params.peer_macaddr, &bcast_addr);
+	} else {
+		osif_err_rl("get_params dialog_id or mac_addr is missing");
+		return -EINVAL;
+	}
+
+	if (!params.dialog_id)
+		params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID;
+
+	if (params.dialog_id != TWT_ALL_SESSIONS_DIALOG_ID &&
+	    qdf_is_macaddr_broadcast(&params.peer_macaddr)) {
+		osif_err("Bcast MAC valid with dlg_id:%d but here dlg_id is:%d",
+			TWT_ALL_SESSIONS_DIALOG_ID, params.dialog_id);
+		return -EINVAL;
+	}
+
+	osif_debug("vdev_id %d dialog_id %d peer mac_addr "
+		  QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id,
+		  QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
+
+	status = ucfg_twt_teardown_req(psoc, &params, NULL);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		osif_err("Failed to send del dialog command");
+		ret = qdf_status_to_os_return(status);
+	}
+
+	return ret;
 }
 
 int osif_twt_sta_teardown_req(struct wlan_objmgr_vdev *vdev,