Sign ITS messages on the ESP32-C5 with vanetza-idf, over USB or BLE
obu-firmware is now a port of the colleague's standalone VRU station (microbu-esp32c5/firmware, kept beside this repository and gitignored): the vanetza-idf C-ITS stack with the TS 103 097 security entity, credentials in NVS, the station-link v1 protocol over the native USB port (frame type 0x10 in the existing 0xAA55 framing) and over a BLE GATT peripheral, and its ITS-G5 radio adapter. The phone still builds CAM and VAM; the board adds GeoNetworking/BTP and signs with the provisioned authorization ticket. The private key never leaves the board. Builds with ESP-IDF 6.0.2 only, which vanetza-idf pins for the radio's private driver ABI. The previous C firmware stays on disk unbuilt; a full-flash backup of the bench board is kept in firmware-backups/ (gitignored). Changed against the colleague's firmware, marked MicrOBU: in the sources: - Reception unchanged for the app. vanetza-idf drops what it cannot verify (unsigned traffic, every RSU), so each captured frame also goes through the previous gn_unwrap.c and reaches the phone as link opcode V2X_RX (0x85), whose body is the old SERIAL_MSG_V2X_RX payload. - Unsigned transmission still possible, with the previous geonet.c header; the phone chooses per message. - Console on UART0 (CH343 port); the native USB port carries only link frames. - BLE advertising pauses while the USB link is in use: BLE and ITS-G5 share one RF front end. - NVS 80 KB (app at 0x20000). At 24 KB, with Wi-Fi settings the previous firmware left behind, the BLE bond could not be stored and the phone had to pair on every connection. - Bench fixes: the radio queue is drained before the first PoTi (no RX and ~177 queue drops before); the station loop waited pdMS_TO_TICKS(5) = 0 ticks at 100 Hz and starved the idle task; the 2.4 KB RX capture buffer is off the Wi-Fi task stack; BLE notifications longer than the MTU are dropped instead of cut short, MTU 517; serial writes are skipped with no USB host. - Manual country policy and TX-power read-back from the previous radio setup; logs for BLE encryption changes and the number of stored bonds. Verified on the bench board (COM3) with the phone over USB and BLE: CAM and VAM, signed and unsigned, go out; reception of the sim car and the RSU's CAM/SPATEM/MAPEM continues; the board survives app restarts and reconnects. See docs/06-signed-its-vam-ble.md.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
#include "test_channel.hpp"
|
||||
#if CONFIG_MICROBU_TEST_CHANNEL
|
||||
#include <algorithm>
|
||||
|
||||
namespace microbu {
|
||||
|
||||
link::Bytes test_channel_execute(Station& station, const link::Bytes& request) {
|
||||
using link::Code;
|
||||
Code result = Code::malformed;
|
||||
std::deque<TestRecord> records;
|
||||
link::Bytes extra;
|
||||
if (!request.empty()) {
|
||||
link::Reader r(request, 1);
|
||||
switch (request[0]) {
|
||||
case 0x01: { // MIRROR mode
|
||||
const auto mode = r.u8();
|
||||
if (r.done() && mode <= 2) { station.test_mirror(static_cast<Station::Mirror>(mode)); result = Code::accepted; }
|
||||
break;
|
||||
}
|
||||
case 0x02: { // INJECT source destination gnpdu
|
||||
vanetza::MacAddress source, destination;
|
||||
r.bytes(source.octets.data(), 6);
|
||||
r.bytes(destination.octets.data(), 6);
|
||||
auto gnpdu = r.rest();
|
||||
if (r.ok() && !gnpdu.empty()) result = station.test_inject(source, destination, std::move(gnpdu));
|
||||
break;
|
||||
}
|
||||
case 0x03: { // GN_REQUEST traffic class payload
|
||||
const auto tc = r.u8();
|
||||
auto payload = r.rest();
|
||||
if (r.ok() && !payload.empty()) result = station.test_gn_request(tc, std::move(payload));
|
||||
break;
|
||||
}
|
||||
case 0x04: { // DRAIN
|
||||
bool overflow = false;
|
||||
records = station.test_drain(overflow, 1536 - 2);
|
||||
result = overflow ? Code::resource_limit : Code::accepted;
|
||||
break;
|
||||
}
|
||||
case 0x05: // RESET
|
||||
station.test_reset();
|
||||
result = Code::accepted;
|
||||
break;
|
||||
case 0x06: { // RADIO_BURST [channel u16 LE][power_quarter_db u8][mcs u8][count u16 LE][interval_ms u16 LE][payload_len u16 LE]
|
||||
const auto channel = r.u16();
|
||||
const auto power_quarter_db = r.u8();
|
||||
const auto mcs = r.u8();
|
||||
const auto count = r.u16();
|
||||
const auto interval_ms = r.u16();
|
||||
const auto payload_len = r.u16();
|
||||
if (r.done()) {
|
||||
const double power_dbm = power_quarter_db / 4.0;
|
||||
result = station.test_radio_burst(channel, power_dbm, mcs, count, interval_ms, payload_len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x07: { // CCA_SAMPLE [duration_ms u16 LE] -- CCA polling feasibility probe
|
||||
const auto duration_ms = r.u16();
|
||||
if (r.done()) result = station.test_cca_sample(duration_ms, extra);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
result = Code::unknown_opcode;
|
||||
}
|
||||
}
|
||||
link::Writer w;
|
||||
w.u8(static_cast<std::uint8_t>(result));
|
||||
w.u8(static_cast<std::uint8_t>(std::min<std::size_t>(records.size(), 255)));
|
||||
for (const auto& record : records) {
|
||||
w.u8(record.kind);
|
||||
w.u16(static_cast<std::uint16_t>(record.bytes.size()));
|
||||
w.bytes(record.bytes);
|
||||
}
|
||||
w.bytes(extra);
|
||||
return w.out;
|
||||
}
|
||||
|
||||
} // namespace microbu
|
||||
#endif // CONFIG_MICROBU_TEST_CHANNEL
|
||||
Reference in New Issue
Block a user