From 0510642b229202c0bbd98026618e7293974c0a15 Mon Sep 17 00:00:00 2001 From: Adrian Date: Tue, 29 Apr 2025 14:07:46 +0200 Subject: [PATCH] feat: Port missing IsoTpBehaviour flags Extend API to add flags --- src/lib.rs | 107 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 35 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index afeb655..129738e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,6 +135,14 @@ bitflags! { const CAN_ISOTP_FORCE_RXSTMIN = 0x100; /// different rx extended addressing const CAN_ISOTP_RX_EXT_ADDR = 0x200; + /// wait for tx completion + const CAN_ISOTP_WAIT_TX_DONE = 0x0400; + /// 1-to-N functional addressing + const CAN_ISOTP_SF_BROADCAST = 0x0800; + /// 1-to-N transmission w/o FC + const CAN_ISOTP_CF_BROADCAST = 0x1000; + /// dynamic FC parameters BS/STmin + const CAN_ISOTP_DYN_FC_PARMS = 0x2000; } } @@ -220,7 +228,12 @@ impl IsoTpOptions { IsoTpBehaviour::from_bits(self.flags) } - /// set flags for isotp behaviour. + /// add the given ISO-TP behavior flags to the current flags + pub fn add_flags(&mut self, flags: IsoTpBehaviour) { + self.flags |= flags.bits(); + } + + /// replace the current ISO-TP behavior flags with the given flags pub fn set_flags(&mut self, flags: IsoTpBehaviour) { self.flags = flags.bits(); } @@ -412,6 +425,13 @@ pub struct IsoTpSocket { } impl IsoTpSocket { + fn new(fd: i32) -> Self { + Self { + fd, + recv_buffer: [0x00; RECV_BUFFER_SIZE], + } + } + /// Open a named CAN ISO-TP device. /// /// Usually the more common case, opens a socket can device by name, such @@ -479,24 +499,28 @@ impl IsoTpSocket { rx_flow_control_options: Option, link_layer_options: Option, ) -> Result { - let rx_id = match rx_id.into() { - Id::Standard(standard_id) => standard_id.as_raw() as u32, - Id::Extended(extended_id) => extended_id.as_raw() | EFF_FLAG, - }; - let tx_id = match tx_id.into() { - Id::Standard(standard_id) => standard_id.as_raw() as u32, - Id::Extended(extended_id) => extended_id.as_raw() | EFF_FLAG, - }; let addr = CanAddr { _af_can: AF_CAN, if_index, - rx_id, - tx_id, + rx_id: Self::to_raw_can_id(rx_id), + tx_id: Self::to_raw_can_id(tx_id), _pgn: 0, _addr: 0, }; - // open socket + let sock_fd = Self::open_socket()?; + Self::set_socket_opts( + sock_fd, + isotp_options, + rx_flow_control_options, + link_layer_options, + )?; + Self::bind_addr(sock_fd, addr)?; + + Ok(Self::new(sock_fd)) + } + + fn open_socket() -> Result { let sock_fd; unsafe { sock_fd = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP); @@ -505,7 +529,37 @@ impl IsoTpSocket { if sock_fd == -1 { return Err(Error::from(io::Error::last_os_error())); } + Ok(sock_fd) + } + + fn bind_addr(sock_fd: i32, addr: CanAddr) -> Result<(), Error> { + let sockaddr_ptr = &addr as *const CanAddr; + let bind_rv = unsafe { + bind( + sock_fd, + sockaddr_ptr as *const sockaddr, + size_of::().try_into().unwrap(), + ) + }; + + // FIXME: on fail, close socket (do not leak socketfds) + if bind_rv == -1 { + let e = io::Error::last_os_error(); + unsafe { + close(sock_fd); + } + return Err(Error::from(e)); + } + Ok(()) + } + + fn set_socket_opts( + sock_fd: i32, + isotp_options: Option, + rx_flow_control_options: Option, + link_layer_options: Option, + ) -> Result<(), Error> { // Set IsoTpOptions if let Some(isotp_options) = isotp_options { let isotp_options_ptr: *const c_void = &isotp_options as *const _ as *const c_void; @@ -558,31 +612,14 @@ impl IsoTpSocket { return Err(Error::from(io::Error::last_os_error())); } } + Ok(()) + } - // bind it - let bind_rv; - unsafe { - let sockaddr_ptr = &addr as *const CanAddr; - bind_rv = bind( - sock_fd, - sockaddr_ptr as *const sockaddr, - size_of::().try_into().unwrap(), - ); - } - - // FIXME: on fail, close socket (do not leak socketfds) - if bind_rv == -1 { - let e = io::Error::last_os_error(); - unsafe { - close(sock_fd); - } - return Err(Error::from(e)); + fn to_raw_can_id(id: impl Into) -> u32 { + match id.into() { + Id::Standard(standard_id) => standard_id.as_raw() as u32, + Id::Extended(extended_id) => extended_id.as_raw() | EFF_FLAG, } - - Ok(Self { - fd: sock_fd, - recv_buffer: [0x00; RECV_BUFFER_SIZE], - }) } fn close(&mut self) -> io::Result<()> {