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 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}