[uwb] Support updateMulticastListNtf for both Fira 1.x and 2.0.

patched from aosp/3018363

Bug: 331836038
Test: manual
Change-Id: I121c9e527d1e94d63c8be6da2512bd7f75d26275
diff --git a/src/rust/uwb_core/src/params/uci_packets.rs b/src/rust/uwb_core/src/params/uci_packets.rs
index 6f42e3b..8ccb0ce 100644
--- a/src/rust/uwb_core/src/params/uci_packets.rs
+++ b/src/rust/uwb_core/src/params/uci_packets.rs
@@ -18,19 +18,22 @@
 use std::collections::{hash_map::RandomState, HashMap};
 use std::iter::FromIterator;
 
+use num_derive::{FromPrimitive, ToPrimitive};
+
 // Re-export enums and structs from uwb_uci_packets.
 pub use uwb_uci_packets::{
     AppConfigStatus, AppConfigTlv as RawAppConfigTlv, AppConfigTlvType, BitsPerSample, CapTlv,
-    CapTlvType, Controlee, ControleePhaseList, ControleeStatus, Controlees, CreditAvailability,
-    DataRcvStatusCode, DataTransferNtfStatusCode, DataTransferPhaseConfigUpdateStatusCode,
-    DeviceConfigId, DeviceConfigStatus, DeviceConfigTlv, DeviceState,
-    ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement,
-    ExtendedAddressTwoWayRangingMeasurement, GroupId, MacAddressIndicator,
-    MessageType, MulticastUpdateStatusCode, PhaseList, PowerStats, RadarConfigStatus,
-    RadarConfigTlv, RadarConfigTlvType, RadarDataType, RangingMeasurementType, ReasonCode,
-    ResetConfig, SessionState, SessionType, ShortAddressDlTdoaRangingMeasurement,
-    ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement,
-    StatusCode, UpdateMulticastListAction,
+    CapTlvType, Controlee, ControleePhaseList, ControleeStatusV1, ControleeStatusV2, Controlees,
+    CreditAvailability, DataRcvStatusCode, DataTransferNtfStatusCode,
+    DataTransferPhaseConfigUpdateStatusCode, DeviceConfigId, DeviceConfigStatus, DeviceConfigTlv,
+    DeviceState, ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement,
+    ExtendedAddressTwoWayRangingMeasurement, GroupId, MacAddressIndicator, MessageType,
+    MulticastUpdateStatusCode, PhaseList, PowerStats, RadarConfigStatus, RadarConfigTlv,
+    RadarConfigTlvType, RadarDataType, RangingMeasurementType, ReasonCode, ResetConfig,
+    SessionState, SessionType, SessionUpdateControllerMulticastListNtfV1Payload,
+    SessionUpdateControllerMulticastListNtfV2Payload, ShortAddressDlTdoaRangingMeasurement,
+    ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode,
+    UpdateMulticastListAction,
 };
 pub(crate) use uwb_uci_packets::{UciControlPacket, UciDataPacket, UciDataPacketHal};
 
@@ -51,6 +54,24 @@
     tlv: RawAppConfigTlv,
 }
 
+/// Controlee Status Enum compatible with different Fira version.
+pub enum ControleeStatusList {
+    /// Controlee status defined in Fira 1.x.
+    V1(Vec<ControleeStatusV1>),
+    /// Controlee status defined in Fira 2.0.
+    V2(Vec<ControleeStatusV2>),
+}
+
+/// UCI major version
+#[derive(FromPrimitive, ToPrimitive, PartialEq, Clone)]
+#[repr(u8)]
+pub enum UCIMajorVersion {
+    /// Version 1.x
+    V1 = 1,
+    /// Version 2.0
+    V2 = 2,
+}
+
 impl std::fmt::Debug for AppConfigTlv {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
         static REDACTED_STR: &str = "redacted";
diff --git a/src/rust/uwb_core/src/session/session_manager.rs b/src/rust/uwb_core/src/session/session_manager.rs
index 40801fa..5436747 100644
--- a/src/rust/uwb_core/src/session/session_manager.rs
+++ b/src/rust/uwb_core/src/session/session_manager.rs
@@ -20,7 +20,8 @@
 use crate::error::{Error, Result};
 use crate::params::app_config_params::AppConfigParams;
 use crate::params::uci_packets::{
-    Controlee, ReasonCode, SessionId, SessionState, SessionType, UpdateMulticastListAction,
+    Controlee, ControleeStatusList, ReasonCode, SessionId, SessionState, SessionType,
+    UpdateMulticastListAction,
 };
 use crate::session::uwb_session::{Response as SessionResponse, ResponseSender, UwbSession};
 use crate::uci::notification::{SessionNotification as UciSessionNotification, SessionRangeData};
@@ -295,7 +296,11 @@
     fn handle_uci_notification(&mut self, notf: UciSessionNotification) {
         match notf {
             UciSessionNotification::Status {
-                    session_id:_, session_token, session_state, reason_code } => {
+                session_id: _,
+                session_token,
+                session_state,
+                reason_code,
+            } => {
                 let reason_code = match ReasonCode::try_from(reason_code) {
                     Ok(r) => r,
                     Err(_) => {
@@ -334,12 +339,26 @@
                     }
                 }
             }
-            UciSessionNotification::UpdateControllerMulticastList {
+            UciSessionNotification::UpdateControllerMulticastListV1 {
                 session_token,
                 remaining_multicast_list_size: _,
                 status_list,
             } => match self.active_sessions.get_mut(&session_token) {
-                Some(session) => session.on_controller_multicast_list_udpated(status_list),
+                Some(session) => session
+                    .on_controller_multicast_list_updated(ControleeStatusList::V1(status_list)),
+                None => {
+                    warn!(
+                        "Received the notification of the unknown Session {}: {:?}",
+                        session_token, status_list
+                    );
+                }
+            },
+            UciSessionNotification::UpdateControllerMulticastListV2 {
+                session_token,
+                status_list,
+            } => match self.active_sessions.get_mut(&session_token) {
+                Some(session) => session
+                    .on_controller_multicast_list_updated(ControleeStatusList::V2(status_list)),
                 None => {
                     warn!(
                         "Received the notification of the unknown Session {}: {:?}",
@@ -586,7 +605,7 @@
 
     use crate::params::ccc_started_app_config_params::CccStartedAppConfigParams;
     use crate::params::uci_packets::{
-        AppConfigTlv, AppConfigTlvType, ControleeStatus, Controlees, MulticastUpdateStatusCode,
+        AppConfigTlv, AppConfigTlvType, ControleeStatusV1, Controlees, MulticastUpdateStatusCode,
         ReasonCode, SetAppConfigResponse, StatusCode,
     };
     use crate::params::utils::{u32_to_bytes, u64_to_bytes, u8_to_bytes};
@@ -812,10 +831,10 @@
         let (mut session_manager, mut mock_uci_manager, _) =
             setup_session_manager(move |uci_manager| {
                 let multicast_list_notf = vec![UciNotification::Session(
-                    UciSessionNotification::UpdateControllerMulticastList {
+                    UciSessionNotification::UpdateControllerMulticastListV1 {
                         session_token: session_id,
                         remaining_multicast_list_size: 1,
-                        status_list: vec![ControleeStatus {
+                        status_list: vec![ControleeStatusV1 {
                             mac_address: [0x34, 0x12],
                             subsession_id: 0x24,
                             status: MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
diff --git a/src/rust/uwb_core/src/session/uwb_session.rs b/src/rust/uwb_core/src/session/uwb_session.rs
index 37fcba4..d41b693 100644
--- a/src/rust/uwb_core/src/session/uwb_session.rs
+++ b/src/rust/uwb_core/src/session/uwb_session.rs
@@ -24,7 +24,7 @@
 use crate::params::app_config_params::AppConfigParams;
 use crate::params::ccc_started_app_config_params::CccStartedAppConfigParams;
 use crate::params::uci_packets::{
-    Controlee, ControleeStatus, Controlees, MulticastUpdateStatusCode, SessionId, SessionState,
+    Controlee, ControleeStatusList, Controlees, MulticastUpdateStatusCode, SessionId, SessionState,
     SessionType, UpdateMulticastListAction,
 };
 use crate::uci::error::status_code_to_result;
@@ -42,7 +42,7 @@
 pub(super) struct UwbSession {
     cmd_sender: mpsc::UnboundedSender<(Command, ResponseSender)>,
     state_sender: watch::Sender<SessionState>,
-    controlee_status_notf_sender: Option<oneshot::Sender<Vec<ControleeStatus>>>,
+    controlee_status_notf_sender: Option<oneshot::Sender<ControleeStatusList>>,
 }
 
 impl UwbSession {
@@ -110,7 +110,7 @@
         let _ = self.state_sender.send(state);
     }
 
-    pub fn on_controller_multicast_list_udpated(&mut self, status_list: Vec<ControleeStatus>) {
+    pub fn on_controller_multicast_list_updated(&mut self, status_list: ControleeStatusList) {
         if let Some(sender) = self.controlee_status_notf_sender.take() {
             let _ = sender.send(status_list);
         }
@@ -294,7 +294,7 @@
         &mut self,
         action: UpdateMulticastListAction,
         controlees: Vec<Controlee>,
-        notf_receiver: oneshot::Receiver<Vec<ControleeStatus>>,
+        notf_receiver: oneshot::Receiver<ControleeStatusList>,
     ) -> Result<Response> {
         if self.session_type == SessionType::Ccc {
             error!("Cannot update multicast list for CCC session");
@@ -329,10 +329,22 @@
 
         // Check the update status for adding new controlees.
         if action == UpdateMulticastListAction::AddControlee {
-            for result in results.iter() {
-                if result.status != MulticastUpdateStatusCode::StatusOkMulticastListUpdate {
-                    error!("Failed to update multicast list: {:?}", result);
-                    return Err(Error::Unknown);
+            match results {
+                ControleeStatusList::V1(res) => {
+                    for result in res.iter() {
+                        if result.status != MulticastUpdateStatusCode::StatusOkMulticastListUpdate {
+                            error!("Failed to update multicast list: {:?}", result);
+                            return Err(Error::Unknown);
+                        }
+                    }
+                }
+                ControleeStatusList::V2(res) => {
+                    for result in res.iter() {
+                        if result.status != MulticastUpdateStatusCode::StatusOkMulticastListUpdate {
+                            error!("Failed to update multicast list: {:?}", result);
+                            return Err(Error::Unknown);
+                        }
+                    }
                 }
             }
         }
@@ -387,7 +399,7 @@
     UpdateControllerMulticastList {
         action: UpdateMulticastListAction,
         controlees: Vec<Controlee>,
-        notf_receiver: oneshot::Receiver<Vec<ControleeStatus>>,
+        notf_receiver: oneshot::Receiver<ControleeStatusList>,
     },
     GetParams,
 }
diff --git a/src/rust/uwb_core/src/uci/message.rs b/src/rust/uwb_core/src/uci/message.rs
index fcbc65d..a4f72e8 100644
--- a/src/rust/uwb_core/src/uci/message.rs
+++ b/src/rust/uwb_core/src/uci/message.rs
@@ -20,21 +20,27 @@
 use crate::uci::notification::UciNotification;
 use crate::uci::response::UciResponse;
 
+use crate::params::UCIMajorVersion;
+
 #[derive(Debug)]
 pub(super) enum UciMessage {
     Response(UciResponse),
     Notification(UciNotification),
 }
 
-impl TryFrom<uwb_uci_packets::UciControlPacket> for UciMessage {
+impl TryFrom<(uwb_uci_packets::UciControlPacket, UCIMajorVersion)> for UciMessage {
     type Error = Error;
-    fn try_from(packet: uwb_uci_packets::UciControlPacket) -> Result<Self, Self::Error> {
+    fn try_from(
+        pair: (uwb_uci_packets::UciControlPacket, UCIMajorVersion),
+    ) -> Result<Self, Self::Error> {
+        let packet = pair.0;
+        let uci_fira_major_ver = pair.1;
         match packet.specialize() {
             uwb_uci_packets::UciControlPacketChild::UciResponse(evt) => {
                 Ok(UciMessage::Response(evt.try_into()?))
             }
             uwb_uci_packets::UciControlPacketChild::UciNotification(evt) => {
-                Ok(UciMessage::Notification(evt.try_into()?))
+                Ok(UciMessage::Notification((evt, uci_fira_major_ver).try_into()?))
             }
             _ => {
                 error!("Unknown packet for converting to UciMessage: {:?}", packet);
diff --git a/src/rust/uwb_core/src/uci/notification.rs b/src/rust/uwb_core/src/uci/notification.rs
index 06cc909..86af468 100644
--- a/src/rust/uwb_core/src/uci/notification.rs
+++ b/src/rust/uwb_core/src/uci/notification.rs
@@ -25,12 +25,14 @@
 use crate::error::{Error, Result};
 use crate::params::fira_app_config_params::UwbAddress;
 use crate::params::uci_packets::{
-    BitsPerSample, ControleeStatus, CreditAvailability, DataRcvStatusCode,
+    BitsPerSample, ControleeStatusV1, ControleeStatusV2, CreditAvailability, DataRcvStatusCode,
     DataTransferNtfStatusCode, DataTransferPhaseConfigUpdateStatusCode, DeviceState,
     ExtendedAddressDlTdoaRangingMeasurement, ExtendedAddressOwrAoaRangingMeasurement,
     ExtendedAddressTwoWayRangingMeasurement, RadarDataType, RangingMeasurementType, RawUciMessage,
-    SessionId, SessionState, SessionToken, ShortAddressDlTdoaRangingMeasurement,
+    SessionId, SessionState, SessionToken, SessionUpdateControllerMulticastListNtfV1Payload,
+    SessionUpdateControllerMulticastListNtfV2Payload, ShortAddressDlTdoaRangingMeasurement,
     ShortAddressOwrAoaRangingMeasurement, ShortAddressTwoWayRangingMeasurement, StatusCode,
+    UCIMajorVersion,
 };
 
 /// enum of all UCI notifications with structured fields.
@@ -67,14 +69,21 @@
         /// uwb_uci_packets::Reasoncode.
         reason_code: u8,
     },
-    /// SessionUpdateControllerMulticastListNtf equivalent.
-    UpdateControllerMulticastList {
+    /// SessionUpdateControllerMulticastListNtfV1 equivalent.
+    UpdateControllerMulticastListV1 {
         /// SessionToken : u32
         session_token: SessionToken,
         /// count of controlees: u8
         remaining_multicast_list_size: usize,
         /// list of controlees.
-        status_list: Vec<ControleeStatus>,
+        status_list: Vec<ControleeStatusV1>,
+    },
+    /// SessionUpdateControllerMulticastListNtfV2 equivalent.
+    UpdateControllerMulticastListV2 {
+        /// SessionToken : u32
+        session_token: SessionToken,
+        /// list of controlees.
+        status_list: Vec<ControleeStatusV2>,
     },
     /// (Short/Extended)Mac()SessionInfoNtf equivalent
     SessionInfo(SessionRangeData),
@@ -333,14 +342,19 @@
     }
 }
 
-impl TryFrom<uwb_uci_packets::UciNotification> for UciNotification {
+impl TryFrom<(uwb_uci_packets::UciNotification, UCIMajorVersion)> for UciNotification {
     type Error = Error;
-    fn try_from(evt: uwb_uci_packets::UciNotification) -> std::result::Result<Self, Self::Error> {
+    fn try_from(
+        pair: (uwb_uci_packets::UciNotification, UCIMajorVersion),
+    ) -> std::result::Result<Self, Self::Error> {
         use uwb_uci_packets::UciNotificationChild;
+        let evt = pair.0;
+        let uci_fira_major_ver = pair.1;
+
         match evt.specialize() {
             UciNotificationChild::CoreNotification(evt) => Ok(Self::Core(evt.try_into()?)),
             UciNotificationChild::SessionConfigNotification(evt) => {
-                Ok(Self::Session(evt.try_into()?))
+                Ok(Self::Session((evt, uci_fira_major_ver).try_into()?))
             }
             UciNotificationChild::SessionControlNotification(evt) => {
                 Ok(Self::Session(evt.try_into()?))
@@ -377,12 +391,16 @@
     }
 }
 
-impl TryFrom<uwb_uci_packets::SessionConfigNotification> for SessionNotification {
+impl TryFrom<(uwb_uci_packets::SessionConfigNotification, UCIMajorVersion)>
+    for SessionNotification
+{
     type Error = Error;
     fn try_from(
-        evt: uwb_uci_packets::SessionConfigNotification,
+        pair: (uwb_uci_packets::SessionConfigNotification, UCIMajorVersion),
     ) -> std::result::Result<Self, Self::Error> {
         use uwb_uci_packets::SessionConfigNotificationChild;
+        let evt = pair.0;
+        let uci_fira_major_ver = pair.1;
         match evt.specialize() {
             SessionConfigNotificationChild::SessionStatusNtf(evt) => Ok(Self::Status {
                 //no sessionId recieved, assign from sessionIdToToken map in uci_manager
@@ -391,11 +409,45 @@
                 session_state: evt.get_session_state(),
                 reason_code: evt.get_reason_code(),
             }),
-            SessionConfigNotificationChild::SessionUpdateControllerMulticastListNtf(evt) => {
-                Ok(Self::UpdateControllerMulticastList {
+            SessionConfigNotificationChild::SessionUpdateControllerMulticastListNtf(evt)
+                if uci_fira_major_ver == UCIMajorVersion::V1 =>
+            {
+                let payload = evt.get_payload();
+                let multicast_update_list_payload_v1 =
+                    SessionUpdateControllerMulticastListNtfV1Payload::parse(payload).map_err(
+                        |e| {
+                            error!(
+                                "Failed to parse Multicast list ntf v1 {:?}, payload: {:?}",
+                                e, &payload
+                            );
+                            Error::BadParameters
+                        },
+                    )?;
+                Ok(Self::UpdateControllerMulticastListV1 {
                     session_token: evt.get_session_token(),
-                    remaining_multicast_list_size: evt.get_remaining_multicast_list_size() as usize,
-                    status_list: evt.get_controlee_status().clone(),
+                    remaining_multicast_list_size: multicast_update_list_payload_v1
+                        .remaining_multicast_list_size
+                        as usize,
+                    status_list: multicast_update_list_payload_v1.controlee_status,
+                })
+            }
+            SessionConfigNotificationChild::SessionUpdateControllerMulticastListNtf(evt)
+                if uci_fira_major_ver == UCIMajorVersion::V2 =>
+            {
+                let payload = evt.get_payload();
+                let multicast_update_list_payload_v2 =
+                    SessionUpdateControllerMulticastListNtfV2Payload::parse(payload).map_err(
+                        |e| {
+                            error!(
+                                "Failed to parse Multicast list ntf v2 {:?}, payload: {:?}",
+                                e, &payload
+                            );
+                            Error::BadParameters
+                        },
+                    )?;
+                Ok(Self::UpdateControllerMulticastListV2 {
+                    session_token: evt.get_session_token(),
+                    status_list: multicast_update_list_payload_v2.controlee_status,
                 })
             }
             SessionConfigNotificationChild::SessionDataTransferPhaseConfigNtf(evt) => {
@@ -623,6 +675,7 @@
 #[cfg(test)]
 mod tests {
     use super::*;
+    use bytes::{BufMut, BytesMut};
 
     #[test]
     fn test_ranging_measurements_trait() {
@@ -889,8 +942,10 @@
         .build();
         let session_notification_packet =
             uwb_uci_packets::SessionConfigNotification::try_from(session_status_ntf).unwrap();
+        let uci_fira_major_version = UCIMajorVersion::V1;
         let session_notification =
-            SessionNotification::try_from(session_notification_packet).unwrap();
+            SessionNotification::try_from((session_notification_packet, uci_fira_major_version))
+                .unwrap();
         let uci_notification_from_session_status_ntf =
             UciNotification::Session(session_notification);
         assert_eq!(
@@ -905,40 +960,130 @@
         );
     }
 
+    fn write_multicast_ntf_v1_payload(
+        payload: &SessionUpdateControllerMulticastListNtfV1Payload,
+        buffer: &mut BytesMut,
+    ) {
+        buffer.put_u8(payload.remaining_multicast_list_size);
+        buffer.put_u8(payload.controlee_status.len() as u8);
+        for elem in &payload.controlee_status {
+            write_v1_controlee_status(elem, buffer);
+        }
+    }
+
+    fn write_v1_controlee_status(status: &ControleeStatusV1, buffer: &mut BytesMut) {
+        for elem in &status.mac_address {
+            buffer.put_u8(*elem);
+        }
+        buffer.put_u32_le(status.subsession_id);
+        buffer.put_u8(u8::from(status.status));
+    }
+
+    fn write_multicast_ntf_v2_payload(
+        payload: &SessionUpdateControllerMulticastListNtfV2Payload,
+        buffer: &mut BytesMut,
+    ) {
+        buffer.put_u8(payload.controlee_status.len() as u8);
+        for elem in &payload.controlee_status {
+            write_v2_controlee_status(elem, buffer);
+        }
+    }
+
+    fn write_v2_controlee_status(status: &ControleeStatusV2, buffer: &mut BytesMut) {
+        for elem in &status.mac_address {
+            buffer.put_u8(*elem);
+        }
+        buffer.put_u8(u8::from(status.status));
+    }
+
     #[test]
-    fn test_session_notification_casting_from_session_update_controller_multicast_list_ntf_packet()
-    {
-        let controlee_status = uwb_uci_packets::ControleeStatus {
+    fn test_session_notification_casting_from_session_update_controller_multicast_list_ntf_v1_packet(
+    ) {
+        let controlee_status_v1 = uwb_uci_packets::ControleeStatusV1 {
             mac_address: [0x0c, 0xa8],
             subsession_id: 0x30,
             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
         };
-        let another_controlee_status = uwb_uci_packets::ControleeStatus {
+        let another_controlee_status_v1 = uwb_uci_packets::ControleeStatusV1 {
             mac_address: [0x0c, 0xa9],
             subsession_id: 0x31,
             status: uwb_uci_packets::MulticastUpdateStatusCode::StatusErrorKeyFetchFail,
         };
-        let session_update_controller_multicast_list_ntf =
+        let payload = uwb_uci_packets::SessionUpdateControllerMulticastListNtfV1Payload {
+            remaining_multicast_list_size: 0x2,
+            controlee_status: vec![
+                controlee_status_v1.clone(),
+                another_controlee_status_v1.clone(),
+            ],
+        };
+        let mut buf = BytesMut::new();
+        write_multicast_ntf_v1_payload(&payload, &mut buf);
+        let session_update_controller_multicast_list_ntf_v1 =
             uwb_uci_packets::SessionUpdateControllerMulticastListNtfBuilder {
                 session_token: 0x32,
-                remaining_multicast_list_size: 0x2,
-                controlee_status: vec![controlee_status.clone(), another_controlee_status.clone()],
+                payload: Some(buf.freeze()),
             }
             .build();
         let session_notification_packet = uwb_uci_packets::SessionConfigNotification::try_from(
-            session_update_controller_multicast_list_ntf,
+            session_update_controller_multicast_list_ntf_v1,
         )
         .unwrap();
+        let uci_fira_major_version = UCIMajorVersion::V1;
         let session_notification =
-            SessionNotification::try_from(session_notification_packet).unwrap();
+            SessionNotification::try_from((session_notification_packet, uci_fira_major_version))
+                .unwrap();
         let uci_notification_from_session_update_controller_multicast_list_ntf =
             UciNotification::Session(session_notification);
         assert_eq!(
             uci_notification_from_session_update_controller_multicast_list_ntf,
-            UciNotification::Session(SessionNotification::UpdateControllerMulticastList {
+            UciNotification::Session(SessionNotification::UpdateControllerMulticastListV1 {
                 session_token: 0x32,
                 remaining_multicast_list_size: 0x2,
-                status_list: vec![controlee_status, another_controlee_status],
+                status_list: vec![controlee_status_v1, another_controlee_status_v1],
+            })
+        );
+    }
+
+    #[test]
+    fn test_session_notification_casting_from_session_update_controller_multicast_list_ntf_v2_packet(
+    ) {
+        let controlee_status_v2 = uwb_uci_packets::ControleeStatusV2 {
+            mac_address: [0x0c, 0xa8],
+            status: uwb_uci_packets::MulticastUpdateStatusCode::StatusOkMulticastListUpdate,
+        };
+        let another_controlee_status_v2 = uwb_uci_packets::ControleeStatusV2 {
+            mac_address: [0x0c, 0xa9],
+            status: uwb_uci_packets::MulticastUpdateStatusCode::StatusErrorKeyFetchFail,
+        };
+        let payload = uwb_uci_packets::SessionUpdateControllerMulticastListNtfV2Payload {
+            controlee_status: vec![
+                controlee_status_v2.clone(),
+                another_controlee_status_v2.clone(),
+            ],
+        };
+        let mut buf = BytesMut::new();
+        write_multicast_ntf_v2_payload(&payload, &mut buf);
+        let session_update_controller_multicast_list_ntf_v2 =
+            uwb_uci_packets::SessionUpdateControllerMulticastListNtfBuilder {
+                session_token: 0x32,
+                payload: Some(buf.freeze()),
+            }
+            .build();
+        let session_notification_packet = uwb_uci_packets::SessionConfigNotification::try_from(
+            session_update_controller_multicast_list_ntf_v2,
+        )
+        .unwrap();
+        let uci_fira_major_version = UCIMajorVersion::V2;
+        let session_notification =
+            SessionNotification::try_from((session_notification_packet, uci_fira_major_version))
+                .unwrap();
+        let uci_notification_from_session_update_controller_multicast_list_ntf =
+            UciNotification::Session(session_notification);
+        assert_eq!(
+            uci_notification_from_session_update_controller_multicast_list_ntf,
+            UciNotification::Session(SessionNotification::UpdateControllerMulticastListV2 {
+                session_token: 0x32,
+                status_list: vec![controlee_status_v2, another_controlee_status_v2],
             })
         );
     }
@@ -957,10 +1102,15 @@
             }
             .build()
             .into();
-        let uci_notification_from_vendor_9 =
-            UciNotification::try_from(vendor_9_empty_notification).unwrap();
+        let uci_fira_major_version = UCIMajorVersion::V1;
+        let uci_notification_from_vendor_9 = UciNotification::try_from((
+            vendor_9_empty_notification,
+            uci_fira_major_version.clone(),
+        ))
+        .unwrap();
         let uci_notification_from_vendor_A =
-            UciNotification::try_from(vendor_A_nonempty_notification).unwrap();
+            UciNotification::try_from((vendor_A_nonempty_notification, uci_fira_major_version))
+                .unwrap();
         assert_eq!(
             uci_notification_from_vendor_9,
             UciNotification::Vendor(RawUciMessage {
@@ -983,7 +1133,9 @@
     fn test_test_to_vendor_notification_casting() {
         let test_notification: uwb_uci_packets::UciNotification =
             uwb_uci_packets::TestNotificationBuilder { opcode: 0x22, payload: None }.build().into();
-        let test_uci_notification = UciNotification::try_from(test_notification).unwrap();
+        let uci_fira_major_version = UCIMajorVersion::V1;
+        let test_uci_notification =
+            UciNotification::try_from((test_notification, uci_fira_major_version)).unwrap();
         assert_eq!(
             test_uci_notification,
             UciNotification::Vendor(RawUciMessage {
diff --git a/src/rust/uwb_core/src/uci/uci_manager.rs b/src/rust/uwb_core/src/uci/uci_manager.rs
index 8fd1acc..d1a289f 100644
--- a/src/rust/uwb_core/src/uci/uci_manager.rs
+++ b/src/rust/uwb_core/src/uci/uci_manager.rs
@@ -18,6 +18,7 @@
 
 use async_trait::async_trait;
 use log::{debug, error, info, warn};
+use num_traits::FromPrimitive;
 use tokio::sync::{mpsc, oneshot, Mutex};
 
 use crate::error::{Error, Result};
@@ -30,6 +31,7 @@
     UciDataPacketHal, UpdateMulticastListAction, UpdateTime,
 };
 use crate::params::utils::{bytes_to_u16, bytes_to_u64};
+use crate::params::UCIMajorVersion;
 use crate::uci::command::UciCommand;
 use crate::uci::message::UciMessage;
 use crate::uci::notification::{
@@ -932,6 +934,15 @@
         }
     }
 
+    fn get_uwbs_uci_major_version(&mut self) -> Option<u8> {
+        if let Some(core_get_device_info_rsp) = &self.get_device_info_rsp {
+            // Byte 0 : Major UCI version
+            // Calling unwrap() will be safe here as with the bitmask, the value will be within u8.
+            return Some((core_get_device_info_rsp.uci_version & 0xFF).try_into().unwrap());
+        }
+        None
+    }
+
     #[allow(unknown_lints)]
     #[allow(clippy::unnecessary_fallible_conversions)]
     fn store_if_uwbs_caps_info(&mut self, resp: &UciResponse) {
@@ -1264,7 +1275,15 @@
             UciDefragPacket::Control(packet) => {
                 self.logger.log_uci_response_or_notification(&packet);
 
-                match packet.try_into() {
+                // Use a safe value of Fira 1.x as the UWBS UCI version.
+                let uci_fira_major_version = self.get_uwbs_uci_major_version().unwrap_or(1);
+                match (
+                    packet,
+                    UCIMajorVersion::from_u8(uci_fira_major_version)
+                        .map_or(UCIMajorVersion::V1, |v| v),
+                )
+                    .try_into()
+                {
                     Ok(UciMessage::Response(resp)) => {
                         self.handle_response(resp).await;
                     }
@@ -1348,9 +1367,7 @@
             }
             UciNotification::Session(orig_session_notf) => {
                 let mod_session_notf = {
-                    match self
-                        .add_session_id_to_session_status_ntf(orig_session_notf.clone())
-                        .await
+                    match self.add_session_id_to_session_status_ntf(orig_session_notf.clone()).await
                     {
                         Ok(session_notf) => session_notf,
                         Err(e) => {
@@ -1361,7 +1378,7 @@
                 };
                 match orig_session_notf {
                     SessionNotification::Status {
-                        session_id:_,
+                        session_id: _,
                         session_token,
                         session_state,
                         reason_code: _,
@@ -1422,23 +1439,31 @@
     ) -> Result<SessionNotification> {
         match session_notification {
             SessionNotification::Status {
-                    session_id:_, session_token, session_state, reason_code } => {
-                Ok(SessionNotification::Status {
-                    session_id: self.get_session_id(&session_token).await?,
-                    session_token,
-                    session_state,
-                    reason_code,
-                })
-            }
-            SessionNotification::UpdateControllerMulticastList {
+                session_id: _,
+                session_token,
+                session_state,
+                reason_code,
+            } => Ok(SessionNotification::Status {
+                session_id: self.get_session_id(&session_token).await?,
+                session_token,
+                session_state,
+                reason_code,
+            }),
+            SessionNotification::UpdateControllerMulticastListV1 {
                 session_token,
                 remaining_multicast_list_size,
                 status_list,
-            } => Ok(SessionNotification::UpdateControllerMulticastList {
+            } => Ok(SessionNotification::UpdateControllerMulticastListV1 {
                 session_token: self.get_session_id(&session_token).await?,
                 remaining_multicast_list_size,
                 status_list,
             }),
+            SessionNotification::UpdateControllerMulticastListV2 { session_token, status_list } => {
+                Ok(SessionNotification::UpdateControllerMulticastListV2 {
+                    session_token: self.get_session_id(&session_token).await?,
+                    status_list,
+                })
+            }
             SessionNotification::SessionInfo(session_range_data) => {
                 Ok(SessionNotification::SessionInfo(SessionRangeData {
                     sequence_number: session_range_data.sequence_number,
diff --git a/src/rust/uwb_uci_packets/uci_packets.pdl b/src/rust/uwb_uci_packets/uci_packets.pdl
index 7b3e174..0fa887d 100644
--- a/src/rust/uwb_uci_packets/uci_packets.pdl
+++ b/src/rust/uwb_uci_packets/uci_packets.pdl
@@ -997,23 +997,37 @@
     "\x41\x07\x00\x01\x00\x00\x00\x00",
 }
 
-struct ControleeStatus {
+struct ControleeStatusV1 {
     mac_address: 8[2],
     subsession_id: 32,
     status: MulticastUpdateStatusCode,
 }
 
+struct ControleeStatusV2 {
+    mac_address: 8[2],
+    status: MulticastUpdateStatusCode,
+}
+
 packet SessionUpdateControllerMulticastListNtf : SessionConfigNotification (opcode = 0x7) { //SESSION_UPDATE_CONTROLLER_MULTICAST_LIST
     session_token: 32, // Session ID or Session Handle (based on UWBS version)
-    remaining_multicast_list_size: 8,
-    _count_(controlee_status): 8,
-    controlee_status: ControleeStatus[],
+    _payload_,
 }
 
 test SessionUpdateControllerMulticastListNtf {
     "\x61\x07\x00\x06\x00\x00\x00\x00\x01\x02\x03\x04\x00",
 }
 
+struct SessionUpdateControllerMulticastListNtfV1Payload {
+    remaining_multicast_list_size: 8,
+    _count_(controlee_status): 8,
+    controlee_status: ControleeStatusV1[],
+}
+
+struct SessionUpdateControllerMulticastListNtfV2Payload {
+    _count_(controlee_status): 8,
+    controlee_status: ControleeStatusV2[],
+}
+
 packet DataCreditNtf : SessionControlNotification (opcode = 0x04) { // SESSION_DATA_CREDIT_NTF
     session_token: 32, // Session ID or Session Handle (based on UWBS version)
     credit_availability: CreditAvailability,