command reply buffer and tcp oversize fix

This commit is contained in:
liquidraver
2026-09-17 10:59:13 +02:00
parent da0450e511
commit 1c2c942849
2 changed files with 58 additions and 6 deletions
@@ -358,11 +358,15 @@ static void listen_thread_fn(void *a, void *b, void *c)
}
uint16_t flen = (uint16_t)hdr[1] | ((uint16_t)hdr[2] << 8);
if (flen > MAX_FRAME_SIZE) {
LOG_WRN("Oversized frame: len=%u, closing client", flen);
break;
}
/* Skip frames not from app ('<'), or bad length. */
if (hdr[0] != '<' || flen == 0 || flen > MAX_FRAME_SIZE) {
if (hdr[0] != '<' || flen == 0) {
/* Drain and discard the payload. */
for (uint16_t i = 0; i < flen && flen <= MAX_FRAME_SIZE; i++) {
for (uint16_t i = 0; i < flen; i++) {
uint8_t discard;
if (sock_recv_all(fd, &discard, 1) != 0) {
goto client_done;
+52 -4
View File
@@ -250,8 +250,17 @@ static void ble_on_connected(void)
* sync state machine), resets message sync (un-ACKed peeked message stays in
* the queue and is re-sent on the next CMD_SYNC_NEXT_MESSAGE), and frees the
* Ed25519 sign buffer if a sign op was interrupted (else an 8KB leak). */
/* One deferred reply is enough: RX pauses until it has been accepted by the
* transport. A msgq also lets the transport's disconnect callback purge it. */
struct pending_reply_frame {
uint16_t len;
uint8_t buf[MAX_FRAME_SIZE];
};
K_MSGQ_DEFINE(pending_reply, sizeof(struct pending_reply_frame), 1, 4);
static void companion_session_cleanup(void)
{
k_msgq_purge(&pending_reply);
#ifdef ZEPHCORE_LORA
companion_mesh_ptr->cancelContactIterator();
companion_mesh_ptr->cancelSyncPending();
@@ -306,7 +315,7 @@ static const struct ble_callbacks ble_cbs = {
/* ========== Frame send/receive (mesh ↔ BLE/USB) ========== */
static size_t write_frame(const uint8_t *src, size_t len)
static size_t transport_write_frame(const uint8_t *src, size_t len)
{
#if ZEPHCORE_USB_STACK
/* When USB owns the interface, replies must go out the CDC port — the BLE
@@ -325,6 +334,38 @@ static size_t write_frame(const uint8_t *src, size_t len)
return zephcore_ble_send(src, (uint16_t)len);
}
static size_t write_frame(const uint8_t *src, size_t len)
{
if (len == 0 || len > MAX_FRAME_SIZE ||
k_msgq_num_used_get(&pending_reply) != 0) {
return 0;
}
if (transport_write_frame(src, len) == len) {
return len;
}
/* Only protocol replies need retention; pushes retain their existing
* lossy semantics. Report success once we own a copy, so callers that
* already retry (contact/message sync) don't send it twice. */
if (src[0] < 0x80) {
struct pending_reply_frame f;
f.len = len;
memcpy(f.buf, src, len);
if (k_msgq_put(&pending_reply, &f, K_NO_WAIT) == 0) {
return len;
}
}
return 0;
}
static void retry_pending_reply(void)
{
struct pending_reply_frame f;
if (k_msgq_peek(&pending_reply, &f) == 0 &&
transport_write_frame(f.buf, f.len) == f.len) {
(void)k_msgq_get(&pending_reply, &f, K_NO_WAIT);
}
}
/**
* Push notification callback - sends push frames to BLE.
* Push frames have format: [push_code] [data...]
@@ -376,7 +417,8 @@ static void process_companion_rx(void)
} f;
/* Process all queued frames */
while (k_msgq_get(zephcore_ble_get_recv_queue(), &f, K_NO_WAIT) == 0) {
while (k_msgq_num_used_get(&pending_reply) == 0 &&
k_msgq_get(zephcore_ble_get_recv_queue(), &f, K_NO_WAIT) == 0) {
#ifdef ZEPHCORE_LORA
/* An in-flight contact dump deliberately survives commands parsed
* here — it is only cancelled by CMD_APP_START (new session) or by
@@ -470,6 +512,10 @@ static void mesh_event_loop(void)
/* Clear the events we're handling */
k_event_clear(&mesh_events, events);
/* TX-idle resumes both the retained reply and commands left in RX.
* Housekeeping is a fallback if a transport loses its drain kick. */
retry_pending_reply();
#ifdef ZEPHCORE_LORA
/* Handle deferred UI button actions (flood advert, pref saves).
* Must run in this thread — LoRa TX and flash writes block. */
@@ -489,7 +535,8 @@ static void mesh_event_loop(void)
/* Parse inbound BLE/USB frames + USB text-CLI lines HERE (main
* thread) before loop() drains any outbound they enqueued — keeps
* all mesh-state mutation on one thread (see ble_on_rx_frame). */
if (events & MESH_EVENT_BLE_RX) {
if (events & (MESH_EVENT_BLE_RX | MESH_EVENT_CONTACT_ITER |
MESH_EVENT_HOUSEKEEPING)) {
process_companion_rx();
#if ZEPHCORE_USB_STACK
struct companion_cli_line c;
@@ -731,7 +778,8 @@ public:
* has not reached the TX queue yet, so a `reboot` typed into the v-contact
* waits for its own ack before resetting. */
bool transportTxIdle() override {
if (companion_mesh.vcontactConfirmPending()) {
if (companion_mesh.vcontactConfirmPending() ||
k_msgq_num_used_get(&pending_reply) != 0) {
return false;
}
#if ZEPHCORE_USB_STACK