1#![deny(clippy::all)]
2#![allow(dead_code)]
3use bitflags::bitflags;
48pub use embedded_can::{ExtendedId, Id, StandardId};
49use libc::{
50 bind, c_int, c_short, c_void, close, fcntl, read, setsockopt, sockaddr, socket, write, F_GETFL,
51 F_SETFL, O_NONBLOCK, SOCK_DGRAM,
52};
53use nix::net::if_::if_nametoindex;
54use std::convert::TryFrom;
55use std::convert::TryInto;
56use std::io;
57use std::mem::size_of;
58use std::num::TryFromIntError;
59use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
60use std::time::Duration;
61use thiserror::Error;
62
63pub const AF_CAN: c_short = 29;
65
66pub const PF_CAN: c_int = 29;
68
69pub const CAN_ISOTP: c_int = 6;
71
72pub const SOL_CAN_BASE: c_int = 100;
74
75pub const SOL_CAN_ISOTP: c_int = SOL_CAN_BASE + CAN_ISOTP;
77
78pub const CAN_ISOTP_OPTS: c_int = 1;
80
81pub const CAN_ISOTP_RECV_FC: c_int = 2;
83
84pub const CAN_ISOTP_TX_STMIN: c_int = 3;
88
89pub const CAN_ISOTP_RX_STMIN: c_int = 4;
93
94pub const CAN_ISOTP_LL_OPTS: c_int = 5;
96
97pub const CAN_MAX_DLEN: u8 = 8;
99
100pub const RECV_BUFFER_SIZE: usize = 4096;
102
103const SIZE_OF_CAN_FRAME: u8 = 16;
106
107const FLOW_CONTROL_OPTIONS_SIZE: usize = size_of::<FlowControlOptions>();
108
109const ISOTP_OPTIONS_SIZE: usize = size_of::<IsoTpOptions>();
110
111const LINK_LAYER_OPTIONS_SIZE: usize = size_of::<LinkLayerOptions>();
112
113const CAN_ISOTP_DEFAULT_RECV_BS: u8 = 0;
114
115const CAN_ISOTP_DEFAULT_RECV_STMIN: u8 = 0x00;
116
117const CAN_ISOTP_DEFAULT_RECV_WFTMAX: u8 = 0;
118
119bitflags! {
120 pub struct IsoTpBehaviour: u32 {
121 const CAN_ISOTP_LISTEN_MODE = 0x001;
123 const CAN_ISOTP_EXTEND_ADDR = 0x002;
125 const CAN_ISOTP_TX_PADDING = 0x004;
127 const CAN_ISOTP_RX_PADDING = 0x008;
129 const CAN_ISOTP_CHK_PAD_LEN = 0x010;
131 const CAN_ISOTP_CHK_PAD_DATA = 0x020;
133 const CAN_ISOTP_HALF_DUPLEX = 0x040;
135 const CAN_ISOTP_FORCE_TXSTMIN = 0x080;
137 const CAN_ISOTP_FORCE_RXSTMIN = 0x100;
139 const CAN_ISOTP_RX_EXT_ADDR = 0x200;
141 }
142}
143
144pub const EFF_FLAG: u32 = 0x8000_0000;
146
147pub const RTR_FLAG: u32 = 0x4000_0000;
149
150pub const ERR_FLAG: u32 = 0x2000_0000;
152
153pub const SFF_MASK: u32 = 0x0000_07ff;
155
156pub const EFF_MASK: u32 = 0x1fff_ffff;
158
159pub const ERR_MASK: u32 = 0x1fff_ffff;
161
162pub const ERR_MASK_ALL: u32 = ERR_MASK;
164
165pub const ERR_MASK_NONE: u32 = 0;
167
168#[derive(Debug)]
169#[repr(C)]
170struct CanAddr {
171 _af_can: c_short,
172 if_index: c_int, rx_id: u32,
175 tx_id: u32,
177 _pgn: u32,
178 _addr: u8,
179}
180
181#[repr(C)]
183pub struct IsoTpOptions {
184 flags: u32,
186 frame_txtime: u32,
189 ext_address: u8,
191 txpad_content: u8,
193 rxpad_content: u8,
195 rx_ext_address: u8,
197}
198
199impl IsoTpOptions {
200 pub fn new(
201 flags: IsoTpBehaviour,
202 frame_txtime: Duration,
203 ext_address: u8,
204 txpad_content: u8,
205 rxpad_content: u8,
206 rx_ext_address: u8,
207 ) -> Result<Self, TryFromIntError> {
208 let flags = flags.bits();
209 let frame_txtime = u32::try_from(frame_txtime.as_nanos())?;
210
211 Ok(Self {
212 flags,
213 frame_txtime,
214 ext_address,
215 txpad_content,
216 rxpad_content,
217 rx_ext_address,
218 })
219 }
220
221 pub fn get_flags(&self) -> Option<IsoTpBehaviour> {
223 IsoTpBehaviour::from_bits(self.flags)
224 }
225
226 pub fn set_flags(&mut self, flags: IsoTpBehaviour) {
228 self.flags = flags.bits();
229 }
230
231 pub fn get_frame_txtime(&self) -> Duration {
233 Duration::from_nanos(self.frame_txtime.into())
234 }
235
236 pub fn set_frame_txtime(&mut self, frame_txtime: Duration) -> Result<(), TryFromIntError> {
238 self.frame_txtime = u32::try_from(frame_txtime.as_nanos())?;
239 Ok(())
240 }
241
242 pub fn get_ext_address(&self) -> u8 {
244 self.ext_address
245 }
246
247 pub fn set_ext_address(&mut self, ext_address: u8) {
249 self.ext_address = ext_address;
250 }
251
252 pub fn get_txpad_content(&self) -> u8 {
254 self.txpad_content
255 }
256
257 pub fn set_txpad_content(&mut self, txpad_content: u8) {
259 self.txpad_content = txpad_content;
260 }
261
262 pub fn get_rxpad_content(&self) -> u8 {
264 self.rxpad_content
265 }
266
267 pub fn set_rxpad_content(&mut self, rxpad_content: u8) {
269 self.rxpad_content = rxpad_content;
270 }
271
272 pub fn get_rx_ext_address(&self) -> u8 {
274 self.rx_ext_address
275 }
276
277 pub fn set_rx_ext_address(&mut self, rx_ext_address: u8) {
279 self.rx_ext_address = rx_ext_address;
280 }
281}
282
283impl Default for IsoTpOptions {
284 fn default() -> Self {
285 Self {
287 flags: 0x00,
288 frame_txtime: 0x00,
289 ext_address: 0x00,
290 txpad_content: 0xCC,
291 rxpad_content: 0xCC,
292 rx_ext_address: 0x00,
293 }
294 }
295}
296
297#[repr(C)]
299pub struct FlowControlOptions {
300 bs: u8,
303 stmin: u8,
310 wftmax: u8,
313}
314
315impl Default for FlowControlOptions {
316 fn default() -> Self {
317 Self {
318 bs: CAN_ISOTP_DEFAULT_RECV_BS,
319 stmin: CAN_ISOTP_DEFAULT_RECV_STMIN,
320 wftmax: CAN_ISOTP_DEFAULT_RECV_WFTMAX,
321 }
322 }
323}
324
325impl FlowControlOptions {
326 pub fn new(bs: u8, stmin: u8, wftmax: u8) -> Self {
335 Self { bs, stmin, wftmax }
336 }
337}
338
339bitflags! {
340 pub struct TxFlags: u8 {
341 const CANFD_BRS = 0x01;
343 const CANFD_ESI = 0x02;
345 }
346}
347
348#[repr(C)]
350pub struct LinkLayerOptions {
351 mtu: u8,
355 tx_dl: u8,
360 tx_flags: u8,
365}
366
367impl LinkLayerOptions {
368 pub fn new(mtu: u8, tx_dl: u8, tx_flags: TxFlags) -> Self {
369 let tx_flags = tx_flags.bits();
370 Self {
371 mtu,
372 tx_dl,
373 tx_flags,
374 }
375 }
376}
377
378impl Default for LinkLayerOptions {
379 fn default() -> Self {
380 Self {
381 mtu: SIZE_OF_CAN_FRAME,
383 tx_dl: CAN_MAX_DLEN,
385 tx_flags: 0x00,
387 }
388 }
389}
390
391#[derive(Error, Debug)]
392pub enum Error {
394 #[error("Failed to find can device: {source:?}")]
396 Lookup {
397 #[from]
398 source: nix::Error,
399 },
400
401 #[error("IO error: {source:?}")]
403 Io {
404 #[from]
405 source: io::Error,
406 },
407}
408pub struct IsoTpSocket {
413 fd: c_int,
414 recv_buffer: [u8; RECV_BUFFER_SIZE],
415}
416
417impl IsoTpSocket {
418 pub fn open(ifname: &str, src: impl Into<Id>, dst: impl Into<Id>) -> Result<Self, Error> {
423 Self::open_with_opts(
424 ifname,
425 src,
426 dst,
427 Some(IsoTpOptions::default()),
428 Some(FlowControlOptions::default()),
429 Some(LinkLayerOptions::default()),
430 )
431 }
432
433 pub fn open_with_opts(
438 ifname: &str,
439 src: impl Into<Id>,
440 dst: impl Into<Id>,
441 isotp_options: Option<IsoTpOptions>,
442 rx_flow_control_options: Option<FlowControlOptions>,
443 link_layer_options: Option<LinkLayerOptions>,
444 ) -> Result<Self, Error> {
445 let if_index = if_nametoindex(ifname)?;
446 Self::open_if_with_opts(
447 if_index.try_into().unwrap(),
448 src,
449 dst,
450 isotp_options,
451 rx_flow_control_options,
452 link_layer_options,
453 )
454 }
455
456 pub fn open_if(if_index: c_int, src: impl Into<Id>, dst: impl Into<Id>) -> Result<Self, Error> {
460 Self::open_if_with_opts(
461 if_index,
462 src,
463 dst,
464 Some(IsoTpOptions::default()),
465 Some(FlowControlOptions::default()),
466 Some(LinkLayerOptions::default()),
467 )
468 }
469
470 pub fn open_if_with_opts(
474 if_index: c_int,
475 src: impl Into<Id>,
476 dst: impl Into<Id>,
477 isotp_options: Option<IsoTpOptions>,
478 rx_flow_control_options: Option<FlowControlOptions>,
479 link_layer_options: Option<LinkLayerOptions>,
480 ) -> Result<Self, Error> {
481 let rx_id = match src.into() {
482 Id::Standard(standard_id) => standard_id.as_raw() as u32,
483 Id::Extended(extended_id) => extended_id.as_raw() | EFF_FLAG,
484 };
485 let tx_id = match dst.into() {
486 Id::Standard(standard_id) => standard_id.as_raw() as u32,
487 Id::Extended(extended_id) => extended_id.as_raw() | EFF_FLAG,
488 };
489 let addr = CanAddr {
490 _af_can: AF_CAN,
491 if_index,
492 rx_id,
493 tx_id,
494 _pgn: 0,
495 _addr: 0,
496 };
497
498 let sock_fd;
500 unsafe {
501 sock_fd = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP);
502 }
503
504 if sock_fd == -1 {
505 return Err(Error::from(io::Error::last_os_error()));
506 }
507
508 if let Some(isotp_options) = isotp_options {
510 let isotp_options_ptr: *const c_void = &isotp_options as *const _ as *const c_void;
511 let err = unsafe {
512 setsockopt(
513 sock_fd,
514 SOL_CAN_ISOTP,
515 CAN_ISOTP_OPTS,
516 isotp_options_ptr,
517 ISOTP_OPTIONS_SIZE.try_into().unwrap(),
518 )
519 };
520 if err == -1 {
521 return Err(Error::from(io::Error::last_os_error()));
522 }
523 }
524
525 if let Some(rx_flow_control_options) = rx_flow_control_options {
527 let rx_flow_control_options_ptr: *const c_void =
528 &rx_flow_control_options as *const _ as *const c_void;
529 let err = unsafe {
530 setsockopt(
531 sock_fd,
532 SOL_CAN_ISOTP,
533 CAN_ISOTP_RECV_FC,
534 rx_flow_control_options_ptr,
535 FLOW_CONTROL_OPTIONS_SIZE.try_into().unwrap(),
536 )
537 };
538 if err == -1 {
539 return Err(Error::from(io::Error::last_os_error()));
540 }
541 }
542
543 if let Some(link_layer_options) = link_layer_options {
545 let link_layer_options_ptr: *const c_void =
546 &link_layer_options as *const _ as *const c_void;
547 let err = unsafe {
548 setsockopt(
549 sock_fd,
550 SOL_CAN_ISOTP,
551 CAN_ISOTP_LL_OPTS,
552 link_layer_options_ptr,
553 LINK_LAYER_OPTIONS_SIZE.try_into().unwrap(),
554 )
555 };
556 if err == -1 {
557 return Err(Error::from(io::Error::last_os_error()));
558 }
559 }
560
561 let bind_rv;
563 unsafe {
564 let sockaddr_ptr = &addr as *const CanAddr;
565 bind_rv = bind(
566 sock_fd,
567 sockaddr_ptr as *const sockaddr,
568 size_of::<CanAddr>().try_into().unwrap(),
569 );
570 }
571
572 if bind_rv == -1 {
574 let e = io::Error::last_os_error();
575 unsafe {
576 close(sock_fd);
577 }
578 return Err(Error::from(e));
579 }
580
581 Ok(Self {
582 fd: sock_fd,
583 recv_buffer: [0x00; RECV_BUFFER_SIZE],
584 })
585 }
586
587 fn close(&mut self) -> io::Result<()> {
588 unsafe {
589 let rv = close(self.fd);
590 if rv != -1 {
591 return Err(io::Error::last_os_error());
592 }
593 }
594 Ok(())
595 }
596
597 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
599 let oldfl = unsafe { fcntl(self.fd, F_GETFL) };
601
602 if oldfl == -1 {
603 return Err(io::Error::last_os_error());
604 }
605
606 let newfl = if nonblocking {
607 oldfl | O_NONBLOCK
608 } else {
609 oldfl & !O_NONBLOCK
610 };
611
612 let rv = unsafe { fcntl(self.fd, F_SETFL, newfl) };
613
614 if rv != 0 {
615 return Err(io::Error::last_os_error());
616 }
617 Ok(())
618 }
619
620 pub fn read(&mut self) -> io::Result<&[u8]> {
622 let buffer_ptr = &mut self.recv_buffer as *mut _ as *mut c_void;
623
624 let read_rv = unsafe { read(self.fd, buffer_ptr, RECV_BUFFER_SIZE) };
625
626 if read_rv < 0 {
627 return Err(io::Error::last_os_error());
628 }
629
630 Ok(&self.recv_buffer[0..read_rv.try_into().unwrap()])
631 }
632
633 pub fn write(&self, buffer: &[u8]) -> io::Result<()> {
634 let write_rv = unsafe {
635 let buffer_ptr = buffer as *const _ as *const c_void;
636 write(self.fd, buffer_ptr, buffer.len())
637 };
638 if write_rv != buffer.len().try_into().unwrap() {
639 return Err(io::Error::last_os_error());
640 }
641 Ok(())
642 }
643
644 pub fn read_to_vec(&self) -> io::Result<Vec<u8>> {
645 let mut buffer: [u8; RECV_BUFFER_SIZE] = [0; RECV_BUFFER_SIZE];
646 let buffer_ptr = &mut buffer as *mut _ as *mut c_void;
647
648 let read_rv = unsafe { read(self.fd, buffer_ptr, RECV_BUFFER_SIZE) };
649
650 if read_rv < 0 {
651 return Err(io::Error::last_os_error());
652 }
653
654 Ok(buffer[0..read_rv.try_into().unwrap()].to_vec())
655 }
656}
657
658impl AsRawFd for IsoTpSocket {
659 fn as_raw_fd(&self) -> RawFd {
660 self.fd
661 }
662}
663
664impl FromRawFd for IsoTpSocket {
665 unsafe fn from_raw_fd(fd: RawFd) -> Self {
666 Self {
667 fd,
668 recv_buffer: [0x00; RECV_BUFFER_SIZE],
669 }
670 }
671}
672
673impl IntoRawFd for IsoTpSocket {
674 fn into_raw_fd(self) -> RawFd {
675 self.fd
676 }
677}
678
679impl Drop for IsoTpSocket {
680 fn drop(&mut self) {
681 self.close().ok(); }
683}