Skip to content

Commit

Permalink
Impl EtherAddr(MAC Addr)
Browse files Browse the repository at this point in the history
  • Loading branch information
luozijun committed Dec 15, 2017
1 parent 4e7a6ec commit 640e2fe
Showing 1 changed file with 131 additions and 1 deletion.
132 changes: 131 additions & 1 deletion src/sys/socket/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl AddressFamily {
/// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
/// the `sa_family` field of a `sockaddr`.
///
/// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink
/// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link
/// and System. Returns None for unsupported or unknown address families.
pub fn from_i32(family: i32) -> Option<AddressFamily> {
match family {
Expand All @@ -217,6 +217,15 @@ impl AddressFamily {
libc::AF_NETLINK => Some(AddressFamily::Netlink),
#[cfg(any(target_os = "macos", target_os = "macos"))]
libc::AF_SYSTEM => Some(AddressFamily::System),
#[cfg(any(target_os = "android", target_os = "linux"))]
libc::AF_PACKET => Some(AddressFamily::Packet),
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
libc::AF_LINK => Some(AddressFamily::Link),
_ => None
}
}
Expand Down Expand Up @@ -721,6 +730,8 @@ pub enum SockAddr {
Netlink(NetlinkAddr),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SysControl(SysControlAddr),
/// Ethernet MAC address
Ether(EtherAddr)
}

impl SockAddr {
Expand Down Expand Up @@ -751,6 +762,15 @@ impl SockAddr {
SockAddr::Netlink(..) => AddressFamily::Netlink,
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(..) => AddressFamily::System,
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Ether(..) => AddressFamily::Packet,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
SockAddr::Ether(..) => AddressFamily::Link
}
}

Expand Down Expand Up @@ -778,6 +798,23 @@ impl SockAddr {
#[cfg(any(target_os = "ios", target_os = "macos"))]
Some(AddressFamily::System) => Some(SockAddr::SysControl(
SysControlAddr(*(addr as *const sys_control::sockaddr_ctl)))),
#[cfg(any(target_os = "android", target_os = "linux"))]
Some(AddressFamily::Packet) => match EtherAddr::from_libc_sockaddr_ll(
addr as *const libc::sockaddr_ll) {
Some(mac_addr) => Some(SockAddr::Ether(mac_addr)),
None => None
},
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
Some(AddressFamily::Link) => match EtherAddr::from_libc_sockaddr_dl(
addr as *const libc::sockaddr_dl) {
Some(mac_addr) => Some(SockAddr::Ether(mac_addr)),
None => None
},
// Other address families are currently not supported and simply yield a None
// entry instead of a proper conversion to a `SockAddr`.
Some(_) => None,
Expand All @@ -795,6 +832,7 @@ impl SockAddr {
SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<sys_control::sockaddr_ctl>() as libc::socklen_t),
SockAddr::Ether(_) => unimplemented!()
}
}
}
Expand All @@ -812,6 +850,9 @@ impl PartialEq for SockAddr {
(SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => {
a == b
}
(SockAddr::Ether(ref a), SockAddr::Ether(ref b)) => {
a == b
}
_ => false,
}
}
Expand All @@ -829,6 +870,7 @@ impl hash::Hash for SockAddr {
SockAddr::Netlink(ref a) => a.hash(s),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(ref a) => a.hash(s),
SockAddr::Ether(ref ether_addr) => ether_addr.hash(s)
}
}
}
Expand All @@ -848,6 +890,7 @@ impl fmt::Display for SockAddr {
SockAddr::Netlink(ref nl) => nl.fmt(f),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(ref sc) => sc.fmt(f),
SockAddr::Ether(ref ether_addr) => ether_addr.fmt(f)
}
}
}
Expand Down Expand Up @@ -1016,3 +1059,90 @@ pub mod sys_control {
}
}
}

#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct EtherAddr {
pub a: u8,
pub b: u8,
pub c: u8,
pub d: u8,
pub e: u8,
pub f: u8,
}

impl EtherAddr {
pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> EtherAddr {
EtherAddr {
a: a,
b: b,
c: c,
d: d,
e: e,
f: f,
}
}

#[cfg(any(target_os = "android", target_os = "linux"))]
pub unsafe fn from_libc_sockaddr_ll(sll: *const libc::sockaddr_ll) -> Option<EtherAddr> {
let mac = EtherAddr::new(
(*sll).sll_addr[0],
(*sll).sll_addr[1],
(*sll).sll_addr[2],
(*sll).sll_addr[3],
(*sll).sll_addr[4],
(*sll).sll_addr[5]);
Some(mac)
}

#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
pub unsafe fn from_libc_sockaddr_dl(sdl: *const libc::sockaddr_dl) -> Option<EtherAddr> {
let nlen = (*sdl).sdl_nlen as usize;
let max_nlen: usize = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
12
} else if cfg!(target_os = "freebsd") {
46
} else if cfg!(target_os = "dragonfly") {
12
} else if cfg!(target_os = "netbsd") {
12
} else if cfg!(target_os = "openbsd") {
24
} else {
unreachable!();
};
if nlen + 5 >= max_nlen {
return None;
}
let mac = EtherAddr::new(
(*sdl).sdl_data[nlen ] as u8,
(*sdl).sdl_data[nlen + 1] as u8,
(*sdl).sdl_data[nlen + 2] as u8,
(*sdl).sdl_data[nlen + 3] as u8,
(*sdl).sdl_data[nlen + 4] as u8,
(*sdl).sdl_data[nlen + 5] as u8);
Some(mac)
}
}

impl fmt::Display for EtherAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.a,
self.b,
self.c,
self.d,
self.e,
self.f)
}
}

impl fmt::Debug for EtherAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}

0 comments on commit 640e2fe

Please sign in to comment.