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/tcp/TcpSegment.lvt
namespace Livt.Net
/**
* Prepared fixed-header TCP segment over a borrowed payload. No options or
* connection state. Preparation reads the complete payload once to calculate
* the IPv4 pseudo-header checksum. Only variable header fields are stored here.
*/
component TcpSegment<P: IPacketData> : IPacketData, IIpv4Payload
{
// Borrowed publication and owned prepared header metadata.
payload: P
sourcePortWord: logic[16]
destinationPortWord: logic[16]
sequenceHigh: logic[16]
sequenceLow: logic[16]
ackHigh: logic[16]
ackLow: logic[16]
windowWord: logic[16]
checksumWord: logic[16]
flagsByte: byte
length: logic[16]
ready: bool
calculator: InternetChecksum
/** Binds stable payload storage; starts unprepared. */
new(payload: P)
{
this.payload = payload
this.calculator = new InternetChecksum()
}
/** Finish dependent reads/TX borrows and invalidate ancestors first. */
public fn Invalidate()
{
this.ready = false
this.length = 0
}
/**
* Arrays are network order. Use these same IP addresses for the enclosing
* IPv4 packet. Payload length may be 0..65495, so the complete IPv4 packet
* fits 65535 bytes. Failure invalidates prior metadata; read errors propagate.
* Keep the payload publication unchanged until all parent/TX borrows finish.
*/
public fn TryPrepare(sourceIp: byte[4], destinationIp: byte[4],
sourcePort: byte[2], destinationPort: byte[2], sequence: byte[4],
acknowledgment: byte[4], flags: byte, window: byte[2]) PacketDataResult
{
this.Invalidate()
if (!this.payload.IsReady()) {
return PacketDataResult.NotReady
}
var size = this.payload.GetAvailableLength()
if (size < 0 || size > 65495) {
return PacketDataResult.Invalid
}
this.calculator.Reset()
sourcePortWord = NetworkOrder.Word(sourcePort[0], sourcePort[1]) as logic[16]
destinationPortWord = NetworkOrder.Word(destinationPort[0], destinationPort[1]) as logic[16]
sequenceHigh = NetworkOrder.Word(sequence[0], sequence[1]) as logic[16]
sequenceLow = NetworkOrder.Word(sequence[2], sequence[3]) as logic[16]
ackHigh = NetworkOrder.Word(acknowledgment[0], acknowledgment[1]) as logic[16]
ackLow = NetworkOrder.Word(acknowledgment[2], acknowledgment[3]) as logic[16]
windowWord = NetworkOrder.Word(window[0], window[1]) as logic[16]
flagsByte = flags
for (var i = 0; i < size; i++) {
var value: byte = 0x00
var result = this.payload.TryRead(i, value)
if (result != PacketDataResult.Success) {
return result
}
this.calculator.AddByte(value)
}
var payloadWordSum = this.calculator.GetWordSum()
checksumWord = TcpChecksum.CalculatePayloadChecksum(sourceIp, destinationIp,
sourcePort, destinationPort, sequence, acknowledgment, flags, window,
20 + size, payloadWordSum) as logic[16]
this.length = (20 + size) as logic[16]
this.ready = true
return PacketDataResult.Success
}
/** Returns TCP's protocol identity, independent of readiness. */
override fn GetProtocol() int
{
return IIpv4Payload.PROTOCOL_TCP as int
}
/** Prepared metadata does not acquire or police external provider ownership. */
override fn IsReady() bool
{
return this.ready
}
/** Returns zero until successfully prepared. */
override fn GetAvailableLength() int
{
if (!this.ready) {
return 0
}
return (this.length as uint) as int
}
/** Header reads are cached; payload read errors propagate. Output is valid only on Success. */
override fn TryRead(index: int, value: out byte) PacketDataResult
{
value = 0x00
if (!this.ready) {
return PacketDataResult.NotReady
}
if (index < 0 || index >= ((this.length as uint) as int)) {
return PacketDataResult.Invalid
}
if (index < 20) {
value = this.TcpHeaderByte(index, sourcePortWord, destinationPortWord, sequenceHigh, sequenceLow, ackHigh, ackLow, windowWord, checksumWord, flagsByte)
return PacketDataResult.Success
}
return this.payload.TryRead(index - 20, value)
}
/** Pure byte selection; no additional scheduled transaction. */
inline fn TcpHeaderByte[](index: int, snapshotsourcePortWord: logic[16], snapshotdestinationPortWord: logic[16], snapshotsequenceHigh: logic[16], snapshotsequenceLow: logic[16], snapshotackHigh: logic[16], snapshotackLow: logic[16], snapshotwindowWord: logic[16], snapshotchecksumWord: logic[16], snapshotflagsByte: byte) byte
{
if (index == 0) { return (snapshotsourcePortWord >> 8) as byte }
if (index == 1) { return snapshotsourcePortWord as byte }
if (index == 2) { return (snapshotdestinationPortWord >> 8) as byte }
if (index == 3) { return snapshotdestinationPortWord as byte }
if (index == 4) { return (snapshotsequenceHigh >> 8) as byte }
if (index == 5) { return snapshotsequenceHigh as byte }
if (index == 6) { return (snapshotsequenceLow >> 8) as byte }
if (index == 7) { return snapshotsequenceLow as byte }
if (index == 8) { return (snapshotackHigh >> 8) as byte }
if (index == 9) { return snapshotackHigh as byte }
if (index == 10) { return (snapshotackLow >> 8) as byte }
if (index == 11) { return snapshotackLow as byte }
if (index == 12) { return 0x50 }
if (index == 13) { return snapshotflagsByte }
if (index == 14) { return (snapshotwindowWord >> 8) as byte }
if (index == 15) { return snapshotwindowWord as byte }
if (index == 16) { return (snapshotchecksumWord >> 8) as byte }
if (index == 17) { return snapshotchecksumWord as byte }
return 0x00
}
}