merge from upstream/master into main at 2023-04-27T20:19:03.821834Z

Change-Id: I6c36a6b69e78afc43cdb212db23880c909725e4c
diff --git a/src/rust/uwb_core/protos/uwb_service.proto b/src/rust/uwb_core/protos/uwb_service.proto
index c5e20f4..3d51c4d 100644
--- a/src/rust/uwb_core/protos/uwb_service.proto
+++ b/src/rust/uwb_core/protos/uwb_service.proto
@@ -174,6 +174,8 @@
   ERROR_REF_UWB_SESSION_LOST = 63;
   ERROR_INVALID_CHANNEL_WITH_AOA = 128;
   ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 129;
+  ERROR_DT_ANCHOR_RANGING_ROUNDS_NOT_CONFIGURED = 130;
+  ERROR_DT_TAG_RANGING_ROUNDS_NOT_CONFIGURED = 131;
   // All vendor reason code will be mapped to ERROR_VENDOR_SPECIFIC.
   ERROR_RFU_OR_VENDOR_SPECIFIC = 255;
 }
diff --git a/src/rust/uwb_core/src/params/uci_packets.rs b/src/rust/uwb_core/src/params/uci_packets.rs
index 2ae7c3a..2e0941e 100644
--- a/src/rust/uwb_core/src/params/uci_packets.rs
+++ b/src/rust/uwb_core/src/params/uci_packets.rs
@@ -139,9 +139,9 @@
     pub config_status: Vec<AppConfigStatus>,
 }
 
-/// The response from UciManager::session_update_active_rounds_dt_tag() method.
+/// The response from UciManager::session_update_dt_tag_ranging_rounds() method.
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub struct SessionUpdateActiveRoundsDtTagResponse {
+pub struct SessionUpdateDtTagRangingRoundsResponse {
     /// The status code of the response.
     pub status: StatusCode,
     /// Indexes of unsuccessful ranging rounds.
@@ -153,11 +153,13 @@
 pub struct CountryCode([u8; 2]);
 
 impl CountryCode {
-    const UNKNOWN_COUNTRY_CODE: [u8; 2] = [0, 0];
+    const UNKNOWN_COUNTRY_CODE: &'static [u8] = "00".as_bytes();
 
     /// Create a CountryCode instance.
     pub fn new(code: &[u8; 2]) -> Option<Self> {
-        if code != &CountryCode::UNKNOWN_COUNTRY_CODE && !code.is_ascii() {
+        if code != CountryCode::UNKNOWN_COUNTRY_CODE
+            && !code.iter().all(|x| (*x as char).is_ascii_alphabetic())
+        {
             None
         } else {
             Some(Self((*code).to_ascii_uppercase().try_into().ok()?))
@@ -235,4 +237,14 @@
         let format_str = format!("{tlv:?}");
         assert_eq!(format_str, "AppConfigTlv { cfg_id: DeviceType, v: [12, 34] }");
     }
+
+    #[test]
+    fn test_country_code() {
+        let _country_code_ascii: CountryCode = String::from("US").try_into().unwrap();
+        let _country_code_unknown: CountryCode = String::from("00").try_into().unwrap();
+        let country_code_invalid_1: Result<CountryCode, Error> = String::from("0S").try_into();
+        country_code_invalid_1.unwrap_err();
+        let country_code_invalid_2: Result<CountryCode, Error> = String::from("ÀÈ").try_into();
+        country_code_invalid_2.unwrap_err();
+    }
 }
diff --git a/src/rust/uwb_core/src/proto/mappings.rs b/src/rust/uwb_core/src/proto/mappings.rs
index 0b7f617..0d21c09 100644
--- a/src/rust/uwb_core/src/proto/mappings.rs
+++ b/src/rust/uwb_core/src/proto/mappings.rs
@@ -510,6 +510,12 @@
             ReasonCode::ErrorStoppedDueToOtherSessionConflict => {
                 ProtoReasonCode::ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT
             }
+            ReasonCode::ErrorDtAnchorRangingRoundsNotConfigured => {
+                ProtoReasonCode::ERROR_DT_ANCHOR_RANGING_ROUNDS_NOT_CONFIGURED
+            }
+            ReasonCode::ErrorDtTagRangingRoundsNotConfigured => {
+                ProtoReasonCode::ERROR_DT_TAG_RANGING_ROUNDS_NOT_CONFIGURED
+            }
             _ => ProtoReasonCode::ERROR_RFU_OR_VENDOR_SPECIFIC,
         }
     }
diff --git a/src/rust/uwb_core/src/uci/command.rs b/src/rust/uwb_core/src/uci/command.rs
index 17128fa..dc06dab 100644
--- a/src/rust/uwb_core/src/uci/command.rs
+++ b/src/rust/uwb_core/src/uci/command.rs
@@ -63,7 +63,7 @@
         action: UpdateMulticastListAction,
         controlees: Controlees,
     },
-    SessionUpdateActiveRoundsDtTag {
+    SessionUpdateDtTagRangingRounds {
         session_id: u32,
         ranging_round_indexes: Vec<u8>,
     },
@@ -138,8 +138,8 @@
                 .build()
                 .into()
             }
-            UciCommand::SessionUpdateActiveRoundsDtTag { session_id, ranging_round_indexes } => {
-                uwb_uci_packets::SessionUpdateActiveRoundsDtTagCmdBuilder {
+            UciCommand::SessionUpdateDtTagRangingRounds { session_id, ranging_round_indexes } => {
+                uwb_uci_packets::SessionUpdateDtTagRangingRoundsCmdBuilder {
                     session_id,
                     ranging_round_indexes,
                 }
@@ -320,14 +320,14 @@
             .into()
         );
 
-        cmd = UciCommand::SessionUpdateActiveRoundsDtTag {
+        cmd = UciCommand::SessionUpdateDtTagRangingRounds {
             session_id: 1,
             ranging_round_indexes: vec![0],
         };
         packet = uwb_uci_packets::UciControlPacket::try_from(cmd.clone()).unwrap();
         assert_eq!(
             packet,
-            uwb_uci_packets::SessionUpdateActiveRoundsDtTagCmdBuilder {
+            uwb_uci_packets::SessionUpdateDtTagRangingRoundsCmdBuilder {
                 session_id: 1,
                 ranging_round_indexes: vec![0]
             }
diff --git a/src/rust/uwb_core/src/uci/mock_uci_manager.rs b/src/rust/uwb_core/src/uci/mock_uci_manager.rs
index 4b620a3..a206392 100644
--- a/src/rust/uwb_core/src/uci/mock_uci_manager.rs
+++ b/src/rust/uwb_core/src/uci/mock_uci_manager.rs
@@ -30,7 +30,7 @@
     app_config_tlvs_eq, device_config_tlvs_eq, AppConfigTlv, AppConfigTlvType, CapTlv, Controlees,
     CoreSetConfigResponse, CountryCode, DeviceConfigId, DeviceConfigTlv, FiraComponent,
     GetDeviceInfoResponse, PowerStats, RawUciMessage, ResetConfig, SessionId, SessionState,
-    SessionType, SessionUpdateActiveRoundsDtTagResponse, SetAppConfigResponse,
+    SessionType, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse,
     UpdateMulticastListAction,
 };
 use crate::uci::notification::{
@@ -264,14 +264,14 @@
     /// Prepare Mock to expect session_update_active_rounds_dt_tag.
     ///
     /// MockUciManager expects call with parameters, returns out as response.
-    pub fn expect_session_update_active_rounds_dt_tag(
+    pub fn expect_session_update_dt_tag_ranging_rounds(
         &mut self,
         expected_session_id: u32,
         expected_ranging_round_indexes: Vec<u8>,
-        out: Result<SessionUpdateActiveRoundsDtTagResponse>,
+        out: Result<SessionUpdateDtTagRangingRoundsResponse>,
     ) {
         self.expected_calls.lock().unwrap().push_back(
-            ExpectedCall::SessionUpdateActiveRoundsDtTag {
+            ExpectedCall::SessionUpdateDtTagRangingRounds {
                 expected_session_id,
                 expected_ranging_round_indexes,
                 out,
@@ -727,14 +727,14 @@
         }
     }
 
-    async fn session_update_active_rounds_dt_tag(
+    async fn session_update_dt_tag_ranging_rounds(
         &self,
         session_id: u32,
         ranging_round_indexes: Vec<u8>,
-    ) -> Result<SessionUpdateActiveRoundsDtTagResponse> {
+    ) -> Result<SessionUpdateDtTagRangingRoundsResponse> {
         let mut expected_calls = self.expected_calls.lock().unwrap();
         match expected_calls.pop_front() {
-            Some(ExpectedCall::SessionUpdateActiveRoundsDtTag {
+            Some(ExpectedCall::SessionUpdateDtTagRangingRounds {
                 expected_session_id,
                 expected_ranging_round_indexes,
                 out,
@@ -752,10 +752,10 @@
         }
     }
 
-     async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16> {
+    async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16> {
         let mut expected_calls = self.expected_calls.lock().unwrap();
         match expected_calls.pop_front() {
-            Some(ExpectedCall::SessionQueryMaxDataSize {expected_session_id, out})
+            Some(ExpectedCall::SessionQueryMaxDataSize { expected_session_id, out })
                 if expected_session_id == session_id =>
             {
                 self.expect_call_consumed.notify_one();
@@ -984,10 +984,10 @@
         notfs: Vec<UciNotification>,
         out: Result<()>,
     },
-    SessionUpdateActiveRoundsDtTag {
+    SessionUpdateDtTagRangingRounds {
         expected_session_id: u32,
         expected_ranging_round_indexes: Vec<u8>,
-        out: Result<SessionUpdateActiveRoundsDtTagResponse>,
+        out: Result<SessionUpdateDtTagRangingRoundsResponse>,
     },
     SessionQueryMaxDataSize {
         expected_session_id: SessionId,
diff --git a/src/rust/uwb_core/src/uci/response.rs b/src/rust/uwb_core/src/uci/response.rs
index f7343ad..b0d5b2b 100644
--- a/src/rust/uwb_core/src/uci/response.rs
+++ b/src/rust/uwb_core/src/uci/response.rs
@@ -17,7 +17,7 @@
 use crate::error::{Error, Result};
 use crate::params::uci_packets::{
     AppConfigTlv, CapTlv, CoreSetConfigResponse, DeviceConfigTlv, GetDeviceInfoResponse,
-    PowerStats, RawUciMessage, SessionState, SessionUpdateActiveRoundsDtTagResponse,
+    PowerStats, RawUciMessage, SessionState, SessionUpdateDtTagRangingRoundsResponse,
     SetAppConfigResponse, StatusCode, UciControlPacket,
 };
 use crate::uci::error::status_code_to_result;
@@ -40,7 +40,7 @@
     SessionGetCount(Result<u8>),
     SessionGetState(Result<SessionState>),
     SessionUpdateControllerMulticastList(Result<()>),
-    SessionUpdateActiveRoundsDtTag(Result<SessionUpdateActiveRoundsDtTagResponse>),
+    SessionUpdateDtTagRangingRounds(Result<SessionUpdateDtTagRangingRoundsResponse>),
     SessionQueryMaxDataSize(Result<u16>),
     SessionStart(Result<()>),
     SessionStop(Result<()>),
@@ -48,6 +48,7 @@
     AndroidSetCountryCode(Result<()>),
     AndroidGetPowerStats(Result<PowerStats>),
     RawUciCmd(Result<RawUciMessage>),
+    SendUciData(Result<()>),
 }
 
 impl UciResponse {
@@ -66,7 +67,7 @@
             Self::SessionUpdateControllerMulticastList(result) => {
                 Self::matches_result_retry(result)
             }
-            Self::SessionUpdateActiveRoundsDtTag(result) => Self::matches_result_retry(result),
+            Self::SessionUpdateDtTagRangingRounds(result) => Self::matches_result_retry(result),
             Self::SessionStart(result) => Self::matches_result_retry(result),
             Self::SessionStop(result) => Self::matches_result_retry(result),
             Self::SessionGetRangingCount(result) => Self::matches_result_retry(result),
@@ -78,6 +79,8 @@
             Self::SessionSetAppConfig(resp) => Self::matches_status_retry(&resp.status),
 
             Self::SessionQueryMaxDataSize(result) => Self::matches_result_retry(result),
+            // TODO(b/273376343): Implement retry logic for Data packet send.
+            Self::SendUciData(_result) => false,
         }
     }
 
@@ -171,9 +174,9 @@
                     evt.get_status(),
                 )))
             }
-            SessionConfigResponseChild::SessionUpdateActiveRoundsDtTagRsp(evt) => {
-                Ok(UciResponse::SessionUpdateActiveRoundsDtTag(Ok(
-                    SessionUpdateActiveRoundsDtTagResponse {
+            SessionConfigResponseChild::SessionUpdateDtTagRangingRoundsRsp(evt) => {
+                Ok(UciResponse::SessionUpdateDtTagRangingRounds(Ok(
+                    SessionUpdateDtTagRangingRoundsResponse {
                         status: evt.get_status(),
                         ranging_round_indexes: evt.get_ranging_round_indexes().to_vec(),
                     },
diff --git a/src/rust/uwb_core/src/uci/timeout_uci_hal.rs b/src/rust/uwb_core/src/uci/timeout_uci_hal.rs
index 37457bc..53c1bcb 100644
--- a/src/rust/uwb_core/src/uci/timeout_uci_hal.rs
+++ b/src/rust/uwb_core/src/uci/timeout_uci_hal.rs
@@ -25,7 +25,8 @@
 use crate::uci::uci_hal::{UciHal, UciHalPacket};
 
 const HAL_API_TIMEOUT_MS: u64 = 1000;
-const HAL_OPEN_TIMEOUT_MS: u64 = 10000; // Extra time may be needed for starting UWB stack.
+// TODO(b/279175027): Reduce this once vendor fixes their initialization sequence.
+const HAL_OPEN_TIMEOUT_MS: u64 = 20000; // Extra time may be needed for starting UWB stack.
 
 pub(crate) struct TimeoutUciHal<T: UciHal>(T);
 
diff --git a/src/rust/uwb_core/src/uci/uci_manager.rs b/src/rust/uwb_core/src/uci/uci_manager.rs
index 5a00332..9d05224 100644
--- a/src/rust/uwb_core/src/uci/uci_manager.rs
+++ b/src/rust/uwb_core/src/uci/uci_manager.rs
@@ -26,7 +26,7 @@
     AppConfigTlv, AppConfigTlvType, CapTlv, Controlees, CoreSetConfigResponse, CountryCode,
     CreditAvailability, DeviceConfigId, DeviceConfigTlv, DeviceState, FiraComponent,
     GetDeviceInfoResponse, GroupId, MessageType, PowerStats, RawUciMessage, ResetConfig, SessionId,
-    SessionState, SessionType, SessionUpdateActiveRoundsDtTagResponse, SetAppConfigResponse,
+    SessionState, SessionType, SessionUpdateDtTagRangingRoundsResponse, SetAppConfigResponse,
     UciDataPacket, UciDataPacketHal, UpdateMulticastListAction,
 };
 use crate::params::utils::bytes_to_u64;
@@ -39,7 +39,8 @@
 use crate::uci::uci_hal::{UciHal, UciHalPacket};
 use crate::uci::uci_logger::{UciLogger, UciLoggerMode, UciLoggerWrapper};
 use crate::utils::{clean_mpsc_receiver, PinSleep};
-use uwb_uci_packets::{Packet, RawUciControlPacket, UciDefragPacket};
+use std::collections::{HashMap, VecDeque};
+use uwb_uci_packets::{Packet, RawUciControlPacket, UciDataSnd, UciDefragPacket};
 
 const UCI_TIMEOUT_MS: u64 = 800;
 const MAX_RETRY_COUNT: usize = 3;
@@ -107,12 +108,12 @@
         controlees: Controlees,
     ) -> Result<()>;
 
-    // Update active ranging rounds update for DT
-    async fn session_update_active_rounds_dt_tag(
+    // Update ranging rounds for DT Tag
+    async fn session_update_dt_tag_ranging_rounds(
         &self,
         session_id: u32,
         ranging_round_indexes: Vec<u8>,
-    ) -> Result<SessionUpdateActiveRoundsDtTagResponse>;
+    ) -> Result<SessionUpdateDtTagRangingRoundsResponse>;
 
     async fn session_query_max_data_size(&self, session_id: SessionId) -> Result<u16>;
 
@@ -149,17 +150,6 @@
 #[derive(Clone)]
 pub struct UciManagerImpl {
     cmd_sender: mpsc::UnboundedSender<(UciManagerCmd, oneshot::Sender<Result<UciResponse>>)>,
-    // Store a sender for sending a oneshot channel sender "data_transfer_status_ntf_sender". This
-    // is done once for each DataSnd packet, before sending it's fragments. After all the DataSnd
-    // packet fragments are sent, UciManagerImpl will wait to receive a UCI DataTransferStatusNtf
-    // packet, on the corresponding oneshot channel receiver "data_transfer_status_ntf_receiver".
-    data_transfer_status_oneshot_sender:
-        mpsc::UnboundedSender<oneshot::Sender<SessionNotification>>,
-    // Store a sender for sending a tuple of DataSnd packet fragment (which should be written to
-    // the HAL), a oneshot channel sender to send back the UCI DataCreditNtf for that DataSnd
-    // packet fragment.
-    data_packet_fragment_sender:
-        mpsc::UnboundedSender<(UciDataPacketHal, oneshot::Sender<SessionNotification>)>,
 }
 
 impl UciManagerImpl {
@@ -170,21 +160,10 @@
         logger_mode: UciLoggerMode,
     ) -> Self {
         let (cmd_sender, cmd_receiver) = mpsc::unbounded_channel();
-        let (data_transfer_status_oneshot_sender, data_transfer_status_oneshot_receiver) =
-            mpsc::unbounded_channel();
-        let (data_packet_fragment_sender, data_packet_fragment_receiver) =
-            mpsc::unbounded_channel();
-        let mut actor = UciManagerActor::new(
-            hal,
-            logger,
-            logger_mode,
-            cmd_receiver,
-            data_transfer_status_oneshot_receiver,
-            data_packet_fragment_receiver,
-        );
+        let mut actor = UciManagerActor::new(hal, logger, logger_mode, cmd_receiver);
         tokio::spawn(async move { actor.run().await });
 
-        Self { cmd_sender, data_transfer_status_oneshot_sender, data_packet_fragment_sender }
+        Self { cmd_sender }
     }
 
     // Send the |cmd| to the UciManagerActor.
@@ -397,14 +376,14 @@
         }
     }
 
-    async fn session_update_active_rounds_dt_tag(
+    async fn session_update_dt_tag_ranging_rounds(
         &self,
         session_id: u32,
         ranging_round_indexes: Vec<u8>,
-    ) -> Result<SessionUpdateActiveRoundsDtTagResponse> {
-        let cmd = UciCommand::SessionUpdateActiveRoundsDtTag { session_id, ranging_round_indexes };
+    ) -> Result<SessionUpdateDtTagRangingRoundsResponse> {
+        let cmd = UciCommand::SessionUpdateDtTagRangingRounds { session_id, ranging_round_indexes };
         match self.send_cmd(UciManagerCmd::SendUciCommand { cmd }).await {
-            Ok(UciResponse::SessionUpdateActiveRoundsDtTag(resp)) => resp,
+            Ok(UciResponse::SessionUpdateDtTagRangingRounds(resp)) => resp,
             Ok(_) => Err(Error::Unknown),
             Err(e) => Err(e),
         }
@@ -494,7 +473,7 @@
         );
         let dest_mac_address =
             bytes_to_u64(dest_mac_address_bytes).ok_or(Error::BadParameters).unwrap();
-        let data_packet = uwb_uci_packets::UciDataSndBuilder {
+        let data_snd_packet = uwb_uci_packets::UciDataSndBuilder {
             session_id,
             dest_mac_address,
             dest_fira_component,
@@ -503,82 +482,11 @@
         }
         .build();
 
-        // We don't expect any other Data Packet Tx to be in progress when we come here.
-        //
-        // Create a oneshot channel to receive the DataTransferStatusNtf packet, and send the
-        // "sender" end of the channel to the UciManagerActor.
-        let (data_transfer_status_ntf_sender, data_transfer_status_ntf_receiver) =
-            oneshot::channel();
-        match self.data_transfer_status_oneshot_sender.send(data_transfer_status_ntf_sender) {
-            Ok(()) => {}
-            Err(e) => {
-                error!(
-                    "Error {} in sending a data_transfer_status_oneshot_sender for UCI Data packet\
-                     session_id {}, sequence_number {}",
-                    e, session_id, uci_sequence_number
-                );
-                return Err(Error::PacketTxError);
-            }
+        match self.send_cmd(UciManagerCmd::SendUciData { data_snd_packet }).await {
+            Ok(UciResponse::SendUciData(resp)) => resp,
+            Ok(_) => Err(Error::Unknown),
+            Err(e) => Err(e),
         }
-
-        // We expect data Credit should be available when we start here, for all UWB Sessions as:
-        // - it's available by default for a UWB Session when it becomes active, and,
-        // - Data packet send completed for earlier packets only after the host received both
-        //   DATA_TRANSFER_STATUS and DATA_CREDIT notifications for them. The latter would have
-        //   indicated credit availability for the UWB session.
-        //
-        // TODO(b/261886903): Use a Map<SessionId, CreditAvailability> to explicitly confirm
-        // credit availability here (before sending any data packet fragment). The map should also
-        // be updated (in handle_notification()), when UWBS unilaterally sends a DATA_CREDIT_NTF.
-        let data_packet_session_id = data_packet.get_session_id();
-        let fragmented_packets: Vec<UciDataPacketHal> = data_packet.into();
-        for packet in fragmented_packets.into_iter() {
-            let (data_credit_ntf_sender, data_credit_ntf_receiver) = oneshot::channel();
-
-            match self.data_packet_fragment_sender.send((packet, data_credit_ntf_sender)) {
-                Ok(()) => {
-                    // Wait to receive a DATA_CREDIT_NTF from UWBS. This indicates that the
-                    // data packet fragment was received and Host can send the next fragment.
-                    let result = data_credit_ntf_receiver.await;
-                    if result.is_err() {
-                        error!("DataCreditNtf oneshot sender is dropped.");
-                        return Err(Error::PacketTxError);
-                    }
-
-                    if let SessionNotification::DataCredit { session_id, credit_availability } =
-                        result.unwrap()
-                    {
-                        if session_id != data_packet_session_id {
-                            error!(
-                                "Received Data Credit NTF for sessionID {}, was expected for \
-                                   sessionID {}",
-                                session_id, data_packet_session_id
-                            );
-                            return Err(Error::PacketTxError);
-                        }
-                        if credit_availability != CreditAvailability::CreditAvailable {
-                            error!("Received Data Credit NTF with no availability.");
-                            return Err(Error::PacketTxError);
-                        }
-                    }
-                }
-                Err(e) => {
-                    error!(
-                        "Failed to send data packet fragment - got error{} for \
-                        uci_sequence_number: {}, session_id: {}",
-                        e, uci_sequence_number, session_id
-                    );
-                    return Err(Error::PacketTxError);
-                }
-            }
-        }
-
-        let result = data_transfer_status_ntf_receiver.await;
-        if result.is_err() {
-            error!("DataTransferStatusNtf oneshot sender is dropped.");
-            return Err(Error::PacketTxError);
-        }
-        Ok(())
     }
 }
 
@@ -590,18 +498,6 @@
     // Receive the commands and the corresponding response senders from UciManager.
     cmd_receiver: mpsc::UnboundedReceiver<(UciManagerCmd, oneshot::Sender<Result<UciResponse>>)>,
 
-    // Receive the oneshot channel sender, for sending back the expected DataTransferStatusNtf
-    // packet, after sending all the Data packet fragments is completed. This receiver is used
-    // to read the "data_transfer_status_ntf_sender" from UciManager, which is required once
-    // for every Tx data packet.
-    data_transfer_status_oneshot_receiver:
-        mpsc::UnboundedReceiver<oneshot::Sender<SessionNotification>>,
-
-    // Receive Data packet fragment(s) (to be sent to UWBS) and the corresponding DataCreditNtf
-    // sender, from the UciManager.
-    data_packet_fragment_receiver:
-        mpsc::UnboundedReceiver<(UciDataPacketHal, oneshot::Sender<SessionNotification>)>,
-
     // Set to true when |hal| is opened successfully.
     is_hal_opened: bool,
     // Receive response, notification and data packets from |hal|. Only used when |hal| is opened
@@ -614,21 +510,28 @@
     // notification.
     open_hal_result_sender: Option<oneshot::Sender<Result<UciResponse>>>,
 
-    // Store the senders for the Data packet send UWBS notifications. These send back the received
-    // UWBS DATA_CREDIT_NTF and DATA_TRANSFER_STATUS_NTF packets back to the UciManager.
-    data_credit_ntf_sender: Option<oneshot::Sender<SessionNotification>>,
-    data_transfer_status_ntf_sender: Option<oneshot::Sender<SessionNotification>>,
+    // Store per-session CreditAvailability. This should be initialized when a UWB session becomes
+    // ACTIVE, and updated every time a Data packet fragment is sent or a DataCreditNtf is received.
+    data_credit_map: HashMap<SessionId, CreditAvailability>,
+
+    // Store the Uci Data packet fragments to be sent to the UWBS, keyed by the SessionId. This
+    // helps to retrieve the next packet fragment to be sent, when the UWBS is ready to accept it.
+    data_packet_fragments_map: HashMap<SessionId, VecDeque<UciDataPacketHal>>,
 
     // The timeout of waiting for the notification of device ready notification.
     wait_device_status_timeout: PinSleep,
 
     // Used for the logic of retrying the command. Only valid when waiting for the response of a
     // UCI command.
-    retryer: Option<Retryer>,
+    uci_cmd_retryer: Option<UciCmdRetryer>,
     // The timeout of waiting for the response. Only used when waiting for the response of a UCI
     // command.
     wait_resp_timeout: PinSleep,
 
+    // Used for the logic of retrying the DataSnd packet. Only valid when waiting for the
+    // DATA_TRANSFER_STATUS_NTF.
+    uci_data_snd_retryer: Option<UciDataSndRetryer>,
+
     // Used to identify if response corresponds to the last vendor command, if so return
     // a raw packet as a response to the sender.
     last_raw_cmd: Option<RawUciControlPacket>,
@@ -649,28 +552,20 @@
             UciManagerCmd,
             oneshot::Sender<Result<UciResponse>>,
         )>,
-        data_transfer_status_oneshot_receiver: mpsc::UnboundedReceiver<
-            oneshot::Sender<SessionNotification>,
-        >,
-        data_packet_fragment_receiver: mpsc::UnboundedReceiver<(
-            UciDataPacketHal,
-            oneshot::Sender<SessionNotification>,
-        )>,
     ) -> Self {
         Self {
             hal: TimeoutUciHal::new(hal),
             logger: UciLoggerWrapper::new(logger, logger_mode),
             cmd_receiver,
-            data_transfer_status_oneshot_receiver,
-            data_packet_fragment_receiver,
             is_hal_opened: false,
             packet_receiver: mpsc::unbounded_channel().1,
             defrager: Default::default(),
             open_hal_result_sender: None,
-            data_credit_ntf_sender: None,
-            data_transfer_status_ntf_sender: None,
+            data_credit_map: HashMap::new(),
+            data_packet_fragments_map: HashMap::new(),
             wait_device_status_timeout: PinSleep::new(Duration::MAX),
-            retryer: None,
+            uci_cmd_retryer: None,
+            uci_data_snd_retryer: None,
             wait_resp_timeout: PinSleep::new(Duration::MAX),
             last_raw_cmd: None,
             core_notf_sender: mpsc::unbounded_channel().0,
@@ -697,54 +592,6 @@
                     }
                 }
 
-                // Listen for and store a oneshot channel sender, for sending back a
-                // DataTransferStatusNtf to the UciManager. This is required once for each Data
-                // Tx packet (and is the first step in being ready to send it).
-                //
-                // The additional check confirms there is currently no stored oneshot channel
-                // sender, which also acts as a flow control mechanism (between UciManager and
-                // UciManagerActor).
-                channel_sender = self.data_transfer_status_oneshot_receiver.recv(),
-                    if !self.is_waiting_data_packet_send_status() => {
-                    match channel_sender {
-                        Some(data_transfer_status_ntf_sender) => {
-                            self.data_transfer_status_ntf_sender = Some(data_transfer_status_ntf_sender);
-                        }
-                        None => {
-                            error!("Unexpected error as no data transfer status sender received\
-                                   from UciManager");
-                        }
-                    }
-                }
-
-                // Handle a data packet - this is to be sent from the Host to UWBS. Listen for a
-                // data packet only after receiving the oneshot sender on which the
-                // DataTransferStatusNtf can be sent back.
-                data = self.data_packet_fragment_receiver.recv(),
-                    if self.is_waiting_data_packet_send_status() => {
-                    match data {
-                        Some((data_packet_fragment, data_credit_ntf_sender)) => {
-                            self.data_credit_ntf_sender = Some(data_credit_ntf_sender);
-                            let result = self.hal.send_packet(data_packet_fragment.to_vec()).await;
-                            if result.is_err() {
-                                error!("Result {:?} in sending data packet to HAL", result);
-                                if self.data_credit_ntf_sender.is_some() {
-                                    drop(self.data_credit_ntf_sender.take());
-                                }
-                                if self.data_transfer_status_ntf_sender.is_some() {
-                                    drop(self.data_transfer_status_ntf_sender.take());
-                                }
-                            }
-                        },
-                        None => {
-                            error!("Unexpected error as no data packet to send from UciManager");
-                            if self.data_transfer_status_ntf_sender.is_some() {
-                                drop(self.data_transfer_status_ntf_sender.take());
-                            }
-                        }
-                    }
-                }
-
                 // Handle the UCI response, notification or data packet from HAL. Only when HAL
                 // is opened.
                 packet = self.packet_receiver.recv(), if self.is_hal_opened => {
@@ -753,7 +600,7 @@
 
                 // Timeout waiting for the response of the UCI command.
                 _ = &mut self.wait_resp_timeout, if self.is_waiting_resp() => {
-                    self.retryer.take().unwrap().send_result(Err(Error::Timeout));
+                    self.uci_cmd_retryer.take().unwrap().send_result(Err(Error::Timeout));
                 }
 
                 // Timeout waiting for the notification of the device status.
@@ -848,7 +695,7 @@
             }
 
             UciManagerCmd::SendUciCommand { cmd } => {
-                debug_assert!(self.retryer.is_none());
+                debug_assert!(self.uci_cmd_retryer.is_none());
 
                 // Remember that this command is a raw UCI command, we'll use this later
                 // to send a raw UCI response.
@@ -874,26 +721,59 @@
                     });
                 }
 
-                self.retryer = Some(Retryer { cmd, result_sender, retry_count: MAX_RETRY_COUNT });
-                self.retry_command().await;
+                self.uci_cmd_retryer =
+                    Some(UciCmdRetryer { cmd, result_sender, retry_count: MAX_RETRY_COUNT });
+                self.retry_uci_cmd().await;
+            }
+
+            UciManagerCmd::SendUciData { data_snd_packet } => {
+                let result = self.handle_data_snd_packet(data_snd_packet).await;
+                let _ = result_sender.send(result);
             }
         }
     }
 
-    async fn retry_command(&mut self) {
-        if let Some(mut retryer) = self.retryer.take() {
-            if !retryer.could_retry() {
-                retryer.send_result(Err(Error::Timeout));
+    async fn retry_uci_cmd(&mut self) {
+        if let Some(mut uci_cmd_retryer) = self.uci_cmd_retryer.take() {
+            if !uci_cmd_retryer.could_retry() {
+                error!("Out of retries for Uci Cmd packet");
+                uci_cmd_retryer.send_result(Err(Error::Timeout));
                 return;
             }
 
-            match self.send_uci_command(retryer.cmd.clone()).await {
+            match self.send_uci_command(uci_cmd_retryer.cmd.clone()).await {
                 Ok(_) => {
                     self.wait_resp_timeout = PinSleep::new(Duration::from_millis(UCI_TIMEOUT_MS));
-                    self.retryer = Some(retryer);
+                    self.uci_cmd_retryer = Some(uci_cmd_retryer);
                 }
                 Err(e) => {
-                    retryer.send_result(Err(e));
+                    error!("Uci Cmd send resulted in error:{}", e);
+                    uci_cmd_retryer.send_result(Err(e));
+                }
+            }
+        }
+    }
+
+    async fn retry_uci_data_snd(&mut self) {
+        if let Some(mut uci_data_snd_retryer) = self.uci_data_snd_retryer.take() {
+            let data_packet_session_id = uci_data_snd_retryer.data_packet_session_id;
+            if !uci_data_snd_retryer.could_retry() {
+                error!(
+                    "Out of retries for Uci DataSnd packet, last DataSnd packet session_id:{}",
+                    data_packet_session_id
+                );
+                return;
+            }
+
+            match self.hal.send_packet(uci_data_snd_retryer.data_packet.clone().to_vec()).await {
+                Ok(_) => {
+                    self.uci_data_snd_retryer = Some(uci_data_snd_retryer);
+                }
+                Err(e) => {
+                    error!(
+                        "DataSnd packet fragment session_id:{} retry failed with error:{}",
+                        data_packet_session_id, e
+                    );
                 }
             }
         }
@@ -911,6 +791,106 @@
         result
     }
 
+    async fn handle_data_snd_packet(&mut self, data_snd_packet: UciDataSnd) -> Result<UciResponse> {
+        // Verify that there's an entry for the Session in the CreditAvailability map.
+        let data_packet_session_id = data_snd_packet.get_session_id();
+        let data_packet_sequence_number = data_snd_packet.get_uci_sequence_number();
+
+        if !self.data_credit_map.contains_key(&data_packet_session_id) {
+            error!(
+                "DataSnd packet session_id:{}, sequence_number:{} cannot be sent as unknown \
+                credit availability for the session",
+                data_packet_session_id, data_packet_sequence_number
+            );
+            return Err(Error::PacketTxError);
+        }
+
+        // Enqueue the data packet fragments, from the data packet to be sent to UWBS.
+        let mut packet_fragments: Vec<UciDataPacketHal> = data_snd_packet.into();
+        if packet_fragments.is_empty() {
+            error!(
+                "DataSnd packet session_id:{}, sequence number:{} could not be split into fragments",
+                data_packet_session_id, data_packet_sequence_number
+            );
+            return Err(Error::PacketTxError);
+        }
+
+        match self.data_packet_fragments_map.get_mut(&data_packet_session_id) {
+            Some(q) => {
+                for p in packet_fragments.drain(..) {
+                    q.push_back(p);
+                }
+            }
+            None => {
+                error!(
+                    "DataSnd packet fragments map not found for session_id:{}",
+                    data_packet_session_id
+                );
+                return Err(Error::PacketTxError);
+            }
+        }
+
+        self.send_data_packet_fragment(data_packet_session_id).await
+    }
+
+    async fn send_data_packet_fragment(
+        &mut self,
+        data_packet_session_id: SessionId,
+    ) -> Result<UciResponse> {
+        // Check if a credit is available before sending this data packet fragment. If not, return
+        // for now, and send this packet later when the credit becomes available (indicated by
+        // receiving a DataCreditNtf).
+        let credit = self.data_credit_map.get(&data_packet_session_id);
+        if credit.is_none() {
+            error!(
+                "DataSnd packet fragment cannot be sent for session_id:{} as unknown \
+                credit availability for the session",
+                data_packet_session_id
+            );
+            return Err(Error::PacketTxError);
+        }
+        if credit == Some(&CreditAvailability::CreditNotAvailable) {
+            return Ok(UciResponse::SendUciData(Ok(())));
+        }
+
+        // We have credit available, let's send the packet to UWBS.
+        let hal_data_packet_fragment =
+            match self.data_packet_fragments_map.get_mut(&data_packet_session_id) {
+                Some(q) => {
+                    match q.pop_front() {
+                        Some(p) => p,
+                        None => {
+                            // No more packets left to send.
+                            return Ok(UciResponse::SendUciData(Ok(())));
+                        }
+                    }
+                }
+                None => {
+                    return Err(Error::PacketTxError);
+                }
+            };
+
+        // Create and save a retryer for sending this data packet fragment.
+        self.uci_data_snd_retryer = Some(UciDataSndRetryer {
+            data_packet: hal_data_packet_fragment.clone(),
+            data_packet_session_id,
+            retry_count: MAX_RETRY_COUNT,
+        });
+
+        let result = self.hal.send_packet(hal_data_packet_fragment.to_vec()).await;
+        if result.is_err() {
+            error!(
+                "Result {:?} of sending data packet fragment SessionId: {} to HAL",
+                result, data_packet_session_id
+            );
+            return Err(Error::PacketTxError);
+        }
+
+        // Update the map after the successful write.
+        self.data_credit_map.insert(data_packet_session_id, CreditAvailability::CreditNotAvailable);
+        Ok(UciResponse::SendUciData(Ok(())))
+    }
+
     async fn handle_hal_packet(&mut self, packet: Option<UciHalPacket>) {
         let defrag_packet = match packet {
             Some(rx_packet) => {
@@ -971,12 +951,12 @@
 
     async fn handle_response(&mut self, resp: UciResponse) {
         if resp.need_retry() {
-            self.retry_command().await;
+            self.retry_uci_cmd().await;
             return;
         }
 
-        if let Some(retryer) = self.retryer.take() {
-            retryer.send_result(Ok(resp));
+        if let Some(uci_cmd_retryer) = self.uci_cmd_retryer.take() {
+            uci_cmd_retryer.send_result(Ok(resp));
         } else {
             warn!("Received an UCI response unexpectedly: {:?}", resp);
         }
@@ -984,7 +964,10 @@
 
     async fn handle_notification(&mut self, notf: UciNotification) {
         if notf.need_retry() {
-            self.retry_command().await;
+            // Retry sending both last sent UCI CMD and UCI DataSnd packet since the notification
+            // could be for either of them.
+            self.retry_uci_cmd().await;
+            self.retry_uci_data_snd().await;
             return;
         }
 
@@ -1004,51 +987,49 @@
                 let _ = self.core_notf_sender.send(core_notf);
             }
             UciNotification::Session(session_notf) => {
-                if let SessionNotification::Status {
-                    session_id,
-                    session_state: SessionState::SessionStateInit,
-                    reason_code: _,
-                } = session_notf
-                {
-                    if let Err(e) = self.hal.notify_session_initialized(session_id).await {
-                        warn!("notify_session_initialized() failed: {:?}", e);
-                    }
-                }
-                if let SessionNotification::DataCredit { session_id, credit_availability: _ } =
+                if let SessionNotification::Status { session_id, session_state, reason_code: _ } =
                     session_notf
                 {
-                    if let Some(data_credit_ntf_sender) = self.data_credit_ntf_sender.take() {
-                        let _ = data_credit_ntf_sender.send(session_notf);
-                    } else {
+                    self.handle_session_state_notification(session_id, session_state).await;
+                }
+                if let SessionNotification::DataCredit { session_id, credit_availability } =
+                    session_notf
+                {
+                    if !self.data_credit_map.contains_key(&session_id) {
+                        // Currently just log, as this is unexpected (the entry should exist once
+                        // the ranging session is Active and be removed once it is Idle).
                         debug!(
-                            "No data_credit_ntf_sender present, when received DataCreditNtf for\
-                               session_id {}",
+                            "Received a DataCreditNtf for non-existent session_id: {}",
+                            session_id
+                        );
+                    }
+                    self.data_credit_map.insert(session_id, credit_availability);
+                    if credit_availability == CreditAvailability::CreditAvailable {
+                        if let Err(e) = self.send_data_packet_fragment(session_id).await {
+                            error!(
+                                "Sending data packet fragment failed with Err:{}, after a\
+                                   DataCreditNtf is received, for sessionId:{}",
+                                e, session_id
+                            );
+                        }
+                    } else {
+                        // Log as this should usually not happen (it's not an error).
+                        debug!(
+                            "Received a DataCreditNtf with no credit available for session_id:{}",
                             session_id
                         );
                     }
                     return; // We consume these here and don't need to send to upper layer.
                 }
                 if let SessionNotification::DataTransferStatus {
-                    session_id,
-                    uci_sequence_number,
-                    status,
+                    session_id: _,
+                    uci_sequence_number: _,
+                    status: _,
                 } = session_notf
                 {
-                    if let Some(data_transfer_status_ntf_sender) =
-                        self.data_transfer_status_ntf_sender.take()
-                    {
-                        let _ = data_transfer_status_ntf_sender.send(session_notf);
-                    } else {
-                        debug!(
-                            "No data_transfer_status_ntf_sender present, when received a \
-                               DataTransferStatusNtf with session_id {}, UCI sequence number {},\
-                                status {:?}",
-                            session_id, uci_sequence_number, status
-                        );
-                    }
-                    return; // We consume these here and don't need to send to upper layer.
+                    // Reset the UciDataSnd Retryer since we received a DataTransferStatusNtf.
+                    let _ = self.uci_data_snd_retryer.take();
                 }
-
                 let _ = self.session_notf_sender.send(session_notf);
             }
             UciNotification::Vendor(vendor_notf) => {
@@ -1057,6 +1038,29 @@
         }
     }
 
+    async fn handle_session_state_notification(
+        &mut self,
+        session_id: SessionId,
+        session_state: SessionState,
+    ) {
+        match session_state {
+            SessionState::SessionStateInit => {
+                if let Err(e) = self.hal.notify_session_initialized(session_id).await {
+                    warn!("notify_session_initialized() failed: {:?}", e);
+                }
+            }
+            SessionState::SessionStateActive => {
+                self.data_credit_map.insert(session_id, CreditAvailability::CreditAvailable);
+                self.data_packet_fragments_map.insert(session_id, VecDeque::new());
+            }
+            SessionState::SessionStateIdle => {
+                self.data_credit_map.remove(&session_id);
+                self.data_packet_fragments_map.remove(&session_id);
+            }
+            _ => {}
+        }
+    }
+
     fn handle_data_rcv(&mut self, packet: UciDataPacket) {
         match packet.try_into() {
             Ok(data_rcv) => {
@@ -1080,14 +1084,11 @@
     }
 
     fn is_waiting_resp(&self) -> bool {
-        self.retryer.is_some()
+        self.uci_cmd_retryer.is_some()
     }
     fn is_waiting_device_status(&self) -> bool {
         self.open_hal_result_sender.is_some()
     }
-    fn is_waiting_data_packet_send_status(&self) -> bool {
-        self.data_transfer_status_ntf_sender.is_some()
-    }
 }
 
 impl<T: UciHal, U: UciLogger> Drop for UciManagerActor<T, U> {
@@ -1097,13 +1098,13 @@
     }
 }
 
-struct Retryer {
+struct UciCmdRetryer {
     cmd: UciCommand,
     result_sender: oneshot::Sender<Result<UciResponse>>,
     retry_count: usize,
 }
 
-impl Retryer {
+impl UciCmdRetryer {
     fn could_retry(&mut self) -> bool {
         if self.retry_count == 0 {
             return false;
@@ -1117,6 +1118,28 @@
     }
 }
 
+struct UciDataSndRetryer {
+    // Store the last-sent DataSnd packet fragment across all the active UWB session, as the UCI
+    // spec states that the "last UCI packet should be re-transmitted from Host".
+    //
+    // TODO(b/273376343): The spec is open to a race condition in the scenario of multiple active
+    // sessions, as there can be outstanding DataSnd packet fragments across them. We could do an
+    // alternative implementation of sending all of them.
+    data_packet: UciDataPacketHal,
+    data_packet_session_id: u32,
+    retry_count: usize,
+}
+
+impl UciDataSndRetryer {
+    fn could_retry(&mut self) -> bool {
+        if self.retry_count == 0 {
+            return false;
+        }
+        self.retry_count -= 1;
+        true
+    }
+}
+
 #[derive(Debug)]
 enum UciManagerCmd {
     SetLoggerMode {
@@ -1141,6 +1164,9 @@
     SendUciCommand {
         cmd: UciCommand,
     },
+    SendUciData {
+        data_snd_packet: UciDataSnd,
+    },
 }
 
 #[cfg(test)]
@@ -1159,8 +1185,6 @@
     use crate::uci::uci_logger::NopUciLogger;
     use crate::utils::init_test_logging;
 
-    // TODO(b/261886903): Check if this should be in a common library file as same function
-    // is defined in uci_hal_android.rs also.
     fn into_uci_hal_packets<T: Into<uwb_uci_packets::UciControlPacket>>(
         builder: T,
     ) -> Vec<UciHalPacket> {
@@ -1636,20 +1660,20 @@
     }
 
     #[tokio::test]
-    async fn test_set_active_ranging_rounds_dt_tag() {
-        let ranging_rounds = SessionUpdateActiveRoundsDtTagResponse {
+    async fn test_set_active_dt_tag_ranging_rounds() {
+        let ranging_rounds = SessionUpdateDtTagRangingRoundsResponse {
             status: StatusCode::UciStatusErrorRoundIndexNotActivated,
             ranging_round_indexes: vec![3],
         };
 
         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
             move |hal| {
-                let cmd = UciCommand::SessionUpdateActiveRoundsDtTag {
+                let cmd = UciCommand::SessionUpdateDtTagRangingRounds {
                     session_id: 1,
                     ranging_round_indexes: vec![3, 5],
                 };
                 let resp = into_uci_hal_packets(
-                    uwb_uci_packets::SessionUpdateActiveRoundsDtTagRspBuilder {
+                    uwb_uci_packets::SessionUpdateDtTagRangingRoundsRspBuilder {
                         status: StatusCode::UciStatusErrorRoundIndexNotActivated,
                         ranging_round_indexes: vec![3],
                     },
@@ -1662,7 +1686,7 @@
         )
         .await;
 
-        let result = uci_manager.session_update_active_rounds_dt_tag(1, vec![3, 5]).await.unwrap();
+        let result = uci_manager.session_update_dt_tag_ranging_rounds(1, vec![3, 5]).await.unwrap();
 
         assert_eq!(result, ranging_rounds);
         assert!(mock_hal.wait_expected_calls_done().await);
@@ -2147,6 +2171,28 @@
         assert!(mock_hal.wait_expected_calls_done().await);
     }
 
+    fn setup_active_session(hal: &mut MockUciHal, session_id: u32) {
+        // First setup the Session to be in Active state.
+        let cmd = UciCommand::SessionStart { session_id };
+        let mut responses = into_uci_hal_packets(uwb_uci_packets::SessionStartRspBuilder {
+            status: uwb_uci_packets::StatusCode::UciStatusOk,
+        });
+        responses.append(&mut into_uci_hal_packets(uwb_uci_packets::SessionStatusNtfBuilder {
+            session_id,
+            session_state: SessionState::SessionStateActive,
+            reason_code: 0, /* ReasonCode::StateChangeWithSessionManagementCommands */
+        }));
+        hal.expected_send_command(cmd, responses, Ok(()));
+    }
+
+    // TODO(b/276320369): Listing down the Data Packet Rx scenarios below, will add unit tests
+    // for them in subsequent CLs.
+    #[tokio::test]
+    async fn test_data_packet_recv_ok() {}
+
+    #[tokio::test]
+    async fn test_data_packet_recv_fragmented_packet_ok() {}
+
     #[tokio::test]
     async fn test_data_packet_send_ok() {
         // Test Data packet send for a single packet (on a UWB session).
@@ -2171,6 +2217,9 @@
 
         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
             move |hal| {
+                setup_active_session(hal, session_id);
+
+                // Now setup the notifications that should be received after a Data packet send.
                 let data_packet_snd =
                     build_uci_packet(mt_data, pbf, dpf, oid, expected_data_snd_payload);
                 let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder {
@@ -2191,6 +2240,9 @@
         )
         .await;
 
+        let result = uci_manager.range_start(session_id).await;
+        assert!(result.is_ok());
+
         let result = uci_manager
             .send_data_packet(
                 session_id,
@@ -2244,6 +2296,8 @@
 
         let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
             move |hal| {
+                setup_active_session(hal, session_id);
+
                 // Expected data packet fragment #1 (UCI Header + Initial App data bytes).
                 let data_packet_snd_fragment_1 = build_uci_packet(
                     mt_data,
@@ -2284,6 +2338,9 @@
         )
         .await;
 
+        let result = uci_manager.range_start(session_id).await;
+        assert!(result.is_ok());
+
         let result = uci_manager
             .send_data_packet(
                 session_id,
@@ -2297,6 +2354,80 @@
         assert!(mock_hal.wait_expected_calls_done().await);
     }
 
+    #[tokio::test]
+    async fn test_data_packet_send_retry_ok() {
+        // Test Data packet send for a single packet (on a UWB session).
+        let mt_data = 0x0;
+        let pbf = 0x0;
+        let dpf = 0x1;
+        let oid = 0x0;
+        let session_id = 0x5;
+        let dest_mac_address = vec![0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1];
+        let dest_fira_component = FiraComponent::Host;
+        let uci_sequence_number = 0xa;
+        let app_data = vec![0x01, 0x02, 0x03];
+        let expected_data_snd_payload = vec![
+            0x05, 0x00, 0x00, 0x00, // SessionID
+            0xa0, 0xb0, 0xc0, 0xd0, 0xa1, 0xb1, 0xc1, 0xd1, // MacAddress
+            0x01, // FiraComponent
+            0x0a, // UciSequenceNumber
+            0x03, 0x00, // AppDataLen
+            0x01, 0x02, 0x03, // AppData
+        ];
+        let status = DataTransferNtfStatusCode::UciDataTransferStatusRepetitionOk;
+
+        let (uci_manager, mut mock_hal) = setup_uci_manager_with_open_hal(
+            move |hal| {
+                setup_active_session(hal, session_id);
+
+                // Setup receiving a CORE_GENERIC_ERROR_NTF with STATUS_COMMAND_RETRY after a
+                // failed Data packet send attempt.
+                let data_packet_snd =
+                    build_uci_packet(mt_data, pbf, dpf, oid, expected_data_snd_payload);
+                let error_ntf = into_uci_hal_packets(uwb_uci_packets::GenericErrorBuilder {
+                    status: StatusCode::UciStatusCommandRetry,
+                });
+                hal.expected_send_packet(data_packet_snd.clone(), error_ntf, Ok(()));
+
+                // Setup the notifications that should be received after the Data packet send
+                // is successfully retried.
+                let mut ntfs = into_uci_hal_packets(uwb_uci_packets::DataCreditNtfBuilder {
+                    session_id,
+                    credit_availability: CreditAvailability::CreditAvailable,
+                });
+                ntfs.append(&mut into_uci_hal_packets(
+                    uwb_uci_packets::DataTransferStatusNtfBuilder {
+                        session_id,
+                        uci_sequence_number,
+                        status,
+                    },
+                ));
+                hal.expected_send_packet(data_packet_snd, ntfs, Ok(()));
+            },
+            UciLoggerMode::Disabled,
+            mpsc::unbounded_channel::<UciLogEvent>().0,
+        )
+        .await;
+
+        let result = uci_manager.range_start(session_id).await;
+        assert!(result.is_ok());
+
+        let result = uci_manager
+            .send_data_packet(
+                session_id,
+                dest_mac_address,
+                dest_fira_component,
+                uci_sequence_number,
+                app_data,
+            )
+            .await;
+        assert!(result.is_ok());
+        assert!(mock_hal.wait_expected_calls_done().await);
+
+        // TODO(b/276320369): Verify that session_notf_sender is called (once implemented), as a
+        // DataTransferStatusNtf is received in this test scenario.
+    }
+
     // TODO(b/276320369): Listing down the Data Packet Tx scenarios below, will add unit tests
     // for them in subsequent CLs.
 
diff --git a/src/rust/uwb_core/src/uci/uci_manager_sync.rs b/src/rust/uwb_core/src/uci/uci_manager_sync.rs
index 971687e..0c62959 100644
--- a/src/rust/uwb_core/src/uci/uci_manager_sync.rs
+++ b/src/rust/uwb_core/src/uci/uci_manager_sync.rs
@@ -28,7 +28,7 @@
 use crate::params::{
     AppConfigTlv, AppConfigTlvType, CapTlv, CoreSetConfigResponse, CountryCode, DeviceConfigId,
     DeviceConfigTlv, FiraComponent, GetDeviceInfoResponse, PowerStats, RawUciMessage, ResetConfig,
-    SessionId, SessionState, SessionType, SessionUpdateActiveRoundsDtTagResponse,
+    SessionId, SessionState, SessionType, SessionUpdateDtTagRangingRoundsResponse,
     SetAppConfigResponse, UpdateMulticastListAction,
 };
 #[cfg(any(test, feature = "mock-utils"))]
@@ -295,14 +295,15 @@
         )
     }
 
-    /// Update active ranging rounds update for DT
-    pub fn session_update_active_rounds_dt_tag(
+    /// Update ranging rounds for DT Tag
+    pub fn session_update_dt_tag_ranging_rounds(
         &self,
         session_id: u32,
         ranging_round_indexes: Vec<u8>,
-    ) -> Result<SessionUpdateActiveRoundsDtTagResponse> {
+    ) -> Result<SessionUpdateDtTagRangingRoundsResponse> {
         self.runtime_handle.block_on(
-            self.uci_manager.session_update_active_rounds_dt_tag(session_id, ranging_round_indexes),
+            self.uci_manager
+                .session_update_dt_tag_ranging_rounds(session_id, ranging_round_indexes),
         )
     }
 
diff --git a/src/rust/uwb_uci_packets/uci_packets.pdl b/src/rust/uwb_uci_packets/uci_packets.pdl
index 9be6f24..edec9a7 100644
--- a/src/rust/uwb_uci_packets/uci_packets.pdl
+++ b/src/rust/uwb_uci_packets/uci_packets.pdl
@@ -405,7 +405,10 @@
     ERROR_REF_UWB_SESSION_RANGING_DURATION_MISMATCH = 0x3D,
     ERROR_REF_UWB_SESSION_INVALID_OFFSET_TIME = 0x3E,
     ERROR_REF_UWB_SESSION_LOST = 0x3F,
-    RFU_REASON_CODE_RANGE_2 = 0x40..0x7F,
+    RFU_REASON_CODE_RANGE_2 = 0x40..0x7F {
+        ERROR_DT_ANCHOR_RANGING_ROUNDS_NOT_CONFIGURED = 0x40,
+        ERROR_DT_TAG_RANGING_ROUNDS_NOT_CONFIGURED = 0x41,
+    },
     VENDOR_SPECIFIC_REASON_CODE_RANGE_1 = 0x80..0xFE {
         ERROR_INVALID_CHANNEL_WITH_AOA = 0x80,
         ERROR_STOPPED_DUE_TO_OTHER_SESSION_CONFLICT = 0x81,
@@ -849,23 +852,23 @@
     "\x41\x06\x00\x02\x00\x00\x00\x00\x01",
 }
 
-packet SessionUpdateActiveRoundsDtTagCmd : SessionConfigCommand (opcode = 0x9) { //SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG
+packet SessionUpdateDtTagRangingRoundsCmd : SessionConfigCommand (opcode = 0x9) { //SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG
     session_id: 32,
     _count_(ranging_round_indexes): 8,
     ranging_round_indexes: 8[],
 }
 
-test SessionUpdateActiveRoundsDtTagCmd {
+test SessionUpdateDtTagRangingRoundsCmd {
     "\x21\x09\x00\x0a\x00\x00\x00\x03\x03\x0f\x0c\x05\x08\x00\x00\x00\x00",
 }
 
-packet SessionUpdateActiveRoundsDtTagRsp : SessionConfigResponse (opcode = 0x9) { //SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG
+packet SessionUpdateDtTagRangingRoundsRsp : SessionConfigResponse (opcode = 0x9) { //SESSION_UPDATE_ACTIVE_ROUNDS_DT_TAG
     status: StatusCode,
     _count_(ranging_round_indexes): 8,
     ranging_round_indexes: 8[],
 }
 
-test SessionUpdateActiveRoundsDtTagRsp {
+test SessionUpdateDtTagRangingRoundsRsp {
     "\x41\x09\x00\x03\x00\x00\x00\x01\x01\x01",
 }
 
@@ -952,7 +955,7 @@
     session_id: 32,
     uci_sequence_number: 8,
     status: DataTransferNtfStatusCode,
-    // TODO(b/261886903): Add the tx_count field for implementing the DATA_REPETITION added in CR490.
+    // TODO(b/269779288): Add the tx_count field for implementing the DATA_REPETITION added in CR490.
 }
 
 test DataTransferStatusNtf {