Livt packages

Livt.Net

Version 1.4.1

Ethernet, IPv4, TCP, UDP, ARP, TFTP, and Telnet networking components for Livt hardware.

Published files (163)

src/arp/ArpResponder.lvt

namespace Livt.Net

/**
 * Prepares an ARP reply from a bound frame provider; response addresses are snapshots.
 */
component ArpResponder<S: IPacketData> : IPacketData
{
	// Borrowed shared parsers; consumers must serialize their use.
	ethernet: EthernetFrameParser<S>
	parser: ArpPacketParser<EthernetFrameParser<S>>

	// Owned reply snapshot and its Ethernet envelope.
	reply: ArpReply
	frame: ArpReplyFrame

	/**
	 * Borrows the shared Ethernet parser and owns ARP parsing and reply composition.
	 * The supplied parser must use the same source and clock/reset domain as its owner.
	 */
	new(ethernet: EthernetFrameParser<S>)
	{
		this.ethernet = ethernet
		parser = new ArpPacketParser<EthernetFrameParser<S>>(ethernet)
		reply = new ArpReply()
		frame = new ArpReplyFrame(reply)
	}

	/**
	 * Invalidates response and input views after outstanding response borrows finish.
	 */
	public fn Invalidate()
	{
		frame.Invalidate()
		reply.Invalidate()
		parser.Invalidate()
		ethernet.Invalidate()
	}

	/**
	 * Replaces the prior response even on rejection; requires Ethernet/IPv4 ARP for the local IP.
	 */
	public fn TryPrepare(localMac: byte[6], localIp: byte[4]) PacketDataResult
	{
		this.Invalidate()
		ethernet.TryParse()
		return this.TryPrepareParsed(localMac, localIp)
	}

	/**
	 * Consumes the shared validated Ethernet view without rereading its header.
	 * Requires exclusive use of the parser; closes request views on completion.
	 */
	public fn TryPrepareParsed(localMac: byte[6], localIp: byte[4]) PacketDataResult
	{
		frame.Invalidate()
		reply.Invalidate()
		parser.Invalidate()

		if (!ethernet.IsReady() || ethernet.GetEtherType() != IEthernetPayload.ETHER_TYPE_ARP) {
			return PacketDataResult.Invalid
		}

		if (parser.TryParse() != PacketParseResult.Success) {
			return PacketDataResult.Invalid
		}

		if (parser.GetOperation() != 1) {
			return PacketDataResult.Invalid
		}

		var destination = parser.GetTargetIpv4()

		if (destination[0] != localIp[0] || destination[1] != localIp[1] || destination[2] != localIp[2] || destination[3] != localIp[3]) {
			return PacketDataResult.Invalid
		}

		var peerMac = parser.GetSenderMac()
		var peerIp = parser.GetSenderIpv4()
		parser.Invalidate()
		ethernet.Invalidate()
		var result = reply.TryPrepare(localMac, localIp, peerMac, peerIp)

		if (result != PacketDataResult.Success) {
			return result
		}

		return frame.TryPrepare(localMac, peerMac)
	}

	/**
	 * Reports prepared reply availability.
	 */
	override fn IsReady() bool
	{
		return frame.IsReady()
	}

	/**
	 * Returns the complete padded reply length.
	 */
	override fn GetAvailableLength() int
	{
		return frame.GetAvailableLength()
	}

	/**
	 * Reads a prepared reply byte; request storage is no longer needed.
	 */
	override fn TryRead(index: int, value: out byte) PacketDataResult
	{
		return frame.TryRead(index, value)
	}
}