Skip to content

adding ethhdr type for linux/android for proper packet filtering. #4239

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions libc-test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2106,6 +2106,8 @@ fn test_android(target: &str) {
(struct_ == "sigaction" && field == "sa_sigaction") ||
// signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet.
(struct_ == "signalfd_siginfo" && field == "ssi_call_addr") ||
// FIXME: `h_proto` is of type __be16 big endian version of __u16
(struct_ == "ethhdr" && field == "h_proto") ||
// FIXME: Seems the type has been changed on NDK r26b
(struct_ == "flock64" && (field == "l_start" || field == "l_len"))
});
Expand Down Expand Up @@ -3686,6 +3688,10 @@ fn test_linux(target: &str) {
if sparc64 && (ty == "Elf32_Rela" || ty == "Elf64_Rela") {
return true;
}
// FIXME: alignment issue with this arch
if loongarch64 && ty == "ethhdr" {
return true;
}
match ty {
// FIXME(sighandler): `sighandler_t` type is incorrect, see:
// https://github.com/rust-lang/libc/issues/1359
Expand Down Expand Up @@ -4395,6 +4401,8 @@ fn test_linux(target: &str) {
(struct_ == "ptp_perout_request" && field == "anonymous_1") ||
// `anonymous_2` is an anonymous union
(struct_ == "ptp_perout_request" && field == "anonymous_2") ||
// FIXME: `h_proto` is of type __be16 big endian version of __u16
(struct_ == "ethhdr" && field == "h_proto") ||
// FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers
// FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers
// the rsv field shrunk when those fields got added, so is omitted too
Expand Down
1 change: 1 addition & 0 deletions libc-test/semver/android.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3230,6 +3230,7 @@ epoll_create1
epoll_ctl
epoll_event
epoll_wait
ethhdr
eventfd
eventfd_read
eventfd_write
Expand Down
1 change: 1 addition & 0 deletions libc-test/semver/linux-gnu.txt
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ dlmopen
eaccess
endutxent
epoll_pwait2
ethhdr
euidaccess
execveat
explicit_bzero
Expand Down
37 changes: 37 additions & 0 deletions src/unix/linux_like/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub type __u16 = c_ushort;
pub type __s16 = c_short;
pub type __u32 = c_uint;
pub type __s32 = c_int;
pub type __be16 = __u16;

// linux/elf.h

Expand Down Expand Up @@ -638,6 +639,15 @@ s_no_extra_traits! {
pub ifc_len: c_int,
pub ifc_ifcu: __c_anonymous_ifc_ifcu,
}

// linux/if_ether.h

#[repr(C, packed)]
pub struct ethhdr {
pub h_dest: [c_uchar; crate::ETH_ALEN as usize],
pub h_source: [c_uchar; crate::ETH_ALEN as usize],
pub h_proto: crate::__be16,
}
}

cfg_if! {
Expand Down Expand Up @@ -1020,6 +1030,33 @@ cfg_if! {
.finish()
}
}

impl Eq for ethhdr {}

impl PartialEq for ethhdr {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PartialEq definition appears to lack a check on the h_proto field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not forget but until I solve the alignment issue in some platforms and as I was playing with the h_proto type I do not bother with it just yet (still a draft).

fn eq(&self, other: &ethhdr) -> bool {
self.h_dest
.iter()
.zip(other.h_dest.iter())
.all(|(a, b)| a == b)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you not want them to compare equal if they have the same CStr value, but different null trailing bytes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that those fields represent mac addresses not as strings (note they re unsigned char).

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, my bad, you're correct.

&& self
.h_source
.iter()
.zip(other.h_source.iter())
.all(|(a, b)| a == b)
&& self.h_proto == other.h_proto
}
}

impl fmt::Debug for ethhdr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ethhdr")
.field("h_dest", &self.h_dest)
.field("h_source", &self.h_source)
.field("h_proto", &{ self.h_proto })
.finish()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing proto field

}
}
}
}

Expand Down
37 changes: 37 additions & 0 deletions src/unix/linux_like/linux/gnu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub type __rlimit_resource_t = c_uint;
pub type Lmid_t = c_long;
pub type regoff_t = c_int;
pub type __kernel_rwf_t = c_int;
pub type __be16 = crate::__u16;

cfg_if! {
if #[cfg(doc)] {
Expand Down Expand Up @@ -437,6 +438,15 @@ s_no_extra_traits! {
__pad: [c_char; 4],
__glibc_reserved: [c_char; 32],
}

// linux/if_ether.h

#[repr(C, packed)]
pub struct ethhdr {
pub h_dest: [c_uchar; crate::ETH_ALEN as usize],
pub h_source: [c_uchar; crate::ETH_ALEN as usize],
pub h_proto: crate::__be16,
}
}

// Internal, for casts to access union fields
Expand Down Expand Up @@ -646,6 +656,33 @@ cfg_if! {
}
}
}

impl Eq for ethhdr {}

impl PartialEq for ethhdr {
fn eq(&self, other: &ethhdr) -> bool {
self.h_dest
.iter()
.zip(other.h_dest.iter())
.all(|(a, b)| a == b)
&& self
.h_source
.iter()
.zip(other.h_source.iter())
.all(|(a, b)| a == b)
&& self.h_proto == other.h_proto
}
}

impl fmt::Debug for ethhdr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ethhdr")
.field("h_dest", &self.h_dest)
.field("h_source", &self.h_source)
.field("h_proto", &{ self.h_proto })
.finish()
}
}
}
}

Expand Down
Loading