From fa6df6a51a781da3f512dbd571d99431ea06fc6b Mon Sep 17 00:00:00 2001 From: Lyle Zhu Date: Thu, 25 Apr 2024 14:41:37 +0800 Subject: [PATCH] Bluetooth: HFP_AG: Protect the consistency of AG state/value Use hfp_ag_lock/hfp_ag_unlock to protect the consistency of AG state or value. Signed-off-by: Lyle Zhu --- subsys/bluetooth/host/classic/hfp_ag.c | 221 +++++++++++++++++++++---- 1 file changed, 188 insertions(+), 33 deletions(-) diff --git a/subsys/bluetooth/host/classic/hfp_ag.c b/subsys/bluetooth/host/classic/hfp_ag.c index eaf06d08805..034cd324b6a 100644 --- a/subsys/bluetooth/host/classic/hfp_ag.c +++ b/subsys/bluetooth/host/classic/hfp_ag.c @@ -135,7 +135,9 @@ static void bt_hfp_ag_set_state(struct bt_hfp_ag *ag, bt_hfp_state_t state) { LOG_DBG("update state %p, old %d -> new %d", ag, ag->state, state); + hfp_ag_lock(ag); ag->state = state; + hfp_ag_unlock(ag); switch (state) { case BT_HFP_DISCONNECTED: @@ -162,9 +164,14 @@ static void bt_hfp_ag_set_state(struct bt_hfp_ag *ag, bt_hfp_state_t state) static void bt_hfp_ag_set_call_state(struct bt_hfp_ag *ag, bt_hfp_call_state_t call_state) { + bt_hfp_state_t state; + LOG_DBG("update call state %p, old %d -> new %d", ag, ag->call_state, call_state); + hfp_ag_lock(ag); ag->call_state = call_state; + state = ag->state; + hfp_ag_unlock(ag); switch (call_state) { case BT_HFP_CALL_TERMINATE: @@ -192,7 +199,7 @@ static void bt_hfp_ag_set_call_state(struct bt_hfp_ag *ag, bt_hfp_call_state_t c break; } - if (ag->state == BT_HFP_DISCONNECTING) { + if (state == BT_HFP_DISCONNECTING) { int err = bt_rfcomm_dlc_disconnect(&ag->rfcomm_dlc); if (err) { @@ -387,7 +394,9 @@ static int bt_hfp_ag_brsf_handler(struct bt_hfp_ag *ag, struct net_buf *buf) return -ENOTSUP; } + hfp_ag_lock(ag); ag->hf_features = hf_features; + hfp_ag_unlock(ag); return hfp_ag_send_data(ag, NULL, NULL, "\r\n+BRSF:%d\r\n", ag->ag_features); } @@ -402,10 +411,13 @@ static int bt_hfp_ag_bac_handler(struct bt_hfp_ag *ag, struct net_buf *buf) return -ENOTSUP; } + hfp_ag_lock(ag); if (!(ag->hf_features & BT_HFP_HF_FEATURE_CODEC_NEG) || !(ag->ag_features & BT_HFP_AG_FEATURE_CODEC_NEG)) { + hfp_ag_unlock(ag); return -EOPNOTSUPP; } + hfp_ag_unlock(ag); while (err == 0) { err = get_number(buf, &codec); @@ -424,7 +436,9 @@ static int bt_hfp_ag_bac_handler(struct bt_hfp_ag *ag, struct net_buf *buf) } } + hfp_ag_lock(ag); ag->hf_codec_ids = codec_ids; + hfp_ag_unlock(ag); if (bt_ag && bt_ag->codec) { bt_ag->codec(ag, ag->hf_codec_ids); @@ -487,7 +501,13 @@ static int bt_hfp_ag_cind_handler(struct bt_hfp_ag *ag, struct net_buf *buf) static void bt_hfp_ag_set_in_band_ring(struct bt_hfp_ag *ag, void *user_data) { - if ((ag->ag_features & BT_HFP_AG_FEATURE_INBAND_RINGTONE) != 0) { + bool is_inband_ringtone; + + hfp_ag_lock(ag); + is_inband_ringtone = (ag->ag_features & BT_HFP_AG_FEATURE_INBAND_RINGTONE) ? true : false; + hfp_ag_unlock(ag); + + if (is_inband_ringtone) { int err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BSIR:1\r\n"); atomic_set_bit_to(ag->flags, BT_HFP_AG_INBAND_RING, err == 0); @@ -555,17 +575,22 @@ static int bt_hfp_ag_bind_handler(struct bt_hfp_ag *ag, struct net_buf *buf) char *data; uint32_t len; + hfp_ag_lock(ag); if (!((ag->ag_features & BT_HFP_AG_FEATURE_HF_IND) && (ag->hf_features & BT_HFP_HF_FEATURE_HF_IND))) { + hfp_ag_unlock(ag); return -EOPNOTSUPP; } + hfp_ag_unlock(ag); if (is_char(buf, '?')) { if (!is_char(buf, '\r')) { return -ENOTSUP; } + hfp_ag_lock(ag); hf_indicators = ag->hf_indicators_of_hf & ag->hf_indicators_of_ag; + hfp_ag_unlock(ag); len = (sizeof(hf_indicators) * 8) > HFP_HF_IND_MAX ? HFP_HF_IND_MAX : (sizeof(hf_indicators) * 8); for (int i = 1; i < len; i++) { @@ -596,7 +621,9 @@ static int bt_hfp_ag_bind_handler(struct bt_hfp_ag *ag, struct net_buf *buf) data = &ag->buffer[0]; *data = '('; data++; + hfp_ag_lock(ag); hf_indicators = ag->hf_indicators_of_ag; + hfp_ag_unlock(ag); len = (sizeof(hf_indicators) * 8) > HFP_HF_IND_MAX ? HFP_HF_IND_MAX : (sizeof(hf_indicators) * 8); for (int i = 1; (i < len) && (hf_indicators != 0); i++) { @@ -640,7 +667,9 @@ static int bt_hfp_ag_bind_handler(struct bt_hfp_ag *ag, struct net_buf *buf) } } + hfp_ag_lock(ag); ag->hf_indicators_of_hf = hf_indicators; + hfp_ag_unlock(ag); return 0; } @@ -705,11 +734,17 @@ static int hfp_ag_update_indicator(struct bt_hfp_ag *ag, enum bt_hfp_ag_indicato static void hfp_ag_close_sco(struct bt_hfp_ag *ag) { + struct bt_conn *sco; + LOG_DBG(""); - if (NULL != ag->sco_chan.sco) { - LOG_DBG("Disconnect sco %p", ag->sco_chan.sco); - bt_conn_disconnect(ag->sco_chan.sco, BT_HCI_ERR_LOCALHOST_TERM_CONN); - ag->sco_chan.sco = NULL; + + hfp_ag_lock(ag); + sco = ag->sco_chan.sco; + ag->sco_chan.sco = NULL; + hfp_ag_unlock(ag); + if (sco != NULL) { + LOG_DBG("Disconnect sco %p", sco); + bt_conn_disconnect(sco, BT_HCI_ERR_LOCALHOST_TERM_CONN); } } @@ -754,17 +789,22 @@ static void bt_hfp_ag_unit_call_terminate(struct bt_hfp_ag *ag, void *user_data) static int bt_hfp_ag_chup_handler(struct bt_hfp_ag *ag, struct net_buf *buf) { int err; + bt_hfp_call_state_t call_state; if (!is_char(buf, '\r')) { return -ENOTSUP; } - if (ag->call_state == BT_HFP_CALL_ALERTING) { + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + + if (call_state == BT_HFP_CALL_ALERTING) { if (!atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { return -ENOTSUP; } err = hfp_ag_next_step(ag, bt_hfp_ag_call_reject, NULL); - } else if ((ag->call_state == BT_HFP_CALL_ACTIVE) || (ag->call_state == BT_HFP_CALL_HOLD)) { + } else if ((call_state == BT_HFP_CALL_ACTIVE) || (call_state == BT_HFP_CALL_HOLD)) { err = hfp_ag_next_step(ag, bt_hfp_ag_unit_call_terminate, NULL); } else { return -ENOTSUP; @@ -776,6 +816,7 @@ static uint8_t bt_hfp_get_call_state(struct bt_hfp_ag *ag) { uint8_t status = HFP_AG_CLCC_STATUS_INVALID; + hfp_ag_lock(ag); switch (ag->call_state) { case BT_HFP_CALL_TERMINATE: break; @@ -801,6 +842,7 @@ static uint8_t bt_hfp_get_call_state(struct bt_hfp_ag *ag) default: break; } + hfp_ag_unlock(ag); return status; } @@ -817,10 +859,13 @@ static int bt_hfp_ag_clcc_handler(struct bt_hfp_ag *ag, struct net_buf *buf) return -ENOTSUP; } + hfp_ag_lock(ag); if (ag->call_state == BT_HFP_CALL_TERMINATE) { /* AG shall always send OK response to HF */ + hfp_ag_unlock(ag); return 0; } + hfp_ag_unlock(ag); dir = atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL) ? 1 : 0; status = bt_hfp_get_call_state(ag); @@ -841,12 +886,16 @@ static int bt_hfp_ag_bia_handler(struct bt_hfp_ag *ag, struct net_buf *buf) uint32_t number; int err; int index = 0; - uint32_t indicator = ag->indicator; + uint32_t indicator; if (!is_char(buf, '=')) { return -ENOTSUP; } + hfp_ag_lock(ag); + indicator = ag->indicator; + hfp_ag_unlock(ag); + while (buf->len > 0) { err = get_number(buf, &number); if (err == 0) { @@ -873,7 +922,10 @@ static int bt_hfp_ag_bia_handler(struct bt_hfp_ag *ag, struct net_buf *buf) /* Force call, call setup and held call indicators are enabled. */ indicator = BIT(BT_HFP_AG_CALL_IND) | BIT(BT_HFP_AG_CALL_SETUP_IND) | BIT(BT_HFP_AG_CALL_HELD_IND); + + hfp_ag_lock(ag); ag->indicator = indicator; + hfp_ag_unlock(ag); return 0; } @@ -897,8 +949,12 @@ static void bt_hfp_ag_call_ringing_cb(struct bt_hfp_ag *ag, bool in_bond) static void hfp_ag_sco_connected(struct bt_sco_chan *chan) { struct bt_hfp_ag *ag = CONTAINER_OF(chan, struct bt_hfp_ag, sco_chan); + bt_hfp_call_state_t call_state; - if (ag->call_state == BT_HFP_CALL_INCOMING) { + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + if (call_state == BT_HFP_CALL_INCOMING) { bt_hfp_ag_set_call_state(ag, BT_HFP_CALL_ALERTING); bt_hfp_ag_call_ringing_cb(ag, true); } @@ -911,12 +967,16 @@ static void hfp_ag_sco_connected(struct bt_sco_chan *chan) static void hfp_ag_sco_disconnected(struct bt_sco_chan *chan, uint8_t reason) { struct bt_hfp_ag *ag = CONTAINER_OF(chan, struct bt_hfp_ag, sco_chan); + bt_hfp_call_state_t call_state; if ((bt_ag) && bt_ag->sco_disconnected) { bt_ag->sco_disconnected(ag); } - if ((ag->call_state == BT_HFP_CALL_INCOMING) || (ag->call_state == BT_HFP_CALL_OUTGOING)) { + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + if ((call_state == BT_HFP_CALL_INCOMING) || (call_state == BT_HFP_CALL_OUTGOING)) { bt_hfp_ag_call_reject(ag, NULL); } } @@ -950,16 +1010,19 @@ static struct bt_conn *bt_hfp_ag_create_sco(struct bt_hfp_ag *ag) static int hfp_ag_open_sco(struct bt_hfp_ag *ag) { + hfp_ag_lock(ag); if (ag->sco_chan.sco == NULL) { struct bt_conn *sco_conn = bt_hfp_ag_create_sco(ag); if (sco_conn == NULL) { LOG_ERR("Fail to create sco connection!"); + hfp_ag_unlock(ag); return -ENOTCONN; } LOG_DBG("SCO connection created (%p)", sco_conn); } + hfp_ag_unlock(ag); return 0; } @@ -970,15 +1033,19 @@ static int bt_hfp_ag_codec_select(struct bt_hfp_ag *ag) LOG_DBG(""); + hfp_ag_lock(ag); if (ag->selected_codec_id == 0) { LOG_ERR("Codec is invalid"); + hfp_ag_unlock(ag); return -EINVAL; } if (!(ag->hf_codec_ids & BIT(ag->selected_codec_id))) { LOG_ERR("Codec is unsupported (codec id %d)", ag->selected_codec_id); + hfp_ag_unlock(ag); return -EINVAL; } + hfp_ag_unlock(ag); err = hfp_ag_send_data(ag, NULL, NULL, "\r\n+BCS:%d\r\n", ag->selected_codec_id); if (err != 0) { @@ -990,8 +1057,13 @@ static int bt_hfp_ag_codec_select(struct bt_hfp_ag *ag) static int bt_hfp_ag_create_audio_connection(struct bt_hfp_ag *ag) { int err; + uint32_t hf_codec_ids; - if ((ag->hf_codec_ids != 0) && atomic_test_bit(ag->flags, BT_HFP_AG_CODEC_CHANGED)) { + hfp_ag_lock(ag); + hf_codec_ids = ag->hf_codec_ids; + hfp_ag_unlock(ag); + + if ((hf_codec_ids != 0) && atomic_test_bit(ag->flags, BT_HFP_AG_CODEC_CHANGED)) { atomic_set_bit(ag->flags, BT_HFP_AG_CODEC_CONN); err = bt_hfp_ag_codec_select(ag); } else { @@ -1035,9 +1107,12 @@ static int bt_hfp_ag_ata_handler(struct bt_hfp_ag *ag, struct net_buf *buf) return -ENOTSUP; } + hfp_ag_lock(ag); if (ag->call_state != BT_HFP_CALL_ALERTING) { + hfp_ag_unlock(ag); return -ENOTSUP; } + hfp_ag_unlock(ag); if (!atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { return -ENOTSUP; @@ -1105,21 +1180,15 @@ static int bt_hfp_ag_bcc_handler(struct bt_hfp_ag *ag, struct net_buf *buf) return -ENOTSUP; } - if (ag->selected_codec_id == 0) { - return -ENOTSUP; - } - - if (!(ag->hf_codec_ids & BIT(ag->selected_codec_id))) { - return -ENOTSUP; - } - - if (ag->call_state == BT_HFP_CALL_TERMINATE) { - return -ENOTSUP; - } - - if (ag->sco_chan.sco != NULL) { + hfp_ag_lock(ag); + if ((ag->selected_codec_id == 0) || + (!(ag->hf_codec_ids & BIT(ag->selected_codec_id))) || + (ag->call_state == BT_HFP_CALL_TERMINATE) || + (ag->sco_chan.sco != NULL)) { + hfp_ag_unlock(ag); return -ENOTSUP; } + hfp_ag_unlock(ag); err = hfp_ag_next_step(ag, bt_hfp_ag_audio_connection, NULL); @@ -1157,6 +1226,7 @@ static int bt_hfp_ag_bcs_handler(struct bt_hfp_ag *ag, struct net_buf *buf) return -ESRCH; } + hfp_ag_lock(ag); if (ag->selected_codec_id != number) { LOG_ERR("Received codec id %d is not aligned with selected %d", number, ag->selected_codec_id); @@ -1166,6 +1236,7 @@ static int bt_hfp_ag_bcs_handler(struct bt_hfp_ag *ag, struct net_buf *buf) ag->selected_codec_id, ag->hf_codec_ids); err = -ENOTSUP; } + hfp_ag_unlock(ag); atomic_clear_bit(ag->flags, BT_HFP_AG_CODEC_CONN); atomic_clear_bit(ag->flags, BT_HFP_AG_CODEC_CHANGED); @@ -1173,7 +1244,12 @@ static int bt_hfp_ag_bcs_handler(struct bt_hfp_ag *ag, struct net_buf *buf) if (err == 0) { err = hfp_ag_next_step(ag, bt_hfp_ag_unit_codec_conn_setup, NULL); } else { - if (ag->call_state != BT_HFP_CALL_TERMINATE) { + bt_hfp_call_state_t call_state; + + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + if (call_state != BT_HFP_CALL_TERMINATE) { (void)hfp_ag_next_step(ag, bt_hfp_ag_unit_call_terminate, NULL); } } @@ -1233,12 +1309,15 @@ static int bt_hfp_ag_atd_handler(struct bt_hfp_ag *ag, struct net_buf *buf) return -ENAMETOOLONG; } + hfp_ag_lock(ag); if (ag->call_state != BT_HFP_CALL_TERMINATE) { + hfp_ag_unlock(ag); return -EBUSY; } /* Copy number to ag->number including null-character */ memcpy(ag->number, number, len + 1); + hfp_ag_unlock(ag); err = hfp_ag_next_step(ag, bt_hfp_ag_unit_call_outgoing, NULL); @@ -1253,13 +1332,17 @@ static int bt_hfp_ag_bldn_handler(struct bt_hfp_ag *ag, struct net_buf *buf) return -ENOTSUP; } + hfp_ag_lock(ag); if (strlen(ag->number) == 0) { + hfp_ag_unlock(ag); return -ENOSR; } if (ag->call_state != BT_HFP_CALL_TERMINATE) { + hfp_ag_unlock(ag); return -EBUSY; } + hfp_ag_unlock(ag); err = hfp_ag_next_step(ag, bt_hfp_ag_unit_call_outgoing, NULL); @@ -1313,11 +1396,15 @@ static void hfp_ag_connected(struct bt_rfcomm_dlc *dlc) static void hfp_ag_disconnected(struct bt_rfcomm_dlc *dlc) { struct bt_hfp_ag *ag = CONTAINER_OF(dlc, struct bt_hfp_ag, rfcomm_dlc); + bt_hfp_call_state_t call_state; bt_hfp_ag_set_state(ag, BT_HFP_DISCONNECTED); - if ((ag->call_state == BT_HFP_CALL_ALERTING) || (ag->call_state == BT_HFP_CALL_ACTIVE) || - (ag->call_state == BT_HFP_CALL_HOLD)) { + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + if ((call_state == BT_HFP_CALL_ALERTING) || (call_state == BT_HFP_CALL_ACTIVE) || + (call_state == BT_HFP_CALL_HOLD)) { bt_hfp_ag_terminate_cb(ag, NULL); } @@ -1420,10 +1507,15 @@ static void hfp_ag_sent(struct bt_rfcomm_dlc *dlc, struct net_buf *buf, int err) static void bt_ag_deferred_work_cb(struct bt_hfp_ag *ag, void *user_data) { int err; + bt_hfp_call_state_t call_state; LOG_DBG(""); - switch (ag->call_state) { + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + + switch (call_state) { case BT_HFP_CALL_TERMINATE: break; case BT_HFP_CALL_ACTIVE: @@ -1483,10 +1575,14 @@ static void bt_ag_deferred_work(struct k_work *work) static void bt_ag_ringing_work_cb(struct bt_hfp_ag *ag, void *user_data) { int err; + bt_hfp_call_state_t call_state; LOG_DBG(""); - if (ag->call_state == BT_HFP_CALL_ALERTING) { + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + if (call_state == BT_HFP_CALL_ALERTING) { if (!atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { return; @@ -1635,6 +1731,7 @@ int bt_hfp_ag_connect(struct bt_conn *conn, struct bt_hfp_ag **ag, uint8_t chann int bt_hfp_ag_disconnect(struct bt_hfp_ag *ag) { int err; + bt_hfp_call_state_t call_state; LOG_DBG(""); @@ -1642,16 +1739,20 @@ int bt_hfp_ag_disconnect(struct bt_hfp_ag *ag) return -EINVAL; } + hfp_ag_lock(ag); + call_state = ag->call_state; + hfp_ag_unlock(ag); + bt_hfp_ag_set_state(ag, BT_HFP_DISCONNECTING); - if ((ag->call_state == BT_HFP_CALL_ACTIVE) || (ag->call_state == BT_HFP_CALL_HOLD)) { + if ((call_state == BT_HFP_CALL_ACTIVE) || (call_state == BT_HFP_CALL_HOLD)) { err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 0, bt_hfp_ag_terminate_cb, NULL); if (err != 0) { LOG_ERR("HFP AG send response err :(%d)", err); } return err; - } else if (ag->call_state != BT_HFP_CALL_TERMINATE) { + } else if (call_state != BT_HFP_CALL_TERMINATE) { err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_NONE, bt_hfp_ag_reject_cb, NULL); if (err != 0) { @@ -1710,21 +1811,27 @@ int bt_hfp_ag_remote_incoming(struct bt_hfp_ag *ag, const char *number) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } if (ag->call_state != BT_HFP_CALL_TERMINATE) { + hfp_ag_unlock(ag); return -EBUSY; } + hfp_ag_unlock(ag); len = strlen(number); if ((len == 0) || (len > CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN)) { return -EINVAL; } + hfp_ag_lock(ag); /* Copy number to ag->number including null-character */ memcpy(ag->number, number, len + 1); + hfp_ag_unlock(ag); atomic_set_bit(ag->flags, BT_HFP_AG_INCOMING_CALL); @@ -1747,13 +1854,17 @@ int bt_hfp_ag_reject(struct bt_hfp_ag *ag) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } if ((ag->call_state != BT_HFP_CALL_ALERTING) && (ag->call_state != BT_HFP_CALL_INCOMING)) { + hfp_ag_unlock(ag); return -EINVAL; } + hfp_ag_unlock(ag); if (!atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { return -EINVAL; @@ -1775,13 +1886,17 @@ int bt_hfp_ag_accept(struct bt_hfp_ag *ag) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } if (ag->call_state != BT_HFP_CALL_ALERTING) { + hfp_ag_unlock(ag); return -EINVAL; } + hfp_ag_unlock(ag); if (!atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { return -EINVAL; @@ -1811,13 +1926,17 @@ int bt_hfp_ag_terminate(struct bt_hfp_ag *ag) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } if ((ag->call_state != BT_HFP_CALL_ACTIVE) || (ag->call_state != BT_HFP_CALL_HOLD)) { + hfp_ag_unlock(ag); return -EINVAL; } + hfp_ag_unlock(ag); err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 0, bt_hfp_ag_terminate_cb, NULL); @@ -1853,21 +1972,27 @@ int bt_hfp_ag_outgoing(struct bt_hfp_ag *ag, const char *number) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } if (ag->call_state != BT_HFP_CALL_TERMINATE) { + hfp_ag_unlock(ag); return -EBUSY; } + hfp_ag_unlock(ag); len = strlen(number); if ((len == 0) || (len > CONFIG_BT_HFP_AG_PHONE_NUMBER_MAX_LEN)) { return -EINVAL; } + hfp_ag_lock(ag); /* Copy number to ag->number including null-character */ memcpy(ag->number, number, len + 1); + hfp_ag_unlock(ag); atomic_clear_bit(ag->flags, BT_HFP_AG_INCOMING_CALL); @@ -1898,19 +2023,24 @@ int bt_hfp_ag_remote_ringing(struct bt_hfp_ag *ag) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } - if (BT_HFP_CALL_OUTGOING != ag->call_state) { + if (ag->call_state != BT_HFP_CALL_OUTGOING) { + hfp_ag_unlock(ag); return -EBUSY; } if (atomic_test_bit(ag->flags, BT_HFP_AG_INBAND_RING)) { if (ag->sco_chan.sco == NULL) { + hfp_ag_unlock(ag); return -ENOTCONN; } } + hfp_ag_unlock(ag); err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_SETUP_IND, BT_HFP_CALL_SETUP_REMOTE_ALERTING, bt_hfp_ag_ringing_cb, @@ -1929,13 +2059,17 @@ int bt_hfp_ag_remote_reject(struct bt_hfp_ag *ag) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } if ((ag->call_state != BT_HFP_CALL_ALERTING) && (ag->call_state != BT_HFP_CALL_OUTGOING)) { + hfp_ag_unlock(ag); return -EINVAL; } + hfp_ag_unlock(ag); if (atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { return -EINVAL; @@ -1957,13 +2091,17 @@ int bt_hfp_ag_remote_accept(struct bt_hfp_ag *ag) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } if (ag->call_state != BT_HFP_CALL_ALERTING) { + hfp_ag_unlock(ag); return -EINVAL; } + hfp_ag_unlock(ag); if (atomic_test_bit(ag->flags, BT_HFP_AG_INCOMING_CALL)) { return -EINVAL; @@ -1993,13 +2131,17 @@ int bt_hfp_ag_remote_terminate(struct bt_hfp_ag *ag) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } if ((ag->call_state != BT_HFP_CALL_ACTIVE) || (ag->call_state != BT_HFP_CALL_HOLD)) { + hfp_ag_unlock(ag); return -EINVAL; } + hfp_ag_unlock(ag); err = hfp_ag_update_indicator(ag, BT_HFP_AG_CALL_IND, 0, bt_hfp_ag_terminate_cb, NULL); @@ -2016,9 +2158,12 @@ int bt_hfp_ag_set_indicator(struct bt_hfp_ag *ag, enum bt_hfp_ag_indicator index return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } + hfp_ag_unlock(ag); switch (index) { case BT_HFP_AG_SERVICE_IND: @@ -2057,7 +2202,9 @@ int bt_hfp_ag_set_operator(struct bt_hfp_ag *ag, char *name) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } @@ -2065,6 +2212,7 @@ int bt_hfp_ag_set_operator(struct bt_hfp_ag *ag, char *name) len = MIN(sizeof(ag->operator) - 1, len); memcpy(ag->operator, name, len); ag->operator[len] = '\0'; + hfp_ag_unlock(ag); return 0; } @@ -2079,19 +2227,26 @@ int bt_hfp_ag_select_codec(struct bt_hfp_ag *ag, uint8_t id) return -EINVAL; } + hfp_ag_lock(ag); if (ag->state != BT_HFP_CONNECTED) { + hfp_ag_unlock(ag); return -ENOTCONN; } if (!(ag->hf_codec_ids && BIT(id))) { + hfp_ag_unlock(ag); return -ENOTSUP; } + hfp_ag_unlock(ag); if (atomic_test_bit(ag->flags, BT_HFP_AG_CODEC_CONN)) { return -EBUSY; } + hfp_ag_lock(ag); ag->selected_codec_id = id; + hfp_ag_unlock(ag); + atomic_set_bit(ag->flags, BT_HFP_AG_CODEC_CHANGED); err = bt_hfp_ag_create_audio_connection(ag);