pub fn build_guti_bytes(
plmn_bytes: &[u8],
amf_region_id: u8,
amf_set_id: u16,
amf_pointer: u8,
tmsi: u32,
) -> Vec<u8> {
debug_assert!(amf_set_id <= 0x3FF, "AMF Set ID must be 10 bits");
debug_assert!(amf_pointer <= 0x3F, "AMF Pointer must be 6 bits");
let mut g = Vec::with_capacity(11);
g.push(0xF2); g.extend_from_slice(&plmn_bytes[..3]);
g.push(amf_region_id);
g.push((amf_set_id >> 2) as u8);
g.push(((amf_set_id as u8 & 0x03) << 6) | (amf_pointer & 0x3F));
g.extend_from_slice(&tmsi.to_be_bytes());
g
}
pub fn parse_guti_tmsi(identity: &[u8]) -> Option<u32> {
if identity.len() < 11 {
return None;
}
if identity[0] & 0x07 != 0x02 {
return None;
}
let tmsi = u32::from_be_bytes(identity[7..11].try_into().ok()?);
Some(tmsi)
}
pub fn parse_s_tmsi(identity: &[u8]) -> Option<u32> {
if identity.len() < 7 {
return None;
}
if identity[0] & 0x07 != 0x04 {
return None;
}
let tmsi = u32::from_be_bytes(identity[3..7].try_into().ok()?);
Some(tmsi)
}
pub fn mobile_identity_type(identity: &[u8]) -> u8 {
if identity.is_empty() {
0
} else {
identity[0] & 0x07
}
}