use crate::ast::*;
use crate::builders::WireContext;
use alloc::vec::Vec;
use core::net::IpAddr;
#[doc(alias = "RADIUS")]
#[doc(alias = "RFC2865")]
#[doc(alias = "RFC2866")]
#[doc(alias = "NAS_IP")]
#[doc(alias = "FRAMED_IP")]
pub fn build_radius_payload(
_ctx: &WireContext,
spec: &RadiusSpec,
payload_bytes: &[u8],
) -> (Vec<u8>, u16) {
let (code, dport) = match spec.code.unwrap_or("ACCESS_REQUEST").to_ascii_uppercase().as_str() {
"ACCESS_REQUEST" => (1u8, 1812u16),
"ACCESS_ACCEPT" => (2u8, 1812u16),
"ACCESS_REJECT" => (3u8, 1812u16),
"ACCOUNTING_REQUEST" => (4u8, 1813u16),
"ACCOUNTING_RESPONSE" => (5u8, 1813u16),
"ACCESS_CHALLENGE" => (11u8, 1812u16),
_ => (1u8, 1812u16),
};
let id = spec.id.unwrap_or(1);
let mut avps = Vec::new();
let user = spec.user.unwrap_or("user");
let user_bytes = user.as_bytes();
avps.push(1); avps.push((user_bytes.len() + 2) as u8);
avps.extend_from_slice(user_bytes);
match spec.nas_ip {
Some(IpAddr::V4(v4)) => {
avps.push(4);
avps.push(6);
avps.extend_from_slice(&v4.octets());
}
Some(IpAddr::V6(v6)) => {
avps.push(95);
avps.push(18);
avps.extend_from_slice(&v6.octets());
}
None => {}
}
if let Some(service_type) = spec.service_type {
avps.push(6);
avps.push(6);
avps.extend_from_slice(&service_type.to_be_bytes());
}
match spec.framed_ip {
Some(IpAddr::V4(v4)) => {
avps.push(8);
avps.push(6);
avps.extend_from_slice(&v4.octets());
}
Some(IpAddr::V6(v6)) => {
avps.push(168);
avps.push(18);
avps.extend_from_slice(&v6.octets());
}
None => {}
}
if !payload_bytes.is_empty() {
avps.extend_from_slice(payload_bytes);
}
let total_len = 20 + avps.len() as u16;
let mut pkt = Vec::with_capacity(total_len as usize);
pkt.push(code);
pkt.push(id);
pkt.extend_from_slice(&total_len.to_be_bytes());
pkt.extend_from_slice(&[0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]);
pkt.extend_from_slice(&avps);
(pkt, dport)
}