mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(bt/bluedroid): support clear legacy advertising
This commit is contained in:
parent
681439b85a
commit
9ecfa6af81
@ -122,6 +122,19 @@ esp_err_t esp_ble_gap_stop_advertising(void)
|
||||
|
||||
return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_ble_gap_clear_advertising(void)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
|
||||
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_GAP_BLE;
|
||||
msg.act = BTC_GAP_BLE_ACT_CLEAR_ADV;
|
||||
|
||||
return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
|
||||
|
||||
esp_err_t esp_ble_gap_update_conn_params(esp_ble_conn_update_params_t *params)
|
||||
|
@ -222,6 +222,8 @@ typedef enum {
|
||||
ESP_GAP_BLE_PERIODIC_ADV_SYNC_TRANS_RECV_EVT, /*!< when periodic advertising sync transfer received, the event comes */
|
||||
// DTM
|
||||
ESP_GAP_BLE_DTM_TEST_UPDATE_EVT, /*!< when direct test mode state changes, the event comes */
|
||||
// BLE_INCLUDED
|
||||
ESP_GAP_BLE_ADV_CLEAR_COMPLETE_EVT, /*!< When clear advertising complete, the event comes */
|
||||
ESP_GAP_BLE_EVT_MAX, /*!< when maximum advertising event complete, the event comes */
|
||||
} esp_gap_ble_cb_event_t;
|
||||
|
||||
@ -1086,6 +1088,12 @@ typedef union {
|
||||
struct ble_adv_stop_cmpl_evt_param {
|
||||
esp_bt_status_t status; /*!< Indicate adv stop operation success status */
|
||||
} adv_stop_cmpl; /*!< Event parameter of ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT */
|
||||
/**
|
||||
* @brief ESP_GAP_BLE_ADV_CLEAR_COMPLETE_EVT
|
||||
*/
|
||||
struct ble_adv_clear_cmpl_evt_param {
|
||||
esp_bt_status_t status; /*!< Indicate adv clear operation success status */
|
||||
} adv_clear_cmpl; /*!< Event parameter of ESP_GAP_BLE_ADV_CLEAR_COMPLETE_EVT */
|
||||
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
|
||||
/**
|
||||
* @brief ESP_GAP_BLE_SET_STATIC_RAND_ADDR_EVT
|
||||
@ -2499,6 +2507,16 @@ esp_err_t esp_ble_dtm_enh_rx_start(const esp_ble_dtm_enh_rx_t *rx_params);
|
||||
*/
|
||||
esp_err_t esp_ble_dtm_stop(void);
|
||||
|
||||
/**
|
||||
* @brief This function is used to clear legacy advertising
|
||||
*
|
||||
*
|
||||
* @return - ESP_OK : success
|
||||
* - other : failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_ble_gap_clear_advertising(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -5711,6 +5711,15 @@ void bta_dm_ble_gap_dtm_stop(tBTA_DM_MSG *p_data)
|
||||
BTM_BleTestEnd(p_data->dtm_stop.p_dtm_cmpl_cback);
|
||||
}
|
||||
|
||||
void bta_dm_ble_gap_clear_adv(tBTA_DM_MSG *p_data)
|
||||
{
|
||||
if (BTM_BleClearAdv(p_data->ble_clear_adv.p_clear_adv_cback) == FALSE) {
|
||||
if (p_data->ble_clear_adv.p_clear_adv_cback) {
|
||||
(*p_data->ble_clear_adv.p_clear_adv_cback)(BTA_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if (BLE_50_FEATURE_SUPPORT == TRUE)
|
||||
void bta_dm_ble_gap_dtm_enhance_tx_start(tBTA_DM_MSG *p_data)
|
||||
{
|
||||
|
@ -1813,6 +1813,29 @@ extern void BTA_DmBleBroadcast (BOOLEAN start, tBTA_START_STOP_ADV_CMPL_CBACK *p
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmBleClearAdv
|
||||
**
|
||||
** Description This function is called to clear Advertising
|
||||
**
|
||||
** Parameters p_adv_data_cback : clear adv complete callback.
|
||||
**
|
||||
** Returns None
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_DmBleClearAdv (tBTA_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cback)
|
||||
{
|
||||
tBTA_DM_API_CLEAR_ADV *p_msg;
|
||||
|
||||
if ((p_msg = (tBTA_DM_API_CLEAR_ADV *)
|
||||
osi_malloc(sizeof(tBTA_DM_API_CLEAR_ADV))) != NULL) {
|
||||
p_msg->hdr.event = BTA_DM_API_BLE_CLEAR_ADV_EVT;
|
||||
p_msg->p_clear_adv_cback = p_clear_adv_cback;
|
||||
|
||||
bta_sys_sendmsg(p_msg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*******************************************************************************
|
||||
**
|
||||
|
@ -224,6 +224,7 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = {
|
||||
bta_dm_ble_gap_dtm_tx_start, /* BTA_DM_API_DTM_TX_START_EVT */
|
||||
bta_dm_ble_gap_dtm_rx_start, /* BTA_DM_API_DTM_RX_START_EVT */
|
||||
bta_dm_ble_gap_dtm_stop, /* BTA_DM_API_DTM_STOP_EVT */
|
||||
bta_dm_ble_gap_clear_adv, /* BTA_DM_API_BLE_CLEAR_ADV_EVT */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -217,6 +217,7 @@ enum {
|
||||
BTA_DM_API_DTM_TX_START_EVT,
|
||||
BTA_DM_API_DTM_RX_START_EVT,
|
||||
BTA_DM_API_DTM_STOP_EVT,
|
||||
BTA_DM_API_BLE_CLEAR_ADV_EVT,
|
||||
#endif
|
||||
BTA_DM_MAX_EVT
|
||||
};
|
||||
@ -896,6 +897,11 @@ typedef struct {
|
||||
tBTA_DTM_CMD_CMPL_CBACK *p_dtm_cmpl_cback;
|
||||
} tBTA_DM_API_BLE_DTM_STOP;
|
||||
|
||||
typedef struct {
|
||||
BT_HDR hdr;
|
||||
tBTA_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cback;
|
||||
} tBTA_DM_API_CLEAR_ADV;
|
||||
|
||||
#endif /* BLE_INCLUDED */
|
||||
|
||||
/* data type for BTA_DM_API_REMOVE_ACL_EVT */
|
||||
@ -1293,6 +1299,7 @@ typedef union {
|
||||
tBTA_DM_API_BLE_DTM_TX_START dtm_tx_start;
|
||||
tBTA_DM_API_BLE_DTM_RX_START dtm_rx_start;
|
||||
tBTA_DM_API_BLE_DTM_STOP dtm_stop;
|
||||
tBTA_DM_API_CLEAR_ADV ble_clear_adv;
|
||||
#endif
|
||||
|
||||
tBTA_DM_API_REMOVE_ACL remove_acl;
|
||||
@ -1732,6 +1739,7 @@ extern void bta_dm_ble_multi_adv_enb(tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_gap_dtm_tx_start(tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_gap_dtm_rx_start(tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_gap_dtm_stop(tBTA_DM_MSG *p_data);
|
||||
extern void bta_dm_ble_gap_clear_adv(tBTA_DM_MSG *p_data);
|
||||
|
||||
#if (BLE_50_FEATURE_SUPPORT == TRUE)
|
||||
extern void bta_dm_ble_gap_dtm_enhance_tx_start(tBTA_DM_MSG *p_data);
|
||||
|
@ -1243,6 +1243,8 @@ typedef void (tBTA_START_STOP_SCAN_CMPL_CBACK) (tBTA_STATUS status);
|
||||
|
||||
typedef void (tBTA_START_STOP_ADV_CMPL_CBACK) (tBTA_STATUS status);
|
||||
|
||||
typedef void (tBTA_CLEAR_ADV_CMPL_CBACK) (tBTA_STATUS status);
|
||||
|
||||
typedef void (tBTA_BLE_TRACK_ADV_CMPL_CBACK)(int action, tBTA_STATUS status,
|
||||
tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
|
||||
tBTA_DM_BLE_REF_VALUE ref_value);
|
||||
@ -2654,6 +2656,19 @@ extern void BTA_DmBleSetAdvConfigRaw (UINT8 *p_raw_adv, UINT32 raw_adv_len,
|
||||
void BTA_DmBleSetLongAdv (UINT8 *adv_data, UINT32 adv_data_len,
|
||||
tBTA_SET_ADV_DATA_CMPL_CBACK *p_adv_data_cback);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmBleClearAdv
|
||||
**
|
||||
** Description This function is called to clear Advertising
|
||||
**
|
||||
** Parameters p_adv_data_cback : clear adv complete callback.
|
||||
**
|
||||
** Returns None
|
||||
**
|
||||
*******************************************************************************/
|
||||
void BTA_DmBleClearAdv (tBTA_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cback);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTA_DmBleSetScanRsp
|
||||
|
@ -477,6 +477,25 @@ static void btc_stop_adv_callback(uint8_t status)
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_clear_adv_callback(uint8_t status)
|
||||
{
|
||||
esp_ble_gap_cb_param_t param;
|
||||
bt_status_t ret;
|
||||
btc_msg_t msg = {0};
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_GAP_BLE;
|
||||
msg.act = ESP_GAP_BLE_ADV_CLEAR_COMPLETE_EVT;
|
||||
param.adv_clear_cmpl.status = btc_hci_to_esp_status(status);
|
||||
|
||||
ret = btc_transfer_context(&msg, ¶m,
|
||||
sizeof(esp_ble_gap_cb_param_t), NULL, NULL);
|
||||
|
||||
if (ret != BT_STATUS_SUCCESS) {
|
||||
BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void btc_update_duplicate_exceptional_list_callback(tBTA_STATUS status, uint8_t subcode, uint32_t length, uint8_t *device_info)
|
||||
{
|
||||
esp_ble_gap_cb_param_t param;
|
||||
@ -1264,13 +1283,17 @@ static void btc_ble_stop_scanning(tBTA_START_STOP_SCAN_CMPL_CBACK *stop_scan_cb)
|
||||
BTA_DmBleScan(false, duration, NULL, stop_scan_cb);
|
||||
}
|
||||
|
||||
|
||||
static void btc_ble_stop_advertising(tBTA_START_STOP_ADV_CMPL_CBACK *stop_adv_cb)
|
||||
{
|
||||
bool stop_adv = false;
|
||||
|
||||
BTA_DmBleBroadcast(stop_adv, stop_adv_cb);
|
||||
}
|
||||
|
||||
static void btc_ble_clear_advertising(tBTA_CLEAR_ADV_CMPL_CBACK *clear_adv_cb)
|
||||
{
|
||||
BTA_DmBleClearAdv(clear_adv_cb);
|
||||
}
|
||||
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
|
||||
static void btc_ble_update_conn_params(BD_ADDR bd_addr, uint16_t min_int,
|
||||
uint16_t max_int, uint16_t latency, uint16_t timeout)
|
||||
@ -1738,6 +1761,9 @@ void btc_gap_ble_call_handler(btc_msg_t *msg)
|
||||
case BTC_GAP_BLE_ACT_STOP_ADV:
|
||||
btc_ble_stop_advertising(btc_stop_adv_callback);
|
||||
break;
|
||||
case BTC_GAP_BLE_ACT_CLEAR_ADV:
|
||||
btc_ble_clear_advertising(btc_clear_adv_callback);
|
||||
break;
|
||||
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
|
||||
case BTC_GAP_BLE_ACT_UPDATE_CONN_PARAM:
|
||||
btc_ble_update_conn_params(arg->conn_update_params.conn_params.bda,
|
||||
|
@ -99,6 +99,9 @@ typedef enum {
|
||||
BTC_GAP_BLE_DTM_RX_START,
|
||||
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
|
||||
BTC_GAP_BLE_DTM_STOP,
|
||||
#if (BLE_42_FEATURE_SUPPORT == TRUE)
|
||||
BTC_GAP_BLE_ACT_CLEAR_ADV,
|
||||
#endif // #if (BLE_42_FEATURE_SUPPORT == TRUE)
|
||||
} btc_gap_ble_act_t;
|
||||
|
||||
/* btc_ble_gap_args_t */
|
||||
|
@ -4673,6 +4673,28 @@ BOOLEAN BTM_Ble_Authorization(BD_ADDR bd_addr, BOOLEAN authorize)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleClearAdv
|
||||
**
|
||||
** Description This function is called to clear legacy advertising
|
||||
**
|
||||
** Parameter p_clear_adv_cback - Command complete callback
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN BTM_BleClearAdv(tBTM_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cback)
|
||||
{
|
||||
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
|
||||
|
||||
if (btsnd_hcic_ble_clear_adv() == FALSE) {
|
||||
BTM_TRACE_ERROR("%s: Unable to Clear Advertising", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
p_cb->inq_var.p_clear_adv_cb = p_clear_adv_cback;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool btm_ble_adv_pkt_ready(void)
|
||||
{
|
||||
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
|
||||
|
@ -731,6 +731,14 @@ void btm_vsc_complete (UINT8 *p, UINT16 opcode, UINT16 evt_len,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HCI_VENDOR_BLE_CLEAR_ADV: {
|
||||
uint8_t status;
|
||||
STREAM_TO_UINT8(status, p);
|
||||
if (ble_cb && ble_cb->inq_var.p_clear_adv_cb) {
|
||||
ble_cb->inq_var.p_clear_adv_cb(status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -159,6 +159,7 @@ typedef struct {
|
||||
tBTM_BLE_SFP sfp; /* scanning filter policy */
|
||||
tBTM_START_ADV_CMPL_CBACK *p_adv_cb;
|
||||
tBTM_START_STOP_ADV_CMPL_CBACK *p_stop_adv_cb;
|
||||
tBTM_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cb;
|
||||
tBLE_ADDR_TYPE adv_addr_type;
|
||||
UINT8 evt_type;
|
||||
UINT8 adv_mode;
|
||||
|
@ -1084,6 +1084,27 @@ BOOLEAN btsnd_hcic_ble_set_channels (BLE_CHANNELS channels)
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
BOOLEAN btsnd_hcic_ble_clear_adv (void)
|
||||
{
|
||||
BT_HDR *p;
|
||||
UINT8 *pp;
|
||||
|
||||
if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_BLE_CLEAR_ADV)) == NULL) {
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
pp = (UINT8 *)(p + 1);
|
||||
|
||||
p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_CLEAR_ADV;
|
||||
p->offset = 0;
|
||||
|
||||
UINT16_TO_STREAM (pp, HCI_VENDOR_BLE_CLEAR_ADV);
|
||||
UINT8_TO_STREAM (pp, HCIC_PARAM_SIZE_BLE_CLEAR_ADV);
|
||||
|
||||
btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define HCIC_BLE_CMD_CREATED(p, pp, size) do{\
|
||||
if ((p = HCI_GET_CMD_BUF(size)) == NULL) { \
|
||||
return FALSE; \
|
||||
|
@ -1000,6 +1000,7 @@ typedef void (tBTM_START_ADV_CMPL_CBACK) (UINT8 status);
|
||||
typedef void (tBTM_START_STOP_ADV_CMPL_CBACK) (UINT8 status);
|
||||
|
||||
typedef void (tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK) (tBTM_STATUS status, uint8_t subcode, uint32_t length, uint8_t *device_info);
|
||||
typedef void (tBTM_CLEAR_ADV_CMPL_CBACK) (UINT8 status);
|
||||
#if (BLE_50_FEATURE_SUPPORT == TRUE)
|
||||
#define BTM_BLE_5_GAP_READ_PHY_COMPLETE_EVT 1
|
||||
#define BTM_BLE_5_GAP_SET_PREFERED_DEFAULT_PHY_COMPLETE_EVT 2
|
||||
@ -2638,6 +2639,17 @@ BOOLEAN BTM_GetCurrentConnParams(BD_ADDR bda, uint16_t *interval, uint16_t *late
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN BTM_Ble_Authorization(BD_ADDR bd_addr, BOOLEAN authorize);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function BTM_BleClearAdv
|
||||
**
|
||||
** Description This function is called to clear legacy advertising
|
||||
**
|
||||
** Parameter p_clear_adv_cback - Command complete callback
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN BTM_BleClearAdv(tBTM_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cback);
|
||||
/*
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -419,6 +419,8 @@
|
||||
#define HCI_SUBCODE_BLE_DUPLICATE_EXCEPTIONAL_LIST 0x08
|
||||
#define HCI_SUBCODE_BLE_SET_ADV_FLOW_CONTROL 0x09
|
||||
#define HCI_SUBCODE_BLE_ADV_REPORT_FLOW_CONTROL 0x0A
|
||||
#define HCI_SUBCODE_BLE_RD_STATIC_ADDR 0x0B
|
||||
#define HCI_SUBCODE_BLE_CLEAR_ADV 0x0C
|
||||
#define HCI_SUBCODE_BLE_MAX 0x7F
|
||||
|
||||
//ESP BT subcode define
|
||||
@ -462,6 +464,8 @@
|
||||
#define HCI_VENDOR_BLE_UPDATE_DUPLICATE_EXCEPTIONAL_LIST HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_DUPLICATE_EXCEPTIONAL_LIST)
|
||||
#define HCI_VENDOR_BLE_SET_ADV_FLOW_CONTROL HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_SET_ADV_FLOW_CONTROL)
|
||||
#define HCI_VENDOR_BLE_ADV_REPORT_FLOW_CONTROL HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_ADV_REPORT_FLOW_CONTROL)
|
||||
/* BLE clear legacy advertising */
|
||||
#define HCI_VENDOR_BLE_CLEAR_ADV HCI_ESP_VENDOR_OPCODE_BUILD(HCI_VENDOR_OGF, HCI_ESP_GROUP_BLE, HCI_SUBCODE_BLE_CLEAR_ADV)
|
||||
//ESP BT HCI CMD
|
||||
|
||||
/* subcode for multi adv feature */
|
||||
|
@ -751,8 +751,9 @@ void btsnd_hcic_vendor_spec_cmd (BT_HDR *buffer, UINT16 opcode,
|
||||
#define HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE 1
|
||||
#define HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT 2
|
||||
#define HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH 6
|
||||
#define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM 11
|
||||
#define HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL 2
|
||||
#define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM 11
|
||||
#define HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL 2
|
||||
#define HCIC_PARAM_SIZE_BLE_CLEAR_ADV 0
|
||||
#if (BLE_50_FEATURE_SUPPORT == TRUE)
|
||||
#define HCIC_PARAM_SIZE_BLE_READ_PHY 2
|
||||
#define HCIC_PARAM_SIZE_BLE_SET_DEF_PHY 3
|
||||
@ -906,6 +907,8 @@ BOOLEAN btsnd_hcic_ble_set_addr_resolution_enable (UINT8 addr_resolution_enable)
|
||||
|
||||
BOOLEAN btsnd_hcic_ble_set_rand_priv_addr_timeout (UINT16 rpa_timout);
|
||||
|
||||
BOOLEAN btsnd_hcic_ble_clear_adv(void);
|
||||
|
||||
#endif /* BLE_INCLUDED */
|
||||
#if (BLE_50_FEATURE_SUPPORT == TRUE)
|
||||
typedef struct {
|
||||
|
Loading…
Reference in New Issue
Block a user