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.Collections.Generic; 10 using System.Linq; 11 using System.Net; 12 using Antmicro.Renode.Core.Structure; 13 using PacketDotNet; 14 using PacketDotNet.Utils; 15 16 namespace Antmicro.Renode.Network 17 { 18 public class EthernetFrame 19 { TryCreateEthernetFrame(byte[] data, bool addCrc, out EthernetFrame frame)20 public static bool TryCreateEthernetFrame(byte[] data, bool addCrc, out EthernetFrame frame) 21 { 22 return TryCreateEthernetFrame(data, addCrc ? CRCMode.Add : CRCMode.NoOperation, out frame); 23 } 24 TryCreateEthernetFrame(byte[] data, CRCMode crcMode, out EthernetFrame frame)25 public static bool TryCreateEthernetFrame(byte[] data, CRCMode crcMode, out EthernetFrame frame) 26 { 27 frame = null; 28 switch(crcMode) 29 { 30 case CRCMode.NoOperation: 31 if(data.Length >= MinFrameSizeWithoutCRC) 32 { 33 frame = new EthernetFrame(data); 34 return true; 35 } 36 return false; 37 case CRCMode.Add: 38 case CRCMode.Replace: 39 case CRCMode.Keep: 40 if(data.Length >= MinFrameSizeWithoutCRC + CRCLength) 41 { 42 var noCrcData = crcMode == CRCMode.Add ? data : data.Take(data.Length - CRCLength).ToArray(); 43 var crc = (crcMode == CRCMode.Keep ? data.Skip(data.Length - CRCLength) : ComputeCRC(noCrcData)).ToArray(); 44 frame = new EthernetFrame(noCrcData, crc); 45 return true; 46 } 47 return false; 48 default: 49 throw new ArgumentException("Illegal value", "crcMode"); 50 } 51 } 52 CheckCRC(byte[] data)53 public static bool CheckCRC(byte[] data) 54 { 55 return CompareCRC(GetCRCFromPacket(data), CalculateCRCFromPayload(data)); 56 } 57 FillWithChecksums(EtherType[] supportedEtherTypes, IPProtocolType[] supportedIpProtocolTypes, bool updateEthernetCrc = true)58 public void FillWithChecksums(EtherType[] supportedEtherTypes, IPProtocolType[] supportedIpProtocolTypes, bool updateEthernetCrc = true) 59 { 60 var packetNetIpProtocols = supportedIpProtocolTypes.Select(x => (PacketDotNet.IPProtocolType)x).ToArray(); 61 var packetNetEtherTypes = supportedEtherTypes.Select(x => (EthernetPacketType)x).ToArray(); 62 UnderlyingPacket.RecursivelyUpdateCalculatedValues(packetNetEtherTypes, packetNetIpProtocols); 63 64 if(updateEthernetCrc) 65 { 66 var data = UnderlyingPacket.Bytes.ToArray(); 67 crc = ComputeCRC(data).ToArray(); 68 } 69 } 70 Clone()71 public EthernetFrame Clone() 72 { 73 return new EthernetFrame(UnderlyingPacket.Bytes.ToArray(), crc?.ToArray()); 74 } 75 ToString()76 public override string ToString() 77 { 78 try 79 { 80 return UnderlyingPacket.ToString(); 81 } 82 catch 83 { 84 return "<failed to decode frame>"; 85 } 86 } 87 88 public EthernetPacket UnderlyingPacket { get; } 89 90 public byte[] Bytes 91 { 92 get 93 { 94 return (crc != null) ? UnderlyingPacket.Bytes.Concat(crc).ToArray() : UnderlyingPacket.Bytes.ToArray(); 95 } 96 } 97 98 public int Length 99 { 100 get 101 { 102 return UnderlyingPacket.BytesHighPerformance.Length; 103 } 104 } 105 106 public MACAddress SourceMAC => (MACAddress)UnderlyingPacket.SourceHwAddress; 107 108 public MACAddress DestinationMAC => (MACAddress)UnderlyingPacket.DestinationHwAddress; 109 110 public IPAddress SourceIP 111 { 112 get 113 { 114 var ip = (IpPacket)UnderlyingPacket.Extract(typeof(IpPacket)); 115 return ip != null ? ip.SourceAddress : null; 116 } 117 } 118 119 public IPAddress DestinationIP 120 { 121 get 122 { 123 var ip = (IpPacket)UnderlyingPacket.Extract(typeof(IpPacket)); 124 return ip != null ? ip.DestinationAddress : null; 125 } 126 } 127 128 // note: the length 18 covers only: 129 // * mac destination (6) 130 // * mac source (6) 131 // * 802.1Q tag (4) 132 // * ether type or length (2) 133 // and is chosen so that Packet .NET doesn't crash 134 // when parsing the packet; 135 // according to the ethernet specs the packet must 136 // be at least 64 bits long, but since not all 137 // ethernet models in Renode support automatic 138 // padding the selected value is a compromise 139 public static int MinFrameSizeWithoutCRC = 18; 140 public static int CRCLength = 4; 141 // 1500 byte upper layer IP packet with 14 byte frame header and 4 byte frame trailer 142 public static readonly int MaximumFrameSize = 1518; 143 public static readonly int RuntPacketMaximumSize = 63; 144 EthernetFrame(byte[] data, byte[] crc = null)145 private EthernetFrame(byte[] data, byte[] crc = null) 146 { 147 this.crc = crc; 148 this.UnderlyingPacket = (EthernetPacket)Packet.ParsePacket(LinkLayers.Ethernet, data); 149 } 150 ComputeCRC(byte[] data, int? lenght = null)151 private static IEnumerable<byte> ComputeCRC(byte[] data, int? lenght = null) 152 { 153 var computedCRC = lenght.HasValue? Crc32.Compute(data, 0, lenght.Value) : Crc32.Compute(data); 154 var result = BitConverter.GetBytes(computedCRC); 155 return result.Reverse(); 156 } 157 CalculateCRCFromPayload(byte[] data)158 private static IEnumerable<byte> CalculateCRCFromPayload(byte[] data) 159 { 160 return ComputeCRC(data, data.Length - CRCLength); 161 } 162 GetCRCFromPacket(byte[] data)163 private static IEnumerable<byte> GetCRCFromPacket(byte[] data) 164 { 165 return data.Skip(data.Length - CRCLength); 166 } 167 CompareCRC(IEnumerable<byte> receivedCrc, IEnumerable<byte> computedCrc)168 private static bool CompareCRC(IEnumerable<byte> receivedCrc, IEnumerable<byte> computedCrc) 169 { 170 return receivedCrc.SequenceEqual(computedCrc); 171 } 172 173 private byte[] crc; 174 } 175 } 176