1use can_isotp_interface::{
7 IsoTpRxFlowControlConfig, RecvControl, RecvError, RecvMeta, RecvMetaIntoStatus, RecvStatus,
8 RxFlowControl, SendError,
9};
10use can_uds::uds29;
11use core::time::Duration;
12use embedded_can::{ExtendedId, Id};
13use socket2::{Domain, Protocol, Socket, Type};
14use socketcan::CanAddr;
15use std::io;
16use std::mem::size_of;
17use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
18use std::thread;
19use std::time::Instant;
20
21#[cfg(feature = "tokio")]
22use tokio::io::unix::AsyncFd;
23
24#[cfg(feature = "tokio")]
25use can_isotp_interface::IsoTpAsyncEndpoint;
26#[cfg(feature = "tokio")]
27use can_isotp_interface::IsoTpAsyncEndpointRecvInto;
28
29#[derive(Debug)]
31pub enum Error {
32 Io(io::Error),
34 InvalidConfig(&'static str),
36}
37
38impl From<io::Error> for Error {
39 fn from(err: io::Error) -> Self {
40 Self::Io(err)
41 }
42}
43
44impl core::fmt::Display for Error {
45 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46 match self {
47 Error::Io(err) => write!(f, "io error: {err}"),
48 Error::InvalidConfig(msg) => write!(f, "invalid config: {msg}"),
49 }
50 }
51}
52
53impl std::error::Error for Error {}
54
55#[derive(Debug, Clone, Default)]
57pub struct IsoTpSocketOptions {
58 pub flags: u32,
60 pub frame_txtime: Option<Duration>,
62 pub ext_address: Option<u8>,
64 pub tx_padding: Option<u8>,
66 pub rx_padding: Option<u8>,
68 pub rx_ext_address: Option<u8>,
70}
71
72#[derive(Debug, Clone, Copy)]
74pub struct IsoTpFlowControlOptions {
75 pub block_size: u8,
77 pub st_min: u8,
79 pub wft_max: u8,
81}
82
83impl IsoTpFlowControlOptions {
84 pub fn new(block_size: u8, st_min: u8, wft_max: u8) -> Self {
86 Self {
87 block_size,
88 st_min,
89 wft_max,
90 }
91 }
92}
93
94#[derive(Debug, Clone, Copy)]
96pub struct IsoTpLinkLayerOptions {
97 pub mtu: u8,
99 pub tx_dl: u8,
101 pub tx_flags: u8,
103}
104
105impl IsoTpLinkLayerOptions {
106 pub fn new(mtu: u8, tx_dl: u8, tx_flags: u8) -> Self {
108 Self {
109 mtu,
110 tx_dl,
111 tx_flags,
112 }
113 }
114}
115
116#[derive(Debug, Clone)]
118pub struct IsoTpKernelOptions {
119 pub max_rx_payload: usize,
121 pub socket: IsoTpSocketOptions,
123 pub flow_control: Option<IsoTpFlowControlOptions>,
125 pub link_layer: Option<IsoTpLinkLayerOptions>,
127 pub force_tx_stmin: Option<Duration>,
129 pub force_rx_stmin: Option<Duration>,
131}
132
133impl Default for IsoTpKernelOptions {
134 fn default() -> Self {
135 Self {
136 max_rx_payload: 4095,
137 socket: IsoTpSocketOptions::default(),
138 flow_control: None,
139 link_layer: None,
140 force_tx_stmin: None,
141 force_rx_stmin: None,
142 }
143 }
144}
145
146#[derive(Debug)]
148pub struct SocketCanIsoTp {
149 fd: OwnedFd,
150 rx_buf: Vec<u8>,
151 wft_max: u8,
152}
153
154impl SocketCanIsoTp {
155 pub fn open(
157 iface: &str,
158 rx_id: Id,
159 tx_id: Id,
160 options: &IsoTpKernelOptions,
161 ) -> Result<Self, Error> {
162 if options.max_rx_payload == 0 {
163 return Err(Error::InvalidConfig("max_rx_payload must be > 0"));
164 }
165
166 let socket = Socket::new(
167 Domain::from(libc::AF_CAN),
168 Type::DGRAM,
169 Some(Protocol::from(libc::CAN_ISOTP)),
170 )?;
171
172 socket.set_nonblocking(true)?;
173
174 apply_kernel_options(socket.as_raw_fd(), options)?;
176
177 let addr = CanAddr::from_iface_isotp(iface, rx_id, tx_id).map_err(Error::Io)?;
178 socket.bind(&addr.into_sock_addr())?;
179
180 let fd = unsafe { OwnedFd::from_raw_fd(socket.into_raw_fd()) };
181 let wft_max = options.flow_control.map(|fc| fc.wft_max).unwrap_or(0);
182 Ok(Self {
183 fd,
184 rx_buf: vec![0u8; options.max_rx_payload],
185 wft_max,
186 })
187 }
188
189 pub fn set_rx_flow_control(&mut self, fc: RxFlowControl) -> Result<(), Error> {
194 let c = can_isotp_fc_options {
195 bs: fc.block_size,
196 stmin: duration_to_isotp_stmin(fc.st_min),
197 wftmax: self.wft_max,
198 };
199 let res = unsafe {
200 libc::setsockopt(
201 self.fd.as_raw_fd(),
202 SOL_CAN_ISOTP,
203 CAN_ISOTP_RECV_FC,
204 &c as *const can_isotp_fc_options as *const libc::c_void,
205 size_of::<can_isotp_fc_options>() as libc::socklen_t,
206 )
207 };
208 if res < 0 {
209 return Err(Error::Io(io::Error::last_os_error()));
210 }
211 Ok(())
212 }
213
214 fn recv_one_ready<Cb>(&mut self, mut on_payload: Cb) -> Result<RecvStatus, RecvError<Error>>
215 where
216 Cb: FnMut(&[u8]) -> Result<RecvControl, Error>,
217 {
218 let read = unsafe {
219 libc::recv(
220 self.fd.as_raw_fd(),
221 self.rx_buf.as_mut_ptr().cast(),
222 self.rx_buf.len(),
223 libc::MSG_DONTWAIT,
224 )
225 };
226 if read < 0 {
227 let err = io::Error::last_os_error();
228 if err.kind() == io::ErrorKind::WouldBlock {
229 return Ok(RecvStatus::TimedOut);
230 }
231 return Err(RecvError::Backend(Error::Io(err)));
232 }
233 if read == 0 {
234 return Err(RecvError::Backend(Error::Io(io::Error::new(
235 io::ErrorKind::UnexpectedEof,
236 "iso-tp socket returned 0 bytes",
237 ))));
238 }
239 let payload = &self.rx_buf[..read as usize];
240 let _ = on_payload(payload).map_err(RecvError::Backend)?;
241 Ok(RecvStatus::DeliveredOne)
242 }
243}
244
245impl AsRawFd for SocketCanIsoTp {
246 fn as_raw_fd(&self) -> RawFd {
247 self.fd.as_raw_fd()
248 }
249}
250
251impl can_isotp_interface::IsoTpEndpoint for SocketCanIsoTp {
252 type Error = Error;
253
254 fn send_to(
255 &mut self,
256 _to: u8,
257 payload: &[u8],
258 timeout: Duration,
259 ) -> Result<(), SendError<Self::Error>> {
260 let deadline = Instant::now() + timeout;
261 loop {
262 let sent = unsafe {
263 libc::send(
264 self.fd.as_raw_fd(),
265 payload.as_ptr().cast(),
266 payload.len(),
267 libc::MSG_DONTWAIT,
268 )
269 };
270 if sent >= 0 {
271 return Ok(());
272 }
273
274 let err = io::Error::last_os_error();
275 if err.kind() == io::ErrorKind::Interrupted {
276 continue;
277 }
278 if err.kind() != io::ErrorKind::WouldBlock {
279 return Err(SendError::Backend(Error::Io(err)));
280 }
281
282 let now = Instant::now();
283 if now >= deadline {
284 return Err(SendError::Timeout);
285 }
286 let remaining = deadline - now;
287 let ready = poll_fd(self.fd.as_raw_fd(), libc::POLLOUT, remaining)
288 .map_err(Error::Io)
289 .map_err(SendError::Backend)?;
290 if !ready {
291 return Err(SendError::Timeout);
292 }
293 }
294 }
295
296 fn send_functional_to(
297 &mut self,
298 _functional_to: u8,
299 payload: &[u8],
300 timeout: Duration,
301 ) -> Result<(), SendError<Self::Error>> {
302 self.send_to(0, payload, timeout)
303 }
304
305 fn recv_one<Cb>(
306 &mut self,
307 timeout: Duration,
308 mut on_payload: Cb,
309 ) -> Result<RecvStatus, RecvError<Self::Error>>
310 where
311 Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>,
312 {
313 let deadline = Instant::now() + timeout;
314 loop {
315 let read = unsafe {
316 libc::recv(
317 self.fd.as_raw_fd(),
318 self.rx_buf.as_mut_ptr().cast(),
319 self.rx_buf.len(),
320 libc::MSG_DONTWAIT,
321 )
322 };
323 if read >= 0 {
324 if read == 0 {
325 return Err(RecvError::Backend(Error::Io(io::Error::new(
326 io::ErrorKind::UnexpectedEof,
327 "iso-tp socket returned 0 bytes",
328 ))));
329 }
330
331 let payload = &self.rx_buf[..read as usize];
332 let _ =
333 on_payload(RecvMeta { reply_to: 0 }, payload).map_err(RecvError::Backend)?;
334 return Ok(RecvStatus::DeliveredOne);
335 }
336
337 let err = io::Error::last_os_error();
338 if err.kind() == io::ErrorKind::Interrupted {
339 continue;
340 }
341 if err.kind() != io::ErrorKind::WouldBlock {
342 return Err(RecvError::Backend(Error::Io(err)));
343 }
344
345 let now = Instant::now();
346 if now >= deadline {
347 return Ok(RecvStatus::TimedOut);
348 }
349 let remaining = deadline - now;
350 let ready = poll_fd(self.fd.as_raw_fd(), libc::POLLIN, remaining)
351 .map_err(Error::Io)
352 .map_err(RecvError::Backend)?;
353 if !ready {
354 return Ok(RecvStatus::TimedOut);
355 }
356 }
357 }
358}
359
360impl IsoTpRxFlowControlConfig for SocketCanIsoTp {
361 type Error = Error;
362
363 fn set_rx_flow_control(&mut self, fc: RxFlowControl) -> Result<(), Self::Error> {
364 SocketCanIsoTp::set_rx_flow_control(self, fc)
365 }
366}
367
368#[cfg(feature = "tokio")]
373#[derive(Debug)]
374pub struct TokioSocketCanIsoTp {
375 io: AsyncFd<SocketCanIsoTp>,
376}
377
378#[cfg(feature = "tokio")]
379impl TokioSocketCanIsoTp {
380 pub fn open(
382 iface: &str,
383 rx_id: Id,
384 tx_id: Id,
385 options: &IsoTpKernelOptions,
386 ) -> Result<Self, Error> {
387 let inner = SocketCanIsoTp::open(iface, rx_id, tx_id, options)?;
388 let io = AsyncFd::new(inner).map_err(Error::Io)?;
389 Ok(Self { io })
390 }
391
392 pub fn inner(&self) -> &SocketCanIsoTp {
393 self.io.get_ref()
394 }
395
396 pub fn inner_mut(&mut self) -> &mut SocketCanIsoTp {
397 self.io.get_mut()
398 }
399
400 pub fn into_inner(self) -> SocketCanIsoTp {
401 self.io.into_inner()
402 }
403}
404
405#[cfg(feature = "tokio")]
406impl IsoTpRxFlowControlConfig for TokioSocketCanIsoTp {
407 type Error = Error;
408
409 fn set_rx_flow_control(&mut self, fc: RxFlowControl) -> Result<(), Self::Error> {
410 self.io.get_mut().set_rx_flow_control(fc)
411 }
412}
413
414#[cfg(feature = "tokio")]
415impl IsoTpAsyncEndpoint for TokioSocketCanIsoTp {
416 type Error = Error;
417
418 async fn send_to(
419 &mut self,
420 _to: u8,
421 payload: &[u8],
422 timeout: Duration,
423 ) -> Result<(), SendError<Self::Error>> {
424 let res = tokio::time::timeout(timeout, async {
425 loop {
426 let fd = self.io.get_ref().as_raw_fd();
427 let sent = unsafe {
428 libc::send(
429 fd,
430 payload.as_ptr().cast(),
431 payload.len(),
432 libc::MSG_DONTWAIT,
433 )
434 };
435 if sent >= 0 {
436 return Ok(());
437 }
438
439 let err = io::Error::last_os_error();
440 if err.kind() == io::ErrorKind::Interrupted {
441 continue;
442 }
443 if err.kind() != io::ErrorKind::WouldBlock {
444 return Err(SendError::Backend(Error::Io(err)));
445 }
446
447 let mut guard = self
448 .io
449 .writable()
450 .await
451 .map_err(|e| SendError::Backend(Error::Io(e)))?;
452 guard.clear_ready();
453 }
454 })
455 .await;
456
457 match res {
458 Ok(v) => v,
459 Err(_) => Err(SendError::Timeout),
460 }
461 }
462
463 async fn send_functional_to(
464 &mut self,
465 _functional_to: u8,
466 payload: &[u8],
467 timeout: Duration,
468 ) -> Result<(), SendError<Self::Error>> {
469 self.send_to(0, payload, timeout).await
470 }
471
472 async fn recv_one<Cb>(
473 &mut self,
474 timeout: Duration,
475 mut on_payload: Cb,
476 ) -> Result<RecvStatus, RecvError<Self::Error>>
477 where
478 Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>,
479 {
480 let res = tokio::time::timeout(timeout, async {
481 loop {
482 match self
483 .io
484 .get_mut()
485 .recv_one_ready(|payload| on_payload(RecvMeta { reply_to: 0 }, payload))
486 {
487 Ok(RecvStatus::DeliveredOne) => return Ok(RecvStatus::DeliveredOne),
488 Ok(RecvStatus::TimedOut) => {
489 let mut guard = self
490 .io
491 .readable()
492 .await
493 .map_err(|e| RecvError::Backend(Error::Io(e)))?;
494 guard.clear_ready();
495 continue;
496 }
497 Err(e) => return Err(e),
498 }
499 }
500 })
501 .await;
502
503 match res {
504 Ok(v) => v,
505 Err(_) => Ok(RecvStatus::TimedOut),
506 }
507 }
508}
509
510#[cfg(feature = "tokio")]
511impl IsoTpAsyncEndpointRecvInto for TokioSocketCanIsoTp {
512 type Error = Error;
513
514 async fn recv_one_into(
515 &mut self,
516 timeout: Duration,
517 out: &mut [u8],
518 ) -> Result<RecvMetaIntoStatus, RecvError<Self::Error>> {
519 let res = tokio::time::timeout(timeout, async {
520 loop {
521 let mut guard = self
522 .io
523 .readable()
524 .await
525 .map_err(|e| RecvError::Backend(Error::Io(e)))?;
526
527 let recv = guard.try_io(|inner| {
528 let fd = inner.get_ref().as_raw_fd();
529 let read = unsafe {
530 libc::recv(
531 fd,
532 out.as_mut_ptr().cast(),
533 out.len(),
534 libc::MSG_DONTWAIT | libc::MSG_TRUNC,
535 )
536 };
537 if read < 0 {
538 Err(io::Error::last_os_error())
539 } else {
540 Ok(read as usize)
541 }
542 });
543
544 match recv {
545 Ok(Ok(read)) => {
546 if read == 0 {
547 return Err(RecvError::Backend(Error::Io(io::Error::new(
548 io::ErrorKind::UnexpectedEof,
549 "iso-tp socket returned 0 bytes",
550 ))));
551 }
552 if read > out.len() {
553 return Err(RecvError::BufferTooSmall {
554 needed: read,
555 got: out.len(),
556 });
557 }
558 return Ok(RecvMetaIntoStatus::DeliveredOne {
559 meta: RecvMeta { reply_to: 0 },
560 len: read,
561 });
562 }
563 Ok(Err(err)) => {
564 if err.kind() == io::ErrorKind::Interrupted {
565 continue;
566 }
567 if err.kind() == io::ErrorKind::WouldBlock {
568 guard.clear_ready();
569 continue;
570 }
571 return Err(RecvError::Backend(Error::Io(err)));
572 }
573 Err(_would_block) => {
574 continue;
575 }
576 }
577 }
578 })
579 .await;
580
581 match res {
582 Ok(v) => v,
583 Err(_) => Ok(RecvMetaIntoStatus::TimedOut),
584 }
585 }
586}
587
588#[derive(Debug)]
590pub struct KernelUdsDemux {
591 iface: String,
592 local_addr: u8,
593 options: IsoTpKernelOptions,
594 rx_flow_control: RxFlowControl,
595 peers: Vec<PeerSocket>,
596}
597
598#[derive(Debug)]
599struct PeerSocket {
600 addr: u8,
601 socket: SocketCanIsoTp,
602}
603
604impl KernelUdsDemux {
605 pub fn new(iface: impl Into<String>, local_addr: u8, options: IsoTpKernelOptions) -> Self {
607 let rx_flow_control = match options.flow_control {
608 Some(fc) => RxFlowControl {
609 block_size: fc.block_size,
610 st_min: isotp_stmin_to_duration(fc.st_min).unwrap_or(Duration::from_millis(0)),
611 },
612 None => RxFlowControl {
613 block_size: 0,
614 st_min: Duration::from_millis(0),
615 },
616 };
617 Self {
618 iface: iface.into(),
619 local_addr,
620 options,
621 rx_flow_control,
622 peers: Vec::new(),
623 }
624 }
625
626 pub fn local_addr(&self) -> u8 {
628 self.local_addr
629 }
630
631 pub fn register_peer(&mut self, peer: u8) -> Result<(), Error> {
633 let _ = self.ensure_peer(peer)?;
634 Ok(())
635 }
636
637 fn ensure_peer(&mut self, peer: u8) -> Result<&mut SocketCanIsoTp, Error> {
638 if peer == self.local_addr {
639 return Err(Error::InvalidConfig(
640 "peer address must differ from local_addr",
641 ));
642 }
643
644 if let Some(idx) = self.peers.iter().position(|p| p.addr == peer) {
645 return Ok(&mut self.peers[idx].socket);
646 }
647
648 let rx_id = uds_phys_id(self.local_addr, peer);
649 let tx_id = uds_phys_id(peer, self.local_addr);
650 let mut socket = SocketCanIsoTp::open(&self.iface, rx_id, tx_id, &self.options)?;
651 let _ = socket.set_rx_flow_control(self.rx_flow_control);
652 self.peers.push(PeerSocket { addr: peer, socket });
653 let idx = self.peers.len() - 1;
654 Ok(&mut self.peers[idx].socket)
655 }
656}
657
658impl IsoTpRxFlowControlConfig for KernelUdsDemux {
659 type Error = Error;
660
661 fn set_rx_flow_control(&mut self, fc: RxFlowControl) -> Result<(), Self::Error> {
662 self.rx_flow_control = fc;
663 for peer in self.peers.iter_mut() {
664 peer.socket.set_rx_flow_control(fc)?;
665 }
666 Ok(())
667 }
668}
669
670impl can_isotp_interface::IsoTpEndpoint for KernelUdsDemux {
671 type Error = Error;
672
673 fn send_to(
674 &mut self,
675 to: u8,
676 payload: &[u8],
677 timeout: Duration,
678 ) -> Result<(), SendError<Self::Error>> {
679 let socket = self.ensure_peer(to).map_err(SendError::Backend)?;
680 socket.send_to(to, payload, timeout)
681 }
682
683 fn send_functional_to(
684 &mut self,
685 _functional_to: u8,
686 _payload: &[u8],
687 _timeout: Duration,
688 ) -> Result<(), SendError<Self::Error>> {
689 Err(SendError::Backend(Error::InvalidConfig(
690 "functional send is not supported by KernelUdsDemux",
691 )))
692 }
693
694 fn recv_one<Cb>(
695 &mut self,
696 timeout: Duration,
697 mut on_payload: Cb,
698 ) -> Result<RecvStatus, RecvError<Self::Error>>
699 where
700 Cb: FnMut(RecvMeta, &[u8]) -> Result<RecvControl, Self::Error>,
701 {
702 if self.peers.is_empty() {
703 thread::sleep(timeout);
704 return Ok(RecvStatus::TimedOut);
705 }
706
707 let mut fds: Vec<libc::pollfd> = self
708 .peers
709 .iter()
710 .map(|peer| libc::pollfd {
711 fd: peer.socket.as_raw_fd(),
712 events: libc::POLLIN,
713 revents: 0,
714 })
715 .collect();
716
717 let ready = poll_fds(&mut fds, timeout)
718 .map_err(Error::Io)
719 .map_err(RecvError::Backend)?;
720 if ready == 0 {
721 return Ok(RecvStatus::TimedOut);
722 }
723
724 for (idx, fd) in fds.iter().enumerate() {
725 if fd.revents & libc::POLLIN != 0 {
726 let reply_to = self.peers[idx].addr;
727 return self.peers[idx]
728 .socket
729 .recv_one_ready(|payload| on_payload(RecvMeta { reply_to }, payload));
730 }
731 if fd.revents & (libc::POLLERR | libc::POLLHUP | libc::POLLNVAL) != 0 {
732 return Err(RecvError::Backend(Error::Io(io::Error::other(
733 "poll error on iso-tp socket",
734 ))));
735 }
736 }
737
738 Ok(RecvStatus::TimedOut)
739 }
740}
741
742fn poll_fd(fd: RawFd, events: i16, timeout: Duration) -> io::Result<bool> {
743 let mut fds = libc::pollfd {
744 fd,
745 events,
746 revents: 0,
747 };
748 let timeout_ms = duration_to_poll_timeout(timeout);
749 loop {
750 let res = unsafe { libc::poll(&mut fds, 1, timeout_ms) };
751 if res >= 0 {
752 return Ok(res > 0);
753 }
754 let err = io::Error::last_os_error();
755 if err.kind() == io::ErrorKind::Interrupted {
756 continue;
757 }
758 return Err(err);
759 }
760}
761
762fn poll_fds(fds: &mut [libc::pollfd], timeout: Duration) -> io::Result<i32> {
763 let timeout_ms = duration_to_poll_timeout(timeout);
764 loop {
765 let res = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as u64, timeout_ms) };
766 if res >= 0 {
767 return Ok(res);
768 }
769 let err = io::Error::last_os_error();
770 if err.kind() == io::ErrorKind::Interrupted {
771 continue;
772 }
773 return Err(err);
774 }
775}
776
777fn duration_to_poll_timeout(timeout: Duration) -> i32 {
778 let ms = timeout.as_millis();
779 i32::try_from(ms).unwrap_or(i32::MAX)
780}
781
782fn duration_to_nanos_u32(d: Duration) -> u32 {
783 d.as_nanos().min(u32::MAX as u128) as u32
784}
785
786fn isotp_stmin_to_duration(raw: u8) -> Option<Duration> {
787 match raw {
788 0x00..=0x7F => Some(Duration::from_millis(raw as u64)),
789 0xF1..=0xF9 => Some(Duration::from_micros((raw as u64 - 0xF0) * 100)),
790 _ => None,
791 }
792}
793
794fn duration_to_isotp_stmin(duration: Duration) -> u8 {
795 let micros = duration.as_micros();
796 if micros == 0 {
797 return 0;
798 }
799 if (100..=900).contains(µs) && micros.is_multiple_of(100) {
800 return 0xF0 + (micros / 100) as u8;
801 }
802 let millis = duration.as_millis();
803 if millis <= 0x7F { millis as u8 } else { 0x7F }
804}
805
806fn uds_phys_id(target: u8, source: u8) -> Id {
807 let raw = uds29::encode_phys_id_raw(target, source);
808 let ext = ExtendedId::new(raw).expect("UDS 29-bit ID must fit in 29 bits");
809 Id::Extended(ext)
810}
811
812fn apply_kernel_options(fd: RawFd, options: &IsoTpKernelOptions) -> Result<(), Error> {
813 if let Some(txtime) = options.socket.frame_txtime {
814 let nanos = duration_to_nanos_u32(txtime);
815 let res = unsafe {
816 libc::setsockopt(
817 fd,
818 libc::SOL_SOCKET,
819 libc::SO_TXTIME,
820 &nanos as *const u32 as *const libc::c_void,
821 size_of::<u32>() as libc::socklen_t,
822 )
823 };
824 if res < 0 {
825 return Err(Error::Io(io::Error::last_os_error()));
826 }
827 }
828
829 let base = build_can_isotp_options(&options.socket);
830 let res = unsafe {
831 libc::setsockopt(
832 fd,
833 SOL_CAN_ISOTP,
834 CAN_ISOTP_OPTS,
835 &base as *const can_isotp_options as *const libc::c_void,
836 size_of::<can_isotp_options>() as libc::socklen_t,
837 )
838 };
839 if res < 0 {
840 return Err(Error::Io(io::Error::last_os_error()));
841 }
842
843 if let Some(fc) = options.flow_control {
844 let c = can_isotp_fc_options {
845 bs: fc.block_size,
846 stmin: fc.st_min,
847 wftmax: fc.wft_max,
848 };
849 let res = unsafe {
850 libc::setsockopt(
851 fd,
852 SOL_CAN_ISOTP,
853 CAN_ISOTP_RECV_FC,
854 &c as *const can_isotp_fc_options as *const libc::c_void,
855 size_of::<can_isotp_fc_options>() as libc::socklen_t,
856 )
857 };
858 if res < 0 {
859 return Err(Error::Io(io::Error::last_os_error()));
860 }
861 }
862
863 if let Some(stmin) = options.force_tx_stmin {
864 let nanos = duration_to_nanos_u32(stmin);
865 let res = unsafe {
866 libc::setsockopt(
867 fd,
868 SOL_CAN_ISOTP,
869 CAN_ISOTP_TX_STMIN,
870 &nanos as *const u32 as *const libc::c_void,
871 size_of::<u32>() as libc::socklen_t,
872 )
873 };
874 if res < 0 {
875 return Err(Error::Io(io::Error::last_os_error()));
876 }
877 }
878
879 if let Some(stmin) = options.force_rx_stmin {
880 let nanos = duration_to_nanos_u32(stmin);
881 let res = unsafe {
882 libc::setsockopt(
883 fd,
884 SOL_CAN_ISOTP,
885 CAN_ISOTP_RX_STMIN,
886 &nanos as *const u32 as *const libc::c_void,
887 size_of::<u32>() as libc::socklen_t,
888 )
889 };
890 if res < 0 {
891 return Err(Error::Io(io::Error::last_os_error()));
892 }
893 }
894
895 if let Some(ll) = options.link_layer {
896 let c = can_isotp_ll_options {
897 mtu: ll.mtu,
898 tx_dl: ll.tx_dl,
899 tx_flags: ll.tx_flags,
900 };
901 let res = unsafe {
902 libc::setsockopt(
903 fd,
904 SOL_CAN_ISOTP,
905 CAN_ISOTP_LL_OPTS,
906 &c as *const can_isotp_ll_options as *const libc::c_void,
907 size_of::<can_isotp_ll_options>() as libc::socklen_t,
908 )
909 };
910 if res < 0 {
911 return Err(Error::Io(io::Error::last_os_error()));
912 }
913 }
914
915 Ok(())
916}
917
918fn build_can_isotp_options(opts: &IsoTpSocketOptions) -> can_isotp_options {
919 let mut flags = opts.flags;
920 if opts.ext_address.is_some() {
921 flags |= CAN_ISOTP_EXTEND_ADDR;
922 }
923 if opts.tx_padding.is_some() {
924 flags |= CAN_ISOTP_TX_PADDING;
925 }
926 if opts.rx_padding.is_some() {
927 flags |= CAN_ISOTP_RX_PADDING;
928 }
929 if opts.rx_ext_address.is_some() {
930 flags |= CAN_ISOTP_RX_EXT_ADDR;
931 }
932
933 can_isotp_options {
934 flags,
935 frame_txtime: opts.frame_txtime.map(duration_to_nanos_u32).unwrap_or(0),
936 ext_address: opts.ext_address.unwrap_or(0),
937 txpad_content: opts.tx_padding.unwrap_or(0),
938 rxpad_content: opts.rx_padding.unwrap_or(0),
939 rx_ext_address: opts.rx_ext_address.unwrap_or(0),
940 }
941}
942
943#[repr(C)]
944#[derive(Debug, Clone, Copy)]
945struct can_isotp_options {
946 flags: u32,
947 frame_txtime: u32,
948 ext_address: u8,
949 txpad_content: u8,
950 rxpad_content: u8,
951 rx_ext_address: u8,
952}
953
954#[repr(C)]
955#[derive(Debug, Clone, Copy)]
956struct can_isotp_fc_options {
957 bs: u8,
958 stmin: u8,
959 wftmax: u8,
960}
961
962#[repr(C)]
963#[derive(Debug, Clone, Copy)]
964struct can_isotp_ll_options {
965 mtu: u8,
966 tx_dl: u8,
967 tx_flags: u8,
968}
969
970const SOL_CAN_ISOTP: i32 = libc::SOL_CAN_BASE + libc::CAN_ISOTP;
971const CAN_ISOTP_OPTS: i32 = 1;
972const CAN_ISOTP_RECV_FC: i32 = 2;
973const CAN_ISOTP_TX_STMIN: i32 = 3;
974const CAN_ISOTP_RX_STMIN: i32 = 4;
975const CAN_ISOTP_LL_OPTS: i32 = 5;
976
977pub mod flags {
979 pub const CAN_ISOTP_LISTEN_MODE: u32 = 0x0001;
981 pub const CAN_ISOTP_EXTEND_ADDR: u32 = 0x0002;
983 pub const CAN_ISOTP_TX_PADDING: u32 = 0x0004;
985 pub const CAN_ISOTP_RX_PADDING: u32 = 0x0008;
987 pub const CAN_ISOTP_CHK_PAD_LEN: u32 = 0x0010;
989 pub const CAN_ISOTP_CHK_PAD_DATA: u32 = 0x0020;
991 pub const CAN_ISOTP_HALF_DUPLEX: u32 = 0x0040;
993 pub const CAN_ISOTP_FORCE_TXSTMIN: u32 = 0x0080;
995 pub const CAN_ISOTP_FORCE_RXSTMIN: u32 = 0x0100;
997 pub const CAN_ISOTP_RX_EXT_ADDR: u32 = 0x0200;
999 pub const CAN_ISOTP_WAIT_TX_DONE: u32 = 0x0400;
1001 pub const CAN_ISOTP_SF_BROADCAST: u32 = 0x0800;
1003 pub const CAN_ISOTP_CF_BROADCAST: u32 = 0x1000;
1005 pub const CAN_ISOTP_DYN_FC_PARMS: u32 = 0x2000;
1007}
1008
1009const CAN_ISOTP_EXTEND_ADDR: u32 = flags::CAN_ISOTP_EXTEND_ADDR;
1010const CAN_ISOTP_TX_PADDING: u32 = flags::CAN_ISOTP_TX_PADDING;
1011const CAN_ISOTP_RX_PADDING: u32 = flags::CAN_ISOTP_RX_PADDING;
1012const CAN_ISOTP_RX_EXT_ADDR: u32 = flags::CAN_ISOTP_RX_EXT_ADDR;
1013
1014#[cfg(test)]
1015mod tests {
1016 use super::*;
1017
1018 #[test]
1019 fn can_isotp_options_layout() {
1020 assert_eq!(size_of::<can_isotp_options>(), 12);
1021 assert_eq!(size_of::<can_isotp_fc_options>(), 3);
1022 assert_eq!(size_of::<can_isotp_ll_options>(), 3);
1023 }
1024
1025 #[test]
1026 fn duration_to_nanos_clamps() {
1027 let huge = Duration::from_secs(u32::MAX as u64 + 42);
1028 assert_eq!(super::duration_to_nanos_u32(huge), u32::MAX);
1029 }
1030
1031 #[test]
1032 fn stmin_duration_round_trips_common_values() {
1033 assert_eq!(
1034 super::duration_to_isotp_stmin(Duration::from_millis(0)),
1035 0x00
1036 );
1037 assert_eq!(
1038 super::duration_to_isotp_stmin(Duration::from_millis(10)),
1039 0x0A
1040 );
1041 assert_eq!(
1042 super::duration_to_isotp_stmin(Duration::from_micros(100)),
1043 0xF1
1044 );
1045 assert_eq!(
1046 super::duration_to_isotp_stmin(Duration::from_micros(900)),
1047 0xF9
1048 );
1049 assert_eq!(
1050 super::isotp_stmin_to_duration(0xF4),
1051 Some(Duration::from_micros(400))
1052 );
1053 }
1054
1055 #[test]
1056 fn options_flags_from_padding_and_ext_addr() {
1057 let opts = IsoTpSocketOptions {
1058 ext_address: Some(0x12),
1059 rx_ext_address: Some(0x34),
1060 tx_padding: Some(0xAA),
1061 rx_padding: Some(0xBB),
1062 ..IsoTpSocketOptions::default()
1063 };
1064 let c = build_can_isotp_options(&opts);
1065 assert_eq!(c.ext_address, 0x12);
1066 assert_eq!(c.rx_ext_address, 0x34);
1067 assert_eq!(c.txpad_content, 0xAA);
1068 assert_eq!(c.rxpad_content, 0xBB);
1069 assert!(c.flags & CAN_ISOTP_EXTEND_ADDR != 0);
1070 assert!(c.flags & CAN_ISOTP_RX_EXT_ADDR != 0);
1071 assert!(c.flags & CAN_ISOTP_TX_PADDING != 0);
1072 assert!(c.flags & CAN_ISOTP_RX_PADDING != 0);
1073 }
1074}