qcacld-3.0: Set unforce mode for link
TDLS for MLO, it forces link active when sending TDLS discovery Request, it needs to unforce the link when: There is no discovery response on that link; or The remain links except the link which is TDLS link; or The link for TDLS but no more TDLS connection. CRs-Fixed: 3623332 Change-Id: Ie9fb0d210952531744bba397c1a34f4d8f1f14fb
This commit is contained in:

committed by
Rahul Choudhary

parent
721acdbab2
commit
59d68775f9
@@ -1661,6 +1661,48 @@ QDF_STATUS tdls_process_add_peer_rsp(struct tdls_add_sta_rsp *rsp)
|
|||||||
return QDF_STATUS_E_INVAL;
|
return QDF_STATUS_E_INVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tdls_process_unforce_link_mode(struct wlan_objmgr_vdev *vdev)
|
||||||
|
{
|
||||||
|
struct tdls_vdev_priv_obj *tdls_vdev;
|
||||||
|
struct tdls_peer *peer;
|
||||||
|
qdf_list_t *head;
|
||||||
|
qdf_list_node_t *p_node;
|
||||||
|
QDF_STATUS status;
|
||||||
|
bool unforce = true;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
|
||||||
|
if (!tdls_vdev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
|
||||||
|
head = &tdls_vdev->peer_list[i];
|
||||||
|
status = qdf_list_peek_front(head, &p_node);
|
||||||
|
while (QDF_IS_STATUS_SUCCESS(status)) {
|
||||||
|
peer = qdf_container_of(p_node, struct tdls_peer, node);
|
||||||
|
|
||||||
|
tdls_debug("Peer: " QDF_MAC_ADDR_FMT "link status %d, vdev id %d",
|
||||||
|
QDF_MAC_ADDR_REF(peer->peer_mac.bytes),
|
||||||
|
peer->link_status, wlan_vdev_get_id(vdev));
|
||||||
|
|
||||||
|
if (peer->link_status == TDLS_LINK_CONNECTED ||
|
||||||
|
peer->link_status == TDLS_LINK_CONNECTING) {
|
||||||
|
unforce = false;
|
||||||
|
goto unforce_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = qdf_list_peek_next(head, p_node, &p_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unforce_exit:
|
||||||
|
if (unforce) {
|
||||||
|
tdls_debug("try to set vdev %d to unforce",
|
||||||
|
wlan_vdev_get_id(vdev));
|
||||||
|
tdls_set_link_unforce(vdev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp)
|
QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp)
|
||||||
{
|
{
|
||||||
uint8_t sta_idx, id;
|
uint8_t sta_idx, id;
|
||||||
@@ -1734,6 +1776,8 @@ QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp)
|
|||||||
TDLS_LINK_DROPPED_BY_REMOTE);
|
TDLS_LINK_DROPPED_BY_REMOTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tdls_process_unforce_link_mode(vdev);
|
||||||
|
|
||||||
cmddone:
|
cmddone:
|
||||||
tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_DEL_PEER);
|
tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_DEL_PEER);
|
||||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
||||||
|
@@ -97,6 +97,7 @@ void tdls_discovery_timeout_peer_cb(void *user_data)
|
|||||||
struct wlan_objmgr_vdev *tdls_link_vdev;
|
struct wlan_objmgr_vdev *tdls_link_vdev;
|
||||||
struct tdls_rx_mgmt_frame *rx_mgmt;
|
struct tdls_rx_mgmt_frame *rx_mgmt;
|
||||||
uint8_t *mac;
|
uint8_t *mac;
|
||||||
|
bool unforce = true;
|
||||||
|
|
||||||
if (!user_data) {
|
if (!user_data) {
|
||||||
tdls_err("discovery time out data is null");
|
tdls_err("discovery time out data is null");
|
||||||
@@ -163,6 +164,15 @@ void tdls_discovery_timeout_peer_cb(void *user_data)
|
|||||||
while (QDF_IS_STATUS_SUCCESS(status)) {
|
while (QDF_IS_STATUS_SUCCESS(status)) {
|
||||||
peer = qdf_container_of(p_node, struct tdls_peer,
|
peer = qdf_container_of(p_node, struct tdls_peer,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
|
tdls_debug("Peer: " QDF_MAC_ADDR_FMT "link status %d, vdev id %d",
|
||||||
|
QDF_MAC_ADDR_REF(peer->peer_mac.bytes),
|
||||||
|
peer->link_status, wlan_vdev_get_id(vdev));
|
||||||
|
|
||||||
|
if (peer->link_status != TDLS_LINK_DISCOVERING &&
|
||||||
|
peer->link_status != TDLS_LINK_IDLE)
|
||||||
|
unforce = false;
|
||||||
|
|
||||||
if (TDLS_LINK_DISCOVERING != peer->link_status) {
|
if (TDLS_LINK_DISCOVERING != peer->link_status) {
|
||||||
status = qdf_list_peek_next(head, p_node,
|
status = qdf_list_peek_next(head, p_node,
|
||||||
&p_node);
|
&p_node);
|
||||||
@@ -176,6 +186,12 @@ void tdls_discovery_timeout_peer_cb(void *user_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wlan_vdev_mlme_is_mlo_vdev(vdev) && unforce) {
|
||||||
|
tdls_debug("try to set vdev %d to unforce",
|
||||||
|
wlan_vdev_get_id(vdev));
|
||||||
|
tdls_set_link_unforce(vdev);
|
||||||
|
}
|
||||||
|
|
||||||
tdls_vdev->discovery_sent_cnt = 0;
|
tdls_vdev->discovery_sent_cnt = 0;
|
||||||
/* add tdls power save prohibited */
|
/* add tdls power save prohibited */
|
||||||
|
|
||||||
@@ -1458,6 +1474,14 @@ void tdls_disable_offchan_and_teardown_links(
|
|||||||
QDF_STATUS status;
|
QDF_STATUS status;
|
||||||
uint8_t vdev_id;
|
uint8_t vdev_id;
|
||||||
bool tdls_in_progress = false;
|
bool tdls_in_progress = false;
|
||||||
|
bool is_mlo_vdev;
|
||||||
|
|
||||||
|
is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev);
|
||||||
|
if (is_mlo_vdev) {
|
||||||
|
tdls_debug("try to set vdev %d to unforce",
|
||||||
|
wlan_vdev_get_id(vdev));
|
||||||
|
tdls_set_link_unforce(vdev);
|
||||||
|
}
|
||||||
|
|
||||||
status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc);
|
status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc);
|
||||||
if (QDF_STATUS_SUCCESS != status) {
|
if (QDF_STATUS_SUCCESS != status) {
|
||||||
|
@@ -80,6 +80,7 @@ static char *tdls_get_cmd_type_str(enum tdls_command_type cmd_type)
|
|||||||
CASE_RETURN_STRING(TDLS_CMD_SET_SECOFFCHANOFFSET);
|
CASE_RETURN_STRING(TDLS_CMD_SET_SECOFFCHANOFFSET);
|
||||||
CASE_RETURN_STRING(TDLS_DELETE_ALL_PEERS_INDICATION);
|
CASE_RETURN_STRING(TDLS_DELETE_ALL_PEERS_INDICATION);
|
||||||
CASE_RETURN_STRING(TDLS_CMD_START_BSS);
|
CASE_RETURN_STRING(TDLS_CMD_START_BSS);
|
||||||
|
CASE_RETURN_STRING(TDLS_CMD_SET_LINK_UNFORCE);
|
||||||
default:
|
default:
|
||||||
return "Invalid TDLS command";
|
return "Invalid TDLS command";
|
||||||
}
|
}
|
||||||
@@ -582,6 +583,17 @@ QDF_STATUS tdls_handle_start_bss(struct wlan_objmgr_psoc *psoc)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void tdls_handle_link_unforce(struct wlan_objmgr_vdev *vdev)
|
||||||
|
{
|
||||||
|
struct tdls_action_frame_request req = {0};
|
||||||
|
|
||||||
|
req.vdev = vdev;
|
||||||
|
req.tdls_mgmt.frame_type = TDLS_MAX_ACTION_CODE;
|
||||||
|
|
||||||
|
tdls_debug("set vdev %d unforce", wlan_vdev_get_id(vdev));
|
||||||
|
tdls_set_link_mode(&req);
|
||||||
|
}
|
||||||
|
|
||||||
QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg)
|
QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg)
|
||||||
{
|
{
|
||||||
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
@@ -668,6 +680,9 @@ QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg)
|
|||||||
case TDLS_CMD_START_BSS:
|
case TDLS_CMD_START_BSS:
|
||||||
tdls_handle_start_bss(msg->bodyptr);
|
tdls_handle_start_bss(msg->bodyptr);
|
||||||
break;
|
break;
|
||||||
|
case TDLS_CMD_SET_LINK_UNFORCE:
|
||||||
|
tdls_handle_link_unforce(msg->bodyptr);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2039,6 +2054,21 @@ void tdls_scan_complete_event_handler(struct wlan_objmgr_vdev *vdev,
|
|||||||
tdls_post_scan_done_msg(tdls_soc);
|
tdls_post_scan_done_msg(tdls_soc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tdls_set_link_unforce(struct wlan_objmgr_vdev *vdev)
|
||||||
|
{
|
||||||
|
QDF_STATUS status;
|
||||||
|
struct scheduler_msg msg = {0};
|
||||||
|
|
||||||
|
msg.callback = tdls_process_cmd;
|
||||||
|
msg.type = TDLS_CMD_SET_LINK_UNFORCE;
|
||||||
|
msg.bodyptr = vdev;
|
||||||
|
status = scheduler_post_message(QDF_MODULE_ID_TDLS,
|
||||||
|
QDF_MODULE_ID_TDLS,
|
||||||
|
QDF_MODULE_ID_OS_IF, &msg);
|
||||||
|
if (QDF_IS_STATUS_ERROR(status))
|
||||||
|
tdls_err("failed to set tdls link mode");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tdls_check_peer_buf_capable() - Check buffer sta capable of tdls peers
|
* tdls_check_peer_buf_capable() - Check buffer sta capable of tdls peers
|
||||||
* @tdls_vdev: TDLS vdev object
|
* @tdls_vdev: TDLS vdev object
|
||||||
|
@@ -811,6 +811,14 @@ void tdls_scan_complete_event_handler(struct wlan_objmgr_vdev *vdev,
|
|||||||
struct scan_event *event,
|
struct scan_event *event,
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tdls_set_link_unforce() - set link unforce
|
||||||
|
* @vdev: vdev object
|
||||||
|
*
|
||||||
|
* Return: void
|
||||||
|
*/
|
||||||
|
void tdls_set_link_unforce(struct wlan_objmgr_vdev *vdev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tdls_scan_callback() - callback for TDLS scan operation
|
* tdls_scan_callback() - callback for TDLS scan operation
|
||||||
* @tdls_soc: tdls soc pvt object
|
* @tdls_soc: tdls soc pvt object
|
||||||
|
@@ -87,6 +87,26 @@ tdls_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev)
|
|||||||
return wlan_mlo_get_tdls_link_vdev(vdev);
|
return wlan_mlo_get_tdls_link_vdev(vdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tdls_set_remain_links_unforce(struct wlan_objmgr_vdev *vdev)
|
||||||
|
{
|
||||||
|
struct wlan_mlo_dev_context *mlo_dev_ctx;
|
||||||
|
struct wlan_objmgr_vdev *mlo_vdev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* TDLS link is selected, unforce link for other vdevs */
|
||||||
|
mlo_dev_ctx = vdev->mlo_dev_ctx;
|
||||||
|
for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
|
||||||
|
mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i];
|
||||||
|
if (!mlo_vdev || mlo_vdev == vdev)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tdls_debug("try to set vdev %d to unforce",
|
||||||
|
wlan_vdev_get_id(mlo_vdev));
|
||||||
|
tdls_set_link_unforce(mlo_vdev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QDF_STATUS
|
QDF_STATUS
|
||||||
tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev)
|
tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev)
|
||||||
{
|
{
|
||||||
@@ -425,6 +445,11 @@ tdls_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tdls_set_remain_links_unforce(struct wlan_objmgr_vdev *vdev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QDF_STATUS
|
QDF_STATUS
|
||||||
tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev)
|
tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev)
|
||||||
{
|
{
|
||||||
@@ -852,7 +877,7 @@ tdls_send_mgmt_serialize_callback(struct wlan_serialization_command *cmd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WLAN_FEATURE_11BE_MLO
|
#ifdef WLAN_FEATURE_11BE_MLO
|
||||||
static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req)
|
QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req)
|
||||||
{
|
{
|
||||||
uint8_t mlo_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS] = {-1};
|
uint8_t mlo_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS] = {-1};
|
||||||
struct wlan_objmgr_psoc *psoc;
|
struct wlan_objmgr_psoc *psoc;
|
||||||
@@ -865,10 +890,6 @@ static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req)
|
|||||||
if (!is_mlo_vdev)
|
if (!is_mlo_vdev)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
mlo_tdls_vdev = wlan_mlo_get_tdls_link_vdev(req->vdev);
|
|
||||||
if (mlo_tdls_vdev)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
psoc = wlan_vdev_get_psoc(req->vdev);
|
psoc = wlan_vdev_get_psoc(req->vdev);
|
||||||
if (!psoc) {
|
if (!psoc) {
|
||||||
tdls_err("psoc is NULL");
|
tdls_err("psoc is NULL");
|
||||||
@@ -877,6 +898,10 @@ static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req)
|
|||||||
|
|
||||||
if (req->tdls_mgmt.frame_type == TDLS_DISCOVERY_RESPONSE ||
|
if (req->tdls_mgmt.frame_type == TDLS_DISCOVERY_RESPONSE ||
|
||||||
req->tdls_mgmt.frame_type == TDLS_DISCOVERY_REQUEST) {
|
req->tdls_mgmt.frame_type == TDLS_DISCOVERY_REQUEST) {
|
||||||
|
mlo_tdls_vdev = wlan_mlo_get_tdls_link_vdev(req->vdev);
|
||||||
|
if (mlo_tdls_vdev)
|
||||||
|
return status;
|
||||||
|
|
||||||
mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev);
|
mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev);
|
||||||
vdev_count = 1;
|
vdev_count = 1;
|
||||||
|
|
||||||
@@ -886,12 +911,20 @@ static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req)
|
|||||||
vdev_count, mlo_vdev_lst);
|
vdev_count, mlo_vdev_lst);
|
||||||
if (status == QDF_STATUS_SUCCESS)
|
if (status == QDF_STATUS_SUCCESS)
|
||||||
req->link_active = true;
|
req->link_active = true;
|
||||||
|
} else if (req->tdls_mgmt.frame_type == TDLS_MAX_ACTION_CODE) {
|
||||||
|
mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev);
|
||||||
|
vdev_count = 1;
|
||||||
|
status =
|
||||||
|
policy_mgr_mlo_sta_set_link(psoc,
|
||||||
|
MLO_LINK_FORCE_REASON_TDLS,
|
||||||
|
MLO_LINK_FORCE_MODE_NO_FORCE,
|
||||||
|
vdev_count, mlo_vdev_lst);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req)
|
QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req)
|
||||||
{
|
{
|
||||||
return QDF_STATUS_SUCCESS;
|
return QDF_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@@ -99,6 +99,14 @@ tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev);
|
|||||||
struct wlan_objmgr_vdev *
|
struct wlan_objmgr_vdev *
|
||||||
tdls_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev);
|
tdls_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tdls_set_remain_links_unforce() - unforce links
|
||||||
|
* @vdev: vdev object
|
||||||
|
*
|
||||||
|
* Return: void
|
||||||
|
*/
|
||||||
|
void tdls_set_remain_links_unforce(struct wlan_objmgr_vdev *vdev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tdls_mgmt_rx_ops() - register or unregister rx callback
|
* tdls_mgmt_rx_ops() - register or unregister rx callback
|
||||||
* @psoc: psoc object
|
* @psoc: psoc object
|
||||||
@@ -150,5 +158,13 @@ tdls_process_mlo_choice_tdls_vdev(struct wlan_objmgr_vdev *vdev);
|
|||||||
* Return: void
|
* Return: void
|
||||||
*/
|
*/
|
||||||
void tdls_set_no_force_vdev(struct wlan_objmgr_vdev *vdev, bool flag);
|
void tdls_set_no_force_vdev(struct wlan_objmgr_vdev *vdev, bool flag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tdls_set_link_mode() - force active or unfore link for MLO case
|
||||||
|
* @req: the pointer of tdls_action_frame_request
|
||||||
|
*
|
||||||
|
* Return: QDF_STATUS
|
||||||
|
*/
|
||||||
|
QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -241,6 +241,7 @@ enum tdls_feature_mode {
|
|||||||
* @TDLS_CMD_SET_SECOFFCHANOFFSET: tdls secondary offchannel offset
|
* @TDLS_CMD_SET_SECOFFCHANOFFSET: tdls secondary offchannel offset
|
||||||
* @TDLS_DELETE_ALL_PEERS_INDICATION: tdls delete all peers indication
|
* @TDLS_DELETE_ALL_PEERS_INDICATION: tdls delete all peers indication
|
||||||
* @TDLS_CMD_START_BSS: SAP start indication to tdls module
|
* @TDLS_CMD_START_BSS: SAP start indication to tdls module
|
||||||
|
* @TDLS_CMD_SET_LINK_UNFORCE: tdls to unforce link for MLO case
|
||||||
*/
|
*/
|
||||||
enum tdls_command_type {
|
enum tdls_command_type {
|
||||||
TDLS_CMD_TX_ACTION = 1,
|
TDLS_CMD_TX_ACTION = 1,
|
||||||
@@ -267,7 +268,8 @@ enum tdls_command_type {
|
|||||||
TDLS_CMD_SET_OFFCHANMODE,
|
TDLS_CMD_SET_OFFCHANMODE,
|
||||||
TDLS_CMD_SET_SECOFFCHANOFFSET,
|
TDLS_CMD_SET_SECOFFCHANOFFSET,
|
||||||
TDLS_DELETE_ALL_PEERS_INDICATION,
|
TDLS_DELETE_ALL_PEERS_INDICATION,
|
||||||
TDLS_CMD_START_BSS
|
TDLS_CMD_START_BSS,
|
||||||
|
TDLS_CMD_SET_LINK_UNFORCE
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -528,6 +528,7 @@ bool ucfg_tdls_link_vdev_is_matching(struct wlan_objmgr_vdev *vdev)
|
|||||||
if (!tdls_link_vdev) {
|
if (!tdls_link_vdev) {
|
||||||
wlan_vdev_mlme_feat_ext2_cap_set(vdev,
|
wlan_vdev_mlme_feat_ext2_cap_set(vdev,
|
||||||
WLAN_VDEV_FEXT2_MLO_STA_TDLS);
|
WLAN_VDEV_FEXT2_MLO_STA_TDLS);
|
||||||
|
tdls_set_remain_links_unforce(vdev);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user