socketcan/nl/mod.rs
1// socketcan/src/nl/mod.rs
2//
3// Netlink access to the SocketCAN interfaces.
4//
5// This file is part of the Rust 'socketcan-rs' library.
6//
7// Licensed under the MIT license:
8// <LICENSE or http://opensource.org/licenses/MIT>
9// This file may not be copied, modified, or distributed except according
10// to those terms.
11
12//! CAN Netlink access
13//!
14//! The netlink module contains the netlink-based management capabilities of
15//! the socketcan crate.
16//!
17//! For SocketCAN, netlink is the primary way for a user-space application to
18//! query or set the parameters of a CAN interface, such as the bitrate, the
19//! control mode bits, and so forth. It also allows the application to get
20//! statistics from the interface and send commands to it, including
21//! performing a bus restart.
22//!
23//1 Netlink is a socket-based mechanism, similar to Unix-domain sockets, which
24//! allows a user-space program communicate with the kernel.
25//!
26//! Unfortunately, the SocketCAN netlink API does not appear to be documented
27//! _anywhere_. The netlink functional summary on the SocketCAN page is here:
28//!
29//! <https://www.kernel.org/doc/html/latest/networking/can.html#netlink-interface-to-set-get-devices-properties>
30//!
31//! The CAN netlink header file for the Linux kernel has the definition of
32//! the constants and data structures that are sent back and forth to the
33//! kernel over netlink. It can be found in the Linux sources here:
34//!
35//! <https://github.com/torvalds/linux/blob/master/include/uapi/linux/can/netlink.h?ts=4>
36//!
37//! The corresponding kernel code that receives and processes messages from
38//! userspace is useful to help figure out what the kernel expects. It's here:
39//!
40//! <https://github.com/torvalds/linux/blob/master/drivers/net/can/dev/netlink.c?ts=4>
41//! <https://github.com/torvalds/linux/blob/master/drivers/net/can/dev/dev.c?ts=4>
42//!
43//! The main Linux user-space client to communicate with network interfaces,
44//! including CAN is _iproute2_. The CAN-specific code for it is here:
45//!
46//! <https://github.com/iproute2/iproute2/blob/main/ip/iplink_can.c?ts=4>
47//!
48//! There is also a C user-space library for SocketCAN, which primarily
49//! deals with the Netlink interface. There are several forks, but one of
50//! the later ones with updated documents is here:
51//!
52//! <https://github.com/lalten/libsocketcan>
53//!
54
55use neli::{
56 attr::Attribute,
57 consts::{
58 nl::{NlType, NlmF, NlmFFlags},
59 rtnl::{Arphrd, RtAddrFamily, Rtm},
60 rtnl::{Iff, IffFlags, Ifla, IflaInfo},
61 socket::NlFamily,
62 },
63 err::NlError,
64 nl::{NlPayload, Nlmsghdr},
65 rtnl::{Ifinfomsg, Rtattr},
66 socket::NlSocketHandle,
67 types::{Buffer, RtBuffer},
68 FromBytes, ToBytes,
69};
70use nix::{self, net::if_::if_nametoindex, unistd};
71use rt::IflaCan;
72use std::{
73 ffi::CStr,
74 fmt::Debug,
75 os::raw::{c_int, c_uint},
76};
77
78/// Low-level Netlink CAN struct bindings.
79mod rt;
80
81use rt::can_ctrlmode;
82pub use rt::CanState;
83
84/// A result for Netlink errors.
85type NlResult<T> = Result<T, NlError>;
86
87/// A Netlink error from an info query
88type NlInfoError = NlError<Rtm, Ifinfomsg>;
89
90/// CAN bit-timing parameters
91pub type CanBitTiming = rt::can_bittiming;
92/// CAN bit-timing const parameters
93pub type CanBitTimingConst = rt::can_bittiming_const;
94/// CAN clock parameter
95pub type CanClock = rt::can_clock;
96/// CAN bus error counters
97pub type CanBerrCounter = rt::can_berr_counter;
98
99/// The details of the interface which can be obtained with the
100/// `CanInterface::details()` function.
101#[allow(missing_copy_implementations)]
102#[derive(Debug, Default, Clone)]
103pub struct InterfaceDetails {
104 /// The name of the interface
105 pub name: Option<String>,
106 /// The index of the interface
107 pub index: c_uint,
108 /// Whether the interface is currently up
109 pub is_up: bool,
110 /// The MTU size of the interface (Standard or FD frames support)
111 pub mtu: Option<Mtu>,
112 /// The CAN-specific parameters for the interface
113 pub can: InterfaceCanParams,
114}
115
116impl InterfaceDetails {
117 /// Creates a new set of interface details with the specified `index`.
118 pub fn new(index: c_uint) -> Self {
119 Self {
120 index,
121 ..Self::default()
122 }
123 }
124}
125
126/// The MTU size for the interface
127///
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129#[repr(u32)]
130pub enum Mtu {
131 /// Standard CAN frame, 8-byte data (16-byte total)
132 Standard = 16,
133 /// FD CAN frame, 64-byte data (64-byte total)
134 Fd = 72,
135}
136
137impl TryFrom<u32> for Mtu {
138 type Error = std::io::Error;
139
140 fn try_from(val: u32) -> Result<Self, Self::Error> {
141 match val {
142 16 => Ok(Mtu::Standard),
143 72 => Ok(Mtu::Fd),
144 _ => Err(std::io::Error::from(std::io::ErrorKind::InvalidData)),
145 }
146 }
147}
148
149/// The CAN-specific parameters for the interface.
150#[allow(missing_copy_implementations)]
151#[derive(Debug, Default, Clone)]
152pub struct InterfaceCanParams {
153 /// The CAN bit timing parameters
154 pub bit_timing: Option<CanBitTiming>,
155 /// The bit timing const parameters
156 pub bit_timing_const: Option<CanBitTimingConst>,
157 /// The CAN clock parameters (read only)
158 pub clock: Option<CanClock>,
159 /// The CAN bus state (read-only)
160 pub state: Option<CanState>,
161 /// The automatic restart time (in millisec)
162 /// Zero means auto-restart is disabled.
163 pub restart_ms: Option<u32>,
164 /// The bit error counter (read-only)
165 pub berr_counter: Option<CanBerrCounter>,
166 /// The control mode bits
167 pub ctrl_mode: Option<CanCtrlModes>,
168 /// The FD data bit timing
169 pub data_bit_timing: Option<CanBitTiming>,
170 /// The FD data bit timing const parameters
171 pub data_bit_timing_const: Option<CanBitTimingConst>,
172 /// The CANbus termination resistance
173 pub termination: Option<u16>,
174}
175
176impl TryFrom<&Rtattr<Ifla, Buffer>> for InterfaceCanParams {
177 type Error = NlInfoError;
178
179 /// Try to parse the CAN parameters out of a Linkinfo attribute
180 fn try_from(link_info: &Rtattr<Ifla, Buffer>) -> Result<Self, Self::Error> {
181 let mut params = Self::default();
182
183 for info in link_info.get_attr_handle::<IflaInfo>()?.get_attrs() {
184 if info.rta_type == IflaInfo::Data {
185 for attr in info.get_attr_handle::<IflaCan>()?.get_attrs() {
186 match attr.rta_type {
187 IflaCan::BitTiming => {
188 params.bit_timing = Some(attr.get_payload_as::<CanBitTiming>()?);
189 }
190 IflaCan::BitTimingConst => {
191 params.bit_timing_const =
192 Some(attr.get_payload_as::<CanBitTimingConst>()?);
193 }
194 IflaCan::Clock => {
195 params.clock = Some(attr.get_payload_as::<CanClock>()?);
196 }
197 IflaCan::State => {
198 params.state = CanState::try_from(attr.get_payload_as::<u32>()?).ok();
199 }
200 IflaCan::CtrlMode => {
201 let ctrl_mode = attr.get_payload_as::<can_ctrlmode>()?;
202 params.ctrl_mode = Some(CanCtrlModes(ctrl_mode));
203 }
204 IflaCan::RestartMs => {
205 params.restart_ms = Some(attr.get_payload_as::<u32>()?);
206 }
207 IflaCan::BerrCounter => {
208 params.berr_counter = Some(attr.get_payload_as::<CanBerrCounter>()?);
209 }
210 IflaCan::DataBitTiming => {
211 params.data_bit_timing = Some(attr.get_payload_as::<CanBitTiming>()?);
212 }
213 IflaCan::DataBitTimingConst => {
214 params.data_bit_timing_const =
215 Some(attr.get_payload_as::<CanBitTimingConst>()?);
216 }
217 IflaCan::Termination => {
218 params.termination = Some(attr.get_payload_as::<u16>()?);
219 }
220 _ => (),
221 }
222 }
223 }
224 }
225 Ok(params)
226 }
227}
228
229impl TryFrom<&InterfaceCanParams> for RtBuffer<Ifla, Buffer> {
230 type Error = NlError;
231
232 /// Try to parse the CAN parameters into a NetLink buffer
233 fn try_from(params: &InterfaceCanParams) -> Result<Self, Self::Error> {
234 let mut rtattrs: RtBuffer<Ifla, Buffer> = RtBuffer::new();
235 let mut data = Rtattr::new(None, IflaInfo::Data, Buffer::new())?;
236
237 // TODO: Set the rest of the writable params
238 if let Some(bt) = params.bit_timing {
239 data.add_nested_attribute(&Rtattr::new(None, IflaCan::BitTiming, bt)?)?;
240 }
241 if let Some(r) = params.restart_ms {
242 data.add_nested_attribute(&Rtattr::new(
243 None,
244 IflaCan::RestartMs,
245 &r.to_ne_bytes()[..],
246 )?)?;
247 }
248 if let Some(cm) = params.ctrl_mode {
249 data.add_nested_attribute(&Rtattr::new::<can_ctrlmode>(
250 None,
251 IflaCan::CtrlMode,
252 cm.into(),
253 )?)?;
254 }
255 if let Some(dbt) = params.data_bit_timing {
256 data.add_nested_attribute(&Rtattr::new(None, IflaCan::DataBitTiming, dbt)?)?;
257 }
258 if let Some(t) = params.termination {
259 data.add_nested_attribute(&Rtattr::new(None, IflaCan::Termination, t)?)?;
260 }
261
262 let mut link_info = Rtattr::new(None, Ifla::Linkinfo, Buffer::new())?;
263 link_info.add_nested_attribute(&Rtattr::new(None, IflaInfo::Kind, "can")?)?;
264 link_info.add_nested_attribute(&data)?;
265
266 rtattrs.push(link_info);
267 Ok(rtattrs)
268 }
269}
270
271// ===== CanCtrlMode(s) =====
272
273///
274/// CAN control modes
275///
276/// Note that these correspond to the bit _numbers_ for the control mode bits.
277#[repr(u32)]
278#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
279pub enum CanCtrlMode {
280 /// Loopback mode
281 Loopback,
282 /// Listen-only mode
283 ListenOnly,
284 /// Triple sampling mode
285 TripleSampling,
286 /// One-Shot mode
287 OneShot,
288 /// Bus-error reporting
289 BerrReporting,
290 /// CAN FD mode
291 Fd,
292 /// Ignore missing CAN ACKs
293 PresumeAck,
294 /// CAN FD in non-ISO mode
295 NonIso,
296 /// Classic CAN DLC option
297 CcLen8Dlc,
298}
299
300impl CanCtrlMode {
301 /// Get the mask for the specific control mode
302 pub fn mask(&self) -> u32 {
303 1u32 << (*self as u32)
304 }
305}
306
307/// The collection of control modes
308#[derive(Debug, Default, Clone, Copy)]
309pub struct CanCtrlModes(can_ctrlmode);
310
311impl CanCtrlModes {
312 /// Create a set of CAN control modes from a mask and set of flags.
313 pub fn new(mask: u32, flags: u32) -> Self {
314 Self(can_ctrlmode { mask, flags })
315 }
316
317 /// Create the set of mode flags for a single mode
318 pub fn from_mode(mode: CanCtrlMode, on: bool) -> Self {
319 let mask = mode.mask();
320 let flags = if on { mask } else { 0 };
321 Self::new(mask, flags)
322 }
323
324 /// Adds a mode flag to the existing set of modes.
325 pub fn add(&mut self, mode: CanCtrlMode, on: bool) {
326 let mask = mode.mask();
327 self.0.mask |= mask;
328 if on {
329 self.0.flags |= mask;
330 }
331 }
332
333 /// Clears all of the mode flags in the collection
334 #[inline]
335 pub fn clear(&mut self) {
336 self.0 = can_ctrlmode::default();
337 }
338
339 /// Test if this CanCtrlModes has a specific `mode` turned on
340 ///
341 /// This can be useful for inspecting an [InterfaceCanParams] obtained from
342 /// [CanInterface::details].
343 ///
344 /// # Examples
345 ///
346 /// ```
347 /// use socketcan::nl::CanCtrlModes;
348 /// use socketcan::CanCtrlMode;
349 ///
350 /// let modes = CanCtrlModes::new(0x20, 0x20); // This is bit 5 (CanCtrlMode::Fd)
351 /// assert_eq!(modes.has_mode(CanCtrlMode::Fd), true);
352 /// assert_eq!(modes.has_mode(CanCtrlMode::ListenOnly), false);
353 /// ```
354 #[inline]
355 pub fn has_mode(&self, mode: CanCtrlMode) -> bool {
356 (mode.mask() & self.0.flags) != 0
357 }
358}
359
360impl From<can_ctrlmode> for CanCtrlModes {
361 fn from(mode: can_ctrlmode) -> Self {
362 Self(mode)
363 }
364}
365
366impl From<CanCtrlModes> for can_ctrlmode {
367 fn from(mode: CanCtrlModes) -> Self {
368 mode.0
369 }
370}
371
372// ===== CanInterface =====
373
374/// SocketCAN Netlink CanInterface
375///
376/// Controlled through the kernel's Netlink interface, CAN devices can be
377/// brought up or down or configured or queried through this.
378///
379/// Note while that this API is designed in an RAII-fashion, it cannot really
380/// make the same guarantees: It is entirely possible for another user/process
381/// to modify, remove and re-add an interface while you are holding this object
382/// with a reference to it.
383///
384/// Some actions possible on this interface require the process/user to have
385/// the `CAP_NET_ADMIN` capability, like the root user does. This is
386/// indicated by their documentation starting with "PRIVILEGED:".
387#[allow(missing_copy_implementations)]
388#[derive(Debug)]
389pub struct CanInterface {
390 if_index: c_uint,
391}
392
393impl CanInterface {
394 /// Open a CAN interface by name.
395 ///
396 /// Similar to `open_iface`, but looks up the device by name instead of
397 /// the interface index.
398 pub fn open(ifname: &str) -> Result<Self, nix::Error> {
399 let if_index = if_nametoindex(ifname)?;
400 Ok(Self::open_iface(if_index))
401 }
402
403 /// Open a CAN interface.
404 ///
405 /// Creates a new `CanInterface` instance.
406 ///
407 /// Note that no actual "opening" or checks are performed when calling
408 /// this function, nor does it test to determine if the interface with
409 /// the specified index actually exists.
410 pub fn open_iface(if_index: u32) -> Self {
411 let if_index = if_index as c_uint;
412 Self { if_index }
413 }
414
415 /// Creates an `Ifinfomsg` for this CAN interface from a buffer
416 fn info_msg(&self, buf: RtBuffer<Ifla, Buffer>) -> Ifinfomsg {
417 Ifinfomsg::new(
418 RtAddrFamily::Unspecified,
419 Arphrd::Netrom,
420 self.if_index as c_int,
421 IffFlags::empty(),
422 IffFlags::empty(),
423 buf,
424 )
425 }
426
427 /// Sends an info message to the kernel.
428 fn send_info_msg(msg_type: Rtm, info: Ifinfomsg, additional_flags: &[NlmF]) -> NlResult<()> {
429 let mut nl = Self::open_route_socket()?;
430
431 // prepare message
432 let hdr = Nlmsghdr::new(
433 None,
434 msg_type,
435 {
436 let mut flags = NlmFFlags::new(&[NlmF::Request, NlmF::Ack]);
437 for flag in additional_flags {
438 flags.set(flag);
439 }
440 flags
441 },
442 None,
443 None,
444 NlPayload::Payload(info),
445 );
446 // send the message
447 Self::send_and_read_ack(&mut nl, hdr)
448 }
449
450 /// Sends a message down a netlink socket, and checks if an ACK was
451 /// properly received.
452 fn send_and_read_ack<T, P>(sock: &mut NlSocketHandle, msg: Nlmsghdr<T, P>) -> NlResult<()>
453 where
454 T: NlType + Debug,
455 P: ToBytes + Debug,
456 {
457 sock.send(msg)?;
458
459 // This will actually produce an Err if the response is a netlink error,
460 // no need to match.
461 if let Some(Nlmsghdr {
462 nl_payload: NlPayload::Ack(_),
463 ..
464 }) = sock.recv()?
465 {
466 Ok(())
467 } else {
468 Err(NlError::NoAck)
469 }
470 }
471
472 /// Opens a new netlink socket, bound to this process' PID.
473 /// The function is generic to allow for usage in contexts where NlError
474 /// has specific, non-default, generic parameters.
475 fn open_route_socket<T, P>() -> Result<NlSocketHandle, NlError<T, P>> {
476 // retrieve PID
477 let pid = unistd::Pid::this().as_raw() as u32;
478
479 // open and bind socket
480 // groups is set to None(0), because we want no notifications
481 let sock = NlSocketHandle::connect(NlFamily::Route, Some(pid), &[])?;
482 Ok(sock)
483 }
484
485 /// Sends a query to the kernel and returns the response info message
486 /// to the caller.
487 fn query_details(&self) -> Result<Option<Nlmsghdr<Rtm, Ifinfomsg>>, NlInfoError> {
488 let mut sock = Self::open_route_socket()?;
489
490 let info = self.info_msg({
491 let mut buffer = RtBuffer::new();
492 buffer.push(Rtattr::new(None, Ifla::ExtMask, rt::EXT_FILTER_VF).unwrap());
493 buffer
494 });
495
496 let hdr = Nlmsghdr::new(
497 None,
498 Rtm::Getlink,
499 NlmFFlags::new(&[NlmF::Request]),
500 None,
501 None,
502 NlPayload::Payload(info),
503 );
504
505 sock.send(hdr)?;
506 sock.recv::<'_, Rtm, Ifinfomsg>()
507 }
508
509 /// Bring down this interface.
510 ///
511 /// Use a netlink control socket to set the interface status to "down".
512 pub fn bring_down(&self) -> NlResult<()> {
513 // Specific iface down info
514 let info = Ifinfomsg::down(
515 RtAddrFamily::Unspecified,
516 Arphrd::Netrom,
517 self.if_index as c_int,
518 RtBuffer::new(),
519 );
520 Self::send_info_msg(Rtm::Newlink, info, &[])
521 }
522
523 /// Bring up this interface
524 ///
525 /// Brings the interface up by settings its "up" flag enabled via netlink.
526 pub fn bring_up(&self) -> NlResult<()> {
527 // Specific iface up info
528 let info = Ifinfomsg::up(
529 RtAddrFamily::Unspecified,
530 Arphrd::Netrom,
531 self.if_index as c_int,
532 RtBuffer::new(),
533 );
534 Self::send_info_msg(Rtm::Newlink, info, &[])
535 }
536
537 /// Create a virtual CAN (VCAN) interface.
538 ///
539 /// Useful for testing applications when a physical CAN interface and
540 /// bus is not available.
541 ///
542 /// Note that the length of the name is capped by ```libc::IFNAMSIZ```.
543 ///
544 /// PRIVILEGED: This requires root privilege.
545 ///
546 pub fn create_vcan(name: &str, index: Option<u32>) -> NlResult<Self> {
547 Self::create(name, index, "vcan")
548 }
549
550 /// Create an interface of the given kind.
551 ///
552 /// Note that the length of the name is capped by ```libc::IFNAMSIZ```.
553 ///
554 /// PRIVILEGED: This requires root privilege.
555 ///
556 pub fn create<I>(name: &str, index: I, kind: &str) -> NlResult<Self>
557 where
558 I: Into<Option<u32>>,
559 {
560 if name.len() > libc::IFNAMSIZ {
561 return Err(NlError::Msg("Interface name too long".into()));
562 }
563 let index = index.into();
564
565 let info = Ifinfomsg::new(
566 RtAddrFamily::Unspecified,
567 Arphrd::Netrom,
568 index.unwrap_or(0) as c_int,
569 IffFlags::empty(),
570 IffFlags::empty(),
571 {
572 let mut buffer = RtBuffer::new();
573 buffer.push(Rtattr::new(None, Ifla::Ifname, name)?);
574 let mut linkinfo = Rtattr::new(None, Ifla::Linkinfo, Vec::<u8>::new())?;
575 linkinfo.add_nested_attribute(&Rtattr::new(None, IflaInfo::Kind, kind)?)?;
576 buffer.push(linkinfo);
577 buffer
578 },
579 );
580 Self::send_info_msg(Rtm::Newlink, info, &[NlmF::Create, NlmF::Excl])?;
581
582 if let Some(if_index) = index {
583 Ok(Self { if_index })
584 } else {
585 // Unfortunately netlink does not return the the if_index assigned to the interface.
586 if let Ok(if_index) = if_nametoindex(name) {
587 Ok(Self { if_index })
588 } else {
589 Err(NlError::Msg(
590 "Interface must have been deleted between request and this if_nametoindex"
591 .into(),
592 ))
593 }
594 }
595 }
596
597 /// Delete the interface.
598 ///
599 /// PRIVILEGED: This requires root privilege.
600 ///
601 pub fn delete(self) -> Result<(), (Self, NlError)> {
602 let info = self.info_msg(RtBuffer::new());
603 match Self::send_info_msg(Rtm::Dellink, info, &[]) {
604 Ok(()) => Ok(()),
605 Err(err) => Err((self, err)),
606 }
607 }
608
609 /// Attempt to query detailed information on the interface.
610 pub fn details(&self) -> Result<InterfaceDetails, NlInfoError> {
611 match self.query_details()? {
612 Some(msg_hdr) => {
613 let mut info = InterfaceDetails::new(self.if_index);
614
615 if let Ok(payload) = msg_hdr.get_payload() {
616 info.is_up = payload.ifi_flags.contains(&Iff::Up);
617
618 for attr in payload.rtattrs.iter() {
619 match attr.rta_type {
620 Ifla::Ifname => {
621 // Note: Use `CStr::from_bytes_until_nul` when MSRV >= 1.69
622 info.name = CStr::from_bytes_with_nul(attr.rta_payload.as_ref())
623 .map(|s| s.to_string_lossy().into_owned())
624 .ok();
625 }
626 Ifla::Mtu => {
627 info.mtu = attr
628 .get_payload_as::<u32>()
629 .ok()
630 .and_then(|mtu| Mtu::try_from(mtu).ok());
631 }
632 Ifla::Linkinfo => {
633 info.can = InterfaceCanParams::try_from(attr)?;
634 }
635 _ => (),
636 }
637 }
638 }
639
640 Ok(info)
641 }
642 None => Err(NlError::NoAck),
643 }
644 }
645
646 /// Set the MTU of this interface.
647 ///
648 /// PRIVILEGED: This requires root privilege.
649 ///
650 pub fn set_mtu(&self, mtu: Mtu) -> NlResult<()> {
651 let mtu = mtu as u32;
652 let info = self.info_msg({
653 let mut buffer = RtBuffer::new();
654 buffer.push(Rtattr::new(None, Ifla::Mtu, &mtu.to_ne_bytes()[..])?);
655 buffer
656 });
657 Self::send_info_msg(Rtm::Newlink, info, &[])
658 }
659
660 /// Set a CAN-specific parameter.
661 ///
662 /// This send a netlink message down to the kernel to set an attribute
663 /// in the link info, such as bitrate, control modes, etc
664 ///
665 /// PRIVILEGED: This requires root privilege.
666 ///
667 pub fn set_can_param<P>(&self, param_type: IflaCan, param: P) -> NlResult<()>
668 where
669 P: ToBytes + neli::Size,
670 {
671 let info = self.info_msg({
672 let mut data = Rtattr::new(None, IflaInfo::Data, Buffer::new())?;
673 data.add_nested_attribute(&Rtattr::new(None, param_type, param)?)?;
674
675 let mut link_info = Rtattr::new(None, Ifla::Linkinfo, Buffer::new())?;
676 link_info.add_nested_attribute(&Rtattr::new(None, IflaInfo::Kind, "can")?)?;
677 link_info.add_nested_attribute(&data)?;
678
679 let mut rtattrs = RtBuffer::new();
680 rtattrs.push(link_info);
681 rtattrs
682 });
683 Self::send_info_msg(Rtm::Newlink, info, &[])
684 }
685
686 /// Set a CAN-specific set of parameters.
687 ///
688 /// This sends a netlink message down to the kernel to set multiple
689 /// attributes in the link info, such as bitrate, control modes, etc.
690 ///
691 /// If you have many attributes to set this is preferred to calling
692 /// [set_can_params][CanInterface::set_can_param] multiple times, since this only sends a
693 /// single netlink message. Also some CAN drivers might only accept
694 /// a set of attributes, not over multiple messages.
695 ///
696 /// PRIVILEGED: This requires root privilege.
697 ///
698 pub fn set_can_params(&self, params: &InterfaceCanParams) -> NlResult<()> {
699 let info = self.info_msg(
700 //RtBuffer<Ifla, Buffer>::try_from(params)?);
701 RtBuffer::try_from(params)?,
702 );
703 /*
704 let mut rtattrs: RtBuffer<Ifla, Buffer> = RtBuffer::new();
705 let mut data = Rtattr::new(None, IflaInfo::Data, Buffer::new())?;
706
707 if let Some(bt) = params.bit_timing {
708 data.add_nested_attribute(&Rtattr::new(None, IflaCan::BitTiming, bt)?)?;
709 }
710 if let Some(r) = params.restart_ms {
711 data.add_nested_attribute(&Rtattr::new(
712 None,
713 IflaCan::RestartMs,
714 &r.to_ne_bytes()[..],
715 )?)?;
716 }
717 if let Some(cm) = params.ctrl_mode {
718 data.add_nested_attribute(&Rtattr::new::<can_ctrlmode>(
719 None,
720 IflaCan::CtrlMode,
721 cm.into(),
722 )?)?;
723 }
724 if let Some(dbt) = params.data_bit_timing {
725 data.add_nested_attribute(&Rtattr::new(None, IflaCan::DataBitTiming, dbt)?)?;
726 }
727 if let Some(t) = params.termination {
728 data.add_nested_attribute(&Rtattr::new(None, IflaCan::Termination, t)?)?;
729 }
730
731 let mut link_info = Rtattr::new(None, Ifla::Linkinfo, Buffer::new())?;
732 link_info.add_nested_attribute(&Rtattr::new(None, IflaInfo::Kind, "can")?)?;
733 link_info.add_nested_attribute(&data)?;
734
735 rtattrs.push(link_info);
736 rtattrs
737 });
738 */
739 Self::send_info_msg(Rtm::Newlink, info, &[])
740 }
741
742 /// Attempt to query an individual CAN parameter on the interface.
743 pub fn can_param<P>(&self, param: IflaCan) -> Result<Option<P>, NlInfoError>
744 where
745 P: for<'a> FromBytes<'a> + Clone,
746 {
747 if let Some(hdr) = self.query_details()? {
748 if let Ok(payload) = hdr.get_payload() {
749 for top_attr in payload.rtattrs.iter() {
750 if top_attr.rta_type == Ifla::Linkinfo {
751 for info in top_attr.get_attr_handle::<IflaInfo>()?.get_attrs() {
752 if info.rta_type == IflaInfo::Data {
753 for attr in info.get_attr_handle::<IflaCan>()?.get_attrs() {
754 if attr.rta_type == param {
755 return Ok(Some(attr.get_payload_as::<P>()?));
756 }
757 }
758 }
759 }
760 }
761 }
762 }
763 Ok(None)
764 } else {
765 Err(NlError::NoAck)
766 }
767 }
768
769 /// Gets the current bit rate for the interface.
770 pub fn bit_rate(&self) -> Result<Option<u32>, NlInfoError> {
771 Ok(self.bit_timing()?.map(|timing| timing.bitrate))
772 }
773
774 /// Set the bitrate and, optionally, sample point of this interface.
775 ///
776 /// The bitrate can *not* be changed if the interface is UP. It is
777 /// specified in Hz (bps) while the sample point is given in tenths
778 /// of a percent/
779 ///
780 /// PRIVILEGED: This requires root privilege.
781 ///
782 pub fn set_bitrate<P>(&self, bitrate: u32, sample_point: P) -> NlResult<()>
783 where
784 P: Into<Option<u32>>,
785 {
786 let sample_point: u32 = sample_point.into().unwrap_or(0);
787
788 debug_assert!(
789 0 < bitrate && bitrate <= 1000000,
790 "Bitrate must be within 1..=1000000, received {}.",
791 bitrate
792 );
793 debug_assert!(
794 sample_point < 1000,
795 "Sample point must be within 0..1000, received {}.",
796 sample_point
797 );
798
799 self.set_bit_timing(CanBitTiming {
800 bitrate,
801 sample_point,
802 ..CanBitTiming::default()
803 })
804 }
805
806 /// Gets the bit timing params for the interface
807 pub fn bit_timing(&self) -> Result<Option<CanBitTiming>, NlInfoError> {
808 self.can_param::<CanBitTiming>(IflaCan::BitTiming)
809 }
810
811 /// Sets the bit timing params for the interface
812 ///
813 /// PRIVILEGED: This requires root privilege.
814 ///
815 pub fn set_bit_timing(&self, timing: CanBitTiming) -> NlResult<()> {
816 self.set_can_param(IflaCan::BitTiming, timing)
817 }
818
819 /// Gets the bit timing const data for the interface
820 pub fn bit_timing_const(&self) -> Result<Option<CanBitTimingConst>, NlInfoError> {
821 self.can_param::<CanBitTimingConst>(IflaCan::BitTimingConst)
822 }
823
824 /// Gets the clock frequency for the interface
825 pub fn clock(&self) -> Result<Option<u32>, NlInfoError> {
826 Ok(self
827 .can_param::<CanClock>(IflaCan::Clock)?
828 .map(|clk| clk.freq))
829 }
830
831 /// Gets the state of the interface
832 pub fn state(&self) -> Result<Option<CanState>, NlInfoError> {
833 Ok(self
834 .can_param::<u32>(IflaCan::State)?
835 .and_then(|st| CanState::try_from(st).ok()))
836 }
837
838 /// Set the full control mode (bit) collection.
839 ///
840 /// PRIVILEGED: This requires root privilege.
841 ///
842 #[deprecated(since = "3.2.0", note = "Use `set_ctrlmodes` instead")]
843 pub fn set_full_ctrlmode(&self, ctrlmode: can_ctrlmode) -> NlResult<()> {
844 self.set_can_param(IflaCan::CtrlMode, ctrlmode)
845 }
846
847 /// Set the full control mode (bit) collection.
848 ///
849 /// PRIVILEGED: This requires root privilege.
850 ///
851 pub fn set_ctrlmodes<M>(&self, ctrlmode: M) -> NlResult<()>
852 where
853 M: Into<CanCtrlModes>,
854 {
855 let modes = ctrlmode.into();
856 let modes: can_ctrlmode = modes.into();
857 self.set_can_param(IflaCan::CtrlMode, modes)
858 }
859
860 /// Set or clear an individual control mode parameter.
861 ///
862 /// PRIVILEGED: This requires root privilege.
863 ///
864 pub fn set_ctrlmode(&self, mode: CanCtrlMode, on: bool) -> NlResult<()> {
865 self.set_ctrlmodes(CanCtrlModes::from_mode(mode, on))
866 }
867
868 /// Gets the automatic CANbus restart time for the interface, in milliseconds.
869 pub fn restart_ms(&self) -> Result<Option<u32>, NlInfoError> {
870 self.can_param::<u32>(IflaCan::RestartMs)
871 }
872
873 /// Set the automatic restart milliseconds of the interface
874 ///
875 /// PRIVILEGED: This requires root privilege.
876 ///
877 pub fn set_restart_ms(&self, restart_ms: u32) -> NlResult<()> {
878 self.set_can_param(IflaCan::RestartMs, &restart_ms.to_ne_bytes()[..])
879 }
880
881 /// Manually restart the interface.
882 ///
883 /// Note that a manual restart if only permitted if automatic restart is
884 /// disabled and the device is in the bus-off state.
885 /// See: linux/drivers/net/can/dev/dev.c
886 ///
887 /// PRIVILEGED: This requires root privilege.
888 ///
889 /// Common Errors:
890 /// EINVAL - The interface is down or automatic restarts are enabled
891 /// EBUSY - The interface is not in a bus-off state
892 ///
893 pub fn restart(&self) -> NlResult<()> {
894 // Note: The linux code shows the data type to be u32, but never
895 // appears to access the value sent. iproute2 sends a 1, so we do
896 // too!
897 // See: linux/drivers/net/can/dev/netlink.c
898 let restart_data: u32 = 1;
899 self.set_can_param(IflaCan::Restart, &restart_data.to_ne_bytes()[..])
900 }
901
902 /// Gets the bus error counter from the interface
903 pub fn berr_counter(&self) -> Result<Option<CanBerrCounter>, NlInfoError> {
904 self.can_param::<CanBerrCounter>(IflaCan::BerrCounter)
905 }
906
907 /// Gets the data bit timing params for the interface
908 pub fn data_bit_timing(&self) -> Result<Option<CanBitTiming>, NlInfoError> {
909 self.can_param::<CanBitTiming>(IflaCan::DataBitTiming)
910 }
911
912 /// Sets the data bit timing params for the interface
913 ///
914 /// PRIVILEGED: This requires root privilege.
915 ///
916 pub fn set_data_bit_timing(&self, timing: CanBitTiming) -> NlResult<()> {
917 self.set_can_param(IflaCan::DataBitTiming, timing)
918 }
919
920 /// Set the data bitrate and, optionally, data sample point of this
921 /// interface.
922 ///
923 /// This only applies to interfaces in FD mode.
924 ///
925 /// The data bitrate can *not* be changed if the interface is UP. It is
926 /// specified in Hz (bps) while the sample point is given in tenths
927 /// of a percent/
928 ///
929 /// PRIVILEGED: This requires root privilege.
930 ///
931 pub fn set_data_bitrate<P>(&self, bitrate: u32, sample_point: P) -> NlResult<()>
932 where
933 P: Into<Option<u32>>,
934 {
935 let sample_point: u32 = sample_point.into().unwrap_or(0);
936
937 self.set_data_bit_timing(CanBitTiming {
938 bitrate,
939 sample_point,
940 ..CanBitTiming::default()
941 })
942 }
943
944 /// Gets the data bit timing const params for the interface
945 pub fn data_bit_timing_const(&self) -> Result<Option<CanBitTimingConst>, NlInfoError> {
946 self.can_param::<CanBitTimingConst>(IflaCan::DataBitTimingConst)
947 }
948
949 /// Sets the CANbus termination for the interface
950 ///
951 /// Not all interfaces support setting a termination.
952 /// Termination is in ohms. Your interface most likely only supports
953 /// certain values. Common values are 0 and 120.
954 ///
955 /// PRIVILEGED: This requires root privilege.
956 ///
957 pub fn set_termination(&self, termination: u16) -> NlResult<()> {
958 self.set_can_param(IflaCan::Termination, termination)
959 }
960
961 /// Gets the CANbus termination for the interface
962 pub fn termination(&self) -> Result<Option<u16>, NlInfoError> {
963 self.can_param::<u16>(IflaCan::Termination)
964 }
965}
966
967/////////////////////////////////////////////////////////////////////////////
968
969/// Netlink tests for SocketCAN control
970#[cfg(feature = "netlink_tests")]
971#[cfg(test)]
972pub mod tests {
973 use super::*;
974 use serial_test::serial;
975 use std::ops::Deref;
976
977 /// RAII-style helper to create and clean-up a specific vcan interface for a single test.
978 /// Using drop here ensures that the interface always gets cleaned up
979 /// (although a restart would also remove it).
980 ///
981 /// Intended for use (ONLY) in tests as follows:
982 /// ```
983 /// #[test]
984 /// fn my_test() {
985 /// let interface = TemporaryInterface::new("my_test").unwrap();
986 /// // use the interface..
987 /// }
988 /// ```
989 /// Please note that there is a limit to the length of interface names,
990 /// namely 16 characters on Linux.
991 #[allow(missing_copy_implementations)]
992 #[derive(Debug)]
993 pub struct TemporaryInterface {
994 interface: CanInterface,
995 }
996
997 impl TemporaryInterface {
998 /// Creates a temporaty interface
999 #[allow(unused)]
1000 pub fn new(name: &str) -> NlResult<Self> {
1001 Ok(Self {
1002 interface: CanInterface::create_vcan(name, None)?,
1003 })
1004 }
1005 }
1006
1007 impl Drop for TemporaryInterface {
1008 fn drop(&mut self) {
1009 assert!(CanInterface::open_iface(self.interface.if_index)
1010 .delete()
1011 .is_ok());
1012 }
1013 }
1014
1015 impl Deref for TemporaryInterface {
1016 type Target = CanInterface;
1017
1018 fn deref(&self) -> &Self::Target {
1019 &self.interface
1020 }
1021 }
1022
1023 #[test]
1024 #[serial]
1025 fn up_down() {
1026 let interface = TemporaryInterface::new("up_down").unwrap();
1027
1028 assert!(interface.bring_up().is_ok());
1029 assert!(interface.details().unwrap().is_up);
1030
1031 assert!(interface.bring_down().is_ok());
1032 assert!(!interface.details().unwrap().is_up);
1033 }
1034
1035 #[test]
1036 #[serial]
1037 fn details() {
1038 let interface = TemporaryInterface::new("info").unwrap();
1039 let details = interface.details().unwrap();
1040 assert_eq!("info", details.name.unwrap());
1041 assert!(details.mtu.is_some());
1042 assert!(!details.is_up);
1043 }
1044
1045 #[test]
1046 #[serial]
1047 fn mtu() {
1048 let interface = TemporaryInterface::new("mtu").unwrap();
1049
1050 assert!(interface.set_mtu(Mtu::Fd).is_ok());
1051 assert_eq!(Mtu::Fd, interface.details().unwrap().mtu.unwrap());
1052
1053 assert!(interface.set_mtu(Mtu::Standard).is_ok());
1054 assert_eq!(Mtu::Standard, interface.details().unwrap().mtu.unwrap());
1055 }
1056}