can_socket/sys/
linux.rs

1use filedesc::FileDesc;
2use std::ffi::{c_int, c_void, CString};
3use std::mem::MaybeUninit;
4
5use crate::{CanData, CanId, ExtendedId, StandardId};
6
7#[repr(C)]
8#[derive(Copy, Clone)]
9#[allow(non_camel_case_types)]
10struct can_frame {
11	pub can_id: u32,
12	pub can_dlc: u8,
13	_pad: u8,
14	_res0: u8,
15	pub len8_dlc: u8,
16	pub data: [u8; 8],
17}
18
19pub(crate) struct Socket {
20	fd: FileDesc,
21}
22
23#[derive(Copy, Clone)]
24pub(crate) struct CanFrame {
25	inner: can_frame
26}
27
28#[repr(transparent)]
29#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
30pub(crate) struct CanInterface {
31	index: u32,
32}
33
34#[repr(transparent)]
35#[derive(Copy, Clone)]
36pub struct CanFilter {
37	filter: libc::can_filter,
38}
39
40impl CanFrame {
41	pub fn new(id: impl Into<CanId>, data: &crate::CanData) -> Self {
42		let id = id.into();
43
44		let mut inner: can_frame = unsafe { std::mem::zeroed() };
45		inner.can_id = match id {
46			CanId::Extended(x) => x.as_u32() | libc::CAN_EFF_FLAG,
47			CanId::Standard(x) => x.as_u16().into(),
48		};
49		inner.can_dlc = data.len() as u8;
50		inner.data[..data.len()].copy_from_slice(data);
51		Self { inner }
52	}
53
54	pub fn new_rtr(id: impl Into<CanId>) -> Self {
55		let id = id.into();
56
57		let mut inner: can_frame = unsafe { std::mem::zeroed() };
58		inner.can_id = match id {
59			CanId::Extended(x) => x.as_u32() | libc::CAN_EFF_FLAG,
60			CanId::Standard(x) => x.as_u16().into(),
61		};
62		inner.can_id |= libc::CAN_RTR_FLAG;
63		inner.can_dlc = 0;
64		inner.len8_dlc = 0;
65		Self { inner }
66	}
67
68	pub fn id(&self) -> CanId {
69		// Unwrap should be fine: the kernel should never give us an invalid CAN ID,
70		// and the Rust constructor doesn't allow it.
71		if self.inner.can_id & libc::CAN_EFF_FLAG == 0 {
72			CanId::new_standard((self.inner.can_id & libc::CAN_SFF_MASK) as u16).unwrap()
73		} else {
74			CanId::new_extended(self.inner.can_id & libc::CAN_EFF_MASK).unwrap()
75		}
76	}
77
78	pub fn is_rtr(&self) -> bool {
79		self.inner.can_id & libc::CAN_RTR_FLAG != 0
80	}
81
82	pub fn data(&self) -> Option<CanData> {
83		if self.is_rtr() {
84			None
85		} else {
86			Some(CanData {
87				data: self.inner.data,
88				len: self.inner.can_dlc,
89			})
90		}
91	}
92
93	pub fn set_data_length_code(&mut self, dlc: u8) -> Result<(), ()> {
94		if dlc > 15 {
95			return Err(());
96		}
97
98		self.inner.can_dlc = dlc.clamp(0, 8);
99		if dlc > 8 {
100			self.inner.len8_dlc = dlc;
101		} else {
102			self.inner.len8_dlc = 0;
103		}
104
105		self.inner.data[self.inner.can_dlc as usize..].fill(0);
106		Ok(())
107	}
108
109	pub fn data_length_code(&self) -> u8 {
110		if self.inner.can_dlc == 8 && self.inner.len8_dlc > 8 {
111			self.inner.len8_dlc
112		} else {
113			self.inner.can_dlc
114		}
115	}
116
117	fn as_c_void_ptr(&self) -> *const c_void {
118		(self as *const Self).cast()
119	}
120}
121
122impl CanInterface {
123	pub fn from_index(index: u32) -> Self {
124		Self { index }
125	}
126
127	pub fn from_name(name: &str) -> std::io::Result<Self> {
128		let name = CString::new(name)
129			.map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "interface name contain a null byte"))?;
130		let index = unsafe { libc::if_nametoindex(name.as_ptr()) };
131		if index == 0 {
132			return Err(std::io::Error::last_os_error());
133		}
134		Ok(Self::from_index(index))
135	}
136
137	pub fn index(&self) -> u32 {
138		self.index
139	}
140
141	pub fn get_name(&self) -> std::io::Result<String> {
142		let mut buffer = vec![0u8; libc::IF_NAMESIZE];
143		let name = unsafe { libc::if_indextoname(self.index, buffer.as_mut_ptr().cast()) };
144		if name.is_null() {
145			return Err(std::io::Error::last_os_error());
146		}
147		if let Some(len) = buffer.iter().position(|&byte| byte == 0) {
148			buffer.truncate(len)
149		}
150		String::from_utf8(buffer)
151			.map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "interface name contains invalid UTF-8"))
152	}
153
154	fn to_address(&self) -> libc::sockaddr_can {
155		unsafe {
156			let mut addr: libc::sockaddr_can = std::mem::zeroed();
157			addr.can_family = libc::AF_CAN as _;
158			addr.can_ifindex = self.index as _;
159			addr
160		}
161	}
162}
163
164impl Socket {
165	pub fn new(non_blocking: bool) -> std::io::Result<Self> {
166		let flags = match non_blocking {
167			true => libc::SOCK_CLOEXEC | libc::SOCK_NONBLOCK,
168			false => libc::SOCK_CLOEXEC,
169		};
170		unsafe {
171			let fd = check_int(libc::socket(libc::PF_CAN, libc::SOCK_RAW | flags, libc::CAN_RAW))?;
172			Ok(Self {
173				fd: FileDesc::from_raw_fd(fd),
174			})
175		}
176	}
177
178	pub fn set_nonblocking(&self, non_blocking: bool) -> std::io::Result<()> {
179		unsafe {
180			let flags = check_int(libc::fcntl(self.fd.as_raw_fd(), libc::F_GETFL))?;
181			let flags = match non_blocking {
182				true => flags | libc::O_NONBLOCK,
183				false => flags & !libc::O_NONBLOCK,
184			};
185			check_int(libc::fcntl(self.fd.as_raw_fd(), libc::F_SETFL, flags | libc::O_NONBLOCK))?;
186		}
187		Ok(())
188	}
189
190	pub fn get_interface_by_name(&self, name: &str) -> std::io::Result<CanInterface> {
191		unsafe {
192			let mut req: libc::ifreq = std::mem::zeroed();
193			if name.len() + 1 > std::mem::size_of_val(&req.ifr_name) {
194				return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "interface name too long"));
195			}
196			if name.as_bytes().contains(&0) {
197				return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "interface name contain a null byte"));
198			}
199			std::ptr::copy(name.as_ptr().cast(), req.ifr_name.as_mut_ptr(), name.len());
200			check_int(libc::ioctl(self.fd.as_raw_fd(), libc::SIOCGIFINDEX as _, &mut req))?;
201			Ok(CanInterface::from_index(req.ifr_ifru.ifru_ifindex as u32))
202		}
203	}
204
205	pub fn bind(&self, interface: &CanInterface) -> std::io::Result<()> {
206		unsafe {
207			let addr = interface.to_address();
208			check_int(libc::bind(
209				self.fd.as_raw_fd(),
210				&addr as *const _ as *const _,
211				std::mem::size_of_val(&addr) as _),
212			)?;
213			Ok(())
214		}
215	}
216
217	pub fn local_addr(&self) -> std::io::Result<CanInterface> {
218		unsafe {
219			let mut addr: libc::sockaddr_can = std::mem::zeroed();
220			let mut addr_len: libc::socklen_t = std::mem::size_of_val(&addr) as _;
221			let _addr_len = check_int(libc::getsockname(
222				self.fd.as_raw_fd(),
223				&mut addr as *mut libc::sockaddr_can as *mut libc::sockaddr,
224				&mut addr_len,
225			));
226			Ok(CanInterface {
227				index: addr.can_ifindex as u32,
228			})
229		}
230	}
231
232	pub fn send(&self, frame: &CanFrame) -> std::io::Result<()> {
233		unsafe {
234			let written = check_isize(libc::send(
235				self.fd.as_raw_fd(),
236				frame.as_c_void_ptr(),
237				std::mem::size_of_val(frame),
238				0,
239			))?;
240			debug_assert!(written as usize == std::mem::size_of_val(frame));
241			Ok(())
242		}
243	}
244
245	pub fn send_to(&self, frame: &CanFrame, interface: &CanInterface) -> std::io::Result<()> {
246		unsafe {
247			let address = interface.to_address();
248			let written = check_isize(libc::sendto(
249				self.fd.as_raw_fd(),
250				&frame as *const _ as *const _,
251				std::mem::size_of_val(frame),
252				0,
253				&address as *const _ as *const _,
254				std::mem::size_of_val(&address) as _,
255			))?;
256			debug_assert!(written as usize == std::mem::size_of_val(frame));
257			Ok(())
258		}
259	}
260
261	pub fn recv(&self) -> std::io::Result<CanFrame> {
262		unsafe {
263			let mut frame: MaybeUninit<CanFrame> = MaybeUninit::uninit();
264			let read = check_isize(libc::recv(
265				self.fd.as_raw_fd(),
266				frame.as_mut_ptr().cast(),
267				std::mem::size_of_val(&frame),
268				0,
269			))?;
270			debug_assert!(read as usize == std::mem::size_of_val(&frame));
271			Ok(frame.assume_init())
272		}
273	}
274
275	pub fn recv_from(&self) -> std::io::Result<(CanFrame, CanInterface)> {
276		unsafe {
277			let mut frame: MaybeUninit<CanFrame> = MaybeUninit::uninit();
278			let mut addr: libc::sockaddr_can = std::mem::zeroed();
279			let read = check_isize(libc::recvfrom(
280				self.fd.as_raw_fd(),
281				frame.as_mut_ptr().cast(),
282				std::mem::size_of_val(&frame),
283				0,
284				&mut addr as *mut _ as *mut _,
285				std::mem::size_of_val(&addr) as _,
286			))?;
287			debug_assert!(read as usize == std::mem::size_of_val(&frame));
288
289			Ok((frame.assume_init(), CanInterface { index: addr.can_ifindex as u32 }))
290		}
291	}
292
293	pub fn set_filters(&self, filters: &[crate::CanFilter]) -> std::io::Result<()> {
294		unsafe {
295			set_socket_option_slice(
296				&self.fd,
297				libc::SOL_CAN_RAW,
298				libc::CAN_RAW_FILTER,
299				filters,
300			)?;
301			Ok(())
302		}
303	}
304
305	pub fn get_loopback(&self) -> std::io::Result<bool> {
306		let enabled: c_int = unsafe {
307			get_socket_option(
308				&self.fd,
309				libc::SOL_CAN_RAW,
310				libc::CAN_RAW_LOOPBACK,
311			)?
312		};
313		Ok(enabled != 0)
314	}
315
316	pub fn set_loopback(&self, enable: bool) -> std::io::Result<()> {
317		unsafe {
318			set_socket_option(
319				&self.fd,
320				libc::SOL_CAN_RAW,
321				libc::CAN_RAW_LOOPBACK,
322				&c_int::from(enable),
323			)?;
324		}
325		Ok(())
326	}
327
328	pub fn get_receive_own_messages(&self) -> std::io::Result<bool> {
329		let enabled: c_int = unsafe {
330			get_socket_option(
331				&self.fd,
332				libc::SOL_CAN_RAW,
333				libc::CAN_RAW_RECV_OWN_MSGS,
334			)?
335		};
336		Ok(enabled != 0)
337	}
338
339	pub fn set_receive_own_messages(&self, enable: bool) -> std::io::Result<()> {
340		unsafe {
341			set_socket_option(
342				&self.fd,
343				libc::SOL_CAN_RAW,
344				libc::CAN_RAW_RECV_OWN_MSGS,
345				&c_int::from(enable),
346			)
347		}
348	}
349}
350
351impl CanFilter {
352	pub const fn new_standard(id: StandardId) -> Self {
353		Self {
354			filter: libc::can_filter {
355				can_id: id.as_u16() as u32,
356				can_mask: 0,
357			},
358		}
359	}
360
361	pub const fn new_extended(id: ExtendedId) -> Self {
362		Self {
363			filter: libc::can_filter {
364				can_id: id.as_u32(),
365				can_mask: 0,
366			},
367		}
368	}
369
370	#[must_use = "returns a new filter, does not modify the existing filter"]
371	pub const fn match_id_value(mut self) -> Self {
372		self.filter.can_mask |= libc::CAN_EFF_MASK;
373		self
374	}
375
376	pub const fn id(self) -> u32 {
377		self.filter.can_id & libc::CAN_EFF_MASK
378	}
379
380	pub const fn id_mask(self) -> u32 {
381		self.filter.can_mask & libc::CAN_EFF_MASK
382	}
383
384	pub const fn matches_rtr_frames(self) -> bool {
385		let rtr_unmasked = self.filter.can_mask & libc::CAN_RTR_FLAG != 0;
386		let is_rtr = self.filter.can_id & libc::CAN_RTR_FLAG != 0;
387		!rtr_unmasked || is_rtr
388	}
389
390	pub const fn matches_data_frames(self) -> bool {
391		let rtr_unmasked = self.filter.can_mask & libc::CAN_RTR_FLAG != 0;
392		let is_rtr = self.filter.can_id & libc::CAN_RTR_FLAG != 0;
393		!rtr_unmasked || !is_rtr
394	}
395
396	pub const fn matches_standard_frames(self) -> bool {
397		let frame_type_unmasked = self.filter.can_mask & libc::CAN_EFF_FLAG != 0;
398		let is_extended = self.filter.can_id & libc::CAN_EFF_FLAG != 0;
399		!frame_type_unmasked || !is_extended
400	}
401
402	pub const fn matches_extended_frames(self) -> bool {
403		let frame_type_unmasked = self.filter.can_mask & libc::CAN_EFF_FLAG != 0;
404		let is_extended = self.filter.can_id & libc::CAN_EFF_FLAG != 0;
405		!frame_type_unmasked || is_extended
406	}
407
408	#[must_use = "returns a new filter, does not modify the existing filter"]
409	pub const fn match_id_mask(mut self, mask: u32) -> Self {
410		self.filter.can_mask |= mask & libc::CAN_EFF_MASK;
411		self
412	}
413
414	#[must_use = "returns a new filter, does not modify the existing filter"]
415	pub const fn match_frame_format(mut self) -> Self {
416		self.filter.can_mask |= libc::CAN_EFF_FLAG;
417		self
418	}
419
420	#[must_use = "returns a new filter, does not modify the existing filter"]
421	pub const fn match_exact_id(mut self) -> Self {
422		self.filter.can_mask |= libc::CAN_EFF_MASK | libc::CAN_EFF_FLAG;
423		self
424	}
425
426	#[must_use = "returns a new filter, does not modify the existing filter"]
427	pub const fn match_rtr_only(mut self) -> Self {
428		self.filter.can_id |= libc::CAN_RTR_FLAG;
429		self.filter.can_mask |= libc::CAN_RTR_FLAG;
430		self
431	}
432
433	#[must_use = "returns a new filter, does not modify the existing filter"]
434	pub const fn match_data_only(mut self) -> Self {
435		self.filter.can_id &= !libc::CAN_RTR_FLAG;
436		self.filter.can_mask |= libc::CAN_RTR_FLAG;
437		self
438	}
439
440	#[must_use = "returns a new filter, does not modify the existing filter"]
441	pub const fn inverted(mut self, inverted: bool) -> Self {
442		if inverted {
443			self.filter.can_id |= libc::CAN_INV_FILTER;
444		} else {
445			self.filter.can_id &= !libc::CAN_INV_FILTER;
446		}
447		self
448	}
449
450	pub const fn is_inverted(self) -> bool {
451		self.filter.can_id & libc::CAN_INV_FILTER != 0
452	}
453
454	pub const fn test(self, frame: &CanFrame) -> bool {
455		let id = self.filter.can_id & !libc::CAN_INV_FILTER;
456		let frame_matches = frame.inner.can_id & self.filter.can_mask == id & self.filter.can_mask;
457		if self.is_inverted() {
458			frame_matches
459		} else {
460			!frame_matches
461		}
462	}
463}
464
465fn check_int(return_value: c_int) -> std::io::Result<c_int> {
466	if return_value == -1 {
467		Err(std::io::Error::last_os_error())
468	} else {
469		Ok(return_value)
470	}
471}
472
473fn check_isize(return_value: isize) -> std::io::Result<isize> {
474	if return_value == -1 {
475		Err(std::io::Error::last_os_error())
476	} else {
477		Ok(return_value)
478	}
479}
480
481unsafe fn set_socket_option<T: Copy>(socket: &FileDesc, level: c_int, option: c_int, value: &T) -> std::io::Result<()> {
482	let len = std::mem::size_of_val(value).try_into().map_err(|_| std::io::ErrorKind::InvalidInput)?;
483	let value: *const T = value;
484	check_int(libc::setsockopt(socket.as_raw_fd(), level, option, value.cast(), len))?;
485	Ok(())
486}
487
488unsafe fn set_socket_option_slice<T: Copy>(socket: &FileDesc, level: c_int, option: c_int, value: &[T]) -> std::io::Result<()> {
489	let len = std::mem::size_of_val(value).try_into().map_err(|_| std::io::ErrorKind::InvalidInput)?;
490	let value = value.as_ptr();
491	check_int(libc::setsockopt(socket.as_raw_fd(), level, option, value.cast(), len))?;
492	Ok(())
493}
494
495unsafe fn get_socket_option<T: Copy + Default>(socket: &FileDesc, level: c_int, option: c_int) -> std::io::Result<T> {
496	let mut value = T::default();
497	let mut len = std::mem::size_of::<T>().try_into().unwrap();
498	{
499		let value: *mut T = &mut value;
500		check_int(libc::getsockopt(socket.as_raw_fd(), level, option, value.cast(), &mut len))?;
501	}
502	Ok(value)
503}
504
505impl std::os::fd::AsFd for Socket {
506	fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
507		self.fd.as_fd()
508	}
509}
510
511impl From<Socket> for std::os::fd::OwnedFd {
512	fn from(value: Socket) -> Self {
513		value.fd.into()
514	}
515}
516
517impl From<std::os::fd::OwnedFd> for Socket {
518	fn from(value: std::os::fd::OwnedFd) -> Self {
519		Self {
520			fd: FileDesc::from(value),
521		}
522	}
523}
524
525impl std::os::fd::AsRawFd for Socket {
526	fn as_raw_fd(&self) -> std::os::fd::RawFd {
527		self.fd.as_raw_fd()
528	}
529}
530
531impl std::os::fd::IntoRawFd for Socket {
532	fn into_raw_fd(self) -> std::os::fd::RawFd {
533		self.fd.into_raw_fd()
534	}
535}
536
537impl std::os::fd::FromRawFd for Socket {
538	unsafe fn from_raw_fd(fd: std::os::fd::RawFd) -> Self {
539		Self {
540			fd: FileDesc::from_raw_fd(fd)
541		}
542	}
543}