diff --git a/libc-test/build.rs b/libc-test/build.rs index b84168f6d2be8..60f6c2a684061 100755 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -2442,6 +2442,7 @@ fn test_linux(target: &str) { headers! { cfg: "asm/mman.h", + "linux/can.h", "linux/dccp.h", "linux/errqueue.h", "linux/falloc.h", @@ -2556,6 +2557,9 @@ fn test_linux(target: &str) { }); cfg.skip_struct(move |ty| { + if ty.starts_with("__c_anonymous_") { + return true; + } match ty { // These cannot be tested when "resolv.h" is included and are tested // in the `linux_elf.rs` file. @@ -2591,6 +2595,9 @@ fn test_linux(target: &str) { // which is absent in musl, has to be defined. "__exit_status" if musl => true, + // FIXME: CI's kernel header version is old. + "sockaddr_can" => true, + _ => false, } }); @@ -2697,6 +2704,11 @@ fn test_linux(target: &str) { | "IFLA_PERM_ADDRESS" | "IFLA_PROTO_DOWN_REASON" => true, + // FIXME: They require recent kernel header: + | "CAN_J1939" + | "CAN_RAW_FILTER_MAX" + | "CAN_NPROTO" => true, + _ => false, } }); @@ -2757,7 +2769,9 @@ fn test_linux(target: &str) { // this one is an anonymous union (struct_ == "ff_effect" && field == "u") || // `__exit_status` type is a patch which is absent in musl - (struct_ == "utmpx" && field == "ut_exit" && musl) + (struct_ == "utmpx" && field == "ut_exit" && musl) || + // `can_addr` is an anonymous union + (struct_ == "sockaddr_can" && field == "can_addr") }); cfg.volatile_item(|i| { diff --git a/src/unix/linux_like/linux/align.rs b/src/unix/linux_like/linux/align.rs index 8bf6895944834..31e9d77dbf5ac 100644 --- a/src/unix/linux_like/linux/align.rs +++ b/src/unix/linux_like/linux/align.rs @@ -52,6 +52,27 @@ macro_rules! expand_align { pub fd: ::c_int, pub pid: ::c_int, } + + // linux/can.h + #[repr(align(8))] + pub struct can_frame { + pub can_id: canid_t, + pub can_dlc: u8, + __pad: u8, + __res0: u8, + __res1: u8, + pub data: [u8; CAN_MAX_DLEN], + } + + #[repr(align(8))] + pub struct canfd_frame { + pub can_id: canid_t, + pub len: u8, + pub flags: u8, + __res0: u8, + __res1: u8, + pub data: [u8; CANFD_MAX_DLEN], + } } s_no_extra_traits! { diff --git a/src/unix/linux_like/linux/mod.rs b/src/unix/linux_like/linux/mod.rs index ed35f87545dfe..60f78dfed2895 100644 --- a/src/unix/linux_like/linux/mod.rs +++ b/src/unix/linux_like/linux/mod.rs @@ -36,6 +36,10 @@ pub type Elf64_Sxword = i64; pub type Elf32_Section = u16; pub type Elf64_Section = u16; +// linux/can.h +pub type canid_t = u32; +pub type can_err_mask_t = u32; + #[cfg_attr(feature = "extra_traits", derive(Debug))] pub enum fpos64_t {} // FIXME: fill this out with a struct impl ::Copy for fpos64_t {} @@ -504,6 +508,23 @@ s! { pub ee_info: u32, pub ee_data: u32, } + + // linux/can.h + pub struct __c_anonymous_sockaddr_can_tp { + pub rx_id: canid_t, + pub tx_id: canid_t, + } + + pub struct __c_anonymous_sockaddr_can_j1939 { + pub name: u64, + pub pgn: u32, + pub addr: u8, + } + + pub struct can_filter { + pub can_id: canid_t, + pub can_mask: canid_t, + } } s_no_extra_traits! { @@ -577,6 +598,26 @@ s_no_extra_traits! { } } +cfg_if! { + if #[cfg(libc_union)] { + s_no_extra_traits! { + // linux/can.h + #[allow(missing_debug_implementations)] + pub union __c_anonymous_sockaddr_can_can_addr { + pub tp: __c_anonymous_sockaddr_can_tp, + pub j1939: __c_anonymous_sockaddr_can_j1939, + } + + #[allow(missing_debug_implementations)] + pub struct sockaddr_can { + pub can_family: ::sa_family_t, + pub can_ifindex: ::c_int, + pub can_addr: __c_anonymous_sockaddr_can_can_addr, + } + } + } +} + cfg_if! { if #[cfg(feature = "extra_traits")] { impl PartialEq for sockaddr_nl { @@ -2584,6 +2625,46 @@ pub const EDOM: ::c_int = 33; pub const ERANGE: ::c_int = 34; pub const EWOULDBLOCK: ::c_int = EAGAIN; +// linux/can.h +pub const CAN_EFF_FLAG: canid_t = 0x80000000; +pub const CAN_RTR_FLAG: canid_t = 0x40000000; +pub const CAN_ERR_FLAG: canid_t = 0x20000000; +pub const CAN_SFF_MASK: canid_t = 0x000007FF; +pub const CAN_EFF_MASK: canid_t = 0x1FFFFFFF; +pub const CAN_ERR_MASK: canid_t = 0x1FFFFFFF; + +pub const CAN_SFF_ID_BITS: ::c_int = 11; +pub const CAN_EFF_ID_BITS: ::c_int = 29; + +pub const CAN_MAX_DLC: ::c_int = 8; +pub const CAN_MAX_DLEN: usize = 8; +pub const CANFD_MAX_DLC: ::c_int = 15; +pub const CANFD_MAX_DLEN: usize = 64; + +pub const CANFD_BRS: ::c_int = 0x01; +pub const CANFD_ESI: ::c_int = 0x02; + +cfg_if! { + if #[cfg(libc_align)] { + pub const CAN_MTU: usize = ::mem::size_of::(); + pub const CANFD_MTU: usize = ::mem::size_of::(); + } +} + +pub const CAN_RAW: ::c_int = 1; +pub const CAN_BCM: ::c_int = 2; +pub const CAN_TP16: ::c_int = 3; +pub const CAN_TP20: ::c_int = 4; +pub const CAN_MCNET: ::c_int = 5; +pub const CAN_ISOTP: ::c_int = 6; +pub const CAN_J1939: ::c_int = 7; +pub const CAN_NPROTO: ::c_int = 8; + +pub const SOL_CAN_BASE: ::c_int = 100; + +pub const CAN_INV_FILTER: canid_t = 0x20000000; +pub const CAN_RAW_FILTER_MAX: ::c_int = 512; + f! { pub fn NLA_ALIGN(len: ::c_int) -> ::c_int { return ((len) + NLA_ALIGNTO - 1) & !(NLA_ALIGNTO - 1)