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 21, 2017
1 parent bc82685 commit cfacb5b
Show file tree
Hide file tree
Showing 3 changed files with 324 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#741](https://github.com/nix-rust/nix/pull/741))
- Added more standard trait implementations for various types.
([#814](https://github.com/nix-rust/nix/pull/814))
- Added `nix::sys::socket::EtherAddr` on Linux and all bsdlike system.
([#813](https://github.com/nix-rust/nix/pull/813))

### Changed
- Use native `pipe2` on all BSD targets. Users should notice no difference.
Expand Down
314 changes: 312 additions & 2 deletions 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/Packet
/// 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 @@ -720,6 +729,16 @@ pub enum SockAddr {
Netlink(NetlinkAddr),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SysControl(SysControlAddr),
/// Ethernet MAC address
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "android",
target_os = "linux"))]
Ether(EtherAddr)
}

impl SockAddr {
Expand Down Expand Up @@ -750,6 +769,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 @@ -777,6 +805,27 @@ 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) => {
let ether_addr = EtherAddr::new(*(addr as *const libc::sockaddr_ll));
match ether_addr {
Some(ether_addr) => Some(SockAddr::Ether(ether_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) => {
let ether_addr = EtherAddr::new(*(addr as *const libc::sockaddr_dl));
match ether_addr {
Some(ether_addr) => Some(SockAddr::Ether(ether_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 @@ -794,6 +843,15 @@ 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),
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
target_os = "android"))]
SockAddr::Ether(_) => unimplemented!()
}
}
}
Expand All @@ -811,6 +869,17 @@ impl PartialEq for SockAddr {
(SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => {
a == b
}
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
target_os = "android"))]
(SockAddr::Ether(ref a), SockAddr::Ether(ref b)) => {
a == b
}
_ => false,
}
}
Expand All @@ -828,6 +897,15 @@ 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),
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
target_os = "android"))]
SockAddr::Ether(ref ether_addr) => ether_addr.hash(s)
}
}
}
Expand All @@ -847,6 +925,15 @@ 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),
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
target_os = "android"))]
SockAddr::Ether(ref ether_addr) => ether_addr.fmt(f)
}
}
}
Expand Down Expand Up @@ -1014,4 +1101,227 @@ pub mod sys_control {
fmt::Display::fmt(self, f)
}
}
}
}


#[cfg(any(target_os = "android", target_os = "linux"))]
#[derive(Clone, Copy)]
pub struct EtherAddr(pub libc::sockaddr_ll);

#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
#[derive(Clone, Copy)]
pub struct EtherAddr(pub libc::sockaddr_dl);


#[cfg(any(target_os = "android", target_os = "linux"))]
impl EtherAddr {
pub fn new(sll: libc::sockaddr_ll) -> Option<EtherAddr> {
Some(EtherAddr(sll))
}

pub fn is_empty(&self) -> bool {
false
}

pub fn addr(&self) -> [u8; 6] {
[self.0.sll_addr[0],
self.0.sll_addr[1],
self.0.sll_addr[2],
self.0.sll_addr[3],
self.0.sll_addr[4],
self.0.sll_addr[5]]
}
}

#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
impl EtherAddr {
pub fn new(sdl: libc::sockaddr_dl) -> Option<EtherAddr> {
let sdl_wrap = EtherAddr(sdl);
match sdl_wrap.is_empty() {
true => None,
false => Some(sdl_wrap),
}
}

pub fn nlen(&self) -> usize {
self.0.sdl_nlen as usize
}

pub fn is_empty(&self) -> bool {
self.nlen() + 5 >= self.max_nlen()
}

#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "dragonfly",
target_os = "netbsd"))]
pub fn max_nlen(&self) -> usize { 12 }

#[cfg(target_os = "openbsd")]
pub fn max_nlen(&self) -> usize { 24 }

#[cfg(target_os = "freebsd")]
pub fn max_nlen(&self) -> usize { 46 }

pub fn addr(&self) -> [u8; 6] {
assert_eq!(self.is_empty(), false);
let nlen = self.nlen();

[self.0.sdl_data[nlen ] as u8,
self.0.sdl_data[nlen + 1] as u8,
self.0.sdl_data[nlen + 2] as u8,
self.0.sdl_data[nlen + 3] as u8,
self.0.sdl_data[nlen + 4] as u8,
self.0.sdl_data[nlen + 5] as u8 ]
}

}

#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
target_os = "android"))]
impl Eq for EtherAddr {}


#[cfg(any(target_os = "android", target_os = "linux"))]
impl PartialEq for EtherAddr {
fn eq(&self, other: &Self) -> bool {
let (a, b) = (self.0, other.0);
(a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
a.sll_pkttype, a.sll_halen, a.sll_addr) ==
(b.sll_family, b.sll_protocol, b.sll_ifindex, b.sll_hatype,
b.sll_pkttype, b.sll_halen, b.sll_addr)
}
}

#[cfg(any(target_os = "android", target_os = "linux"))]
impl hash::Hash for EtherAddr {
fn hash<H: hash::Hasher>(&self, s: &mut H) {
let a = self.0;
(a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
a.sll_pkttype, a.sll_halen, a.sll_addr).hash(s);
}
}

#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
impl PartialEq for EtherAddr {
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "netbsd",
target_os = "openbsd"))]
fn eq(&self, other: &Self) -> bool {
let (a, b) = (self.0, other.0);
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
a.sdl_nlen, a.sdl_alen, a.sdl_slen, a.sdl_data) ==
(b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type,
b.sdl_nlen, b.sdl_alen, b.sdl_slen, b.sdl_data)
}

#[cfg(target_os = "freebsd")]
fn eq(&self, other: &Self) -> bool {
let (a, b) = (self.0, other.0);
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
a.sdl_nlen, a.sdl_alen, a.sdl_slen,
&a.sdl_data[0..30], &a.sdl_data[30..46]) ==
(b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type,
b.sdl_nlen, b.sdl_alen, b.sdl_slen,
&b.sdl_data[0..30], &b.sdl_data[30..46])
}

#[cfg(target_os = "dragonfly")]
fn eq(&self, other: &Self) -> bool {
let (a, b) = (self.0, other.0);
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route) ==
(b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type, b.sdl_nlen,
b.sdl_alen, b.sdl_slen, b.sdl_data, b.sdl_rcf, b.sdl_route)
}
}

#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
impl hash::Hash for EtherAddr {
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "netbsd",
target_os = "openbsd"))]
fn hash<H: hash::Hasher>(&self, s: &mut H) {
let a = self.0;
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
a.sdl_nlen, a.sdl_alen, a.sdl_slen, a.sdl_data).hash(s);
}

#[cfg(target_os = "freebsd")]
fn hash<H: hash::Hasher>(&self, s: &mut H) {
let a = self.0;
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
a.sdl_nlen, a.sdl_alen, a.sdl_slen,
&a.sdl_data[0..30], &a.sdl_data[30..46]).hash(s);
}

#[cfg(target_os = "dragonfly")]
fn hash<H: hash::Hasher>(&self, s: &mut H) {
let a = self.0;
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route).hash(s);
}
}

#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
target_os = "android"))]
impl fmt::Display for EtherAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let addr = self.addr();
write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
addr[0],
addr[1],
addr[2],
addr[3],
addr[4],
addr[5])
}
}

#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "linux",
target_os = "android"))]
impl fmt::Debug for EtherAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
Loading

0 comments on commit cfacb5b

Please sign in to comment.