Skip to content

Commit a088b56

Browse files
committed
feat(srv/nbus2): PoC of the transmit path
1 parent 734173f commit a088b56

File tree

2 files changed

+127
-64
lines changed

2 files changed

+127
-64
lines changed

services/nbus2/nbus2.c

+127-61
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
#define MODULE_NAME "nbus"
2222

2323

24+
uint8_t nbus_my_id[4] = {0, 0, 0, 1};
25+
uint8_t nbus_my_ep = 0;
26+
uint16_t nbus_tx_counter = 0;
27+
28+
2429
/**
2530
* tl;dr of the nbus2 packet format
2631
*
@@ -50,6 +55,19 @@
5055
*/
5156

5257

58+
static void marker(uint32_t port, uint32_t pin, bool len) {
59+
gpio_set(port, pin);
60+
if (len) {
61+
vTaskDelay(1);
62+
} else {
63+
for (int i = 0; i < 1000; i++) {
64+
;
65+
}
66+
}
67+
gpio_clear(port, pin);
68+
}
69+
70+
5371
/**
5472
* @brief Receive exact number of bytes from the input stream
5573
*
@@ -80,6 +98,7 @@ static nbus_ret_t stream_receive_expect(Nbus *self, uint8_t *buf, size_t size) {
8098
return NBUS_RET_TIMEOUT;
8199
} else {
82100
/* Something wrong, EOF, EOT or whatever. */
101+
u_log(system_log, LOG_TYPE_WARN, U_LOG_MODULE_PREFIX("stream_receive_expect: no-OK %d"), ret);
83102
return NBUS_RET_FAILED;
84103
}
85104
}
@@ -133,7 +152,7 @@ static nbus_ret_t stream_wait_for_eot(Nbus *self) {
133152

134153

135154
static nbus_ret_t pbuf_receive_expect(Nbus *self, struct nbus_pbuf *pbuf, size_t len) {
136-
if (pbuf->buf_len + len > pbuf->buf_size) {
155+
if ((pbuf->buf_len + len) > pbuf->buf_size) {
137156
stream_wait_for_eot(self);
138157
return NBUS_RET_FAILED;
139158
}
@@ -167,85 +186,108 @@ static nbus_ret_t pbuf_receive_expect(Nbus *self, struct nbus_pbuf *pbuf, size_t
167186
* Key derivation alone is 80 us but it is done only once.
168187
* Chacha20 decryption alone is 38 us.
169188
*/
170-
static nbus_ret_t receive_process_header(Nbus *self, struct nbus_pbuf *pbuf) {
171-
if (pbuf_receive_expect(self, pbuf, 24) != NBUS_RET_OK) {
189+
static nbus_ret_t nbus_pbuf_receive_header(struct nbus_pbuf *self, Nbus *nbus) {
190+
if (pbuf_receive_expect(nbus, self, 24) != NBUS_RET_OK) {
191+
//u_log(system_log, LOG_TYPE_WARN, U_LOG_MODULE_PREFIX("bad header recv"));
172192
return NBUS_RET_FAILED;
173193
}
194+
//u_log(system_log, LOG_TYPE_WARN, U_LOG_MODULE_PREFIX("ke = 0x%02x 0x%02x"), pbuf->ke[0], pbuf->ke[1]);
174195

175-
/* 24 bytes received correctly. Decrypt the header (bytes 8-23)
176-
* using the derived key Ke and SIV as a nonce (bytes 0-7). */
177-
b2s_derive_keys(self->mac_key, self->mac_key_len, pbuf->ke, pbuf->km);
178-
//b2s_crypt(
179-
//pbuf->buf + 8, /* Fixed part of the header starts from byte 8, it is 16 bytes long. */
180-
//16,
181-
//pbuf->buf, /* SIV starts t the beginning, it is always 8 bytees long. */
182-
//8,
183-
//pbuf->ke
184-
//);
185-
gpio_set(GPIOA, GPIO15);
186-
chacha20_context ctx;
187-
chacha20_keysetup(&ctx, pbuf->ke, 128);
188-
chacha20_nonce(&ctx, pbuf->buf);
189-
190-
for (uint32_t counter = 0; counter < 16; counter++) {
191-
chacha20_counter(&ctx, counter);
192-
193-
uint8_t keystream[64];
194-
chacha20_keystream(&ctx, keystream);
195-
for (size_t i = 0; i < 16; i++) {
196-
pbuf->buf[i + 8] ^= keystream[i];
197-
}
198-
}
199-
gpio_clear(GPIOA, GPIO15);
200-
201-
//u_log(system_log, LOG_TYPE_DEBUG, U_LOG_MODULE_PREFIX("decrypted magic 0x%02x 0x%02x"), pbuf->buf[8], pbuf->buf[9]);
196+
/* Decrypt the header. */
197+
ChaCha20 ch;
198+
chacha20_keysetup(&ch, self->ke, 128);
199+
chacha20_nonce(&ch, self->buf);
200+
chacha20_encrypt(&ch, self->buf + 8, self->buf + 8, 16);
202201

203202
/* Check the magic. It is right at the beginning of the fixed header. */
204-
if (pbuf->buf[8] != 'n' || pbuf->buf[9] != '2') {
203+
if (self->buf[8] != 'n' || self->buf[9] != '2') {
204+
u_log(system_log, LOG_TYPE_WARN, U_LOG_MODULE_PREFIX("bac magic"));
205205
return NBUS_RET_FAILED;
206206
}
207207

208-
memcpy(pbuf->dstid, pbuf->buf + 16, 4);
209-
memcpy(pbuf->srcid, pbuf->buf + 20, 4);
210-
211208
return NBUS_RET_OK;
212209
}
213210

214211

215-
static nbus_ret_t receive_process_data(Nbus *self, struct nbus_pbuf *pbuf) {
216-
size_t packet_len = pbuf->buf[10] << 8 | pbuf->buf[11];
212+
static nbus_ret_t nbus_pbuf_receive_data(struct nbus_pbuf *self, Nbus *nbus) {
213+
size_t packet_len = self->buf[10] << 8 | self->buf[11];
217214
if (packet_len == 0) {
218215
/* Zero length packet is valid, do not read anything. */
219216
return NBUS_RET_OK;
220217
}
221-
if (pbuf_receive_expect(self, pbuf, packet_len) != NBUS_RET_OK) {
218+
if (pbuf_receive_expect(nbus, self, packet_len) != NBUS_RET_OK) {
222219
return NBUS_RET_FAILED;
223220
}
224-
//u_log(system_log, LOG_TYPE_DEBUG, U_LOG_MODULE_PREFIX("received packet data len %u"), packet_len);
225221

222+
//u_log(system_log, LOG_TYPE_DEBUG, U_LOG_MODULE_PREFIX("received packet data len %u"), packet_len);
223+
//u_log(system_log, LOG_TYPE_WARN, U_LOG_MODULE_PREFIX("data 0x%02x, 0x%02x, 0x%02x, 0x%02x"), pbuf->buf[24], pbuf->buf[25], pbuf->buf[26], pbuf->buf[27]);
226224

227-
/* Decrypt data only, headers are already decrypted. It is not possible yet, so do a workaround
228-
* (encrypt header back, decrypt as a whole). */
229-
/** @todo This decryption takes 2.16 ms for a 1024 byte packet */
230-
b2s_crypt(pbuf->buf + 8, 16, pbuf->buf, 8, pbuf->ke);
231-
b2s_crypt(pbuf->buf + 8, pbuf->buf_len - 8, pbuf->buf, 8, pbuf->ke);
232-
/** @todo The same decryption using chacha20 should be around 680 us
233-
* and 570 us when XORing 32 bits at once. */
225+
/* Decrypt data only, headers are already decrypted. */
226+
ChaCha20 ch;
227+
chacha20_keysetup(&ch, self->ke, 128);
228+
chacha20_nonce(&ch, self->buf);
229+
/* Consume first counter. */
230+
uint8_t foo[8] = {0};
231+
chacha20_encrypt(&ch, foo, foo, sizeof(foo));
232+
chacha20_encrypt(&ch, self->buf + 24, self->buf + 24, packet_len);
234233

235234
/* Compute MAC from header and data. Compare with the SIV from the message. */
236-
/** @todo MAC computation takes 440 us for a 1024 byte packet (blake2s) */
237-
//uint8_t mac[BLAKE2S_OUTBYTES];
238-
//b2s_siv(pbuf->buf + 8, pbuf->buf_len - 8, mac, sizeof(mac), pbuf->km);
239-
/** @todo MAC computation takes 59 us for a 1024 byte packet (halfsiphash) */
240235
uint8_t mac[8];
241-
halfsiphash(pbuf->buf + 8, pbuf->buf_len - 8, pbuf->km, mac, sizeof(mac));
236+
halfsiphash(self->buf + 8, self->buf_len - 8, self->km, mac, sizeof(mac));
237+
238+
if (memcmp(self->buf, mac, 8)) {
239+
//syslog(LOG_ERR, "pbuf: receive data bad MAC");
240+
return NBUS_RET_FAILED;
241+
}
242+
243+
return NBUS_RET_OK;
244+
}
245+
242246

243-
if (memcmp(pbuf->buf, mac, 8)) {
244-
//u_log(system_log, LOG_TYPE_WARN, U_LOG_MODULE_PREFIX("bad MAC 0x%02x 0x%02x != 0x%02x 0x%02x"), pbuf->buf[0], pbuf->buf[1], mac[0], mac[1]);
247+
static nbus_ret_t nbus_pbuf_send(struct nbus_pbuf *self, void *buf, size_t len, uint8_t dst_id[4], uint8_t dst_ep) {
248+
if ((len + 24) > self->buf_size) {
249+
return NBUS_RET_FAILED;
250+
}
251+
memcpy(self->buf + 24, buf, len);
252+
self->buf_len = len + 24;
253+
254+
self->buf[8] = 'n';
255+
self->buf[9] = '2';
256+
257+
self->buf[10] = len / 256;
258+
self->buf[11] = len % 256;
259+
260+
self->buf[12] = nbus_tx_counter / 256;
261+
self->buf[13] = nbus_tx_counter % 256;
262+
nbus_tx_counter++;
263+
264+
/* Set IDs and endpoints. */
265+
self->buf[14] = (dst_ep & 0xf) << 4 | (nbus_my_ep & 0xf);
266+
self->buf[15] = 0;
267+
memcpy(self->buf + 16, dst_id, 4);
268+
memcpy(self->buf + 20, nbus_my_id, 4);
269+
270+
return NBUS_RET_OK;
271+
}
272+
273+
274+
static nbus_ret_t nbus_pbuf_transmit(struct nbus_pbuf *self, Nbus *nbus) {
275+
276+
/* Compute SIV first */
277+
halfsiphash(self->buf + 8, self->buf_len - 8, self->km, self->buf, 8);
278+
279+
ChaCha20 ch;
280+
chacha20_keysetup(&ch, self->ke, 128);
281+
chacha20_nonce(&ch, self->buf);
282+
/* Encrypt the header first. */
283+
chacha20_encrypt(&ch, self->buf + 8, self->buf + 8, 16);
284+
/* Counter is incremented, the rest of the input is kept. Encrypt the data. */
285+
chacha20_encrypt(&ch, self->buf + 24, self->buf + 24, self->buf_len - 24);
286+
287+
if (nbus->stream->vmt->write(nbus->stream, self->buf, self->buf_len) != STREAM_RET_OK) {
245288
return NBUS_RET_FAILED;
246289
}
247290

248-
//b2s_crypt(pbuf->data, pbuf->len, pbuf->siv, 8, self->ke);
249291
return NBUS_RET_OK;
250292
}
251293

@@ -254,6 +296,7 @@ static void addr_to_str(uint8_t addr[4], char *s, size_t size) {
254296
snprintf(s, size, "0x%02x%02x%02x%02x", addr[0], addr[1], addr[2], addr[3]);
255297
}
256298

299+
/*
257300
static void print_pbuf(Nbus *self, struct nbus_pbuf *pbuf, const char *prefix) {
258301
(void)self;
259302
@@ -264,7 +307,7 @@ static void print_pbuf(Nbus *self, struct nbus_pbuf *pbuf, const char *prefix) {
264307
265308
u_log(system_log, LOG_TYPE_DEBUG, U_LOG_MODULE_PREFIX("%s%s -> %s, len %u, 0x%02x 0x%02x"), prefix, srcid, dstid, pbuf->buf_len, pbuf->buf[24], pbuf->buf[25]);
266309
}
267-
310+
*/
268311

269312
static void nbus_mac_task(void *p) {
270313
Nbus *self = (Nbus *)p;
@@ -274,40 +317,57 @@ static void nbus_mac_task(void *p) {
274317
if (pbuf == NULL) {
275318
/* Cannot allocate a buffer, we must drop the packet. Wait at least for EOT. */
276319
stream_wait_for_eot(self);
320+
u_log(system_log, LOG_TYPE_WARN, U_LOG_MODULE_PREFIX("buffer allocation error"));
277321
goto err;
278322
}
279-
if (receive_process_header(self, pbuf) != NBUS_RET_OK) {
323+
324+
if (nbus_pbuf_receive_header(pbuf, self) != NBUS_RET_OK) {
280325
stream_wait_for_eot(self);
326+
u_log(system_log, LOG_TYPE_WARN, U_LOG_MODULE_PREFIX("packet header reception error"));
281327
goto err;
282328
}
329+
/* After first 24 bytes */
330+
marker(GPIOE, GPIO11, false);
283331

284-
if (receive_process_data(self, pbuf) != NBUS_RET_OK) {
332+
if (nbus_pbuf_receive_data(pbuf, self) != NBUS_RET_OK) {
333+
u_log(system_log, LOG_TYPE_WARN, U_LOG_MODULE_PREFIX("packet data reception error"));
285334
goto err;
286335
}
287-
288336
//print_pbuf(self, pbuf, "received ");
289337

290-
291-
292338
/* End of packet. No additional data should be in the receive buffer. Check for EOT now
293339
* before a new packet reception starts. */
294340
if (stream_eot_expect(self) != NBUS_RET_OK) {
295341
/* No EOT, additional data received, wait for one. */
296342
stream_wait_for_eot(self);
343+
//goto err;
297344
}
298345

299-
self->stream->vmt->write(self->stream, "\x00\x55\x00\x55\x00\x55\x00\x55", 8);
346+
//self->stream->vmt->write(self->stream, pbuf->buf, pbuf->buf_len);
347+
nbus_pbuf_release(self, pbuf);
348+
349+
struct nbus_pbuf *txp = nbus_pbuf_allocate(self);
350+
uint8_t txbuf[256] = {0};
351+
uint8_t dstid[4] = {0, 0, 0, 1};
352+
nbus_pbuf_send(txp, txbuf, sizeof(txbuf), dstid, 1);
353+
nbus_pbuf_transmit(txp, self);
354+
nbus_pbuf_release(self, txp);
355+
/* Consume echo until EOT. */
356+
stream_wait_for_eot(self);
357+
358+
continue;
300359

301360
err:
302361
nbus_pbuf_release(self, pbuf);
303-
362+
marker(GPIOE, GPIO10, false);
304363
}
305364
vTaskDelete(NULL);
306365
}
307366

308367

309368
static void nbus_hk_task(void *p) {
310369
Nbus *self = (Nbus *)p;
370+
(void)self;
311371

312372
while (true) {
313373
vTaskDelay(1000);
@@ -363,6 +423,12 @@ struct nbus_pbuf *nbus_pbuf_allocate(Nbus *self) {
363423
if (self->pbufs[i].used == false) {
364424
self->pbufs[i].used = true;
365425
self->pbufs[i].buf_len = 0;
426+
self->pbufs[i].buf_size = NBUS_PBUF_DATA_SIZE;
427+
memset(self->pbufs[i].buf, 0, 24);
428+
429+
/* Prepare keys for the new pbuf */
430+
b2s_derive_keys(self->mac_key, self->mac_key_len, self->pbufs[i].ke, self->pbufs[i].km);
431+
366432
return &(self->pbufs[i]);
367433
}
368434
}

services/nbus2/nbus2.h

-3
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ struct nbus_pbuf {
3535
uint8_t ke[B2S_KE_LEN];
3636
uint8_t km[B2S_KM_LEN];
3737

38-
uint8_t dstid[4];
39-
uint8_t srcid[4];
40-
4138
uint8_t *buf;
4239
size_t buf_size;
4340
size_t buf_len;

0 commit comments

Comments
 (0)