diff --git a/Build/VMWare/Workstation/Cosmos.vmx b/Build/VMWare/Workstation/Cosmos.vmx index 64a71f3db..1ca66858d 100644 --- a/Build/VMWare/Workstation/Cosmos.vmx +++ b/Build/VMWare/Workstation/Cosmos.vmx @@ -51,7 +51,6 @@ serial0.pipe.endPoint = "client" serial0.tryNoRxLoss = "TRUE" sound.present = "TRUE" ethernet0.present = "TRUE" -ethernet0.connectionType = "nat" ethernet0.wakeOnPcktRcv = "FALSE" ethernet0.addressType = "generated" usb.present = "TRUE" diff --git a/source2/Debug/Cosmos.Debug.Common/DebugInfo.cs b/source2/Debug/Cosmos.Debug.Common/DebugInfo.cs index 2180f7d43..049550d54 100644 --- a/source2/Debug/Cosmos.Debug.Common/DebugInfo.cs +++ b/source2/Debug/Cosmos.Debug.Common/DebugInfo.cs @@ -138,7 +138,7 @@ namespace Cosmos.Debug.Common xExec.SqlStatements.Add( "CREATE TABLE Label (" - + " LABELNAME VARCHAR(255) NOT NULL" + + " LABELNAME VARCHAR(4000) NOT NULL" + ", ADDRESS BIGINT NOT NULL" + ");"); diff --git a/source2/Users/SSchocke/SSchockeTest/BinaryHelper.cs b/source2/Kernel/Common/Cosmos.Common.Extensions/BinaryHelper.cs similarity index 94% rename from source2/Users/SSchocke/SSchockeTest/BinaryHelper.cs rename to source2/Kernel/Common/Cosmos.Common.Extensions/BinaryHelper.cs index 781ddf3be..c5a450cbf 100644 --- a/source2/Users/SSchocke/SSchockeTest/BinaryHelper.cs +++ b/source2/Kernel/Common/Cosmos.Common.Extensions/BinaryHelper.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace SSchockeTest +namespace Cosmos.Common.Extensions { /// /// Contains various helpermethods to make bitfiddling easier. diff --git a/source2/Kernel/Common/Cosmos.Common.Extensions/Cosmos.Common.Extensions.csproj b/source2/Kernel/Common/Cosmos.Common.Extensions/Cosmos.Common.Extensions.csproj index 23f4bfe72..301f23724 100644 --- a/source2/Kernel/Common/Cosmos.Common.Extensions/Cosmos.Common.Extensions.csproj +++ b/source2/Kernel/Common/Cosmos.Common.Extensions/Cosmos.Common.Extensions.csproj @@ -72,6 +72,7 @@ + diff --git a/source2/Kernel/System/Cosmos.System/Cosmos.System.csproj b/source2/Kernel/System/Cosmos.System/Cosmos.System.csproj index 17901fba0..4c532595a 100644 --- a/source2/Kernel/System/Cosmos.System/Cosmos.System.csproj +++ b/source2/Kernel/System/Cosmos.System/Cosmos.System.csproj @@ -78,6 +78,17 @@ + + + + + + + + + + + @@ -93,6 +104,10 @@ {61607F1E-58F9-41CF-972F-128384F3E115} Cosmos.Debug.Kernel + + {5AC4773C-CB4E-4CD9-8D50-02E10A07DEE6} + Cosmos.Core + {6A991D03-1435-4005-9809-B8BACDF3B021} Cosmos.Hardware diff --git a/source2/Kernel/System/Cosmos.System/Global.cs b/source2/Kernel/System/Cosmos.System/Global.cs index 2a9ea1007..4d3dc7187 100644 --- a/source2/Kernel/System/Cosmos.System/Global.cs +++ b/source2/Kernel/System/Cosmos.System/Global.cs @@ -14,6 +14,7 @@ namespace Cosmos.System { Console = new Console(); Cosmos.Hardware.Global.Init(); + Network.NetworkStack.Init(); } } } diff --git a/source2/Kernel/System/Cosmos.System/Kernel.cs b/source2/Kernel/System/Cosmos.System/Kernel.cs index 4571a4d1a..97db51c67 100644 --- a/source2/Kernel/System/Cosmos.System/Kernel.cs +++ b/source2/Kernel/System/Cosmos.System/Kernel.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Cosmos.Hardware; namespace Cosmos.System { // MtW: if the fullname (namespace + name) of this class changes, please also change IL2CPU msbuild task @@ -36,7 +32,8 @@ namespace Cosmos.System { BeforeRun(); while (!mStopped) { - Run(); + Network.NetworkStack.Update(); + Run(); } AfterRun(); bool xTest = 1 != 3; diff --git a/source2/Kernel/System/Cosmos.System/Network/ARP/ARPCache.cs b/source2/Kernel/System/Cosmos.System/Network/ARP/ARPCache.cs new file mode 100644 index 000000000..1f9e37569 --- /dev/null +++ b/source2/Kernel/System/Cosmos.System/Network/ARP/ARPCache.cs @@ -0,0 +1,54 @@ +using System; +using Cosmos.Core.Network; + +namespace Cosmos.System.Network.ARP +{ + internal static class ARPCache + { + private static TempDictionary cache; + + private static void ensureCacheExists() + { + if (cache == null) + { + cache = new TempDictionary(); + } + } + + internal static bool Contains(IPv4.Address ipAddress) + { + ensureCacheExists(); + return cache.ContainsKey(ipAddress.Hash); + } + + internal static void Update(IPv4.Address ipAddress, MACAddress macAddress) + { + ensureCacheExists(); + UInt32 ip_hash = ipAddress.Hash; + if (ip_hash == 0) + { + return; + } + + if (cache.ContainsKey(ip_hash) == false) + { + cache.Add(ip_hash, macAddress); + } + else + { + cache[ip_hash] = macAddress; + } + } + + internal static MACAddress Resolve(IPv4.Address ipAddress) + { + ensureCacheExists(); + if (cache.ContainsKey(ipAddress.Hash) == false) + { + return null; + } + + return cache[ipAddress.Hash]; + } + } +} diff --git a/source2/Kernel/System/Cosmos.System/Network/ARP/ARPPacket.cs b/source2/Kernel/System/Cosmos.System/Network/ARP/ARPPacket.cs new file mode 100644 index 000000000..e91235c88 --- /dev/null +++ b/source2/Kernel/System/Cosmos.System/Network/ARP/ARPPacket.cs @@ -0,0 +1,102 @@ +using System; +using Sys = System; +using Cosmos.Core.Network; +using Cosmos.Hardware; + +namespace Cosmos.System.Network.ARP +{ + internal class ARPPacket : EthernetPacket + { + protected UInt16 aHardwareType; + protected UInt16 aProtocolType; + protected byte aHardwareLen; + protected byte aProtocolLen; + protected UInt16 aOperation; + + internal static void ARPHandler(byte[] packetData) + { + ARPPacket arp_packet = new ARPPacket(packetData); + //Sys.Console.WriteLine("Received ARP Packet"); + //Sys.Console.WriteLine(arp_packet.ToString()); + if (arp_packet.Operation == 0x01) + { + if ((arp_packet.HardwareType == 1) && (arp_packet.ProtocolType == 0x0800)) + { + IPv4.ARPRequest_Ethernet arp_request = new IPv4.ARPRequest_Ethernet(packetData); + ARPCache.Update(arp_request.SenderIP, arp_request.SenderMAC); + + if (NetworkStack.AddressMap.ContainsKey(arp_request.TargetIP.Hash) == true) + { + Sys.Console.WriteLine("ARP Request Recvd from " + arp_request.SenderIP.ToString()); + NetworkDevice nic = NetworkStack.AddressMap[arp_request.TargetIP.Hash]; + + IPv4.ARPReply_Ethernet reply = + new IPv4.ARPReply_Ethernet(nic.MACAddress, arp_request.TargetIP, arp_request.SenderMAC, arp_request.SenderIP); + + nic.QueueBytes(reply.RawData); + } + } + } + //else if (arp_packet.Operation == 0x02) + //{ + // if ((arp_packet.HardwareType == 1) && (arp_packet.ProtocolType == 0x0800)) + // { + // ARP.IPv4.ARPReply_Ethernet arp_reply = new ARP.IPv4.ARPReply_Ethernet(packetData); + // ARP.ARPCache.Update(arp_reply.SenderIP, arp_reply.SenderMAC); + + // //Sys.Console.WriteLine("ARP Reply Recvd for IP=" + arp_reply.SenderIP.ToString()); + // TCPIP.IPv4.OutgoingBuffer.ARPCache_Update(arp_reply); + // } + //} + } + + internal ARPPacket(byte[] rawData) + : base(rawData) + { } + + protected override void initFields() + { + base.initFields(); + aHardwareType = (UInt16)((mRawData[14] << 8) | mRawData[15]); + aProtocolType = (UInt16)((mRawData[16] << 8) | mRawData[17]); + aHardwareLen = mRawData[18]; + aProtocolLen = mRawData[19]; + aOperation = (UInt16)((mRawData[20] << 8) | mRawData[21]); + } + + protected ARPPacket(MACAddress dest, MACAddress src, UInt16 hwType, UInt16 protoType, + byte hwLen, byte protoLen, UInt16 operation, int packet_size) + : base(dest, src, 0x0806, packet_size) + { + mRawData[14] = (byte)(hwType >> 8); + mRawData[15] = (byte)(hwType >> 0); + mRawData[16] = (byte)(protoType >> 8); + mRawData[17] = (byte)(protoType >> 0); + mRawData[18] = hwLen; + mRawData[19] = protoLen; + mRawData[20] = (byte)(operation >> 8); + mRawData[21] = (byte)(operation >> 0); + + initFields(); + } + + internal UInt16 Operation + { + get { return this.aOperation; } + } + internal UInt16 HardwareType + { + get { return this.aHardwareType; } + } + internal UInt16 ProtocolType + { + get { return this.aProtocolType; } + } + + public override string ToString() + { + return "ARP Packet Src=" + srcMAC + ", Dest=" + destMAC + ", HWType=" + aHardwareType + ", Protocol=" + aProtocolType + + ", Operation=" + Operation; + } + } +} diff --git a/source2/Kernel/System/Cosmos.System/Network/EthernetPacket.cs b/source2/Kernel/System/Cosmos.System/Network/EthernetPacket.cs new file mode 100644 index 000000000..28c8a80e2 --- /dev/null +++ b/source2/Kernel/System/Cosmos.System/Network/EthernetPacket.cs @@ -0,0 +1,89 @@ +using System; +using Cosmos.Core.Network; + +namespace Cosmos.System.Network +{ + internal class EthernetPacket + { + protected byte[] mRawData; + protected MACAddress srcMAC; + protected MACAddress destMAC; + protected UInt16 aEtherType; + + protected EthernetPacket(byte[] rawData) + { + mRawData = rawData; + initFields(); + } + + protected virtual void initFields() + { + destMAC = new MACAddress(mRawData, 0); + srcMAC = new MACAddress(mRawData, 6); + aEtherType = (UInt16)((mRawData[12] << 8) | mRawData[13]); + } + + protected EthernetPacket(UInt16 type, int packet_size) + : this(MACAddress.None, MACAddress.None, type, packet_size) + { + } + + protected EthernetPacket(MACAddress dest, MACAddress src, UInt16 type, int packet_size) + { + mRawData = new byte[packet_size]; + for (int i = 0; i < 6; i++) + { + mRawData[i] = dest.bytes[i]; + mRawData[6 + i] = src.bytes[i]; + } + + mRawData[12] = (byte)(type >> 8); + mRawData[13] = (byte)(type >> 0); + initFields(); + } + + internal MACAddress SourceMAC + { + get { return this.srcMAC; } + set + { + for (int i = 0; i < 6; i++) + { + mRawData[6 + i] = value.bytes[i]; + } + initFields(); + } + } + internal MACAddress DestinationMAC + { + get { return this.destMAC; } + set + { + for (int i = 0; i < 6; i++) + { + mRawData[i] = value.bytes[i]; + } + initFields(); + } + } + internal UInt16 EthernetType + { + get { return this.aEtherType; } + } + + internal byte[] GetBytes() + { + return this.mRawData; + } + + internal byte[] RawData + { + get { return this.mRawData; } + } + + public override string ToString() + { + return "Ethernet Packet : Src=" + srcMAC + ", Dest=" + destMAC + ", Type=" + aEtherType; + } + } +} diff --git a/source2/Kernel/System/Cosmos.System/Network/IPv4/ARPPacket_Ethernet.cs b/source2/Kernel/System/Cosmos.System/Network/IPv4/ARPPacket_Ethernet.cs new file mode 100644 index 000000000..d0a23df5e --- /dev/null +++ b/source2/Kernel/System/Cosmos.System/Network/IPv4/ARPPacket_Ethernet.cs @@ -0,0 +1,99 @@ +using System; +using Cosmos.Core.Network; +using Cosmos.System.Network.ARP; + +namespace Cosmos.System.Network.IPv4 +{ + internal abstract class ARPPacket_Ethernet : ARPPacket + { + protected MACAddress mSenderMAC; + protected MACAddress mTargetMAC; + protected Address mSenderIP; + protected Address mTargetIP; + + internal ARPPacket_Ethernet(byte[] rawData) + : base(rawData) + { } + + protected override void initFields() + { + base.initFields(); + mSenderMAC = new MACAddress(mRawData, 22); + mSenderIP = new Address(mRawData, 28); + mTargetMAC = new MACAddress(mRawData, 32); + mTargetIP = new Address(mRawData, 38); + } + + protected ARPPacket_Ethernet(UInt16 operation, MACAddress senderMAC, Address senderIP, + MACAddress targetMAC, Address targetIP, int packet_size) + : base(targetMAC, senderMAC, 1, 0x0800, 6, 4, operation, packet_size) + { + for (int i = 0; i < 6; i++) + { + mRawData[22 + i] = senderMAC.bytes[i]; + mRawData[32 + i] = targetMAC.bytes[i]; + } + for (int i = 0; i < 4; i++) + { + mRawData[28 + i] = senderIP.address[i]; + mRawData[38 + i] = targetIP.address[i]; + } + + initFields(); + } + + internal MACAddress SenderMAC + { + get { return this.mSenderMAC; } + } + internal MACAddress TargetMAC + { + get { return this.mTargetMAC; } + } + internal Address SenderIP + { + get { return this.mSenderIP; } + } + internal Address TargetIP + { + get { return this.mTargetIP; } + } + + public override string ToString() + { + return "IPv4 Ethernet ARP Packet SenderMAC=" + mSenderMAC + ", TargetMAC=" + mTargetMAC + ", SenderIP=" + mSenderIP + + ", TargetIP=" + mTargetIP + ", Operation=" + aOperation; + } + } + + internal class ARPReply_Ethernet : ARPPacket_Ethernet + { + internal ARPReply_Ethernet(byte[] rawData) + : base(rawData) + { } + + internal ARPReply_Ethernet(MACAddress ourMAC, Address ourIP, MACAddress targetMAC, Address targetIP) + : base(2, ourMAC, ourIP, targetMAC, targetIP, 42) + { } + + public override string ToString() + { + return "ARP Reply Src=" + srcMAC + ", Dest=" + destMAC + ", Sender=" + mSenderIP + ", Target=" + mTargetIP; + } + } + internal class ARPRequest_Ethernet : ARPPacket_Ethernet + { + internal ARPRequest_Ethernet(byte[] rawData) + : base(rawData) + { } + + internal ARPRequest_Ethernet(MACAddress ourMAC, Address ourIP, MACAddress targetMAC, Address targetIP) + : base(1, ourMAC, ourIP, targetMAC, targetIP, 42) + { } + + public override string ToString() + { + return "ARP Request Src=" + srcMAC + ", Dest=" + destMAC + ", Sender=" + mSenderIP + ", Target=" + mTargetIP; + } + } +} diff --git a/source2/Kernel/System/Cosmos.System/Network/IPv4/Address.cs b/source2/Kernel/System/Cosmos.System/Network/IPv4/Address.cs new file mode 100644 index 000000000..e3418878e --- /dev/null +++ b/source2/Kernel/System/Cosmos.System/Network/IPv4/Address.cs @@ -0,0 +1,151 @@ +using System; + +namespace Cosmos.System.Network.IPv4 +{ + /// + /// Defines a IPv4 Address + /// Should actually be using System.Net.IPAddress, but gives problems + /// + public class Address : IComparable + { + /// + /// Predefined 0.0.0.0 address + /// + public static Address Zero = new Address(0, 0, 0, 0); + + internal byte[] address = new byte[4]; + + public Address(byte aFirst, byte aSecond, byte aThird, byte aFourth) + { + address[0] = aFirst; + address[1] = aSecond; + address[2] = aThird; + address[3] = aFourth; + } + + public Address(byte[] buffer, int offset) + { + if (buffer == null || buffer.Length < (offset + 4)) + throw new ArgumentException("buffer does not contain enough data starting at offset", "buffer"); + + address[0] = buffer[offset]; + address[1] = buffer[offset + 1]; + address[2] = buffer[offset + 2]; + address[3] = buffer[offset + 3]; + } + + /// + /// Parse a IP Address in string representation + /// + /// IP Address as string + /// + public static Address Parse(string adr) + { + string[] fragments = adr.Split('.'); + if (fragments.Length == 4) + { + byte first = byte.Parse(fragments[0]); + byte second = byte.Parse(fragments[1]); + byte third = byte.Parse(fragments[2]); + byte fourth = byte.Parse(fragments[3]); + + return new Address(first, second, third, fourth); + } + else + { + return null; + } + } + + public bool IsLoopbackAddress() + { + if (address[0] == 127) + return true; + else + return false; + } + + public bool IsBroadcastAddress() + { + if (address[0] == 255) + { + return true; + } + + return false; + } + + /// + /// Converts IP Address to String + /// + /// String with IP Address in dotted notation + public override string ToString() + { + return + address[0] + + "." + + address[1] + + "." + + address[2] + + "." + + address[3]; + } + + public byte[] ToByteArray() + { + return address; + } + + private UInt32 to32BitNumber() + { + return (UInt32)((address[0] << 24) | (address[1] << 16) | (address[2] << 8) | (address[3] << 0)); + } + + private UInt32 hash; + /// + /// Hash value for this IP. Used to uniquely identify each IP + /// + public UInt32 Hash + { + get + { + if (hash == 0) + { + hash = to32BitNumber(); + } + + return hash; + } + } + + #region IComparable Members + + /// + /// Compare 2 IP Address objects for equality + /// + /// + /// 0 if equal, or non-zero otherwise + public int CompareTo(object obj) + { + if (obj is Address) + { + Address other = (Address)obj; + int i = 0; + i = address[0].CompareTo(other.address[0]); + if (i != 0) return i; + i = address[1].CompareTo(other.address[1]); + if (i != 0) return i; + i = address[2].CompareTo(other.address[2]); + if (i != 0) return i; + i = address[3].CompareTo(other.address[3]); + if (i != 0) return i; + + return 0; + } + else + throw new ArgumentException("obj is not a IPv4Address", "obj"); + } + + #endregion + } +} diff --git a/source2/Kernel/System/Cosmos.System/Network/IPv4/Config.cs b/source2/Kernel/System/Cosmos.System/Network/IPv4/Config.cs new file mode 100644 index 000000000..c4ce91c83 --- /dev/null +++ b/source2/Kernel/System/Cosmos.System/Network/IPv4/Config.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using Cosmos.Hardware; +using System; + +namespace Cosmos.System.Network.IPv4 +{ + /// + /// Contains a IPv4 configuration + /// + public class Config + { + internal static List ipConfigs; + + static Config() + { + ipConfigs = new List(); + } + + internal static void Add(Config config) + { + ipConfigs.Add(config); + } + + internal static Address FindNetwork(Address destIP) + { + Address default_gw = null; + + for (int c = 0; c < ipConfigs.Count; c++) + { + if ((ipConfigs[c].IPAddress.Hash & ipConfigs[c].SubnetMask.Hash) == + (destIP.Hash & ipConfigs[c].SubnetMask.Hash)) + { + return ipConfigs[c].IPAddress; + } + if ((default_gw == null) && (ipConfigs[c].DefaultGateway.CompareTo(Address.Zero) != 0)) + { + default_gw = ipConfigs[c].IPAddress; + } + } + + return default_gw; + } + + internal static bool IsLocalAddress(Address destIP) + { + for (int c = 0; c < ipConfigs.Count; c++) + { + if ((ipConfigs[c].IPAddress.Hash & ipConfigs[c].SubnetMask.Hash) == + (destIP.Hash & ipConfigs[c].SubnetMask.Hash)) + { + return true; + } + } + + return false; + } + + internal static NetworkDevice FindInterface(Address sourceIP) + { + return NetworkStack.AddressMap[sourceIP.Hash]; + } + + internal static Address FindRoute(Address destIP) + { + for (int c = 0; c < ipConfigs.Count; c++) + { + if (ipConfigs[c].DefaultGateway.CompareTo(Address.Zero) != 0) + { + return ipConfigs[c].DefaultGateway; + } + } + + return null; + } + + protected Address address; + protected Address defaultGateway; + protected Address subnetMask; + + /// + /// Create a IPv4 Configuration with no default gateway + /// + /// IP Address + /// Subnet Mask + public Config(Address ip, Address subnet) + : this(ip, subnet, Address.Zero) + { } + + /// + /// Create a IPv4 Configuration + /// + /// IP Address + /// Subnet Mask + /// Default gateway + public Config(Address ip, Address subnet, Address gw) + { + this.address = ip; + this.subnetMask = subnet; + this.defaultGateway = gw; + } + + public Address IPAddress + { + get { return this.address; } + } + public Address SubnetMask + { + get { return this.subnetMask; } + } + public Address DefaultGateway + { + get { return this.defaultGateway; } + } + } +} diff --git a/source2/Kernel/System/Cosmos.System/Network/IPv4/ICMPPacket.cs b/source2/Kernel/System/Cosmos.System/Network/IPv4/ICMPPacket.cs new file mode 100644 index 000000000..24c9e1372 --- /dev/null +++ b/source2/Kernel/System/Cosmos.System/Network/IPv4/ICMPPacket.cs @@ -0,0 +1,224 @@ +using System; +using Sys = System; + +namespace Cosmos.System.Network.IPv4 +{ + internal class ICMPPacket : IPPacket + { + protected byte icmpType; + protected byte icmpCode; + protected UInt16 icmpCRC; + + internal static void ICMPHandler(byte[] packetData) + { + ICMPPacket icmp_packet = new ICMPPacket(packetData); + icmp_packet.initICMPFields(); + //Sys.Console.WriteLine("Received " + icmp_packet.ToString()); + switch (icmp_packet.ICMP_Type) + { + case 0: + ICMPEchoReply recvd_reply = new ICMPEchoReply(packetData); + recvd_reply.initICMPEchoFields(); + Sys.Console.WriteLine("Received ICMP Echo reply from " + recvd_reply.SourceIP.ToString()); + break; + case 8: + ICMPEchoRequest request = new ICMPEchoRequest(packetData); + request.initICMPEchoFields(); + Sys.Console.WriteLine("Received " + request.ToString()); + ICMPEchoReply reply = new ICMPEchoReply(request); + Sys.Console.WriteLine("Sending ICMP Echo reply to " + reply.DestinationIP.ToString()); + OutgoingBuffer.AddPacket(reply); + break; + } + } + + public ICMPPacket(byte[] rawData) + : base(rawData) + { + } + + protected override void initFields() + { + Sys.Console.WriteLine("ICMPPacket.initFields() called;"); + base.initFields(); + icmpType = mRawData[this.dataOffset]; + icmpCode = mRawData[this.dataOffset + 1]; + icmpCRC = (UInt16)((mRawData[this.dataOffset + 2] << 8) | mRawData[this.dataOffset + 3]); + } + + // TODO: Temporary until we have a fix for the VMT Scan issue + internal void initICMPFields() + { + icmpType = mRawData[this.dataOffset]; + icmpCode = mRawData[this.dataOffset + 1]; + icmpCRC = (UInt16)((mRawData[this.dataOffset + 2] << 8) | mRawData[this.dataOffset + 3]); + } + + internal ICMPPacket(Address source, Address dest, byte type, byte code, UInt16 id, UInt16 seq, UInt16 icmpDataSize) + : base(icmpDataSize, 1, source, dest) + { + mRawData[this.dataOffset] = type; + mRawData[this.dataOffset + 1] = code; + mRawData[this.dataOffset + 2] = 0x00; + mRawData[this.dataOffset + 3] = 0x00; + mRawData[this.dataOffset + 4] = (byte)((id >> 8) & 0xFF); + mRawData[this.dataOffset + 5] = (byte)((id >> 0) & 0xFF); + mRawData[this.dataOffset + 6] = (byte)((seq >> 8) & 0xFF); + mRawData[this.dataOffset + 7] = (byte)((seq >> 0) & 0xFF); + + icmpCRC = CalcICMPCRC((UInt16)(icmpDataSize + 8)); + mRawData[this.dataOffset + 2] = (byte)((icmpCRC >> 8) & 0xFF); + mRawData[this.dataOffset + 3] = (byte)((icmpCRC >> 0) & 0xFF); + initFields(); + } + + protected UInt16 CalcICMPCRC(UInt16 length) + { + return CalcOcCRC(this.dataOffset, length); + } + + internal byte ICMP_Type + { + get { return this.icmpType; } + } + internal byte ICMP_Code + { + get { return this.icmpCode; } + } + internal UInt16 ICMP_CRC + { + get { return this.icmpCRC; } + } + internal UInt16 ICMP_DataLength + { + get { return (UInt16)(this.DataLength - 8); } + } + + internal byte[] GetICMPData() + { + byte[] data = new byte[ICMP_DataLength]; + + for (int b = 0; b < ICMP_DataLength; b++) + { + data[b] = mRawData[this.dataOffset + 8 + b]; + } + + return data; + } + + public override string ToString() + { + return "ICMP Packet Src=" + sourceIP + ", Dest=" + destIP + ", Type=" + icmpType + ", Code=" + icmpCode; + } + } + + internal class ICMPEchoRequest : ICMPPacket + { + protected UInt16 icmpID; + protected UInt16 icmpSequence; + + internal ICMPEchoRequest(byte[] rawData) + : base(rawData) + { + } + + internal ICMPEchoRequest(Address source, Address dest, UInt16 id, UInt16 sequence) + : base(source, dest, 8, 0, id, sequence, 40) + { + for (byte b = 8; b < this.ICMP_DataLength; b++) + { + mRawData[this.dataOffset + b] = b; + } + + mRawData[this.dataOffset + 2] = 0x00; + mRawData[this.dataOffset + 3] = 0x00; + icmpCRC = CalcICMPCRC((UInt16)(this.ICMP_DataLength + 8)); + mRawData[this.dataOffset + 2] = (byte)((icmpCRC >> 8) & 0xFF); + mRawData[this.dataOffset + 3] = (byte)((icmpCRC >> 0) & 0xFF); + } + + protected override void initFields() + { + base.initFields(); + icmpID = (UInt16)((mRawData[this.dataOffset + 4] << 8) | mRawData[this.dataOffset + 5]); + icmpSequence = (UInt16)((mRawData[this.dataOffset + 6] << 8) | mRawData[this.dataOffset + 7]); + } + + // TODO: Temporary until we have a fix for the VMT Scan issue + internal void initICMPEchoFields() + { + base.initICMPFields(); + icmpID = (UInt16)((mRawData[this.dataOffset + 4] << 8) | mRawData[this.dataOffset + 5]); + icmpSequence = (UInt16)((mRawData[this.dataOffset + 6] << 8) | mRawData[this.dataOffset + 7]); + } + + internal UInt16 ICMP_ID + { + get { return this.icmpID; } + } + internal UInt16 ICMP_Sequence + { + get { return this.icmpSequence; } + } + + public override string ToString() + { + return "ICMP Echo Request Src=" + sourceIP + ", Dest=" + destIP + ", ID=" + icmpID + ", Sequence=" + icmpSequence; + } + } + internal class ICMPEchoReply : ICMPPacket + { + protected UInt16 icmpID; + protected UInt16 icmpSequence; + + internal ICMPEchoReply(byte[] rawData) + : base(rawData) + { + } + + protected override void initFields() + { + base.initFields(); + icmpID = (UInt16)((mRawData[this.dataOffset + 4] << 8) | mRawData[this.dataOffset + 5]); + icmpSequence = (UInt16)((mRawData[this.dataOffset + 6] << 8) | mRawData[this.dataOffset + 7]); + } + + // TODO: Temporary until we have a fix for the VMT Scan issue + internal void initICMPEchoFields() + { + base.initICMPFields(); + icmpID = (UInt16)((mRawData[this.dataOffset + 4] << 8) | mRawData[this.dataOffset + 5]); + icmpSequence = (UInt16)((mRawData[this.dataOffset + 6] << 8) | mRawData[this.dataOffset + 7]); + } + + internal ICMPEchoReply(ICMPEchoRequest request) + : base(request.DestinationIP, request.SourceIP, 0, 0, + request.ICMP_ID, request.ICMP_Sequence, (UInt16)(request.ICMP_DataLength + 8)) + { + for (int b = 0; b < this.ICMP_DataLength; b++) + { + mRawData[this.dataOffset + 8 + b] = request.RawData[this.dataOffset + 8 + b]; + } + + mRawData[this.dataOffset + 2] = 0x00; + mRawData[this.dataOffset + 3] = 0x00; + icmpCRC = CalcICMPCRC((UInt16)(this.ICMP_DataLength + 8)); + mRawData[this.dataOffset + 2] = (byte)((icmpCRC >> 8) & 0xFF); + mRawData[this.dataOffset + 3] = (byte)((icmpCRC >> 0) & 0xFF); + } + + internal UInt16 ICMP_ID + { + get { return this.icmpID; } + } + internal UInt16 ICMP_Sequence + { + get { return this.icmpSequence; } + } + + public override string ToString() + { + return "ICMP Echo Reply Src=" + sourceIP + ", Dest=" + destIP + ", ID=" + icmpID + ", Sequence=" + icmpSequence; + } + } +} diff --git a/source2/Kernel/System/Cosmos.System/Network/IPv4/IPPacket.cs b/source2/Kernel/System/Cosmos.System/Network/IPv4/IPPacket.cs new file mode 100644 index 000000000..8c4312243 --- /dev/null +++ b/source2/Kernel/System/Cosmos.System/Network/IPv4/IPPacket.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Cosmos.Core.Network; +using Cosmos.System.Network.ARP; + +namespace Cosmos.System.Network.IPv4 +{ + internal class IPPacket : EthernetPacket + { + protected byte ipVersion; + protected byte ipHeaderLength; + protected byte tos; + protected UInt16 ipLength; + protected UInt16 fragmentID; + protected UInt16 fragmentOffset; + protected byte flags; + protected byte ttl; + protected byte proto; + protected UInt16 ipCRC; + protected Address sourceIP; + protected Address destIP; + protected UInt16 dataOffset; + + private static UInt16 sNextFragmentID; + + internal static void IPv4Handler(byte[] packetData) + { + IPPacket ip_packet = new IPPacket(packetData); + //Sys.Console.WriteLine("Received IP Packet"); + //Sys.Console.WriteLine(ip_packet.ToString()); + ARPCache.Update(ip_packet.SourceIP, ip_packet.SourceMAC); + + if ((NetworkStack.AddressMap.ContainsKey(ip_packet.DestinationIP.Hash) == true) || + (ip_packet.DestinationIP.address[3] == 255)) + { + switch (ip_packet.Protocol) + { + case 1: + ICMPPacket.ICMPHandler(packetData); + break; + //case 6: + // IPv4_TCPHandler(packetData); + // break; + //case 17: + // IPv4_UDPHandler(packetData); + // break; + } + } + } + + public static UInt16 NextIPFragmentID + { + get + { + return sNextFragmentID++; + } + } + + internal IPPacket(byte[] rawData) + : base(rawData) + { } + + protected override void initFields() + { + base.initFields(); + ipVersion = (byte)((mRawData[14] & 0xF0) >> 4); + ipHeaderLength = (byte)(mRawData[14] & 0x0F); + tos = mRawData[15]; + ipLength = (UInt16)((mRawData[16] << 8) | mRawData[17]); + fragmentID = (UInt16)((mRawData[18] << 8) | mRawData[19]); + flags = (byte)((mRawData[20] & 0xE0) >> 5); + fragmentOffset = (UInt16)(((mRawData[20] & 0x1F) << 8) | mRawData[21]); + ttl = mRawData[22]; + proto = mRawData[23]; + ipCRC = (UInt16)((mRawData[24] << 8) | mRawData[25]); + sourceIP = new Address(mRawData, 26); + destIP = new Address(mRawData, 30); + dataOffset = (UInt16)(14 + HeaderLength); + } + + protected IPPacket(UInt16 dataLength, byte protocol, Address source, Address dest) + : this(MACAddress.None, MACAddress.None, dataLength, protocol, source, dest) + { } + + private IPPacket(MACAddress srcMAC, MACAddress destMAC, UInt16 dataLength, byte protocol, + Address source, Address dest) + : base(destMAC, srcMAC, 0x0800, dataLength + 14 + 20) + { + mRawData[14] = 0x45; + mRawData[15] = 0; + ipLength = (UInt16)(dataLength + 20); + ipHeaderLength = 5; + mRawData[16] = (byte)((ipLength >> 8) & 0xFF); + mRawData[17] = (byte)((ipLength >> 0) & 0xFF); + fragmentID = NextIPFragmentID; + mRawData[18] = (byte)((fragmentID >> 8) & 0xFF); + mRawData[19] = (byte)((fragmentID >> 0) & 0xFF); + mRawData[20] = 0x00; + mRawData[21] = 0x00; + mRawData[22] = 0x80; + mRawData[23] = protocol; + mRawData[24] = 0x00; + mRawData[25] = 0x00; + for (int b = 0; b < 4; b++) + { + mRawData[26 + b] = source.address[b]; + mRawData[30 + b] = dest.address[b]; + } + ipCRC = CalcIPCRC(20); + mRawData[24] = (byte)((ipCRC >> 8) & 0xFF); + mRawData[25] = (byte)((ipCRC >> 0) & 0xFF); + + initFields(); + } + + protected UInt16 CalcOcCRC(UInt16 offset, UInt16 length) + { + return IPPacket.CalcOcCRC(this.RawData, offset, length); + } + + protected static UInt16 CalcOcCRC(byte[] buffer, UInt16 offset, int length) + { + UInt32 crc = 0; + + for (UInt16 w = offset; w < offset + length; w += 2) + { + crc += (UInt16)((buffer[w] << 8) | buffer[w + 1]); + } + + crc = (~((crc & 0xFFFF) + (crc >> 16))); + + return (UInt16)crc; + } + + protected UInt16 CalcIPCRC(UInt16 headerLength) + { + return CalcOcCRC(14, headerLength); + } + + internal byte IPVersion + { + get { return this.ipVersion; } + } + internal UInt16 HeaderLength + { + get { return (UInt16)(this.ipHeaderLength * 4); } + } + internal byte TypeOfService + { + get { return this.tos; } + } + internal UInt16 IPLength + { + get { return this.ipLength; } + } + internal UInt16 FragmentID + { + get { return this.fragmentID; } + } + internal UInt16 FragmentOffset + { + get { return this.fragmentOffset; } + } + internal byte Flags + { + get { return this.flags; } + } + internal byte TTL + { + get { return this.ttl; } + } + internal byte Protocol + { + get { return this.proto; } + } + internal UInt16 IPCRC + { + get { return this.ipCRC; } + } + internal Address SourceIP + { + get { return this.sourceIP; } + } + internal Address DestinationIP + { + get { return this.destIP; } + } + internal UInt16 DataLength + { + get { return (UInt16)(this.ipLength - this.HeaderLength); } + } + + public override string ToString() + { + return "IP Packet Src=" + sourceIP + ", Dest=" + destIP + ", Protocol=" + proto + ", TTL=" + ttl + ", DataLen=" + DataLength; + } + } +} diff --git a/source2/Kernel/System/Cosmos.System/Network/IPv4/OutgoingBuffer.cs b/source2/Kernel/System/Cosmos.System/Network/IPv4/OutgoingBuffer.cs new file mode 100644 index 000000000..cd444cf4a --- /dev/null +++ b/source2/Kernel/System/Cosmos.System/Network/IPv4/OutgoingBuffer.cs @@ -0,0 +1,156 @@ +using System.Collections.Generic; +using Cosmos.Core.Network; +using Cosmos.Hardware; +using Cosmos.System.Network.ARP; + +namespace Cosmos.System.Network.IPv4 +{ + internal static class OutgoingBuffer + { + private class BufferEntry + { + public enum EntryStatus { ADDED, ARP_SENT, ROUTE_ARP_SENT, JUST_SEND, DONE }; + + public NetworkDevice NIC; + public IPPacket Packet; + public EntryStatus Status; + public Address nextHop; + + public BufferEntry(NetworkDevice nic, IPPacket packet) + { + this.NIC = nic; + this.Packet = packet; + this.Status = EntryStatus.ADDED; + } + } + + private static List queue; + + private static void ensureQueueExists() + { + if (queue == null) + { + queue = new List(); + } + } + + internal static void AddPacket(IPPacket packet) + { + ensureQueueExists(); + NetworkDevice nic = Config.FindInterface(packet.SourceIP); + packet.SourceMAC = nic.MACAddress; + queue.Add(new BufferEntry(nic, packet)); + } + + internal static void Send() + { + ensureQueueExists(); + if (queue.Count < 1) + { + return; + } + + //foreach (BufferEntry entry in queue) + for (int e = 0; e < queue.Count; e++) + { + BufferEntry entry = queue[e]; + if (entry.Status == BufferEntry.EntryStatus.ADDED) + { + if (Config.IsLocalAddress(entry.Packet.DestinationIP) == false) + { + entry.nextHop = Config.FindRoute(entry.Packet.DestinationIP); + if (entry.nextHop == null) + { + entry.Status = BufferEntry.EntryStatus.DONE; + continue; + } + + if (ARPCache.Contains(entry.nextHop) == true) + { + entry.Packet.DestinationMAC = ARPCache.Resolve(entry.nextHop); + + entry.NIC.QueueBytes(entry.Packet.RawData); + + entry.Status = BufferEntry.EntryStatus.DONE; + } + else + { + ARPRequest_Ethernet arp_request = new ARPRequest_Ethernet(entry.NIC.MACAddress, entry.Packet.SourceIP, + MACAddress.Broadcast, entry.nextHop); + + entry.NIC.QueueBytes(arp_request.RawData); + + entry.Status = BufferEntry.EntryStatus.ROUTE_ARP_SENT; + } + continue; + } + + if (ARPCache.Contains(entry.Packet.DestinationIP) == true) + { + entry.Packet.DestinationMAC = ARPCache.Resolve(entry.Packet.DestinationIP); + + entry.NIC.QueueBytes(entry.Packet.RawData); + + entry.Status = BufferEntry.EntryStatus.DONE; + } + else + { + ARPRequest_Ethernet arp_request = new ARPRequest_Ethernet(entry.NIC.MACAddress, entry.Packet.SourceIP, + MACAddress.Broadcast, entry.Packet.DestinationIP); + + entry.NIC.QueueBytes(arp_request.RawData); + + entry.Status = BufferEntry.EntryStatus.ARP_SENT; + } + } + else if (entry.Status == BufferEntry.EntryStatus.JUST_SEND) + { + entry.NIC.QueueBytes(entry.Packet.RawData); + + entry.Status = BufferEntry.EntryStatus.DONE; + } + } + + int i = 0; + while (i < queue.Count) + { + if (queue[i].Status == BufferEntry.EntryStatus.DONE) + { + queue.RemoveAt(i); + } + else + { + i++; + } + } + } + + internal static void ARPCache_Update(ARPReply_Ethernet arp_reply) + { + ensureQueueExists(); + //foreach (BufferEntry entry in queue) + for (int e = 0; e < queue.Count; e++) + { + BufferEntry entry = queue[e]; + if (entry.Status == BufferEntry.EntryStatus.ARP_SENT) + { + if (entry.Packet.DestinationIP.CompareTo(arp_reply.SenderIP) == 0) + { + entry.Packet.DestinationMAC = arp_reply.SenderMAC; + + entry.Status = BufferEntry.EntryStatus.JUST_SEND; + } + } + else if (entry.Status == BufferEntry.EntryStatus.ROUTE_ARP_SENT) + { + if (entry.nextHop.CompareTo(arp_reply.SenderIP) == 0) + { + entry.Packet.DestinationMAC = arp_reply.SenderMAC; + + entry.Status = BufferEntry.EntryStatus.JUST_SEND; + } + } + } + } + } +} diff --git a/source2/Kernel/System/Cosmos.System/Network/NetworkStack.cs b/source2/Kernel/System/Cosmos.System/Network/NetworkStack.cs new file mode 100644 index 000000000..bc7c7801c --- /dev/null +++ b/source2/Kernel/System/Cosmos.System/Network/NetworkStack.cs @@ -0,0 +1,64 @@ +using System; +using Sys = System; +using System.Collections.Generic; +using Cosmos.Hardware; +using Cosmos.System.Network.ARP; + +namespace Cosmos.System.Network +{ + /// + /// Implement a Network Stack for all network devices and protocols + /// + public static class NetworkStack + { + internal static TempDictionary AddressMap { get; private set; } + + /// + /// Initialize the Network Stack to prepare it for operation + /// + internal static void Init() + { + AddressMap = new TempDictionary(); + } + + /// + /// Configure a IP configuration on the given network device. + /// Multiple IP Configurations can be made, like *nix environments + /// + /// that will have the assigned configuration + /// instance that defines the IP Address, Subnet + /// Mask and Default Gateway for the device + public static void ConfigIP(NetworkDevice nic, IPv4.Config config) + { + AddressMap.Add(config.IPAddress.Hash, nic); + IPv4.Config.Add(config); + nic.DataReceived = HandlePacket; + } + + internal static void HandlePacket(byte[] packetData) + { + //Sys.Console.Write("Received Packet Length="); + //Sys.Console.WriteLine(packetData.Length); + //Sys.Console.WriteLine(BitConverter.ToString(packetData)); + + UInt16 etherType = (UInt16)((packetData[12] << 8) | packetData[13]); + switch (etherType) + { + case 0x0806: + ARPPacket.ARPHandler(packetData); + break; + case 0x0800: + IPv4.IPPacket.IPv4Handler(packetData); + break; + } + } + + /// + /// Called continously to keep the Network Stack going. + /// + internal static void Update() + { + IPv4.OutgoingBuffer.Send(); + } + } +} diff --git a/source2/Users/SSchocke/SSchockeTest/TempDictionary.cs b/source2/Kernel/System/Cosmos.System/Network/TempDictionary.cs similarity index 92% rename from source2/Users/SSchocke/SSchockeTest/TempDictionary.cs rename to source2/Kernel/System/Cosmos.System/Network/TempDictionary.cs index 56b8eee7c..d675b6e35 100644 --- a/source2/Users/SSchocke/SSchockeTest/TempDictionary.cs +++ b/source2/Kernel/System/Cosmos.System/Network/TempDictionary.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace SSchockeTest +namespace Cosmos.System.Network { - public class TempDictionary + internal class TempDictionary { private List mKeys; private List mValues; diff --git a/source2/Kernel/System/Hardware/Core/Cosmos.Core/Cosmos.Core.csproj b/source2/Kernel/System/Hardware/Core/Cosmos.Core/Cosmos.Core.csproj index b98368278..f4e67a0fc 100644 --- a/source2/Kernel/System/Hardware/Core/Cosmos.Core/Cosmos.Core.csproj +++ b/source2/Kernel/System/Hardware/Core/Cosmos.Core/Cosmos.Core.csproj @@ -75,6 +75,8 @@ + + diff --git a/source2/Users/SSchocke/SSchockeTest/ManagedMemoryBlock.cs b/source2/Kernel/System/Hardware/Core/Cosmos.Core/ManagedMemoryBlock.cs similarity index 93% rename from source2/Users/SSchocke/SSchockeTest/ManagedMemoryBlock.cs rename to source2/Kernel/System/Hardware/Core/Cosmos.Core/ManagedMemoryBlock.cs index 57cde4459..467e9ee32 100644 --- a/source2/Users/SSchocke/SSchockeTest/ManagedMemoryBlock.cs +++ b/source2/Kernel/System/Hardware/Core/Cosmos.Core/ManagedMemoryBlock.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Cosmos.Core; -namespace SSchockeTest +namespace Cosmos.Core { public unsafe class ManagedMemoryBlock { diff --git a/source2/Users/SSchocke/SSchockeTest/MACAddress.cs b/source2/Kernel/System/Hardware/Core/Cosmos.Core/Network/MACAddress.cs similarity index 95% rename from source2/Users/SSchocke/SSchockeTest/MACAddress.cs rename to source2/Kernel/System/Hardware/Core/Cosmos.Core/Network/MACAddress.cs index a73853456..724c6f362 100644 --- a/source2/Users/SSchocke/SSchockeTest/MACAddress.cs +++ b/source2/Kernel/System/Hardware/Core/Cosmos.Core/Network/MACAddress.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace SSchockeTest +namespace Cosmos.Core.Network { public class MACAddress : IComparable { diff --git a/source2/Kernel/System/Hardware/Cosmos.Hardware/Cosmos.Hardware.csproj b/source2/Kernel/System/Hardware/Cosmos.Hardware/Cosmos.Hardware.csproj index fe4cf201b..53eee5286 100644 --- a/source2/Kernel/System/Hardware/Cosmos.Hardware/Cosmos.Hardware.csproj +++ b/source2/Kernel/System/Hardware/Cosmos.Hardware/Cosmos.Hardware.csproj @@ -75,12 +75,14 @@ + + @@ -88,6 +90,10 @@ + + {C801F19C-A9D3-42D5-9A57-9FFDF9B4D05E} + Cosmos.IL2CPU.Plugs + {1FAC100C-D732-4EA4-B518-5AF4BAF64F2E} Cosmos.Common.Extensions @@ -112,6 +118,7 @@ +