diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs index 0b0d29ceeb..d06543301e 100644 --- a/src/sys/socket/addr.rs +++ b/src/sys/socket/addr.rs @@ -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 { match family { @@ -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 } } @@ -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 { @@ -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 } } @@ -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, @@ -795,6 +832,7 @@ impl SockAddr { SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::() as libc::socklen_t), #[cfg(any(target_os = "ios", target_os = "macos"))] SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::() as libc::socklen_t), + SockAddr::Ether(_) => unimplemented!() } } } @@ -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, } } @@ -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) } } } @@ -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) } } } @@ -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 { + 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 { + 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) + } +}