using sys = System; using System.Collections.Generic; using Cosmos.Debug.Kernel; using Cosmos.HAL; using Cosmos.HAL.Network; using Cosmos.System.Network.ARP; namespace Cosmos.System.Network.IPv4 { /// /// OutgoingBuffer class. /// internal static class OutgoingBuffer { /// /// BufferEntry class. /// private class BufferEntry { /// /// Entry status. /// public enum EntryStatus { /// /// Added. /// ADDED, /// /// ARP sent. /// ARP_SENT, /// /// Route ARP sent. /// ROUTE_ARP_SENT, /// /// Just send. /// JUST_SEND, /// /// Done. /// DONE, /// /// DHCP request. /// DHCP_REQUEST }; /// /// Network Interface Controller. /// public NetworkDevice NIC; /// /// IP packet. /// public IPPacket Packet; /// /// Entry status /// public EntryStatus Status; /// /// Next hop. /// public Address nextHop; /// /// Create new inctanse of the class. /// /// Network device. /// IP packet. public BufferEntry(NetworkDevice nic, IPPacket packet) { this.NIC = nic; this.Packet = packet; if (Packet.DestinationIP.IsBroadcastAddress()) { this.Status = EntryStatus.DHCP_REQUEST; } else { this.Status = EntryStatus.ADDED; } } } /// /// Buffer queue. /// private static List queue; /// /// Ensure queue exists. /// private static void ensureQueueExists() { if (queue == null) { queue = new List(); } } /// /// Add packet. /// /// IP packet. internal static void AddPacket(IPPacket packet) { ensureQueueExists(); NetworkDevice nic = Config.FindInterface(packet.SourceIP); packet.SourceMAC = nic.MACAddress; queue.Add(new BufferEntry(nic, packet)); } /// /// Add packet. /// /// IP packet. /// Network Interface Controller. internal static void AddPacket(IPPacket packet, NetworkDevice device) { ensureQueueExists(); packet.SourceMAC = device.MACAddress; queue.Add(new BufferEntry(device, packet)); } /// /// Send packet. /// /// Thrown on fatal error (contact support). /// Thrown on memory error. /// Thrown if RawData length is bigger than Int32.MaxValue. internal static void Send() { ensureQueueExists(); int _deltaT = 0; int second = 0; while (queue.Count > 0) { if (_deltaT != Cosmos.HAL.RTC.Second) { second++; _deltaT = Cosmos.HAL.RTC.Second; } if (second >= 4) { NetworkStack.debugger.Send("No response in 4 secondes..."); break; } //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, MACAddress.None); 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, MACAddress.None); entry.NIC.QueueBytes(arp_request.RawData); entry.Status = BufferEntry.EntryStatus.ARP_SENT; } } else if (entry.Status == BufferEntry.EntryStatus.DHCP_REQUEST) { entry.NIC.QueueBytes(entry.Packet.RawData); entry.Status = BufferEntry.EntryStatus.DONE; } 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++; } } } } /// /// ARP cache update. /// /// ARP reply. /// Thrown if arp_reply.SenderIP is not a IPv4Address. 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) { var xDestIP = entry.Packet.DestinationIP.Hash; var xSenderIP = arp_reply.SenderIP.Hash; 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; } } } } } }