1 //
2 // Copyright (c) 2010-2023 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.Net.NetworkInformation;
10 using System.Globalization;
11 using Antmicro.Renode.Utilities;
12 
13 namespace Antmicro.Renode.Core.Structure
14 {
15     [Convertible]
16     public struct MACAddress : IEquatable<MACAddress>
17     {
18         public byte A { get; private set; }
19 
20         public byte B { get; private set; }
21 
22         public byte C { get; private set; }
23 
24         public byte D { get; private set; }
25 
26         public byte E { get; private set; }
27 
28         public byte F { get; private set; }
29 
30         public byte[] Bytes { get { return new [] { A, B, C, D, E, F }; } }
31 
MACAddressAntmicro.Renode.Core.Structure.MACAddress32         public MACAddress(ulong address) : this()
33         {
34             A = (byte)(address >> 40);
35             B = (byte)(address >> 32);
36             C = (byte)(address >> 24);
37             D = (byte)(address >> 16);
38             E = (byte)(address >> 8);
39             F = (byte)address;
40         }
41 
42         public static MACAddress Default { get { return new MACAddress(); } }
43 
44         public MACAddress WithNewOctets(byte? a = null, byte? b = null, byte? c = null, byte? d = null, byte? e = null, byte? f = null)
45         {
46             var result = new MACAddress();
47             result.A = a ?? A;
48             result.B = b ?? B;
49             result.C = c ?? C;
50             result.D = d ?? D;
51             result.E = e ?? E;
52             result.F = f ?? F;
53             return result;
54         }
55 
NextAntmicro.Renode.Core.Structure.MACAddress56         public MACAddress Next(int count = 1)
57         {
58             for(var i = 0; i < count; i++)
59             {
60                 InnerNext();
61             }
62 
63             return this;
64 	}
65 
PreviousAntmicro.Renode.Core.Structure.MACAddress66         public MACAddress Previous()
67         {
68             var result = this;
69 
70             var cp = 5;
71             while(true)
72             {
73                 if(result.GetByte(cp) == 0)
74                 {
75                     if(cp == 0)
76                     {
77                         throw new OverflowException();
78                     }
79                     cp--;
80                 }
81                 else
82                 {
83                     result.SetByte(cp, (byte)(result.GetByte(cp) - 1));
84                     for(int i = cp + 1; i < 6; i++)
85                     {
86                         result.SetByte(i, byte.MaxValue);
87                     }
88                     break;
89                 }
90             }
91 
92             return result;
93         }
94 
GetBytesAntmicro.Renode.Core.Structure.MACAddress95         public byte[] GetBytes()
96         {
97             var bytes = new byte[6];
98             for(var i = 0; i < 6; ++i)
99             {
100                 bytes[i] = GetByte(i);
101             }
102             return bytes;
103         }
104 
EqualsAntmicro.Renode.Core.Structure.MACAddress105         public override bool Equals(object obj)
106         {
107             if(obj == null)
108             {
109                 return false;
110             }
111             if(obj.GetType() != typeof(MACAddress))
112             {
113                 return false;
114             }
115             var other = (MACAddress)obj;
116             return this == other;
117         }
118 
GetHashCodeAntmicro.Renode.Core.Structure.MACAddress119         public override int GetHashCode()
120         {
121             unchecked
122             {
123                 return A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode() ^ D.GetHashCode() ^ E.GetHashCode() ^ F.GetHashCode();
124             }
125         }
126 
TryParseAntmicro.Renode.Core.Structure.MACAddress127         public static bool TryParse(string str, out MACAddress result)
128         {
129             result = default(MACAddress);
130 
131             var splits = str.Split(':');
132             if(splits.Length != 6)
133             {
134                 return false;
135             }
136 
137             for(var i = 0; i < 6; i++)
138             {
139                 result.SetByte(i, byte.Parse(splits[i], NumberStyles.HexNumber));
140             }
141 
142             return true;
143         }
144 
ParseAntmicro.Renode.Core.Structure.MACAddress145         public static MACAddress Parse(string str)
146         {
147             if(!TryParse(str, out var result))
148             {
149                 throw new FormatException();
150             }
151 
152             return result;
153         }
154 
FromBytesAntmicro.Renode.Core.Structure.MACAddress155         public static MACAddress FromBytes(byte[] array, int startingIndex = 0)
156         {
157             var result = new MACAddress();
158             for(var i = 0; i < 6; i++)
159             {
160                 result.SetByte(i, array[startingIndex + i]);
161             }
162             return result;
163         }
164 
165         public bool IsBroadcast
166         {
167             get
168             {
169                 return A == 0xFF && B == 0xFF && C == 0xFF && D == 0xFF && E == 0xFF && F == 0xFF;
170             }
171         }
172 
173         public bool IsMulticast
174         {
175             get
176             {
177                 return A == 0x01 && B == 0x00 && C == 0x5E;
178             }
179         }
180 
181         public bool IsUnicast
182         {
183             get
184             {
185                 return !IsBroadcast && !IsMulticast;
186             }
187         }
188 
ToStringAntmicro.Renode.Core.Structure.MACAddress189         public override string ToString()
190         {
191             return string.Format("{0:X2}:{1:X2}:{2:X2}:{3:X2}:{4:X2}:{5:X2}", A, B, C, D, E, F);
192         }
193 
operator MACAddressAntmicro.Renode.Core.Structure.MACAddress194         public static explicit operator MACAddress(PhysicalAddress address)
195         {
196             return MACAddress.FromBytes(address.GetAddressBytes());
197         }
198 
operator PhysicalAddressAntmicro.Renode.Core.Structure.MACAddress199         public static explicit operator PhysicalAddress(MACAddress address)
200         {
201             return new PhysicalAddress(address.GetBytes());
202         }
203 
operator stringAntmicro.Renode.Core.Structure.MACAddress204         public static explicit operator string(MACAddress m)
205         {
206             return m.ToString();
207         }
208 
operator MACAddressAntmicro.Renode.Core.Structure.MACAddress209         public static explicit operator MACAddress(string input)
210         {
211             return MACAddress.Parse(input);
212         }
213 
EqualsAntmicro.Renode.Core.Structure.MACAddress214         public bool Equals(MACAddress other)
215         {
216             return this == other;
217         }
218 
operator ==Antmicro.Renode.Core.Structure.MACAddress219         public static bool operator ==(MACAddress a, MACAddress b)
220         {
221             return a.A == b.A && a.B == b.B && a.C == b.C && a.D == b.D && a.E == b.E && a.F == b.F;
222         }
223 
operator !=Antmicro.Renode.Core.Structure.MACAddress224         public static bool operator !=(MACAddress a, MACAddress b)
225         {
226             return !(a == b);
227         }
228 
InnerNextAntmicro.Renode.Core.Structure.MACAddress229         private void InnerNext()
230         {
231             var cp = 5;
232             while(true)
233             {
234                 if(this.GetByte(cp) == byte.MaxValue)
235                 {
236                     if(cp == 0)
237                     {
238                         throw new OverflowException();
239                     }
240                     cp--;
241                 }
242                 else
243                 {
244                     this.SetByte(cp, (byte)(this.GetByte(cp) + 1));
245                     for(int i = cp + 1; i < 6; i++)
246                     {
247                         this.SetByte(i, 0);
248                     }
249                     break;
250                 }
251             }
252         }
253 
GetByteAntmicro.Renode.Core.Structure.MACAddress254         private byte GetByte(int index)
255         {
256             switch(index)
257             {
258             case 0:
259                 return A;
260             case 1:
261                 return B;
262             case 2:
263                 return C;
264             case 3:
265                 return D;
266             case 4:
267                 return E;
268             case 5:
269                 return F;
270             default:
271                 throw new ArgumentException();
272             }
273         }
274 
SetByteAntmicro.Renode.Core.Structure.MACAddress275         private void SetByte(int index, byte value)
276         {
277             switch(index)
278             {
279             case 0:
280                 A = value;
281                 break;
282             case 1:
283                 B = value;
284                 break;
285             case 2:
286                 C = value;
287                 break;
288             case 3:
289                 D = value;
290                 break;
291             case 4:
292                 E = value;
293                 break;
294             case 5:
295                 F = value;
296                 break;
297             default:
298                 throw new ArgumentException();
299             }
300         }
301     }
302 }
303 
304