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/Ipv4PacketParser.lvt
namespace Livt.Net
/**
* Parses fixed, unfragmented IPv4 headers and bounds payload by total length.
* Options and fragmentation are Unsupported. Success means declared bytes are
* captured; checksum verification is a separate explicit query.
* Bind a protocol-relative provider. Invalidate children before this parser, then
* release the source. Metadata is cached only for the current parse lifetime.
*/
component Ipv4PacketParser<S: IPacketData> : IPacketData
{
public const HEADER_LENGTH: int = 20
// Owned header snapshot and payload view borrowing the constructor source.
header: PacketHeader<S, HEADER_LENGTH>
// Validation state for the current parse lifetime.
status: PacketParseResult
/**
* Binds the protocol input; construction performs no reads.
*/
new(source: S)
{
header = new PacketHeader<S, HEADER_LENGTH>(source)
}
/**
* Discards validated metadata and closes the borrowed payload view.
*/
public fn Invalidate()
{
status = PacketParseResult.NotReady
header.Invalidate()
}
/**
* Parses once and replaces prior state even on failure. Checks structure,
* not endpoint policy or transport checksums.
*/
public fn TryParse() PacketParseResult
{
status = header.TryLoad()
if (status != PacketParseResult.Success) {
return status
}
var versionAndLength = header.GetByte(0)
var version = ((versionAndLength as uint) >> 4) as int
var ihl = ((versionAndLength as uint) & (0x0F as uint)) as int
var total = header.GetWord(2)
if (version != 4) {
status = PacketParseResult.Unsupported
return status
}
if (ihl < 5 || total < (ihl << 2)) {
status = PacketParseResult.Invalid
return status
}
var fragment = header.GetWord(6)
if (ihl != 5 || (fragment != 0 && fragment != 16384)) {
status = PacketParseResult.Unsupported
return status
}
var captured = header.GetCapturedLength()
var bounded = total
if (bounded > captured) {
bounded = captured
}
status = header.TryOpenPayload(HEADER_LENGTH, bounded - HEADER_LENGTH)
if (status == PacketParseResult.Success && captured < total) {
status = PacketParseResult.HeaderOnly
}
return status
}
/**
* Returns current validation state; unavailable sources invalidate access.
*/
public fn GetStatus() PacketParseResult
{
if ((status == PacketParseResult.Success || status == PacketParseResult.HeaderOnly) && !header.IsReady()) {
return PacketParseResult.NotReady
}
return status
}
/**
* Reports available supported metadata, including partial captures.
*/
override fn IsReady() bool
{
return (status == PacketParseResult.Success || status == PacketParseResult.HeaderOnly) && header.IsReady()
}
/**
* Returns bounded captured payload bytes, not declared or wire length.
*/
override fn GetAvailableLength() int
{
if (!this.IsReady()) {
return 0
}
return header.GetAvailableLength()
}
/**
* Reads the borrowed payload relative to this protocol's header.
*/
override fn TryRead(index: int, value: out byte) PacketDataResult
{
value = 0x00
if (!this.IsReady()) {
return PacketDataResult.NotReady
}
var readValue: byte = 0x00
var result = header.TryRead(index, readValue)
value = readValue
return result
}
/**
* Returns TotalLength from the supported cached header; unavailable metadata returns 0.
*/
public fn GetTotalLength() int
{
if (!this.IsReady()) {
return 0
}
return header.GetWord(2)
}
/**
* Returns Identification from the supported cached header; unavailable metadata returns 0.
*/
public fn GetIdentification() int
{
if (!this.IsReady()) {
return 0
}
return header.GetWord(4)
}
/**
* Returns Protocol from the supported cached header; unavailable metadata returns 0.
*/
public fn GetProtocol() byte
{
if (!this.IsReady()) {
return 0
}
return header.GetByte(9)
}
/**
* Returns DeclaredPayloadLength from the supported cached header; unavailable metadata returns 0.
*/
public fn GetDeclaredPayloadLength() int
{
if (!this.IsReady()) {
return 0
}
return header.GetWord(2) - HEADER_LENGTH
}
/**
* Copies the cached SourceIpv4 value; unavailable metadata returns zero bytes.
*/
public fn GetSourceIpv4() byte[4]
{
if (!this.IsReady()) { return [0x00, 0x00, 0x00, 0x00] }
var word0 = header.GetWord(12)
var word1 = header.GetWord(14)
return [NetworkOrder.HighByte(word0), NetworkOrder.LowByte(word0), NetworkOrder.HighByte(word1), NetworkOrder.LowByte(word1)]
}
/**
* Copies the cached DestinationIpv4 value; unavailable metadata returns zero bytes.
*/
public fn GetDestinationIpv4() byte[4]
{
if (!this.IsReady()) { return [0x00, 0x00, 0x00, 0x00] }
var word0 = header.GetWord(16)
var word1 = header.GetWord(18)
return [NetworkOrder.HighByte(word0), NetworkOrder.LowByte(word0), NetworkOrder.HighByte(word1), NetworkOrder.LowByte(word1)]
}
/**
* Checks the cached IPv4 header checksum only. Parsing does not enforce it,
* preserving the endpoint's existing unchecked receive-checksum policy.
*/
public fn IsHeaderChecksumValid() bool
{
if (!this.IsReady()) {
return false
}
var sum: int = 0
for (var i = 0; i < HEADER_LENGTH; i = i + 2) {
sum = sum + header.GetWord(i)
}
sum = ChecksumArithmetic.Fold(sum)
sum = ChecksumArithmetic.Fold(sum)
return sum == 65535
}
}