rusty-cotp 0.9.0

Implements the Kernel Function of Connection Oriented Transport Protocol/ISO 8073/IEC 8073/ITU-T X.224 standard.
Documentation
use crate::{
    api::CotpError,
    packet::parameters::{ALTERNATIVE_CLASS_PARAMETER_CODE, CALLED_TSAP_PARAMETER_CODE, CALLING_TSAP_PARAMETER_CODE, ConnectionClass, CotpParameter, TPDU_SIZE_PARAMETER_CODE, TpduSize},
};

pub fn parse_parameters(buffer: &[u8]) -> Result<Vec<CotpParameter>, CotpError> {
    let mut offset = 0;
    let mut parameter_list = Vec::new();

    while offset < buffer.len() {
        let (parameter, consumed) = parse_parameter(&buffer[offset..])?;
        parameter_list.push(parameter);
        offset += consumed;
    }
    Ok(parameter_list)
}

pub fn parse_parameter(buffer: &[u8]) -> Result<(CotpParameter, usize), CotpError> {
    if buffer.len() < 2 {
        return Err(CotpError::ProtocolError(format!("Insufficient data to parse parameter header: {}", buffer.len())));
    }

    let parameter_code = buffer[0];
    let parameter_value_length = buffer[1] as usize;
    if buffer.len() < parameter_value_length + 2 {
        return Err(CotpError::ProtocolError(format!("Insufficient data to parse parameter. The buffer has {} bytes but the header claims the parameter is {} bytes.", buffer.len(), parameter_value_length + 2)));
    }

    match parameter_code {
        CALLING_TSAP_PARAMETER_CODE => Ok((parse_calling_tsap_parameter(&buffer[2..(2 + parameter_value_length)])?, 2 + parameter_value_length)),
        CALLED_TSAP_PARAMETER_CODE => Ok((parse_called_tsap_parameter(&buffer[2..(2 + parameter_value_length)])?, 2 + parameter_value_length)),
        TPDU_SIZE_PARAMETER_CODE => Ok((parse_tpdu_size_parameter(&buffer[2..(2 + parameter_value_length)])?, 2 + parameter_value_length)),
        ALTERNATIVE_CLASS_PARAMETER_CODE => Ok((parse_alternative_class_parameter(&buffer[2..(2 + parameter_value_length)])?, 2 + parameter_value_length)),
        _ => Ok((CotpParameter::UnknownParameter(parameter_code, Vec::from(&buffer[2..(2 + parameter_value_length)])), 2 + parameter_value_length)),
    }
}

pub fn parse_tpdu_size_parameter(buffer: &[u8]) -> Result<CotpParameter, CotpError> {
    if buffer.len() != 1 {
        return Err(CotpError::ProtocolError(format!("Invalid TPDU length: {}", buffer.len())));
    }
    Ok(CotpParameter::TpduLengthParameter(TpduSize::from(buffer[0])))
}

pub fn parse_calling_tsap_parameter(buffer: &[u8]) -> Result<CotpParameter, CotpError> {
    Ok(CotpParameter::CallingTsap(buffer.to_vec()))
}

pub fn parse_called_tsap_parameter(buffer: &[u8]) -> Result<CotpParameter, CotpError> {
    Ok(CotpParameter::CalledTsap(buffer.to_vec()))
}

pub fn parse_alternative_class_parameter(buffer: &[u8]) -> Result<CotpParameter, CotpError> {
    Ok(CotpParameter::AlternativeClassParameter(buffer.iter().map(|x| ConnectionClass::from((x & 0xF0) >> 4)).collect()))
}