#include "OtaProtocol.h" #include namespace mesh { namespace ota { // Little-endian cursor helpers. namespace { struct W { uint8_t* p; uint16_t cap; uint16_t n; bool ok; W(uint8_t* b, uint16_t c) : p(b), cap(c), n(0), ok(true) {} void u8(uint8_t v) { if (n + 1 > cap) { ok = false; return; } p[n++] = v; } void u16(uint16_t v){ u8(v & 0xFF); u8(v >> 8); } void u32(uint32_t v){ u8(v); u8(v >> 8); u8(v >> 16); u8(v >> 24); } void raw(const uint8_t* d, uint16_t l) { if (n + l > cap) { ok = false; return; } memcpy(p + n, d, l); n += l; } }; struct R { const uint8_t* p; uint16_t len; uint16_t n; bool ok; R(const uint8_t* b, uint16_t l) : p(b), len(l), n(0), ok(true) {} uint8_t u8() { if (n + 1 > len) { ok = false; return 0; } return p[n++]; } uint16_t u16() { uint16_t a = u8(); return a | ((uint16_t)u8() << 8); } uint32_t u32() { uint32_t a = u8(); a |= (uint32_t)u8() << 8; a |= (uint32_t)u8() << 16; a |= (uint32_t)u8() << 24; return a; } const uint8_t* raw(uint16_t l) { if (n + l > len) { ok = false; return nullptr; } const uint8_t* r = p + n; n += l; return r; } uint16_t remaining() const { return len - n; } }; } // namespace uint16_t encode_adv(uint8_t* buf, uint16_t cap, const AdvMsg& m) { // tiny per-node beacon W w(buf, cap); w.u8(OTA_ADV); w.raw(m.seeder_id, 4); w.u8(m.n_motas); w.raw(m.set_digest, 4); return w.ok ? w.n : 0; } bool decode_adv(const uint8_t* buf, uint16_t len, AdvMsg& m) { R r(buf, len); if (r.u8() != OTA_ADV) return false; const uint8_t* sid = r.raw(4); if (sid) memcpy(m.seeder_id, sid, 4); m.n_motas = r.u8(); const uint8_t* d = r.raw(4); if (d) memcpy(m.set_digest, d, 4); return r.ok; } uint16_t encode_query(uint8_t* buf, uint16_t cap, const QueryMsg& m) { W w(buf, cap); w.u8(OTA_QUERY); w.raw(m.seeder_id, 4); w.raw(m.set_digest, 4); w.u32(m.filter_target); return w.ok ? w.n : 0; } bool decode_query(const uint8_t* buf, uint16_t len, QueryMsg& m) { R r(buf, len); if (r.u8() != OTA_QUERY) return false; const uint8_t* sid = r.raw(4); if (sid) memcpy(m.seeder_id, sid, 4); const uint8_t* dg = r.raw(4); if (dg) memcpy(m.set_digest, dg, 4); m.filter_target = r.u32(); return r.ok; } uint16_t encode_have(uint8_t* buf, uint16_t cap, const HaveMsg& m) { W w(buf, cap); w.u8(OTA_HAVE); w.raw(m.seeder_id, 4); w.raw(m.set_digest, 4); w.u8(m.frag_idx); w.u8(m.frag_total); w.u8(m.n_rows); w.raw(m.rows, (uint16_t)m.n_rows * OTA_HAVE_ROW_BYTES); return w.ok ? w.n : 0; } bool decode_have(const uint8_t* buf, uint16_t len, HaveMsg& m) { R r(buf, len); if (r.u8() != OTA_HAVE) return false; const uint8_t* sid = r.raw(4); if (sid) memcpy(m.seeder_id, sid, 4); const uint8_t* dg = r.raw(4); if (dg) memcpy(m.set_digest, dg, 4); m.frag_idx = r.u8(); m.frag_total = r.u8(); m.n_rows = r.u8(); m.rows = r.raw((uint16_t)m.n_rows * OTA_HAVE_ROW_BYTES); return r.ok; } uint16_t encode_get_manifest(uint8_t* buf, uint16_t cap, const GetManifestMsg& m) { W w(buf, cap); w.u8(OTA_GET_MANIFEST); w.raw(m.manifest_id, 4); w.u16(m.want_mask); return w.ok ? w.n : 0; } bool decode_get_manifest(const uint8_t* buf, uint16_t len, GetManifestMsg& m) { R r(buf, len); if (r.u8() != OTA_GET_MANIFEST) return false; const uint8_t* id = r.raw(4); if (id) memcpy(m.manifest_id, id, 4); m.want_mask = r.u16(); return r.ok; } uint16_t encode_manifest(uint8_t* buf, uint16_t cap, const ManifestMsg& m) { W w(buf, cap); w.u8(OTA_MANIFEST); w.raw(m.manifest_id, 4); w.u8(m.frag_idx); w.u8(m.frag_total); w.raw(m.bytes, m.len); return w.ok ? w.n : 0; } bool decode_manifest(const uint8_t* buf, uint16_t len, ManifestMsg& m) { R r(buf, len); if (r.u8() != OTA_MANIFEST) return false; const uint8_t* id = r.raw(4); if (id) memcpy(m.manifest_id, id, 4); m.frag_idx = r.u8(); m.frag_total = r.u8(); m.len = r.remaining(); m.bytes = r.raw(m.len); return r.ok; } uint16_t encode_req(uint8_t* buf, uint16_t cap, const ReqMsg& m) { W w(buf, cap); w.u8(OTA_REQ); w.raw(m.manifest_id, 4); w.u16(m.block_idx); w.u16(m.want_mask); return w.ok ? w.n : 0; } bool decode_req(const uint8_t* buf, uint16_t len, ReqMsg& m) { R r(buf, len); if (r.u8() != OTA_REQ) return false; const uint8_t* id = r.raw(4); if (id) memcpy(m.manifest_id, id, 4); m.block_idx = r.u16(); m.want_mask = r.u16(); return r.ok; } uint16_t encode_data(uint8_t* buf, uint16_t cap, const DataMsg& m) { W w(buf, cap); w.u8(OTA_DATA); w.raw(m.manifest_id, 4); w.u16(m.block_idx); w.u16(m.frag_off); w.raw(m.data, m.data_len); return w.ok ? w.n : 0; } bool decode_data(const uint8_t* buf, uint16_t len, DataMsg& m) { R r(buf, len); if (r.u8() != OTA_DATA) return false; const uint8_t* id = r.raw(4); if (id) memcpy(m.manifest_id, id, 4); m.block_idx = r.u16(); m.frag_off = r.u16(); m.data_len = r.remaining(); m.data = r.raw(m.data_len); return r.ok; } uint16_t encode_req_proof(uint8_t* buf, uint16_t cap, const ReqProofMsg& m) { W w(buf, cap); w.u8(OTA_REQ_PROOF); w.raw(m.manifest_id, 4); w.u16(m.block_idx); return w.ok ? w.n : 0; } bool decode_req_proof(const uint8_t* buf, uint16_t len, ReqProofMsg& m) { R r(buf, len); if (r.u8() != OTA_REQ_PROOF) return false; const uint8_t* id = r.raw(4); if (id) memcpy(m.manifest_id, id, 4); m.block_idx = r.u16(); return r.ok; } uint16_t encode_proof(uint8_t* buf, uint16_t cap, const ProofMsg& m) { W w(buf, cap); w.u8(OTA_PROOF); w.raw(m.manifest_id, 4); w.u16(m.block_idx); w.u8(m.n_proof); w.raw(m.proof, (uint16_t)m.n_proof * 4); return w.ok ? w.n : 0; } bool decode_proof(const uint8_t* buf, uint16_t len, ProofMsg& m) { R r(buf, len); if (r.u8() != OTA_PROOF) return false; const uint8_t* id = r.raw(4); if (id) memcpy(m.manifest_id, id, 4); m.block_idx = r.u16(); m.n_proof = r.u8(); m.proof = r.raw((uint16_t)m.n_proof * 4); return r.ok; } uint16_t encode_get_leaves(uint8_t* buf, uint16_t cap, const GetLeavesMsg& m) { W w(buf, cap); w.u8(OTA_GET_LEAVES); w.raw(m.manifest_id, 4); w.u16(m.want_mask); return w.ok ? w.n : 0; } bool decode_get_leaves(const uint8_t* buf, uint16_t len, GetLeavesMsg& m) { R r(buf, len); if (r.u8() != OTA_GET_LEAVES) return false; const uint8_t* id = r.raw(4); if (id) memcpy(m.manifest_id, id, 4); m.want_mask = r.u16(); return r.ok; } uint16_t encode_leaves(uint8_t* buf, uint16_t cap, const LeavesMsg& m) { W w(buf, cap); w.u8(OTA_LEAVES); w.raw(m.manifest_id, 4); w.u8(m.frag_idx); w.u8(m.frag_total); w.raw(m.bytes, m.len); return w.ok ? w.n : 0; } bool decode_leaves(const uint8_t* buf, uint16_t len, LeavesMsg& m) { R r(buf, len); if (r.u8() != OTA_LEAVES) return false; const uint8_t* id = r.raw(4); if (id) memcpy(m.manifest_id, id, 4); m.frag_idx = r.u8(); m.frag_total = r.u8(); m.len = r.remaining(); m.bytes = r.raw(m.len); return r.ok; } } // namespace ota } // namespace mesh