Skip to content

Commit b9fda8b

Browse files
author
luozijun
committed
Impl EtherAddr(MAC Addr)
1 parent 0e6b034 commit b9fda8b

File tree

3 files changed

+315
-1
lines changed

3 files changed

+315
-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: 312 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,27 @@ 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+
let ether_addr = EtherAddr::new(*(addr as *const libc::sockaddr_ll));
812+
match ether_addr {
813+
Some(ether_addr) => Some(SockAddr::Ether(ether_addr)),
814+
None => None
815+
}
816+
},
817+
#[cfg(any(target_os = "dragonfly",
818+
target_os = "freebsd",
819+
target_os = "ios",
820+
target_os = "macos",
821+
target_os = "netbsd",
822+
target_os = "openbsd"))]
823+
Some(AddressFamily::Link) => {
824+
let ether_addr = EtherAddr::new(*(addr as *const libc::sockaddr_dl));
825+
match ether_addr {
826+
Some(ether_addr) => Some(SockAddr::Ether(ether_addr)),
827+
None => None
828+
}
829+
},
781830
// Other address families are currently not supported and simply yield a None
782831
// entry instead of a proper conversion to a `SockAddr`.
783832
Some(_) => None,
@@ -795,6 +844,15 @@ impl SockAddr {
795844
SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
796845
#[cfg(any(target_os = "ios", target_os = "macos"))]
797846
SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<sys_control::sockaddr_ctl>() as libc::socklen_t),
847+
#[cfg(any(target_os = "dragonfly",
848+
target_os = "freebsd",
849+
target_os = "ios",
850+
target_os = "macos",
851+
target_os = "netbsd",
852+
target_os = "openbsd",
853+
target_os = "linux",
854+
target_os = "android"))]
855+
SockAddr::Ether(_) => unimplemented!()
798856
}
799857
}
800858
}
@@ -812,6 +870,17 @@ impl PartialEq for SockAddr {
812870
(SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => {
813871
a == b
814872
}
873+
#[cfg(any(target_os = "dragonfly",
874+
target_os = "freebsd",
875+
target_os = "ios",
876+
target_os = "macos",
877+
target_os = "netbsd",
878+
target_os = "openbsd",
879+
target_os = "linux",
880+
target_os = "android"))]
881+
(SockAddr::Ether(ref a), SockAddr::Ether(ref b)) => {
882+
a == b
883+
}
815884
_ => false,
816885
}
817886
}
@@ -829,6 +898,15 @@ impl hash::Hash for SockAddr {
829898
SockAddr::Netlink(ref a) => a.hash(s),
830899
#[cfg(any(target_os = "ios", target_os = "macos"))]
831900
SockAddr::SysControl(ref a) => a.hash(s),
901+
#[cfg(any(target_os = "dragonfly",
902+
target_os = "freebsd",
903+
target_os = "ios",
904+
target_os = "macos",
905+
target_os = "netbsd",
906+
target_os = "openbsd",
907+
target_os = "linux",
908+
target_os = "android"))]
909+
SockAddr::Ether(ref ether_addr) => ether_addr.hash(s)
832910
}
833911
}
834912
}
@@ -848,6 +926,15 @@ impl fmt::Display for SockAddr {
848926
SockAddr::Netlink(ref nl) => nl.fmt(f),
849927
#[cfg(any(target_os = "ios", target_os = "macos"))]
850928
SockAddr::SysControl(ref sc) => sc.fmt(f),
929+
#[cfg(any(target_os = "dragonfly",
930+
target_os = "freebsd",
931+
target_os = "ios",
932+
target_os = "macos",
933+
target_os = "netbsd",
934+
target_os = "openbsd",
935+
target_os = "linux",
936+
target_os = "android"))]
937+
SockAddr::Ether(ref ether_addr) => ether_addr.fmt(f)
851938
}
852939
}
853940
}
@@ -1016,3 +1103,227 @@ pub mod sys_control {
10161103
}
10171104
}
10181105
}
1106+
1107+
1108+
#[cfg(any(target_os = "android", target_os = "linux"))]
1109+
#[derive(Clone, Copy)]
1110+
pub struct EtherAddr(pub libc::sockaddr_ll);
1111+
1112+
#[cfg(any(target_os = "dragonfly",
1113+
target_os = "freebsd",
1114+
target_os = "ios",
1115+
target_os = "macos",
1116+
target_os = "netbsd",
1117+
target_os = "openbsd"))]
1118+
#[derive(Clone, Copy)]
1119+
pub struct EtherAddr(pub libc::sockaddr_dl);
1120+
1121+
1122+
#[cfg(any(target_os = "android", target_os = "linux"))]
1123+
impl EtherAddr {
1124+
pub fn new(sll: libc::sockaddr_ll) -> Option<EtherAddr> {
1125+
Some(EtherAddr(sll))
1126+
}
1127+
1128+
pub fn is_empty(&self) -> bool {
1129+
false
1130+
}
1131+
1132+
pub fn addr(&self) -> [u8; 6] {
1133+
[self.0.sll_addr[0],
1134+
self.0.sll_addr[1],
1135+
self.0.sll_addr[2],
1136+
self.0.sll_addr[3],
1137+
self.0.sll_addr[4],
1138+
self.0.sll_addr[5]]
1139+
}
1140+
}
1141+
1142+
#[cfg(any(target_os = "dragonfly",
1143+
target_os = "freebsd",
1144+
target_os = "ios",
1145+
target_os = "macos",
1146+
target_os = "netbsd",
1147+
target_os = "openbsd"))]
1148+
impl EtherAddr {
1149+
pub fn new(sdl: libc::sockaddr_dl) -> Option<EtherAddr> {
1150+
let sdl_wrap = EtherAddr(sdl);
1151+
match sdl_wrap.is_empty() {
1152+
true => None,
1153+
false => Some(sdl_wrap),
1154+
}
1155+
}
1156+
1157+
pub fn nlen(&self) -> usize {
1158+
self.0.sdl_nlen as usize
1159+
}
1160+
1161+
pub fn is_empty(&self) -> bool {
1162+
self.nlen() + 5 >= self.max_nlen()
1163+
}
1164+
1165+
#[cfg(any(target_os = "macos",
1166+
target_os = "ios",
1167+
target_os = "dragonfly",
1168+
target_os = "netbsd"))]
1169+
pub fn max_nlen(&self) -> usize { 12 }
1170+
1171+
#[cfg(target_os = "openbsd")]
1172+
pub fn max_nlen(&self) -> usize { 24 }
1173+
1174+
#[cfg(target_os = "freebsd")]
1175+
pub fn max_nlen(&self) -> usize { 46 }
1176+
1177+
pub fn addr(&self) -> [u8; 6] {
1178+
assert_eq!(self.is_empty(), false);
1179+
let nlen = self.nlen();
1180+
1181+
[self.0.sdl_data[nlen ] as u8,
1182+
self.0.sdl_data[nlen + 1] as u8,
1183+
self.0.sdl_data[nlen + 2] as u8,
1184+
self.0.sdl_data[nlen + 3] as u8,
1185+
self.0.sdl_data[nlen + 4] as u8,
1186+
self.0.sdl_data[nlen + 5] as u8 ]
1187+
}
1188+
1189+
}
1190+
1191+
#[cfg(any(target_os = "dragonfly",
1192+
target_os = "freebsd",
1193+
target_os = "ios",
1194+
target_os = "macos",
1195+
target_os = "netbsd",
1196+
target_os = "openbsd",
1197+
target_os = "linux",
1198+
target_os = "android"))]
1199+
impl Eq for EtherAddr {}
1200+
1201+
1202+
#[cfg(any(target_os = "android", target_os = "linux"))]
1203+
impl PartialEq for EtherAddr {
1204+
fn eq(&self, other: &Self) -> bool {
1205+
let (a, b) = (self.0, other.0);
1206+
(a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
1207+
a.sll_pkttype, a.sll_halen, a.sll_addr) ==
1208+
(b.sll_family, b.sll_protocol, b.sll_ifindex, b.sll_hatype,
1209+
b.sll_pkttype, b.sll_halen, b.sll_addr)
1210+
}
1211+
}
1212+
1213+
#[cfg(any(target_os = "android", target_os = "linux"))]
1214+
impl hash::Hash for EtherAddr {
1215+
fn hash<H: hash::Hasher>(&self, s: &mut H) {
1216+
let a = self.0;
1217+
(a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
1218+
a.sll_pkttype, a.sll_halen, a.sll_addr).hash(s);
1219+
}
1220+
}
1221+
1222+
#[cfg(any(target_os = "dragonfly",
1223+
target_os = "freebsd",
1224+
target_os = "ios",
1225+
target_os = "macos",
1226+
target_os = "netbsd",
1227+
target_os = "openbsd"))]
1228+
impl PartialEq for EtherAddr {
1229+
#[cfg(any(target_os = "macos",
1230+
target_os = "ios",
1231+
target_os = "netbsd",
1232+
target_os = "openbsd"))]
1233+
fn eq(&self, other: &Self) -> bool {
1234+
let (a, b) = (self.0, other.0);
1235+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
1236+
a.sdl_nlen, a.sdl_alen, a.sdl_slen, a.sdl_data) ==
1237+
(b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type,
1238+
b.sdl_nlen, b.sdl_alen, b.sdl_slen, b.sdl_data)
1239+
}
1240+
1241+
#[cfg(target_os = "freebsd")]
1242+
fn eq(&self, other: &Self) -> bool {
1243+
let (a, b) = (self.0, other.0);
1244+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
1245+
a.sdl_nlen, a.sdl_alen, a.sdl_slen,
1246+
&a.sdl_data[0..30], &a.sdl_data[30..46]) ==
1247+
(b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type,
1248+
b.sdl_nlen, b.sdl_alen, b.sdl_slen,
1249+
&b.sdl_data[0..30], &b.sdl_data[30..46])
1250+
}
1251+
1252+
#[cfg(target_os = "dragonfly")]
1253+
fn eq(&self, other: &Self) -> bool {
1254+
let (a, b) = (self.0, other.0);
1255+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
1256+
a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route) ==
1257+
(b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type, b.sdl_nlen,
1258+
b.sdl_alen, b.sdl_slen, b.sdl_data, b.sdl_rcf, b.sdl_route)
1259+
}
1260+
}
1261+
1262+
#[cfg(any(target_os = "dragonfly",
1263+
target_os = "freebsd",
1264+
target_os = "ios",
1265+
target_os = "macos",
1266+
target_os = "netbsd",
1267+
target_os = "openbsd"))]
1268+
impl hash::Hash for EtherAddr {
1269+
#[cfg(any(target_os = "macos",
1270+
target_os = "ios",
1271+
target_os = "netbsd",
1272+
target_os = "openbsd"))]
1273+
fn hash<H: hash::Hasher>(&self, s: &mut H) {
1274+
let a = self.0;
1275+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
1276+
a.sdl_nlen, a.sdl_alen, a.sdl_slen, a.sdl_data).hash(s);
1277+
}
1278+
1279+
#[cfg(target_os = "freebsd")]
1280+
fn hash<H: hash::Hasher>(&self, s: &mut H) {
1281+
let a = self.0;
1282+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
1283+
a.sdl_nlen, a.sdl_alen, a.sdl_slen,
1284+
&a.sdl_data[0..30], &a.sdl_data[30..46]).hash(s);
1285+
}
1286+
1287+
#[cfg(target_os = "dragonfly")]
1288+
fn hash<H: hash::Hasher>(&self, s: &mut H) {
1289+
let a = self.0;
1290+
(a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
1291+
a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route).hash(s);
1292+
}
1293+
}
1294+
1295+
#[cfg(any(target_os = "dragonfly",
1296+
target_os = "freebsd",
1297+
target_os = "ios",
1298+
target_os = "macos",
1299+
target_os = "netbsd",
1300+
target_os = "openbsd",
1301+
target_os = "linux",
1302+
target_os = "android"))]
1303+
impl fmt::Display for EtherAddr {
1304+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1305+
let addr = self.addr();
1306+
write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
1307+
addr[0],
1308+
addr[1],
1309+
addr[2],
1310+
addr[3],
1311+
addr[4],
1312+
addr[5])
1313+
}
1314+
}
1315+
1316+
#[cfg(any(target_os = "dragonfly",
1317+
target_os = "freebsd",
1318+
target_os = "ios",
1319+
target_os = "macos",
1320+
target_os = "netbsd",
1321+
target_os = "openbsd",
1322+
target_os = "linux",
1323+
target_os = "android"))]
1324+
impl fmt::Debug for EtherAddr {
1325+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1326+
fmt::Display::fmt(self, f)
1327+
}
1328+
}
1329+

src/sys/socket/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub use self::addr::{
2727
IpAddr,
2828
Ipv4Addr,
2929
Ipv6Addr,
30+
EtherAddr
3031
};
3132
#[cfg(any(target_os = "linux", target_os = "android"))]
3233
pub use ::sys::socket::addr::netlink::NetlinkAddr;

0 commit comments

Comments
 (0)