Timestamps & lots of fixes!
- Added ability to get timestamp for received frames
- New
CanTimestampstype carrying socket-layer, network-stack software, and hardware receive timestamps SocketOptions::set_recv_timestamp(SO_TIMESTAMPNS) andSocketOptions::set_timestamping(SO_TIMESTAMPING) to enable delivery on the socketSocket::read_frame_with_timestamp,Socket::read_frame_with_timestamps, andSocket::read_frame_with_hw_timestampon theSockettrait (default implementations returnENOSYSto preserve semver for out-of-treeSocketimplementors)CanSocket::has_hw_timestamps/CanFdSocket::has_hw_timestampsquery interface capability viaETHTOOL_GET_TS_INFO- Re-exports for the
SOF_TIMESTAMPING_*flag constants from the crate root - All read methods deliver the frame and ancillary timestamp data in a single
recvmsg()call, eliminating the race window of the oldSIOCGSTAMPNSapproach - Async equivalents on the
tokio::CanSocket/CanFdSocketandasync_io::CanSocket/CanFdSocketwrappers
- New
async_io::CanSocketandasync_io::CanFdSocketgainedopen_if(ifindex: u32)andopen_addr(&CanAddr)constructors (parity with the tokio wrappers, which previously had all three)async_io::CanSocketandasync_io::CanFdSocketnow implementfutures::Stream(yieldingResult<CanFrame>/Result<CanAnyFrame>) andfutures::Sink(overCanFrame/CanAnyFrame), parity with the tokio wrappers. Theasync-io,async-std, andsmolfeatures now pull infutures(previously it was wired in only via thetokiofeature)async_io::CanSocketandasync_io::CanFdSocketgainedtry_read_frame()andtry_write_frame()methods, parity with the tokio wrappers (added in #84). Both returnWouldBlockwhen no frame is available / send buffer is full and go straight to the underlying non-blocking fd (bypassing the async-io reactor); mixing with the async-path methods is safe- New example
tokio_recvts— tokio mirror ofcan_recvts, prints software and hardware timestamps alongside each frame - Bumped MSRV to v1.75.0
- All frame types now derive
PartialEq,Eq, andHash— both the concrete frame structs (CanDataFrame,CanRemoteFrame,CanErrorFrame,CanFdFrame) and the wrapper enums (CanFrame,CanAnyFrame,CanRawFrame). Equality is field-wise on the underlyinglibc::can_frame/libc::canfd_frame, which means it includes every byte of the structure (id, dlc, flags, the libc__pad/__res0fields, and the full data array). Note thatset_datadoes not zero the unused trailing bytes ofcan_frame::data, so two semantically-equivalent frames built by different code paths may still compare unequal — callers should treat equality as "byte-identical wire image" rather than "same logical frame". - Enabled the
extra_traitsfeature on thelibcdependency so the trait derives can flow through (libc::can_frame/canfd_frameonlyderive(PartialEq, Eq, Hash)when that feature is on). - Bug fixes:
recvmsg()ancillary control buffer is now properly aligned and validated;MSG_TRUNC/MSG_CTRUNChandled correctlytimespec_to_durationno longer wraps on a negativetv_secin release buildsFrom<canfd_frame> for CanFdFramenormalises non-spec lengths sodlc()anddata()stay consistent and no uninitialised bytes can leakTryFrom<can_frame> for CanErrorFrameforcescan_dlc = CAN_MAX_DLENso the len/dlc/data invariant holdsCanDataFrame::set_idandCanFdFrame::set_idpreserveCAN_ERR_FLAG/CAN_RTR_FLAGbits in the ID wordCanId + u32no longer panics on overflow in debug buildsAsPtr::as_bytes_mutnow returns&mut [u8]instead of&[u8]rcanCLI no longer contains duplicateloopbacksubcommand armsexamples/can_recvts.rsnow requests the full set of timestamp flags so software and hardware timestamps actually arriveexamples/fd_send.rsnow sends an actual CAN FD framefmt::UpperHexon classic frames usesraw_id()(no flag-bit leakage), zero-pads the ID to 3 chars (SFF) / 8 chars (EFF), joins data bytes without spaces, and emits#R<dlc>for remote frames so the output matches candump's log formatfmt::UpperHexonCanFdFrameprints the FD flags as a single hex nibble between##and the data bytes (no stray space)CanRemoteFrame::data()now returns&[](spec-correct: remote frames carry only a DLC); usedlc()to read the requested lengthCanInterface::createrejects names of lengthIFNAMSIZand above (off-by-one —IFNAMSIZincludes the trailing NUL)CAN_TERMINATION_DISABLEDis nowu16(matches the rest of the termination API)From<libudev::Error>preserves the underlying description on the wrappedio::ErrorCanAddrgained hand-rolledPartialEq/Eq/Hashimpls comparing(can_family, can_ifindex)only; deriving them would compare thecan_addrunion plus padding, which is unsoundCanAddr::Debugnow renders thecan_addrunion bytes (J1939 / ISO-TP fields are no longer dropped)From<sockaddr_can> for CanAddrnowdebug_assert!scan_family == AF_CANavailable_interfaces()was silently ignoring udev errors and returning an empty list of interfaces. It now returns an error on udev failure.- Tokio
Sink::poll_closeno longer attempts a spuriousclear_ready();Sink::start_sendissues a single non-blockingwrite_frame()instead of busy-retrying viawrite_frame_insist - Typo: "socke options" → "socket options" in
set_socket_option_multdoc dump::Readercaps each line at 64 KiB so a malformed or hostile log can't OOM the reader; over-long lines produceInvalidCanFramedump::Readerrequires exactly six mantissa digits on the timestamp (real candump format), and uses checked arithmetic so an overflow errors instead of producing a wrong timestampdump::Readerpropagates remote-frame DLC parse errors viaInvalidCanFrame(previously silently coerced to 0); the DLC is now parsed as a hex nibble matching candump'sR<X>formatdump::CanDumpRecordDisplaynow emits parseable lines for error frames (<error_bits>#<8 hex bytes>) and FD frames (##<flag-nibble><bytes>), and zero-pads the ID width (3 hex for SFF, 8 hex for EFF) on all variants
- New
Errorconversions:From<neli::err::NlError<T, P>>(featurenetlink) — netlink errors flow into the crate-levelErrorviaio::Error::otherFrom<dump::ParseError>(featuredump) — dump-parse errors flow intoErrorviaio::Error::new(InvalidData, …)(passing through I/O variants)
- Docs:
Socket::read_framedocuments concurrent-reader semantics (each&selfreader sees a disjoint subset of frames)CanCtrlModes::has_modedocuments that it inspectsflags(kernel-reported state) and ignores pendingmaskbitsCanFdFrame::new_remotedocuments that CAN FD has no RTR by spec, so the method always returnsNone
- Internals:
crate::as_bytes/crate::as_bytes_muthelpers are nowunsafe fnwith a proper# Safetycontract; call sites annotated
- Issues & PR's