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/udp/UdpPacketParser.lvt
namespace Livt.Net
/**
* Complete IPv4 UDP validation over a borrowed IPv4 packet (byte zero is the IP header).
* Rejects IPv4 options/fragments, truncation, bad IP checksums and invalid nonzero
* UDP checksums. UDP length must equal the declared IP payload length. A zero UDP
* checksum is accepted as omitted. No port dispatch, ARP, reassembly or IPv6.
* One serialized owner keeps source bytes published and stable through all reads;
* invalidate this parser before releasing/replacing that source.
*/
component UdpPacketParser<S: IPacketData> : IPacketData
{
// Owned metadata/checksum state; payload bytes remain in the borrowed source.
ip: Ipv4PacketParser<S>
header: PacketHeader<Ipv4PacketParser<S>, 8>
checksum: InternetChecksum
status: PacketParseResult
new(source: S)
{
this.ip = new Ipv4PacketParser<S>(source)
this.header = new PacketHeader<Ipv4PacketParser<S>, 8>(this.ip)
this.checksum = new InternetChecksum()
}
public fn Invalidate()
{
this.status = PacketParseResult.NotReady
this.header.Invalidate()
this.ip.Invalidate()
}
public fn TryParse() PacketParseResult
{
this.Invalidate()
var result = this.ip.TryParse()
if (result == PacketParseResult.HeaderOnly) { result = PacketParseResult.Truncated }
if (result != PacketParseResult.Success) { this.status = result; return result }
if (this.ip.GetProtocol() != 17) {
this.status = PacketParseResult.Unsupported
return this.status
}
if (!this.ip.IsHeaderChecksumValid()) {
this.status = PacketParseResult.Invalid
return this.status
}
result = this.header.TryLoad()
if (result != PacketParseResult.Success) { this.status = result; return result }
var length = this.header.GetWord(4)
if (length < 8 || length != this.ip.GetDeclaredPayloadLength()) {
this.status = PacketParseResult.Invalid
return this.status
}
if (this.header.GetWord(6) != 0) {
this.checksum.Reset()
var sourceIp = this.ip.GetSourceIpv4()
var destinationIp = this.ip.GetDestinationIpv4()
for (var index = 0; index < 4; index++) { this.checksum.AddByte(sourceIp[index]) }
for (var index = 0; index < 4; index++) { this.checksum.AddByte(destinationIp[index]) }
this.checksum.AddByte(0)
this.checksum.AddByte(17)
this.checksum.AddByte(NetworkOrder.HighByte(length))
this.checksum.AddByte(NetworkOrder.LowByte(length))
for (var index = 0; index < length; index++) {
var value: byte = 0
if (this.ip.TryRead(index, value) != PacketDataResult.Success) {
this.status = PacketParseResult.NotReady
return this.status
}
this.checksum.AddByte(value)
}
if (this.checksum.GetChecksum() != 0) {
this.status = PacketParseResult.Invalid
return this.status
}
}
this.status = this.header.TryOpenPayload(8, length - 8)
return this.status
}
public fn GetStatus() PacketParseResult
{
if (this.status == PacketParseResult.Success && !this.header.IsReady()) {
return PacketParseResult.NotReady
}
return this.status
}
override fn IsReady() bool { return this.GetStatus() == PacketParseResult.Success }
override fn GetAvailableLength() int
{
if (!this.IsReady()) { return 0 }
return this.header.GetAvailableLength()
}
override fn TryRead(index: int, value: out byte) PacketDataResult
{
value = 0
if (!this.IsReady()) { return PacketDataResult.NotReady }
return this.header.TryRead(index, value)
}
public fn GetSourcePort() int
{
if (!this.IsReady()) { return 0 }
return this.header.GetWord(0)
}
public fn GetDestinationPort() int
{
if (!this.IsReady()) { return 0 }
return this.header.GetWord(2)
}
public fn HasChecksum() bool
{
return this.IsReady() && this.header.GetWord(6) != 0
}
}