diff --git a/Contralto/IO/HostEthernet.cs b/Contralto/IO/HostEthernet.cs deleted file mode 100644 index f6a9617..0000000 --- a/Contralto/IO/HostEthernet.cs +++ /dev/null @@ -1,281 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using PcapDotNet.Base; -using PcapDotNet.Core; -using PcapDotNet.Core.Extensions; -using PcapDotNet.Packets; -using PcapDotNet.Packets.Ethernet; -using System.IO; -using Contralto.Logging; -using System.Threading; - -namespace Contralto.IO -{ - - public struct EthernetInterface - { - public EthernetInterface(string name, string description, MacAddress macAddress) - { - Name = name; - Description = description; - MacAddress = macAddress; - } - - public static List EnumerateDevices() - { - List interfaces = new List(); - - foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine) - { - interfaces.Add(new EthernetInterface(device.Name, device.Description, device.GetMacAddress())); - } - - return interfaces; - } - - public string Name; - public string Description; - public MacAddress MacAddress; - } - - public delegate void ReceivePacketDelegate(MemoryStream data); - - /// - /// Implements the logic for encapsulating a 3mbit ethernet packet into a 10mb packet and sending it over an actual - /// interface controlled by the host operating system. - /// - /// This uses PCap.NET to do the dirty work. - /// - public class HostEthernet - { - public HostEthernet(EthernetInterface iface) - { - AttachInterface(iface); - } - - public HostEthernet(string name) - { - // Find the specified device by name - List interfaces = EthernetInterface.EnumerateDevices(); - - foreach (EthernetInterface i in interfaces) - { - if (name == i.Name) - { - AttachInterface(i); - return; - } - } - - throw new InvalidOperationException("Specified ethernet interface does not exist."); - } - - public void RegisterReceiveCallback(ReceivePacketDelegate callback) - { - _callback = callback; - - // Now that we have a callback we can start receiving stuff. - Open(true /* promiscuous */, int.MaxValue); - BeginReceive(); - } - - - /// - /// Sends an array of bytes over the ethernet as a 3mbit packet encapsulated in a 10mbit packet. - /// - /// - /// - public void Send(ushort[] packet, int length) - { - // Sanity check. - if (length < 1) - { - throw new InvalidOperationException("Raw packet data must contain at least two bytes for addressing."); - } - - - // - // Outgoing packet contains 1 extra word (2 bytes) containing - // the prepended packet length (one word) - byte[] packetBytes = new byte[length * 2 + 2]; - - // - // First two bytes include the length of the 3mbit packet; since 10mbit packets have a minimum length of 46 - // bytes, and 3mbit packets have no minimum length this is necessary so the receiver can pull out the - // correct amount of data. - // - packetBytes[0] = (byte)(length); - packetBytes[1] = (byte)((length) >> 8); - - // - // Do this annoying dance to stuff the ushorts into bytes because this is C#. - // - for (int i = 0; i < length; i++) - { - packetBytes[i * 2 + 2] = (byte)(packet[i]); - packetBytes[i * 2 + 3] = (byte)(packet[i] >> 8); - } - - // - // Grab the source and destination host addresses from the packet we're sending - // and build 10mbit versions. - // - byte destinationHost = packetBytes[3]; - byte sourceHost = packetBytes[2]; - - Log.Write(LogComponent.HostEthernet, "Sending packet; source {0} destination {1}, length {2} words.", - Conversion.ToOctal(sourceHost), - Conversion.ToOctal(destinationHost), - length); - - MacAddress destinationMac = Get10mbitDestinationMacFrom3mbit(destinationHost); - MacAddress sourceMac = new MacAddress((UInt48)(_10mbitMACPrefix | Configuration.HostAddress)); - - // Build the outgoing packet; place the source/dest addresses, type field and the raw data. - EthernetLayer ethernetLayer = new EthernetLayer - { - Source = sourceMac, - Destination = destinationMac, - EtherType = (EthernetType)_3mbitFrameType, - }; - - PayloadLayer payloadLayer = new PayloadLayer - { - Data = new Datagram(packetBytes), - }; - - PacketBuilder builder = new PacketBuilder(ethernetLayer, payloadLayer); - - // Send it over the 'net! - _communicator.SendPacket(builder.Build(DateTime.Now)); - - Log.Write(LogComponent.HostEthernet, "Encapsulated 3mbit packet sent."); - } - - private void ReceiveCallback(Packet p) - { - // - // Filter out packets intended for the emulator, forward them on, drop everything else. - // - if ((int)p.Ethernet.EtherType == _3mbitFrameType && // encapsulated 3mbit frames - ((p.Ethernet.Destination.ToValue() & 0xffffffffff00) == _10mbitMACPrefix || // addressed to any emulator OR - p.Ethernet.Destination.ToValue() == _10mbitBroadcast) && // broadcast - (p.Ethernet.Source.ToValue() != (UInt48)(_10mbitMACPrefix | Configuration.HostAddress))) // and not sent by this emulator - { - Log.Write(LogComponent.HostEthernet, "Received encapsulated 3mbit packet."); - _callback(p.Ethernet.Payload.ToMemoryStream()); - } - else - { - // Not for us, discard the packet. - } - } - - private void AttachInterface(EthernetInterface iface) - { - _interface = null; - - // Find the specified device by name - foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine) - { - if (device.Name == iface.Name && device.GetMacAddress() == iface.MacAddress) - { - _interface = device; - break; - } - } - - if (_interface == null) - { - throw new InvalidOperationException("Requested interface not found."); - } - - Log.Write(LogComponent.HostEthernet, "Attached to host interface {0}", iface.Name); - } - - private void Open(bool promiscuous, int timeout) - { - _communicator = _interface.Open(65536, promiscuous ? PacketDeviceOpenAttributes.MaximumResponsiveness | PacketDeviceOpenAttributes.Promiscuous : PacketDeviceOpenAttributes.MaximumResponsiveness, timeout); - - // Set this to 1 so we'll get packets as soon as they arrive, no buffering. - _communicator.SetKernelMinimumBytesToCopy(1); - - Log.Write(LogComponent.HostEthernet, "Host interface opened and receiving packets."); - } - - /// - /// Begin receiving packets, forever. - /// - private void BeginReceive() - { - // Kick off receive thread. - _receiveThread = new Thread(ReceiveThread); - _receiveThread.Start(); - } - - private void ReceiveThread() - { - // Just call ReceivePackets, that's it. This will never return. - // (probably need to make this more elegant so we can tear down the thread - // properly.) - Log.Write(LogComponent.HostEthernet, "Receiver thread started."); - _communicator.ReceivePackets(-1, ReceiveCallback); - } - - private MacAddress Get10mbitDestinationMacFrom3mbit(byte destinationHost) - { - MacAddress destinationMac; - - if (destinationHost == _3mbitBroadcast) - { - // 3mbit broadcast gets translated to 10mbit broadcast - destinationMac = new MacAddress(_10mbitBroadcast); - } - else - { - // Check addressing table for external (non emulator) addresses; - // otherwise just address other emulators - // TODO: implement table. Currently hardcoded address 1 to test IFS on dev machine - // - if (destinationHost == 1) - { - destinationMac = new MacAddress((UInt48)(_ifsTestMAC)); - } - else - { - destinationMac = new MacAddress((UInt48)(_10mbitMACPrefix | destinationHost)); // emulator destination address - } - - } - - return destinationMac; - } - - private LivePacketDevice _interface; - private PacketCommunicator _communicator; - private ReceivePacketDelegate _callback; - - - // Thread used for receive - private Thread _receiveThread; - - private const int _3mbitFrameType = 0xbeef; // easy to identify, ostensibly unused by anything of any import - - /// - /// On output, these bytes are prepended to the Alto's 3mbit (1 byte) address to form a full - /// 6 byte Ethernet MAC. - /// On input, ethernet frames are checked for this prefix - /// - private UInt48 _10mbitMACPrefix = 0x0000aa010200; // 00-00-AA is the Xerox vendor code, used just to be cute. - - private UInt48 _10mbitBroadcast = (UInt48)0xffffffffffff; - private const int _3mbitBroadcast = 0; - - // Temporary; to be replaced with an external address mapping table - private UInt48 _ifsTestMAC = (UInt48)0x001060b88e3e; - } -}