Contiki-NG
Loading...
Searching...
No Matches
border-router-cbor.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024, RISE Research Institutes of Sweden
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * \file
33 * CBOR-over-SLIP protocol implementation for the native border
34 * router talking to the serialradio firmware.
35 * \author
36 * Joakim Eriksson <joakim.eriksson@ri.se>
37 */
38
39#include "contiki.h"
40#include "border-router.h"
41
42#if BORDER_ROUTER_SERIAL_RADIO
43
44#include "border-router-cbor.h"
45#include "lib/cbor.h"
46#include "lib/crc16.h"
47#include "net/netstack.h"
48#include "net/packetbuf.h"
49#include <string.h>
50
51/*---------------------------------------------------------------------------*/
52/* Log configuration */
53#include "sys/log.h"
54#define LOG_MODULE "BR-CBOR"
55#define LOG_LEVEL LOG_LEVEL_NONE
56
57/* TX status report from border-router-mac.c */
58void packet_sent(uint8_t sessionid, uint8_t status, uint8_t tx);
59
60/* Largest CBOR message we build: a full 802.15.4 frame plus map overhead and
61 * the trailing CRC16. */
62#define BR_CBOR_BUF_SIZE 280
63
64/*---------------------------------------------------------------------------*/
65/* Append a CRC16 (little-endian) to an encoded CBOR message and write the
66 * result to SLIP. The buffer must have room for the two trailing CRC bytes. */
67static void
68cbor_frame_send(uint8_t *buf, size_t len)
69{
70 uint16_t crc;
71
72 if(len == 0 || len + 2 > BR_CBOR_BUF_SIZE) {
73 LOG_WARN("dropping oversized CBOR frame (%u bytes)\n", (unsigned)len);
74 return;
75 }
76
77 crc = crc16_data(buf, len, 0);
78 buf[len] = crc & 0xff;
79 buf[len + 1] = (crc >> 8) & 0xff;
80
81 write_to_slip(buf, (int)(len + 2));
82}
83/*---------------------------------------------------------------------------*/
84void
85br_cbor_send_tx_frame(uint8_t msg_id, const uint8_t *frame, uint16_t len)
86{
87 static uint8_t buf[BR_CBOR_BUF_SIZE];
89
90 cbor_init_writer(&writer, buf, BR_CBOR_BUF_SIZE - 2);
91 cbor_open_map(&writer);
92 cbor_write_text(&writer, "t", 1);
93 cbor_write_unsigned(&writer, SRADIO_CMD_TX_RAW_FRAME);
94 cbor_write_text(&writer, "i", 1);
95 cbor_write_unsigned(&writer, msg_id);
96 cbor_write_text(&writer, "f", 1);
97 cbor_write_data(&writer, frame, len);
98 cbor_close_map(&writer);
99
100 cbor_frame_send(buf, cbor_end_writer(&writer));
101}
102/*---------------------------------------------------------------------------*/
103void
104br_cbor_send_set_param(uint8_t msg_id, uint16_t param, int32_t value)
105{
106 static uint8_t buf[BR_CBOR_BUF_SIZE];
107 cbor_writer_state_t writer;
108
109 cbor_init_writer(&writer, buf, BR_CBOR_BUF_SIZE - 2);
110 cbor_open_map(&writer);
111 cbor_write_text(&writer, "t", 1);
112 cbor_write_unsigned(&writer, SRADIO_CMD_SET_PARAM);
113 cbor_write_text(&writer, "i", 1);
114 cbor_write_unsigned(&writer, msg_id);
115 cbor_write_text(&writer, "p", 1);
116 cbor_write_unsigned(&writer, param);
117 cbor_write_text(&writer, "v", 1);
118 cbor_write_signed(&writer, value);
119 cbor_close_map(&writer);
120
121 cbor_frame_send(buf, cbor_end_writer(&writer));
122}
123/*---------------------------------------------------------------------------*/
124void
125br_cbor_send_get_addr64(uint8_t msg_id)
126{
127 static uint8_t buf[BR_CBOR_BUF_SIZE];
128 cbor_writer_state_t writer;
129
130 cbor_init_writer(&writer, buf, BR_CBOR_BUF_SIZE - 2);
131 cbor_open_map(&writer);
132 cbor_write_text(&writer, "t", 1);
133 cbor_write_unsigned(&writer, SRADIO_CMD_GET_ADDR64);
134 cbor_write_text(&writer, "i", 1);
135 cbor_write_unsigned(&writer, msg_id);
136 cbor_close_map(&writer);
137
138 cbor_frame_send(buf, cbor_end_writer(&writer));
139}
140/*---------------------------------------------------------------------------*/
141void
142br_cbor_send_router_mode(uint8_t msg_id, bool enable)
143{
144 static uint8_t buf[BR_CBOR_BUF_SIZE];
145 cbor_writer_state_t writer;
146
147 cbor_init_writer(&writer, buf, BR_CBOR_BUF_SIZE - 2);
148 cbor_open_map(&writer);
149 cbor_write_text(&writer, "t", 1);
150 cbor_write_unsigned(&writer, SRADIO_CMD_ROUTER_MODE);
151 cbor_write_text(&writer, "i", 1);
152 cbor_write_unsigned(&writer, msg_id);
153 cbor_write_text(&writer, "v", 1);
154 cbor_write_unsigned(&writer, enable ? 1 : 0);
155 cbor_close_map(&writer);
156
157 cbor_frame_send(buf, cbor_end_writer(&writer));
158}
159/*---------------------------------------------------------------------------*/
160/* os/lib/cbor has no skip primitive; provide a minimal recursive one so that
161 * unknown map keys can be stepped over. */
162static bool
163cbor_skip_value(cbor_reader_state_t *reader)
164{
165 cbor_major_type_t type = cbor_peek_next(reader);
166 uint64_t uval;
167 int64_t ival;
168 size_t len;
169
170 switch(type) {
171 case CBOR_MAJOR_TYPE_UNSIGNED:
172 return cbor_read_unsigned(reader, &uval) != CBOR_SIZE_NONE;
173 case CBOR_MAJOR_TYPE_SIGNED:
174 return cbor_read_signed(reader, &ival) != CBOR_SIZE_NONE;
175 case CBOR_MAJOR_TYPE_BYTE_STRING:
176 return cbor_read_data(reader, &len) != NULL;
177 case CBOR_MAJOR_TYPE_TEXT_STRING:
178 return cbor_read_text(reader, &len) != NULL;
179 case CBOR_MAJOR_TYPE_ARRAY:
180 len = cbor_read_array(reader);
181 if(len == SIZE_MAX) {
182 return false;
183 }
184 for(size_t i = 0; i < len; i++) {
185 if(!cbor_skip_value(reader)) {
186 return false;
187 }
188 }
189 return true;
190 case CBOR_MAJOR_TYPE_MAP:
191 len = cbor_read_map(reader);
192 if(len == SIZE_MAX) {
193 return false;
194 }
195 for(size_t i = 0; i < len; i++) {
196 if(!cbor_skip_value(reader) || !cbor_skip_value(reader)) {
197 return false;
198 }
199 }
200 return true;
201 case CBOR_MAJOR_TYPE_SIMPLE:
202 return cbor_read_simple(reader) != CBOR_SIMPLE_VALUE_NONE;
203 default:
204 return false;
205 }
206}
207/*---------------------------------------------------------------------------*/
208void
209border_router_cbor_input(const uint8_t *data, int len)
210{
211 cbor_reader_state_t reader;
212 size_t num_pairs;
213 uint16_t received_crc, computed_crc;
214 uint8_t msg_type = 0;
215 uint8_t msg_id = 0;
216 uint16_t param = 0;
217 int32_t value = 0;
218 int16_t rssi = 0;
219 uint8_t lqi = 0;
220 uint8_t error_code = 0;
221 const uint8_t *frame = NULL;
222 size_t frame_len = 0;
223
224 /* Verify the trailing CRC16 (little-endian, computed over the CBOR). */
225 if(len < 3) {
226 return;
227 }
228 received_crc = data[len - 2] | (data[len - 1] << 8);
229 computed_crc = crc16_data(data, len - 2, 0);
230 if(received_crc != computed_crc) {
231 LOG_WARN("CRC mismatch: got 0x%04x expected 0x%04x\n",
232 received_crc, computed_crc);
233 return;
234 }
235
236 cbor_init_reader(&reader, data, len - 2);
237 num_pairs = cbor_read_map(&reader);
238 if(num_pairs == SIZE_MAX) {
239 LOG_WARN("not a CBOR map\n");
240 return;
241 }
242
243 for(size_t i = 0; i < num_pairs; i++) {
244 const char *key;
245 size_t key_len;
246 uint64_t u;
247 int64_t s;
248
249 key = cbor_read_text(&reader, &key_len);
250 if(key == NULL || key_len != 1) {
251 if(key == NULL || !cbor_skip_value(&reader)) {
252 return;
253 }
254 continue;
255 }
256
257 switch(key[0]) {
258 case 't':
259 if(cbor_read_unsigned(&reader, &u) != CBOR_SIZE_NONE) {
260 msg_type = (uint8_t)u;
261 }
262 break;
263 case 'i':
264 if(cbor_read_unsigned(&reader, &u) != CBOR_SIZE_NONE) {
265 msg_id = (uint8_t)u;
266 }
267 break;
268 case 'p':
269 if(cbor_read_unsigned(&reader, &u) != CBOR_SIZE_NONE) {
270 param = (uint16_t)u;
271 }
272 break;
273 case 'v':
274 if(cbor_read_signed(&reader, &s) != CBOR_SIZE_NONE) {
275 value = (int32_t)s;
276 }
277 break;
278 case 'r':
279 if(cbor_read_signed(&reader, &s) != CBOR_SIZE_NONE) {
280 rssi = (int16_t)s;
281 }
282 break;
283 case 'l':
284 if(cbor_read_unsigned(&reader, &u) != CBOR_SIZE_NONE) {
285 lqi = (uint8_t)u;
286 }
287 break;
288 case 'x':
289 if(cbor_read_unsigned(&reader, &u) != CBOR_SIZE_NONE) {
290 error_code = (uint8_t)u;
291 }
292 break;
293 case 'f':
294 frame = cbor_read_data(&reader, &frame_len);
295 if(frame == NULL) {
296 return;
297 }
298 break;
299 default:
300 if(!cbor_skip_value(&reader)) {
301 return;
302 }
303 break;
304 }
305 }
306
307 switch(msg_type) {
308 case SRADIO_EVT_RX_FRAME:
309 if(frame != NULL && frame_len > 0) {
310 if(frame_len > PACKETBUF_SIZE) {
311 /* Would be silently truncated by packetbuf_copyfrom(); drop instead of
312 injecting a mangled frame into the network stack. */
313 LOG_WARN("RX frame too large (%u > %u), dropping\n",
314 (unsigned)frame_len, (unsigned)PACKETBUF_SIZE);
315 break;
316 }
317 packetbuf_copyfrom(frame, frame_len);
318 packetbuf_set_attr(PACKETBUF_ATTR_RSSI, rssi);
319 packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, lqi);
320 NETSTACK_MAC.input();
321 }
322 break;
323
324 case SRADIO_EVT_TX_RESPONSE:
325 packet_sent(msg_id, (uint8_t)value, 1);
326 break;
327
328 case SRADIO_EVT_ADDR64_RESPONSE:
329 if(frame != NULL && frame_len == 8) {
330 LOG_INFO("Got radio EUI-64\n");
331 border_router_set_mac(frame);
332 } else {
333 LOG_WARN("ADDR64 response with bad length %u\n", (unsigned)frame_len);
334 }
335 break;
336
337 case SRADIO_EVT_PARAM_RESPONSE:
338 LOG_DBG("Param %u = %ld\n", param, (long)value);
339 break;
340
341 case SRADIO_EVT_HEARTBEAT:
342 LOG_DBG("Radio heartbeat\n");
343 break;
344
345 case SRADIO_EVT_PONG:
346 LOG_DBG("Radio pong\n");
347 break;
348
349 case SRADIO_EVT_ERROR:
350 LOG_WARN("Radio reported error %u\n", error_code);
351 break;
352
353 default:
354 LOG_DBG("Unhandled radio message type %u\n", msg_type);
355 break;
356 }
357}
358/*---------------------------------------------------------------------------*/
359
360#endif /* BORDER_ROUTER_SERIAL_RADIO */
CBOR-over-SLIP protocol for talking to the serialradio firmware (examples/serialradio) from the nativ...
void br_cbor_send_router_mode(uint8_t msg_id, bool enable)
Enable or disable border-router radio mode (ROUTER_MODE).
void br_cbor_send_get_addr64(uint8_t msg_id)
Request the radio's EUI-64 link-layer address (GET_ADDR64).
void br_cbor_send_tx_frame(uint8_t msg_id, const uint8_t *frame, uint16_t len)
Send a raw 802.15.4 frame to the radio for transmission.
void br_cbor_send_set_param(uint8_t msg_id, uint16_t param, int32_t value)
Set a radio parameter on the serial radio (SET_PARAM).
void border_router_cbor_input(const uint8_t *data, int len)
Parse and dispatch a complete CBOR frame (including trailing CRC16) received from the serial radio.
Border router header file.
CBOR API.
Header file for the CRC16 calculcation.
size_t cbor_end_writer(cbor_writer_state_t *state)
Finishes writing CBOR output.
Definition cbor.c:54
void cbor_open_map(cbor_writer_state_t *state)
Adds subsequent entries to a map.
Definition cbor.c:276
cbor_size_t cbor_read_signed(cbor_reader_state_t *state, int64_t *value)
Reads a signed integer.
Definition cbor.c:373
size_t cbor_read_array(cbor_reader_state_t *state)
Reads the number of elements of an array.
Definition cbor.c:451
cbor_major_type_t
Enumeration of major types.
Definition cbor.h:75
cbor_size_t cbor_read_unsigned(cbor_reader_state_t *state, uint64_t *value)
Reads an unsigned integer.
Definition cbor.c:364
cbor_simple_value_t cbor_read_simple(cbor_reader_state_t *state)
Reads a simple value.
Definition cbor.c:429
void cbor_write_text(cbor_writer_state_t *state, const char *text, size_t text_size)
Appends a text string.
Definition cbor.c:196
void cbor_write_unsigned(cbor_writer_state_t *state, uint64_t value)
Appends an unsigned integer.
Definition cbor.c:169
cbor_major_type_t cbor_peek_next(cbor_reader_state_t *state)
Inspects the next major type.
Definition cbor.c:301
const uint8_t * cbor_read_data(cbor_reader_state_t *state, size_t *data_size)
Reads a byte string.
Definition cbor.c:411
void cbor_close_map(cbor_writer_state_t *state)
Stops adding subsequent entries to the innermost map.
Definition cbor.c:282
void cbor_init_writer(cbor_writer_state_t *state, uint8_t *buffer, size_t buffer_size)
Prepares for writing CBOR output.
Definition cbor.c:44
void cbor_init_reader(cbor_reader_state_t *state, const uint8_t *cbor, size_t cbor_size)
Prepares for reading CBOR input.
Definition cbor.c:293
void cbor_write_data(cbor_writer_state_t *state, const uint8_t *data, size_t data_size)
Appends a byte string.
Definition cbor.c:187
void cbor_write_signed(cbor_writer_state_t *state, int64_t value)
Appends a signed integer.
Definition cbor.c:176
size_t cbor_read_map(cbor_reader_state_t *state)
Reads the number of entries of a map.
Definition cbor.c:460
const char * cbor_read_text(cbor_reader_state_t *state, size_t *text_size)
Reads a text string.
Definition cbor.c:420
@ CBOR_SIZE_NONE
error condition
Definition cbor.h:101
static int value(int type)
unsigned short crc16_data(const unsigned char *data, int len, unsigned short acc)
Calculate the CRC16 over a data area.
Definition crc16.c:66
int packetbuf_copyfrom(const void *from, uint16_t len)
Copy from external data into the packetbuf.
Definition packetbuf.c:84
#define PACKETBUF_SIZE
The size of the packetbuf, in bytes.
Definition packetbuf.h:67
static void packet_sent(void *ptr, int status, int transmissions)
Callback function for the MAC packet sent callback.
Header file for the logging system.
Include file for the Contiki low-layer network stack (NETSTACK).
Header file for the Packet buffer (packetbuf) management.
Structure of the internal state of a CBOR reader.
Definition cbor.h:130
Structure of the internal state of a CBOR writer.
Definition cbor.h:119