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/ipv4/Ipv4Packet.lvt
namespace Livt.Net
/**
* Fixed 20-byte IPv4 header, DF, TTL=64, with a typed protocol payload.
* Prepare the child first and keep it unchanged until emission finishes.
* Only variable header fields are stored; payload reads delegate to the child.
*/
component Ipv4Packet<P: IPacketData & IIpv4Payload> : IPacketData, IEthernetPayload
{
// Borrowed prepared payload; must remain stable until emission finishes.
payload: P
// Owned network-order words; constants are selected during emission.
length: logic[16]
identificationWord: logic[16]
protocolByte: byte
checksumWord: logic[16]
sourceHigh: logic[16]
sourceLow: logic[16]
destinationHigh: logic[16]
destinationLow: logic[16]
ready: bool
/**
* Borrows the fixed payload; starts unprepared and performs no payload reads.
*/
new(payload: P)
{
this.payload = payload
}
/**
* Discards prepared metadata without changing the payload. Finish all dependent
* reads and transmit borrows before invalidating.
*/
public fn Invalidate()
{
ready = false;
length = 0
}
/**
* All address and identification arrays use network byte order.
*/
public fn TryPrepare(sourceIp: byte[4], destinationIp: byte[4], identification: byte[2]) PacketDataResult
{
this.Invalidate()
if (!payload.IsReady()) {
return PacketDataResult.NotReady
}
var size = payload.GetAvailableLength()
var protocol = payload.GetProtocol()
if (size <= 0 || size > 65515 || protocol < 0 || protocol > 255) {
return PacketDataResult.Invalid
}
var totalLength = size + 20
// Validate in the public integer domain before narrowing stored fields.
length = totalLength as logic[16]
identificationWord = NetworkOrder.Word(identification[0], identification[1]) as logic[16]
protocolByte = protocol as byte
sourceHigh = NetworkOrder.Word(sourceIp[0], sourceIp[1]) as logic[16]
sourceLow = NetworkOrder.Word(sourceIp[2], sourceIp[3]) as logic[16]
destinationHigh = NetworkOrder.Word(destinationIp[0], destinationIp[1]) as logic[16]
destinationLow = NetworkOrder.Word(destinationIp[2], destinationIp[3]) as logic[16]
// Sum the fixed header words directly, without constructing/rereading bytes.
checksumWord = Ipv4HeaderChecksum.Calculate(totalLength, identification,
sourceIp, destinationIp, protocol as byte) as logic[16]
ready = true
return PacketDataResult.Success
}
/**
* Returns the Ethernet II EtherType identifying this payload, independent of readiness.
*/
override fn GetEtherType() int
{
return IEthernetPayload.ETHER_TYPE_IPV4
}
/**
* Reports prepared metadata; the owner must still keep all borrowed payloads stable.
*/
override fn IsReady() bool
{
return ready
}
/**
* Returns the prepared packet length in bytes, or zero while unprepared.
*/
override fn GetAvailableLength() int
{
if (!ready) {
return 0
}
return (length as uint) as int
}
/**
* Reads a packet-relative byte; returns NotReady while unprepared and Invalid
* outside the prepared length. Delegated payload errors propagate; the output
* is data only on Success. Keep the prepared graph stable throughout the call.
* Bytes 0..19 are the IPv4 header; remaining bytes delegate to the payload.
*/
override fn TryRead(index: int, value: out byte) PacketDataResult
{
value = 0x00
if (!ready) {
return PacketDataResult.NotReady
}
if (index < 0 || index >= ((length as uint) as int)) {
return PacketDataResult.Invalid
}
if (index < 20) {
value = this.Ipv4HeaderByte(index, length, identificationWord, protocolByte, checksumWord, sourceHigh, sourceLow, destinationHigh, destinationLow)
return PacketDataResult.Success
}
return payload.TryRead(index - 20, value)
}
/** Pure selector over the prepared snapshot. */
inline fn Ipv4HeaderByte[](index: int, snapshotlength: logic[16], snapshotidentificationWord: logic[16], snapshotprotocolByte: byte, snapshotchecksumWord: logic[16], snapshotsourceHigh: logic[16], snapshotsourceLow: logic[16], snapshotdestinationHigh: logic[16], snapshotdestinationLow: logic[16]) byte
{
if (index == 0) { return 0x45 }
elif (index == 2) { return (snapshotlength >> 8) as byte }
elif (index == 3) { return snapshotlength as byte }
elif (index == 4) { return (snapshotidentificationWord >> 8) as byte }
elif (index == 5) { return snapshotidentificationWord as byte }
elif (index == 6 || index == 8) { return 0x40 }
elif (index == 9) { return snapshotprotocolByte }
elif (index == 10) { return (snapshotchecksumWord >> 8) as byte }
elif (index == 11) { return snapshotchecksumWord as byte }
elif (index == 12) { return (snapshotsourceHigh >> 8) as byte }
elif (index == 13) { return snapshotsourceHigh as byte }
elif (index == 14) { return (snapshotsourceLow >> 8) as byte }
elif (index == 15) { return snapshotsourceLow as byte }
elif (index == 16) { return (snapshotdestinationHigh >> 8) as byte }
elif (index == 17) { return snapshotdestinationHigh as byte }
elif (index == 18) { return (snapshotdestinationLow >> 8) as byte }
elif (index == 19) { return snapshotdestinationLow as byte }
return 0x00
}
}