use crate::block::opts::*;
use crate::block::util::*;
use crate::iface::LinkType;
use bytes::Buf;
use tracing::*;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct InterfaceDescription {
pub link_type: LinkType,
pub snap_len: Option<u32>,
pub if_name: String,
pub if_description: String,
pub if_ipv4_addr: Vec<[u8; 8]>,
pub if_ipv6_addr: Vec<[u8; 17]>,
pub if_mac_addr: Option<[u8; 6]>,
pub if_eui_addr: Option<[u8; 8]>,
pub if_speed: Option<u64>,
pub if_tsresol: u32,
pub if_tzone: Option<[u8; 4]>,
pub if_filter: String,
pub if_os: String,
pub if_fcslen: Option<[u8; 1]>,
pub if_tsoffset: Option<[u8; 8]>,
pub if_hardware: String,
pub if_txspeed: Option<[u8; 8]>,
pub if_rxspeed: Option<[u8; 8]>,
}
impl FromBytes for InterfaceDescription {
fn parse<T: Buf>(
mut buf: T,
endianness: Endianness,
) -> Result<InterfaceDescription, BlockError> {
ensure_remaining!(buf, 8);
let link_type = {
let code = read_u16(&mut buf, endianness);
buf.advance(2); LinkType::from_u16(code)
};
let snap_len = match read_u32(&mut buf, endianness) {
0 => None,
x => Some(x),
};
let mut if_name = String::new();
let mut if_description = String::new();
let mut if_ipv4_addr = vec![];
let mut if_ipv6_addr = vec![];
let mut if_mac_addr = None;
let mut if_eui_addr = None;
let mut if_speed = None;
let mut if_tsresol = 1_000_000;
let mut if_tzone = None;
let mut if_filter = String::new();
let mut if_os = String::new();
let mut if_fcslen = None;
let mut if_tsoffset = None;
let mut if_hardware = String::new();
let mut if_txspeed = None;
let mut if_rxspeed = None;
parse_options(buf, endianness, |ty, bytes| {
match ty {
2 => if_name = bytes_to_string(bytes),
3 => if_description = bytes_to_string(bytes),
4 => {
if let Some(x) = bytes_to_array(bytes) {
if_ipv4_addr.push(x)
}
}
5 => {
if let Some(x) = bytes_to_array(bytes) {
if_ipv6_addr.push(x)
}
}
6 => if_mac_addr = bytes_to_array(bytes),
7 => if_eui_addr = bytes_to_array(bytes),
8 => if_speed = bytes_to_u64(bytes, endianness),
9 => {
if let Some([v]) = bytes_to_array(bytes) {
let exp = u32::from(v & 0b0111_1111);
let base = match v >> 7 {
0 => 10_u32,
1 => 2_u32,
_ => unreachable!(),
};
if let Some(x) = base.checked_pow(exp) {
if_tsresol = x;
} else {
warn!(
"Saw an interface with a timestamp resolution \
of {base}^{exp}. The timestamps of packets \
captured from this interface won't fit into \
a u32."
)
}
}
}
10 => if_tzone = bytes_to_array(bytes),
11 => if_filter = bytes_to_string(bytes),
12 => if_os = bytes_to_string(bytes),
13 => if_fcslen = bytes_to_array(bytes),
14 => if_tsoffset = bytes_to_array(bytes),
15 => if_hardware = bytes_to_string(bytes),
16 => if_txspeed = bytes_to_array(bytes),
17 => if_rxspeed = bytes_to_array(bytes),
_ => (), }
});
Ok(InterfaceDescription {
link_type,
snap_len,
if_name,
if_description,
if_ipv4_addr,
if_ipv6_addr,
if_mac_addr,
if_eui_addr,
if_speed,
if_tsresol,
if_tzone,
if_filter,
if_os,
if_fcslen,
if_tsoffset,
if_hardware,
if_txspeed,
if_rxspeed,
})
}
}