Skip to content

Commit d8cbaae

Browse files
author
luozijun
committed
Impl EtherAddr(MAC Addr)
1 parent 4e7a6ec commit d8cbaae

File tree

2 files changed

+252
-1
lines changed

2 files changed

+252
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
5050
([#741](https://github.com/nix-rust/nix/pull/741))
5151
- Added more standard trait implementations for various types.
5252
([#814](https://github.com/nix-rust/nix/pull/814))
53+
- Added `nix::sys::socket::EtherAddr` on Linux and all bsdlike system.
54+
([#813](https://github.com/nix-rust/nix/pull/813))
5355

5456
### Changed
5557
- Use native `pipe2` on all BSD targets. Users should notice no difference.

src/sys/socket/addr.rs

Lines changed: 250 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ impl AddressFamily {
206206
/// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
207207
/// the `sa_family` field of a `sockaddr`.
208208
///
209-
/// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink
209+
/// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet
210210
/// and System. Returns None for unsupported or unknown address families.
211211
pub fn from_i32(family: i32) -> Option<AddressFamily> {
212212
match family {
@@ -217,6 +217,15 @@ impl AddressFamily {
217217
libc::AF_NETLINK => Some(AddressFamily::Netlink),
218218
#[cfg(any(target_os = "macos", target_os = "macos"))]
219219
libc::AF_SYSTEM => Some(AddressFamily::System),
220+
#[cfg(any(target_os = "android", target_os = "linux"))]
221+
libc::AF_PACKET => Some(AddressFamily::Packet),
222+
#[cfg(any(target_os = "dragonfly",
223+
target_os = "freebsd",
224+
target_os = "ios",
225+
target_os = "macos",
226+
target_os = "netbsd",
227+
target_os = "openbsd"))]
228+
libc::AF_LINK => Some(AddressFamily::Link),
220229
_ => None
221230
}
222231
}
@@ -721,6 +730,16 @@ pub enum SockAddr {
721730
Netlink(NetlinkAddr),
722731
#[cfg(any(target_os = "ios", target_os = "macos"))]
723732
SysControl(SysControlAddr),
733+
/// Ethernet MAC address
734+
#[cfg(any(target_os = "dragonfly",
735+
target_os = "freebsd",
736+
target_os = "ios",
737+
target_os = "macos",
738+
target_os = "netbsd",
739+
target_os = "openbsd",
740+
target_os = "android",
741+
target_os = "linux"))]
742+
Ether(EtherAddr)
724743
}
725744

726745
impl SockAddr {
@@ -751,6 +770,15 @@ impl SockAddr {
751770
SockAddr::Netlink(..) => AddressFamily::Netlink,
752771
#[cfg(any(target_os = "ios", target_os = "macos"))]
753772
SockAddr::SysControl(..) => AddressFamily::System,
773+
#[cfg(any(target_os = "android", target_os = "linux"))]
774+
SockAddr::Ether(..) => AddressFamily::Packet,
775+
#[cfg(any(target_os = "dragonfly",
776+
target_os = "freebsd",
777+
target_os = "ios",
778+
target_os = "macos",
779+
target_os = "netbsd",
780+
target_os = "openbsd"))]
781+
SockAddr::Ether(..) => AddressFamily::Link
754782
}
755783
}
756784

@@ -778,6 +806,25 @@ impl SockAddr {
778806
#[cfg(any(target_os = "ios", target_os = "macos"))]
779807
Some(AddressFamily::System) => Some(SockAddr::SysControl(
780808
SysControlAddr(*(addr as *const sys_control::sockaddr_ctl)))),
809+
#[cfg(any(target_os = "android", target_os = "linux"))]
810+
Some(AddressFamily::Packet) => {
811+
match EtherAddr::new_checked(*(addr as *const libc::sockaddr_ll)) {
812+
Some(ether_addr) => Some(SockAddr::Ether(ether_addr)),
813+
None => None
814+
}
815+
},
816+
#[cfg(any(target_os = "dragonfly",
817+
target_os = "freebsd",
818+
target_os = "ios",
819+
target_os = "macos",
820+
target_os = "netbsd",
821+
target_os = "openbsd"))]
822+
Some(AddressFamily::Link) => {
823+
match EtherAddr::new_checked(*(addr as *const libc::sockaddr_dl)) {
824+
Some(ether_addr) => Some(SockAddr::Ether(ether_addr)),
825+
None => None
826+
}
827+
},
781828
// Other address families are currently not supported and simply yield a None
782829
// entry instead of a proper conversion to a `SockAddr`.
783830
Some(_) => None,
@@ -795,6 +842,7 @@ impl SockAddr {
795842
SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
796843
#[cfg(any(target_os = "ios", target_os = "macos"))]
797844
SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<sys_control::sockaddr_ctl>() as libc::socklen_t),
845+
SockAddr::Ether(_) => unimplemented!()
798846
}
799847
}
800848
}
@@ -812,6 +860,9 @@ impl PartialEq for SockAddr {
812860
(SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => {
813861
a == b
814862
}
863+
(SockAddr::Ether(ref a), SockAddr::Ether(ref b)) => {
864+
a == b
865+
}
815866
_ => false,
816867
}
817868
}
@@ -829,6 +880,7 @@ impl hash::Hash for SockAddr {
829880
SockAddr::Netlink(ref a) => a.hash(s),
830881
#[cfg(any(target_os = "ios", target_os = "macos"))]
831882
SockAddr::SysControl(ref a) => a.hash(s),
883+
SockAddr::Ether(ref ether_addr) => ether_addr.hash(s)
832884
}
833885
}
834886
}
@@ -848,6 +900,7 @@ impl fmt::Display for SockAddr {
848900
SockAddr::Netlink(ref nl) => nl.fmt(f),
849901
#[cfg(any(target_os = "ios", target_os = "macos"))]
850902
SockAddr::SysControl(ref sc) => sc.fmt(f),
903+
SockAddr::Ether(ref ether_addr) => ether_addr.fmt(f)
851904
}
852905
}
853906
}
@@ -1016,3 +1069,199 @@ pub mod sys_control {
10161069
}
10171070
}
10181071
}
1072+
1073+
#[cfg(any(target_os = "android", target_os = "linux"))]
1074+
#[derive(Clone, Copy)]
1075+
pub struct EtherAddr(libc::sockaddr_ll);
1076+
1077+
#[cfg(any(target_os = "dragonfly",
1078+
target_os = "freebsd",
1079+
target_os = "ios",
1080+
target_os = "macos",
1081+
target_os = "netbsd",
1082+
target_os = "openbsd"))]
1083+
#[derive(Clone, Copy)]
1084+
pub struct EtherAddr(libc::sockaddr_dl);
1085+
1086+
impl EtherAddr {
1087+
#[cfg(any(target_os = "android", target_os = "linux"))]
1088+
pub fn new_checked(sll: libc::sockaddr_ll) -> Option<EtherAddr> {
1089+
Some(EtherAddr(sll))
1090+
}
1091+
1092+
#[cfg(any(target_os = "dragonfly",
1093+
target_os = "freebsd",
1094+
target_os = "ios",
1095+
target_os = "macos",
1096+
target_os = "netbsd",
1097+
target_os = "openbsd"))]
1098+
pub fn new_checked(sdl: libc::sockaddr_dl) -> Option<EtherAddr> {
1099+
let ether_addr = EtherAddr(sdl);
1100+
if ether_addr.is_empty() {
1101+
None
1102+
} else {
1103+
Some(ether_addr)
1104+
}
1105+
}
1106+
1107+
#[cfg(any(target_os = "dragonfly",
1108+
target_os = "freebsd",
1109+
target_os = "ios",
1110+
target_os = "macos",
1111+
target_os = "netbsd",
1112+
target_os = "openbsd"))]
1113+
pub fn is_empty(&self) -> bool {
1114+
self.nlen() + 5 >= self.max_nlen()
1115+
}
1116+
1117+
#[cfg(any(target_os = "dragonfly",
1118+
target_os = "freebsd",
1119+
target_os = "ios",
1120+
target_os = "macos",
1121+
target_os = "netbsd",
1122+
target_os = "openbsd"))]
1123+
pub fn nlen(&self) -> usize {
1124+
self.0.sdl_nlen as usize
1125+
}
1126+
1127+
#[cfg(any(target_os = "macos",
1128+
target_os = "ios",
1129+
target_os = "dragonfly",
1130+
target_os = "netbsd"))]
1131+
pub fn max_nlen(&self) -> usize { 12 }
1132+
1133+
#[cfg(target_os = "openbsd")]
1134+
pub fn max_nlen(&self) -> usize { 24 }
1135+
1136+
#[cfg(target_os = "freebsd")]
1137+
pub fn max_nlen(&self) -> usize { 46 }
1138+
1139+
#[cfg(any(target_os = "android", target_os = "linux"))]
1140+
pub fn addr(&self) -> [u8; 6] {
1141+
[
1142+
self.0.sll_addr[0],
1143+
self.0.sll_addr[1],
1144+
self.0.sll_addr[2],
1145+
self.0.sll_addr[3],
1146+
self.0.sll_addr[4],
1147+
self.0.sll_addr[5]
1148+
]
1149+
}
1150+
1151+
#[cfg(any(target_os = "dragonfly",
1152+
target_os = "freebsd",
1153+
target_os = "ios",
1154+
target_os = "macos",
1155+
target_os = "netbsd",
1156+
target_os = "openbsd"))]
1157+
pub fn addr(&self) -> [u8; 6] {
1158+
assert_eq!(self.is_empty(), false);
1159+
let nlen = self.nlen();
1160+
[
1161+
self.0.sdl_data[nlen ] as u8,
1162+
self.0.sdl_data[nlen + 1] as u8,
1163+
self.0.sdl_data[nlen + 2] as u8,
1164+
self.0.sdl_data[nlen + 3] as u8,
1165+
self.0.sdl_data[nlen + 4] as u8,
1166+
self.0.sdl_data[nlen + 5] as u8
1167+
]
1168+
}
1169+
}
1170+
1171+
impl Eq for EtherAddr {}
1172+
1173+
impl PartialEq for EtherAddr {
1174+
#[cfg(any(target_os = "android", target_os = "linux"))]
1175+
fn eq(&self, other: &Self) -> bool {
1176+
let (a, b) = (self.0, other.0);
1177+
(a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
1178+
a.sll_pkttype, a.sll_halen, a.sll_addr) ==
1179+
(b.sll_family, b.sll_protocol, b.sll_ifindex, b.sll_hatype,
1180+
b.sll_pkttype, b.sll_halen, b.sll_addr)
1181+
}
1182+
1183+
#[cfg(any(target_os = "macos",
1184+
target_os = "ios",
1185+
target_os = "netbsd",
1186+
target_os = "openbsd"))]
1187+
fn eq(&self, other: &Self) -> bool {
1188+
let (a, b) = (self.0, other.0);
1189+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
1190+
a.sdl_nlen, a.sdl_alen, a.sdl_slen, a.sdl_data) ==
1191+
(b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type,
1192+
b.sdl_nlen, b.sdl_alen, b.sdl_slen, b.sdl_data)
1193+
}
1194+
1195+
#[cfg(target_os = "freebsd")]
1196+
fn eq(&self, other: &Self) -> bool {
1197+
let (a, b) = (self.0, other.0);
1198+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
1199+
a.sdl_nlen, a.sdl_alen, a.sdl_slen,
1200+
&a.sdl_data[0..30], &a.sdl_data[30..46]) ==
1201+
(b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type,
1202+
b.sdl_nlen, b.sdl_alen, b.sdl_slen,
1203+
&b.sdl_data[0..30], &b.sdl_data[30..46])
1204+
}
1205+
1206+
#[cfg(target_os = "dragonfly")]
1207+
fn eq(&self, other: &Self) -> bool {
1208+
let (a, b) = (self.0, other.0);
1209+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
1210+
a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route) ==
1211+
(b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type, b.sdl_nlen,
1212+
b.sdl_alen, b.sdl_slen, b.sdl_data, b.sdl_rcf, b.sdl_route)
1213+
}
1214+
}
1215+
1216+
impl hash::Hash for EtherAddr {
1217+
#[cfg(any(target_os = "android", target_os = "linux"))]
1218+
fn hash<H: hash::Hasher>(&self, s: &mut H) {
1219+
let a = self.0;
1220+
(a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
1221+
a.sll_pkttype, a.sll_halen, a.sll_addr).hash(s);
1222+
}
1223+
1224+
#[cfg(any(target_os = "macos",
1225+
target_os = "ios",
1226+
target_os = "netbsd",
1227+
target_os = "openbsd"))]
1228+
fn hash<H: hash::Hasher>(&self, s: &mut H) {
1229+
let a = self.0;
1230+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
1231+
a.sdl_nlen, a.sdl_alen, a.sdl_slen, a.sdl_data).hash(s);
1232+
}
1233+
1234+
#[cfg(target_os = "freebsd")]
1235+
fn hash<H: hash::Hasher>(&self, s: &mut H) {
1236+
let a = self.0;
1237+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
1238+
a.sdl_nlen, a.sdl_alen, a.sdl_slen,
1239+
&a.sdl_data[0..30], &a.sdl_data[30..46]).hash(s);
1240+
}
1241+
1242+
#[cfg(target_os = "dragonfly")]
1243+
fn hash<H: hash::Hasher>(&self, s: &mut H) {
1244+
let a = self.0;
1245+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
1246+
a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route).hash(s);
1247+
}
1248+
}
1249+
1250+
impl fmt::Display for EtherAddr {
1251+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1252+
let elems = self.addr();
1253+
write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
1254+
elems[0],
1255+
elems[1],
1256+
elems[2],
1257+
elems[3],
1258+
elems[4],
1259+
elems[5])
1260+
}
1261+
}
1262+
1263+
impl fmt::Debug for EtherAddr {
1264+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1265+
fmt::Display::fmt(self, f)
1266+
}
1267+
}

0 commit comments

Comments
 (0)