fix: enforce BLE route frame limits

This commit is contained in:
Dev 2026-07-27 23:55:43 +03:00
parent 9abb8fce0f
commit 4d76e03eb1
3 changed files with 76 additions and 2 deletions

View File

@ -94,9 +94,14 @@ enum BLEOutboundFragmentPlanner {
calculatedChunk = max(minimumChunkSize, bleMaxMTU - overhead)
}
let linkBoundedChunk = min(
requestedMaxChunk ?? calculatedChunk,
calculatedChunk
)
return (
fragmentVersion: fragmentVersion,
chunkSize: max(minimumChunkSize, requestedMaxChunk ?? calculatedChunk)
chunkSize: max(minimumChunkSize, linkBoundedChunk)
)
}

View File

@ -2,7 +2,11 @@ import BitFoundation
import Foundation
enum BLEOutboundPacketPolicy {
private static let fragmentFrameOverhead = 13 + 8 + 8 + 13
private static let fragmentFrameOverhead =
BinaryProtocol.v1HeaderSize
+ BinaryProtocol.senderIDSize
+ BinaryProtocol.recipientIDSize
+ 13
static func messageID(for packet: BitchatPacket) -> String {
BLEIngressLinkRegistry.messageID(for: packet)

View File

@ -78,6 +78,34 @@ struct BLEOutboundFragmentPlannerTests {
#expect(plan.fragmentPackets.allSatisfy { $0.recipientID == Data(hexString: directedPeer.id) })
}
@Test("link-derived chunks keep every directed fragment within the link limit")
func linkDerivedChunksFitTheLinkLimit() throws {
let linkLimit = 512
let directedPeer = PeerID(str: "8877665544332211")
let packet = makePacket(payload: makePayload(count: 1_024))
let request = BLEOutboundFragmentTransferRequest(
packet: packet,
pad: false,
maxChunk: BLEOutboundPacketPolicy.fragmentChunkSize(
forLinkLimit: linkLimit
),
directedPeer: directedPeer,
transferId: nil
)
let plan = try #require(BLEOutboundFragmentPlanner.makePlan(
for: request,
defaultChunkSize: TransportConfig.bleDefaultFragmentSize,
bleMaxMTU: linkLimit,
fragmentID: Data(repeating: 0xB3, count: 8)
))
let encodedFragments = try plan.fragmentPackets.map {
try #require($0.toBinaryData(padding: false))
}
#expect(encodedFragments.allSatisfy { $0.count <= linkLimit })
}
@Test("route-aware fragments use version two and route-sized chunking")
func routeAwareFragmentsUseVersionTwoAndRouteSizedChunking() throws {
let route = [
@ -107,6 +135,43 @@ struct BLEOutboundFragmentPlannerTests {
#expect(plan.fragmentPackets.allSatisfy { $0.route == route && $0.isRSR })
}
@Test("link-derived chunks cannot override route-safe fragment sizing")
func linkDerivedChunksRespectRouteOverhead() throws {
let linkLimit = 512
let route = [
Data([0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]),
Data([0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27])
]
let directedPeer = PeerID(str: "8877665544332211")
let packet = makePacket(
payload: makePayload(count: 1_024),
route: route
)
let requestedChunk = BLEOutboundPacketPolicy.fragmentChunkSize(
forLinkLimit: linkLimit
)
let request = BLEOutboundFragmentTransferRequest(
packet: packet,
pad: false,
maxChunk: requestedChunk,
directedPeer: directedPeer,
transferId: nil
)
let plan = try #require(BLEOutboundFragmentPlanner.makePlan(
for: request,
defaultChunkSize: TransportConfig.bleDefaultFragmentSize,
bleMaxMTU: linkLimit,
fragmentID: Data(repeating: 0xC4, count: 8)
))
let encodedFragments = try plan.fragmentPackets.map {
try #require($0.toBinaryData(padding: false))
}
#expect(plan.chunkSize < requestedChunk)
#expect(encodedFragments.allSatisfy { $0.count <= linkLimit })
}
@Test("invalid fragment IDs do not produce a plan")
func invalidFragmentIDReturnsNil() {
let packet = makePacket(payload: makePayload(count: 128))