pnet_base/
macaddr.rs

1// Copyright (c) 2014-2016 Robert Clipsham <robert@octarineparrot.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9#[cfg(feature = "std")]
10use std::error::Error;
11
12use core::fmt;
13use core::str::FromStr;
14
15#[cfg(feature = "serde")]
16use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
17
18/// The number of bytes in an ethernet (MAC) address.
19pub const ETHER_ADDR_LEN: usize = 6;
20
21/// Structure of a 48-bit Ethernet address.
22type EtherAddr = [u8; ETHER_ADDR_LEN];
23
24const LOCAL_ADDR_BIT: u8 = 0x02;
25const MULTICAST_ADDR_BIT: u8 = 0x01;
26
27/// A MAC address.
28#[derive(PartialEq, Eq, Clone, Copy, Default, Hash, Ord, PartialOrd)]
29pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);
30
31impl MacAddr {
32    /// Construct a new `MacAddr` instance.
33    pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> MacAddr {
34        MacAddr(a, b, c, d, e, f)
35    }
36
37    /// Construct an all-zero `MacAddr` instance.
38    pub fn zero() -> MacAddr {
39        Default::default()
40    }
41
42    /// Construct a broadcast `MacAddr` instance.
43    pub fn broadcast() -> MacAddr {
44        [0xff; ETHER_ADDR_LEN].into()
45    }
46
47    /// Returns true if a `MacAddr` is an all-zero address.
48    pub fn is_zero(&self) -> bool {
49        *self == Self::zero()
50    }
51
52    /// Returns true if the MacAddr is a universally administered addresses (UAA).
53    pub fn is_universal(&self) -> bool {
54        !self.is_local()
55    }
56
57    /// Returns true if the MacAddr is a locally administered addresses (LAA).
58    pub fn is_local(&self) -> bool {
59        (self.0 & LOCAL_ADDR_BIT) == LOCAL_ADDR_BIT
60    }
61
62    /// Returns true if the MacAddr is a unicast address.
63    pub fn is_unicast(&self) -> bool {
64        !self.is_multicast()
65    }
66
67    /// Returns true if the MacAddr is a multicast address.
68    pub fn is_multicast(&self) -> bool {
69        (self.0 & MULTICAST_ADDR_BIT) == MULTICAST_ADDR_BIT
70    }
71
72    /// Returns true if the MacAddr is a broadcast address.
73    pub fn is_broadcast(&self) -> bool {
74        *self == Self::broadcast()
75    }
76
77    /// Returns the six eight-bit integers that make up this address
78    pub fn octets(&self) -> [u8; 6] {
79        [self.0, self.1, self.2, self.3, self.4, self.5]
80    }
81}
82
83impl From<EtherAddr> for MacAddr {
84    fn from(addr: EtherAddr) -> MacAddr {
85        MacAddr(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5])
86    }
87}
88
89impl From<MacAddr> for EtherAddr {
90    fn from(addr: MacAddr) -> Self {
91        [addr.0, addr.1, addr.2, addr.3, addr.4, addr.5]
92    }
93}
94
95impl PartialEq<EtherAddr> for MacAddr {
96    fn eq(&self, other: &EtherAddr) -> bool {
97        *self == MacAddr::from(*other)
98    }
99}
100
101impl fmt::Display for MacAddr {
102    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
103        write!(
104            fmt,
105            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
106            self.0, self.1, self.2, self.3, self.4, self.5
107        )
108    }
109}
110
111#[cfg(feature = "serde")]
112impl Serialize for MacAddr {
113    /// Serializes the MAC address.
114    ///
115    /// It serializes either to a string or its binary representation, depending on what the format
116    /// prefers.
117    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
118        if serializer.is_human_readable() {
119            serializer.collect_str(self)
120        } else {
121            serializer.serialize_bytes(&[self.0, self.1, self.2, self.3, self.4, self.5])
122        }
123    }
124}
125
126#[cfg(feature = "serde")]
127impl<'de> Deserialize<'de> for MacAddr {
128    /// Deserializes the MAC address.
129    ///
130    /// It deserializes it from either a byte array (of size 6) or a string. If the format is
131    /// self-descriptive (like JSON or MessagePack), it auto-detects it. If not, it obeys the
132    /// human-readable property of the deserializer.
133    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
134        struct MacAddrVisitor;
135        impl<'de> de::Visitor<'de> for MacAddrVisitor {
136            type Value = MacAddr;
137
138            fn visit_str<E: de::Error>(self, value: &str) -> Result<MacAddr, E> {
139                value.parse().map_err(|err| E::custom(err))
140            }
141
142            fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<MacAddr, E> {
143                if v.len() == 6 {
144                    Ok(MacAddr::new(v[0], v[1], v[2], v[3], v[4], v[5]))
145                } else {
146                    Err(E::invalid_length(v.len(), &self))
147                }
148            }
149
150            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
151                write!(
152                    formatter,
153                    "either a string representation of a MAC address or 6-element byte array"
154                )
155            }
156        }
157
158        // Decide what hint to provide to the deserializer based on if it is human readable or not
159        if deserializer.is_human_readable() {
160            deserializer.deserialize_str(MacAddrVisitor)
161        } else {
162            deserializer.deserialize_bytes(MacAddrVisitor)
163        }
164    }
165}
166
167impl fmt::Debug for MacAddr {
168    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
169        fmt::Display::fmt(self, fmt)
170    }
171}
172
173/// Represents an error which occurred whilst parsing a MAC address.
174#[derive(Copy, Debug, PartialEq, Eq, Clone)]
175pub enum ParseMacAddrErr {
176    /// The MAC address has too many components, eg. 00:11:22:33:44:55:66.
177    TooManyComponents,
178    /// The MAC address has too few components, eg. 00:11.
179    TooFewComponents,
180    /// One of the components contains an invalid value, eg. 00:GG:22:33:44:55.
181    InvalidComponent,
182}
183
184#[cfg(feature = "std")]
185impl Error for ParseMacAddrErr {}
186
187impl ParseMacAddrErr {
188    fn description(&self) -> &str {
189        match *self {
190            ParseMacAddrErr::TooManyComponents => "Too many components in a MAC address string",
191            ParseMacAddrErr::TooFewComponents => "Too few components in a MAC address string",
192            ParseMacAddrErr::InvalidComponent => "Invalid component in a MAC address string",
193        }
194    }
195}
196
197impl fmt::Display for ParseMacAddrErr {
198    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199        write!(f, "{}", self.description())
200    }
201}
202
203impl FromStr for MacAddr {
204    type Err = ParseMacAddrErr;
205    fn from_str(s: &str) -> Result<MacAddr, ParseMacAddrErr> {
206        let mut parts = [0u8; 6];
207        let splits = s.split(':');
208        let mut i = 0;
209        for split in splits {
210            if i == 6 {
211                return Err(ParseMacAddrErr::TooManyComponents);
212            }
213            match u8::from_str_radix(split, 16) {
214                Ok(b) if split.len() != 0 => parts[i] = b,
215                _ => return Err(ParseMacAddrErr::InvalidComponent),
216            }
217            i += 1;
218        }
219
220        if i == 6 {
221            Ok(MacAddr(
222                parts[0], parts[1], parts[2], parts[3], parts[4], parts[5],
223            ))
224        } else {
225            Err(ParseMacAddrErr::TooFewComponents)
226        }
227    }
228}
229
230#[cfg(test)]
231mod tests {
232    use super::*;
233
234    #[test]
235    fn mac_addr_from_str() {
236        assert_eq!("00:00:00:00:00:00".parse(), Ok(MacAddr::zero()));
237        assert_eq!("ff:ff:ff:ff:ff:ff".parse(), Ok(MacAddr::broadcast()));
238        assert_eq!(
239            "12:34:56:78:90:ab".parse(),
240            Ok(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB))
241        );
242        assert_eq!(
243            "::::::".parse::<MacAddr>(),
244            Err(ParseMacAddrErr::InvalidComponent)
245        );
246        assert_eq!(
247            "0::::::".parse::<MacAddr>(),
248            Err(ParseMacAddrErr::InvalidComponent)
249        );
250        assert_eq!(
251            "::::0::".parse::<MacAddr>(),
252            Err(ParseMacAddrErr::InvalidComponent)
253        );
254        assert_eq!(
255            "12:34:56:78".parse::<MacAddr>(),
256            Err(ParseMacAddrErr::TooFewComponents)
257        );
258        assert_eq!(
259            "12:34:56:78:".parse::<MacAddr>(),
260            Err(ParseMacAddrErr::InvalidComponent)
261        );
262        assert_eq!(
263            "12:34:56:78:90".parse::<MacAddr>(),
264            Err(ParseMacAddrErr::TooFewComponents)
265        );
266        assert_eq!(
267            "12:34:56:78:90:".parse::<MacAddr>(),
268            Err(ParseMacAddrErr::InvalidComponent)
269        );
270        assert_eq!(
271            "12:34:56:78:90:00:00".parse::<MacAddr>(),
272            Err(ParseMacAddrErr::TooManyComponents)
273        );
274        assert_eq!(
275            "xx:xx:xx:xx:xx:xx".parse::<MacAddr>(),
276            Err(ParseMacAddrErr::InvalidComponent)
277        );
278    }
279
280    #[test]
281    fn str_from_mac_addr() {
282        assert_eq!(format!("{}", MacAddr::zero()), "00:00:00:00:00:00");
283        assert_eq!(format!("{}", MacAddr::broadcast()), "ff:ff:ff:ff:ff:ff");
284        assert_eq!(
285            format!("{}", MacAddr(0x12, 0x34, 0x56, 0x78, 0x09, 0xAB)),
286            "12:34:56:78:09:ab"
287        );
288    }
289
290    #[test]
291    fn fixed_size_slice_from_mac_addr() {
292        assert_eq!(
293            MacAddr(0x00, 0x01, 0x02, 0x03, 0x04, 0x05).octets(),
294            [0x00, 0x01, 0x02, 0x03, 0x04, 0x05]
295        );
296    }
297
298    #[test]
299    fn type_of_addr() {
300        assert!(MacAddr::zero().is_zero());
301        assert!(MacAddr::broadcast().is_broadcast());
302
303        let mac = MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB);
304        assert!(mac.is_local());
305        assert!(mac.is_unicast());
306
307        let mac = MacAddr(0xac, 0x87, 0xa3, 0x07, 0x32, 0xb8);
308        assert!(mac.is_universal());
309        assert!(mac.is_unicast());
310    }
311
312    #[test]
313    fn conversion() {
314        let mac = MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB);
315        let addr = [0x12, 0x34, 0x56, 0x78, 0x90, 0xAB];
316
317        assert_eq!(mac, MacAddr::from(addr));
318        assert_eq!(addr, EtherAddr::from(mac));
319        assert!(mac == addr);
320    }
321
322    #[cfg(feature = "serde")]
323    mod serde {
324        extern crate serde_test;
325        use self::serde_test::{
326            assert_de_tokens, assert_de_tokens_error, assert_tokens, Compact, Configure, Readable,
327            Token,
328        };
329        use super::*;
330
331        #[test]
332        fn string() {
333            let mac = MacAddr::new(0x11, 0x22, 0x33, 0x44, 0x55, 0x66);
334            assert_tokens(&mac.readable(), &[Token::Str("11:22:33:44:55:66")]);
335            assert_de_tokens(&mac.readable(), &[Token::String("11:22:33:44:55:66")]);
336            assert_de_tokens(&mac.readable(), &[Token::BorrowedStr("11:22:33:44:55:66")]);
337            assert_de_tokens_error::<Readable<MacAddr>>(
338                &[Token::Str("not an address")],
339                "Invalid component in a MAC address string",
340            );
341            // It still can detect bytes if provided
342            assert_de_tokens(
343                &mac.readable(),
344                &[Token::Bytes(&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66])],
345            );
346        }
347
348        #[test]
349        fn bytes() {
350            let mac = MacAddr::new(0x11, 0x22, 0x33, 0x44, 0x55, 0x66);
351            assert_tokens(
352                &mac.compact(),
353                &[Token::Bytes(&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66])],
354            );
355            assert_de_tokens(
356                &mac.compact(),
357                &[Token::BorrowedBytes(&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66])],
358            );
359            let err = "invalid length 2, expected either a string representation of a MAC address or 6-element byte array";
360            assert_de_tokens_error::<Compact<MacAddr>>(&[Token::Bytes(&[0x11, 0x33])], err);
361            let err = "invalid length 7, expected either a string representation of a MAC address or 6-element byte array";
362            assert_de_tokens_error::<Compact<MacAddr>>(
363                &[Token::Bytes(&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77])],
364                err,
365            );
366            // Still can decode string in the compact mode
367            assert_de_tokens(&mac.compact(), &[Token::Str("11:22:33:44:55:66")]);
368        }
369    }
370}