diff --git a/Sources/SwiftNetwork/Protocols/Frame.swift b/Sources/SwiftNetwork/Protocols/Frame.swift
index b98e3934..07c33198 100644
--- a/Sources/SwiftNetwork/Protocols/Frame.swift
+++ b/Sources/SwiftNetwork/Protocols/Frame.swift
@@ -507,6 +507,12 @@ public struct Frame: ~Copyable {
static let isChecksumIPChecked = Flags(rawValue: 1 << 1)
static let isChecksumIPValid = Flags(rawValue: 1 << 2)
static let fragmentationOverride = Flags(rawValue: 1 << 3)
+ // RX: the hardware validated the transport (TCP/UDP) checksum.
+ static let isChecksumDataValid = Flags(rawValue: 1 << 4)
+ // RX: the validated checksum value already folds in the pseudo-header.
+ static let isChecksumPseudoHeader = Flags(rawValue: 1 << 5)
+ // TX: the TSO segment size below describes an IPv6 super-packet.
+ static let isTSOIPv6 = Flags(rawValue: 1 << 6)
}
var flags: Flags = Flags()
var serviceClass = Parameters.ServiceClass.bestEffort
@@ -514,6 +520,22 @@ public struct Frame: ~Copyable {
var dscpValue: UInt8?
var hopLimit: UInt8 = 0
var checksumOffloadFlags: UInt8 = 0
+
+ // TX partial-checksum offload: byte offset (from the packet start / IP header)
+ // where the NIC begins the 1's-complement sum, and where it stores the result.
+ // Zero for the IP-header-only case, which the NIC locates itself.
+ var checksumStartOffset: UInt16 = 0
+ var checksumStoreOffset: UInt16 = 0
+
+ // TX segmentation offload (TSO): the per-segment TCP payload size the
+ // hardware should cut this frame into, or 0 for an ordinary single-segment
+ // frame. A non-zero value means the frame's payload deliberately exceeds
+ // the path MTU.
+ var tsoSegmentSize: UInt16 = 0
+
+ // RX: the final/partial transport checksum value the hardware reported.
+ var hardwareChecksumValue: UInt16 = 0
+
var departureTime: UInt64 = 0 // departure time at which kernel should send the packet, used for kernel pacing
var isLastPacket: Bool {
get { flags.contains(.isLastPacket) }
@@ -527,6 +549,14 @@ public struct Frame: ~Copyable {
get { flags.contains(.isChecksumIPValid) }
set { if newValue { flags.insert(.isChecksumIPValid) } else { flags.remove(.isChecksumIPValid) } }
}
+ var isChecksumDataValid: Bool {
+ get { flags.contains(.isChecksumDataValid) }
+ set { if newValue { flags.insert(.isChecksumDataValid) } else { flags.remove(.isChecksumDataValid) } }
+ }
+ var isChecksumPseudoHeader: Bool {
+ get { flags.contains(.isChecksumPseudoHeader) }
+ set { if newValue { flags.insert(.isChecksumPseudoHeader) } else { flags.remove(.isChecksumPseudoHeader) } }
+ }
var fragmentationOverride: Bool? {
get { flags.contains(.fragmentationOverride) ? true : nil }
set {
@@ -581,14 +611,14 @@ public struct Frame: ~Copyable {
var packetChainTotalLength: Int {
get {
- guard !isSingleIPAggregate else {
+ guard isSingleIPAggregate else {
Logger.proto.fault("Attempt to get aggregate buffer length on a non-single IP aggregate")
return 0
}
return aggregateBufferLength
}
set {
- guard !isSingleIPAggregate else {
+ guard isSingleIPAggregate else {
Logger.proto.fault("Attempt to get aggregate buffer length on a non-single IP aggregate")
return
}
@@ -697,6 +727,82 @@ public struct Frame: ~Copyable {
}
}
+ var isChecksumDataValid: Bool {
+ get { ipPacketValues?.isChecksumDataValid ?? false }
+ set {
+ if ipPacketValues == nil {
+ ipPacketValues = IPPacketValues()
+ }
+ ipPacketValues!.isChecksumDataValid = newValue
+ }
+ }
+
+ var isChecksumPseudoHeader: Bool {
+ get { ipPacketValues?.isChecksumPseudoHeader ?? false }
+ set {
+ if ipPacketValues == nil {
+ ipPacketValues = IPPacketValues()
+ }
+ ipPacketValues!.isChecksumPseudoHeader = newValue
+ }
+ }
+
+ var checksumStartOffset: UInt16 {
+ get { ipPacketValues?.checksumStartOffset ?? 0 }
+ set {
+ if ipPacketValues == nil {
+ ipPacketValues = IPPacketValues()
+ }
+ ipPacketValues!.checksumStartOffset = newValue
+ }
+ }
+
+ var checksumStoreOffset: UInt16 {
+ get { ipPacketValues?.checksumStoreOffset ?? 0 }
+ set {
+ if ipPacketValues == nil {
+ ipPacketValues = IPPacketValues()
+ }
+ ipPacketValues!.checksumStoreOffset = newValue
+ }
+ }
+
+ var hardwareChecksumValue: UInt16 {
+ get { ipPacketValues?.hardwareChecksumValue ?? 0 }
+ set {
+ if ipPacketValues == nil {
+ ipPacketValues = IPPacketValues()
+ }
+ ipPacketValues!.hardwareChecksumValue = newValue
+ }
+ }
+
+ // Per-segment TCP payload size for a TSO super-packet, 0 when this frame is an
+ // ordinary single-segment frame.
+ var tsoSegmentSize: UInt16 {
+ get { ipPacketValues?.tsoSegmentSize ?? 0 }
+ set {
+ if ipPacketValues == nil {
+ ipPacketValues = IPPacketValues()
+ }
+ ipPacketValues!.tsoSegmentSize = newValue
+ }
+ }
+
+ var isTSOIPv6: Bool {
+ get { ipPacketValues?.flags.contains(.isTSOIPv6) ?? false }
+ set {
+ if ipPacketValues == nil {
+ ipPacketValues = IPPacketValues()
+ }
+ if newValue {
+ ipPacketValues!.flags.insert(.isTSOIPv6)
+ } else {
+ ipPacketValues!.flags.remove(.isTSOIPv6)
+ }
+ }
+ }
+
struct FrameProtocolMetadata: ~Copyable {
var uuid: SystemUUID
var metadata: AbstractProtocolMetadata
@@ -726,7 +832,7 @@ public struct Frame: ~Copyable {
mutating func reduceAggregateBufferLength(by length: Int) {
if isSingleIPAggregate {
- guard aggregateBufferLength < length else {
+ guard length <= aggregateBufferLength else {
let existingLength = aggregateBufferLength
Logger.proto.fault("Aggregate buffer length \(existingLength) cannot remove \(length)")
aggregateBufferLength = 0
diff --git a/Tests/SwiftNetworkTests/SwiftNetworkFrameTests.swift b/Tests/SwiftNetworkTests/SwiftNetworkFrameTests.swift
index 6d4f283c..9ecfdafb 100644
--- a/Tests/SwiftNetworkTests/SwiftNetworkFrameTests.swift
+++ b/Tests/SwiftNetworkTests/SwiftNetworkFrameTests.swift
@@ -18,7 +18,7 @@ import XCTest
@available(anyAppleOS 27, *)
final class SwiftNetworkFrameTests: XCTestCase {
func testFrameLayout() {
- XCTAssertEqual(MemoryLayout.size, 136)
- XCTAssertEqual(MemoryLayout.stride, 136)
+ XCTAssertEqual(MemoryLayout.size, 144)
+ XCTAssertEqual(MemoryLayout.stride, 144)
}
}