diff --git a/src/main.rs b/src/main.rs index 11b9b14..4ab1607 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ use std::{ }; use anyhow::Result; -use ax25::frame::{Ax25Frame, CommandResponse, FrameContent}; +use ax25::frame::Ax25Frame; use pcap_file::{ pcap::{PcapHeader, PcapPacket, PcapWriter}, DataLink, @@ -18,6 +18,8 @@ use std::net::TcpStream; use std::time::Duration; use std::time::SystemTime; +mod print_frame; +use print_frame::PrintFrame; struct KissPkt { timestamp: Duration, orig_len: u32, @@ -147,221 +149,3 @@ fn main() -> Result<()> { Ok(()) } - -trait PrintData { - fn type_str_short(&self) -> &'static str; - fn print_short(&self); - fn print_long(&self); -} -impl PrintData for Ax25Frame { - fn type_str_short(&self) -> &'static str { - match self.content { - FrameContent::Information(_) => "Info", - FrameContent::ReceiveReady(_) => "RecvRdy", - FrameContent::ReceiveNotReady(_) => "RecvNotRdy", - FrameContent::Reject(_) => "Reject", - FrameContent::SetAsynchronousBalancedMode(_) => "AsyncBalMode", //12 long - FrameContent::Disconnect(_) => "Disconnect", - FrameContent::DisconnectedMode(_) => "DisconMode", - FrameContent::UnnumberedAcknowledge(_) => "UnNumAck", - FrameContent::FrameReject(_) => "FrameReject", - FrameContent::UnnumberedInformation(_) => "UnNumInfo", - FrameContent::UnknownContent(_) => "Unknown", - } - } - fn print_short(&self) { - //Format: "[source] -> [dest] via [..] [CMD/RSP/NIL] [frameType]: [DATA str rep]" - let src = self.source.to_string(); - let dst = self.destination.to_string(); - //let via: String = self.route.iter().map(|re| format!(" {} ", re.repeater.to_string())).collect(); //todo - let rsp = match self.command_or_response { - Some(CommandResponse::Command) => "CMD", - Some(CommandResponse::Response) => "RSP", - None => "NIL", - }; - let ftype = self.type_str_short(); - let mut routed = false; - for route in self.route.iter() { - if route.has_repeated { - routed = true; - break; - } - } - let arrow_shaft = if routed { "=" } else { "-" }; - - //let mut rawdata; - let (rawdata, finfo) = match &self.content { - FrameContent::Information(_i) => ( - _i.info.clone(), - format!( - "pid: {:?}, seq: {}/{}, info: ", - _i.pid, _i.send_sequence, _i.receive_sequence - ), - ), - FrameContent::ReceiveReady(rr) => ( - vec![], - format!( - "seq: {}, poll/final: {}", - rr.receive_sequence, rr.poll_or_final - ), - ), - FrameContent::ReceiveNotReady(rnr) => ( - vec![], - format!( - "seq: {}, poll/final: {}", - rnr.receive_sequence, rnr.poll_or_final - ), - ), - FrameContent::Reject(rnr) => ( - vec![], - format!( - "seq: {}, poll/final: {}", - rnr.receive_sequence, rnr.poll_or_final - ), - ), - FrameContent::SetAsynchronousBalancedMode(abm) => { - (vec![], format!("poll: {}", abm.poll)) - } - FrameContent::Disconnect(abm) => (vec![], format!("poll: {}", abm.poll)), - FrameContent::DisconnectedMode(abm) => { - (vec![], format!("final bit: {}", abm.final_bit)) - } - FrameContent::UnnumberedAcknowledge(abm) => { - (vec![], format!("final bit: {}", abm.final_bit)) - } - FrameContent::FrameReject(fr) => ( - vec![], - format!( - "[{}{}{}{}], seq: {}/{}, raw: {}, cmdRsp: {}, final: {}", - if fr.z { "Z" } else { "" }, - if fr.y { "Y" } else { "" }, - if fr.x { "X" } else { "" }, - if fr.w { "W" } else { "" }, - fr.send_sequence, - fr.receive_sequence, - fr.rejected_control_field_raw, - match fr.command_response { - CommandResponse::Command => "CMD", - CommandResponse::Response => "RSP", - }, - fr.final_bit - ), - ), - FrameContent::UnnumberedInformation(ui) => { - (ui.info.clone(), format!("pid: {:?} info:", ui.pid)) - } - FrameContent::UnknownContent(ukn) => (ukn.raw.clone(), format!("")), - }; - let mut data = String::new(); - for byte in rawdata.iter() { - //if byte >= ' '.into() && byte <= '~'.into() { - if *byte >= 32 && *byte <= 126 { - data.push((*byte).into()); - } else { - data.push_str(&format!("\\{:x?} ", *byte)); - } - } - println!( - "AX.25 {:12} {} {:9} {}> {:9} {}", - ftype, - rsp, - src, - arrow_shaft, - dst, - if !data.is_empty() { data } else { finfo } - ); - } - fn print_long(&self) { - //Format: "[source] -> [dest] via [..] [CMD/RSP/NIL] [frameType]: [DATA str rep]" - let src = self.source.to_string(); - let dst = self.destination.to_string(); - let via: String = self - .route - .iter() - .map(|re| format!(" {} ", re.repeater.to_string())) - .collect(); //todo - let rsp = match self.command_or_response { - Some(CommandResponse::Command) => "CMD", - Some(CommandResponse::Response) => "RSP", - None => "NIL", - }; - let ftype = self.type_str_short(); - - //let mut rawdata; - let (rawdata, finfo) = match &self.content { - FrameContent::Information(_i) => ( - _i.info.clone(), - format!( - "pid: {:?}, seq: {}/{}, info: ", - _i.pid, _i.send_sequence, _i.receive_sequence - ), - ), - FrameContent::ReceiveReady(rr) => ( - vec![], - format!( - "seq: {}, poll/final: {}", - rr.receive_sequence, rr.poll_or_final - ), - ), - FrameContent::ReceiveNotReady(rnr) => ( - vec![], - format!( - "seq: {}, poll/final: {}", - rnr.receive_sequence, rnr.poll_or_final - ), - ), - FrameContent::Reject(rnr) => ( - vec![], - format!( - "seq: {}, poll/final: {}", - rnr.receive_sequence, rnr.poll_or_final - ), - ), - FrameContent::SetAsynchronousBalancedMode(abm) => { - (vec![], format!("poll: {}", abm.poll)) - } - FrameContent::Disconnect(abm) => (vec![], format!("poll: {}", abm.poll)), - FrameContent::DisconnectedMode(abm) => { - (vec![], format!("final bit: {}", abm.final_bit)) - } - FrameContent::UnnumberedAcknowledge(abm) => { - (vec![], format!("final bit: {}", abm.final_bit)) - } - FrameContent::FrameReject(fr) => ( - vec![], - format!( - "[{}{}{}{}], seq: {}/{}, raw: {}, cmdRsp: {}, final: {}", - if fr.z { "Z" } else { "" }, - if fr.y { "Y" } else { "" }, - if fr.x { "X" } else { "" }, - if fr.w { "W" } else { "" }, - fr.send_sequence, - fr.receive_sequence, - fr.rejected_control_field_raw, - match fr.command_response { - CommandResponse::Command => "CMD", - CommandResponse::Response => "RSP", - }, - fr.final_bit - ), - ), - FrameContent::UnnumberedInformation(ui) => { - (ui.info.clone(), format!("pid: {:?} info:", ui.pid)) - } - FrameContent::UnknownContent(ukn) => (ukn.raw.clone(), format!("")), - }; - let mut data = String::new(); - for byte in rawdata.iter() { - //if byte >= ' '.into() && byte <= '~'.into() { - if *byte >= 32 && *byte <= 126 { - data.push((*byte).into()); - } else { - data.push_str(&format!("\\{:x?} ", *byte)); - } - } - println!( - "AX.25 {:12} {} {:9} -> {:9} via [{}] {} {}", - ftype, rsp, src, dst, via, finfo, data - ); - } -} diff --git a/src/print_frame.rs b/src/print_frame.rs new file mode 100644 index 0000000..b1bc2f3 --- /dev/null +++ b/src/print_frame.rs @@ -0,0 +1,218 @@ +use ax25::frame::{Ax25Frame, CommandResponse, FrameContent}; +pub trait PrintFrame { + fn type_str_short(&self) -> &'static str; + fn print_short(&self); + fn print_long(&self); +} +impl PrintFrame for Ax25Frame { + fn type_str_short(&self) -> &'static str { + match self.content { + FrameContent::Information(_) => "Info", + FrameContent::ReceiveReady(_) => "RecvRdy", + FrameContent::ReceiveNotReady(_) => "RecvNotRdy", + FrameContent::Reject(_) => "Reject", + FrameContent::SetAsynchronousBalancedMode(_) => "AsyncBalMode", //12 long + FrameContent::Disconnect(_) => "Disconnect", + FrameContent::DisconnectedMode(_) => "DisconMode", + FrameContent::UnnumberedAcknowledge(_) => "UnNumAck", + FrameContent::FrameReject(_) => "FrameReject", + FrameContent::UnnumberedInformation(_) => "UnNumInfo", + FrameContent::UnknownContent(_) => "Unknown", + } + } + fn print_short(&self) { + //Format: "[source] -> [dest] via [..] [CMD/RSP/NIL] [frameType]: [DATA str rep]" + let src = self.source.to_string(); + let dst = self.destination.to_string(); + //let via: String = self.route.iter().map(|re| format!(" {} ", re.repeater.to_string())).collect(); //todo + let rsp = match self.command_or_response { + Some(CommandResponse::Command) => "CMD", + Some(CommandResponse::Response) => "RSP", + None => "NIL", + }; + let ftype = self.type_str_short(); + let mut routed = false; + for route in self.route.iter() { + if route.has_repeated { + routed = true; + break; + } + } + let arrow_shaft = if routed { "=" } else { "-" }; + + //let mut rawdata; + let (rawdata, finfo) = match &self.content { + FrameContent::Information(_i) => ( + _i.info.clone(), + format!( + "pid: {:?}, seq: {}/{}, info: ", + _i.pid, _i.send_sequence, _i.receive_sequence + ), + ), + FrameContent::ReceiveReady(rr) => ( + vec![], + format!( + "seq: {}, poll/final: {}", + rr.receive_sequence, rr.poll_or_final + ), + ), + FrameContent::ReceiveNotReady(rnr) => ( + vec![], + format!( + "seq: {}, poll/final: {}", + rnr.receive_sequence, rnr.poll_or_final + ), + ), + FrameContent::Reject(rnr) => ( + vec![], + format!( + "seq: {}, poll/final: {}", + rnr.receive_sequence, rnr.poll_or_final + ), + ), + FrameContent::SetAsynchronousBalancedMode(abm) => { + (vec![], format!("poll: {}", abm.poll)) + } + FrameContent::Disconnect(abm) => (vec![], format!("poll: {}", abm.poll)), + FrameContent::DisconnectedMode(abm) => { + (vec![], format!("final bit: {}", abm.final_bit)) + } + FrameContent::UnnumberedAcknowledge(abm) => { + (vec![], format!("final bit: {}", abm.final_bit)) + } + FrameContent::FrameReject(fr) => ( + vec![], + format!( + "[{}{}{}{}], seq: {}/{}, raw: {}, cmdRsp: {}, final: {}", + if fr.z { "Z" } else { "" }, + if fr.y { "Y" } else { "" }, + if fr.x { "X" } else { "" }, + if fr.w { "W" } else { "" }, + fr.send_sequence, + fr.receive_sequence, + fr.rejected_control_field_raw, + match fr.command_response { + CommandResponse::Command => "CMD", + CommandResponse::Response => "RSP", + }, + fr.final_bit + ), + ), + FrameContent::UnnumberedInformation(ui) => { + (ui.info.clone(), format!("pid: {:?} info:", ui.pid)) + } + FrameContent::UnknownContent(ukn) => (ukn.raw.clone(), format!("")), + }; + let mut data = String::new(); + for byte in rawdata.iter() { + //if byte >= ' '.into() && byte <= '~'.into() { + if *byte >= 32 && *byte <= 126 { + data.push((*byte).into()); + } else { + data.push_str(&format!("\\{:x?} ", *byte)); + } + } + println!( + "AX.25 {:12} {} {:9} {}> {:9} {}", + ftype, + rsp, + src, + arrow_shaft, + dst, + if !data.is_empty() { data } else { finfo } + ); + } + fn print_long(&self) { + //Format: "[source] -> [dest] via [..] [CMD/RSP/NIL] [frameType]: [DATA str rep]" + let src = self.source.to_string(); + let dst = self.destination.to_string(); + let via: String = self + .route + .iter() + .map(|re| format!(" {} ", re.repeater.to_string())) + .collect(); //todo + let rsp = match self.command_or_response { + Some(CommandResponse::Command) => "CMD", + Some(CommandResponse::Response) => "RSP", + None => "NIL", + }; + let ftype = self.type_str_short(); + + //let mut rawdata; + let (rawdata, finfo) = match &self.content { + FrameContent::Information(_i) => ( + _i.info.clone(), + format!( + "pid: {:?}, seq: {}/{}, info: ", + _i.pid, _i.send_sequence, _i.receive_sequence + ), + ), + FrameContent::ReceiveReady(rr) => ( + vec![], + format!( + "seq: {}, poll/final: {}", + rr.receive_sequence, rr.poll_or_final + ), + ), + FrameContent::ReceiveNotReady(rnr) => ( + vec![], + format!( + "seq: {}, poll/final: {}", + rnr.receive_sequence, rnr.poll_or_final + ), + ), + FrameContent::Reject(rnr) => ( + vec![], + format!( + "seq: {}, poll/final: {}", + rnr.receive_sequence, rnr.poll_or_final + ), + ), + FrameContent::SetAsynchronousBalancedMode(abm) => { + (vec![], format!("poll: {}", abm.poll)) + } + FrameContent::Disconnect(abm) => (vec![], format!("poll: {}", abm.poll)), + FrameContent::DisconnectedMode(abm) => { + (vec![], format!("final bit: {}", abm.final_bit)) + } + FrameContent::UnnumberedAcknowledge(abm) => { + (vec![], format!("final bit: {}", abm.final_bit)) + } + FrameContent::FrameReject(fr) => ( + vec![], + format!( + "[{}{}{}{}], seq: {}/{}, raw: {}, cmdRsp: {}, final: {}", + if fr.z { "Z" } else { "" }, + if fr.y { "Y" } else { "" }, + if fr.x { "X" } else { "" }, + if fr.w { "W" } else { "" }, + fr.send_sequence, + fr.receive_sequence, + fr.rejected_control_field_raw, + match fr.command_response { + CommandResponse::Command => "CMD", + CommandResponse::Response => "RSP", + }, + fr.final_bit + ), + ), + FrameContent::UnnumberedInformation(ui) => { + (ui.info.clone(), format!("pid: {:?} info:", ui.pid)) + } + FrameContent::UnknownContent(ukn) => (ukn.raw.clone(), format!("")), + }; + let mut data = String::new(); + for byte in rawdata.iter() { + //if byte >= ' '.into() && byte <= '~'.into() { + if *byte >= 32 && *byte <= 126 { + data.push((*byte).into()); + } else { + data.push_str(&format!("\\{:x?} ", *byte)); + } + } + println!( + "AX.25 {:12} {} {:9} -> {:9} via [{}] {} {}", + ftype, rsp, src, dst, via, finfo, data + ); + } +}