blob: 47baa58d745b59f95488e0f5687c729b93251017 [file] [log] [blame]
Christopher Collins92ea77f2016-12-12 15:59:26 -08001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19#include <assert.h>
20#include <stddef.h>
21#include <inttypes.h>
22#include <ctype.h>
23#include <stdio.h>
24
25#include "sysflash/sysflash.h"
26
Fabio Utzig1a2e41a2017-11-17 12:13:09 -020027#include "bootutil/bootutil_log.h"
28
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020029#ifdef __ZEPHYR__
Andrzej Puzdrowskif1d189c2019-12-12 09:34:11 +010030#include <power/reboot.h>
31#include <sys/byteorder.h>
32#include <sys/__assert.h>
Peter Bigot54c1e3f2020-01-25 05:50:12 -060033#include <drivers/flash.h>
Andrzej Puzdrowskif1d189c2019-12-12 09:34:11 +010034#include <sys/crc.h>
35#include <sys/base64.h>
Dominik Ermel470e2f32020-01-10 13:28:48 +000036#include <tinycbor/cbor.h>
37#include <tinycbor/cbor_buf_reader.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020038#else
Christopher Collins92ea77f2016-12-12 15:59:26 -080039#include <bsp/bsp.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080040#include <hal/hal_system.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080041#include <os/endian.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080042#include <os/os_cputime.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020043#include <crc/crc16.h>
44#include <base64/base64.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080045#include <tinycbor/cbor.h>
46#include <tinycbor/cbor_buf_reader.h>
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +020047#endif /* __ZEPHYR__ */
48
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +020049#include <flash_map_backend/flash_map_backend.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020050#include <hal/hal_flash.h>
51#include <os/os.h>
52#include <os/os_malloc.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080053
54#include <bootutil/image.h>
55
56#include "boot_serial/boot_serial.h"
57#include "boot_serial_priv.h"
58
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +020059#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
60#include "bootutil_priv.h"
61#endif
62
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010063MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
64
Marko Kiiskila149b4572018-06-06 14:18:54 +030065#define BOOT_SERIAL_INPUT_MAX 512
Fabio Utzig6f49c272019-08-23 11:42:58 -030066#define BOOT_SERIAL_OUT_MAX 128
Christopher Collins92ea77f2016-12-12 15:59:26 -080067
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020068#ifdef __ZEPHYR__
Carles Cufi0165be82018-03-26 17:43:51 +020069/* base64 lib encodes data to null-terminated string */
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020070#define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
71
72#define CRC16_INITIAL_CRC 0 /* what to seed crc16 with */
73#define CRC_CITT_POLYMINAL 0x1021
74
75#define ntohs(x) sys_be16_to_cpu(x)
76#define htons(x) sys_cpu_to_be16(x)
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020077#endif
Emanuele Di Santo9f1933d2018-11-20 10:59:59 +010078
Fabio Utzig6f49c272019-08-23 11:42:58 -030079#ifndef BOOT_IMAGE_NUMBER
80#define BOOT_IMAGE_NUMBER MCUBOOT_IMAGE_NUMBER
81#endif
82
83#if (BOOT_IMAGE_NUMBER > 1)
84#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x))
85#else
86#define IMAGES_ITER(x)
87#endif
88
Marko Kiiskila149b4572018-06-06 14:18:54 +030089static char in_buf[BOOT_SERIAL_INPUT_MAX + 1];
90static char dec_buf[BOOT_SERIAL_INPUT_MAX + 1];
Marko Kiiskila8b1ce3a2018-06-14 13:20:46 -070091const struct boot_uart_funcs *boot_uf;
Christopher Collins92ea77f2016-12-12 15:59:26 -080092static uint32_t curr_off;
93static uint32_t img_size;
94static struct nmgr_hdr *bs_hdr;
95
96static char bs_obuf[BOOT_SERIAL_OUT_MAX];
97
98static int bs_cbor_writer(struct cbor_encoder_writer *, const char *data,
99 int len);
100static void boot_serial_output(void);
101
102static struct cbor_encoder_writer bs_writer = {
103 .write = bs_cbor_writer
104};
105static CborEncoder bs_root;
106static CborEncoder bs_rsp;
107
108int
109bs_cbor_writer(struct cbor_encoder_writer *cew, const char *data, int len)
110{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300111 if (cew->bytes_written + len > sizeof(bs_obuf)) {
112 return CborErrorOutOfMemory;
113 }
114
Christopher Collins92ea77f2016-12-12 15:59:26 -0800115 memcpy(&bs_obuf[cew->bytes_written], data, len);
116 cew->bytes_written += len;
117
118 return 0;
119}
120
121/*
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300122 * Convert version into string without use of snprintf().
Christopher Collins92ea77f2016-12-12 15:59:26 -0800123 */
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300124static int
125u32toa(char *tgt, uint32_t val)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800126{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300127 char *dst;
128 uint32_t d = 1;
129 uint32_t dgt;
130 int n = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800131
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300132 dst = tgt;
133 while (val / d >= 10) {
134 d *= 10;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800135 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300136 while (d) {
137 dgt = val / d;
138 val %= d;
139 d /= 10;
140 if (n || dgt > 0 || d == 0) {
141 *dst++ = dgt + '0';
142 ++n;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800143 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800144 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300145 *dst = '\0';
146
147 return dst - tgt;
148}
149
150/*
151 * dst has to be able to fit "255.255.65535.4294967295" (25 characters).
152 */
153static void
154bs_list_img_ver(char *dst, int maxlen, struct image_version *ver)
155{
156 int off;
157
158 off = u32toa(dst, ver->iv_major);
159 dst[off++] = '.';
160 off += u32toa(dst + off, ver->iv_minor);
161 dst[off++] = '.';
162 off += u32toa(dst + off, ver->iv_revision);
163 dst[off++] = '.';
164 off += u32toa(dst + off, ver->iv_build_num);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800165}
166
167/*
168 * List images.
169 */
170static void
171bs_list(char *buf, int len)
172{
173 CborEncoder images;
174 CborEncoder image;
175 struct image_header hdr;
176 uint8_t tmpbuf[64];
Fabio Utzig6f49c272019-08-23 11:42:58 -0300177 int slot, area_id;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800178 const struct flash_area *fap;
Fabio Utzig6f49c272019-08-23 11:42:58 -0300179 uint8_t image_index;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800180
181 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
182 cbor_encode_text_stringz(&bs_rsp, "images");
183 cbor_encoder_create_array(&bs_rsp, &images, CborIndefiniteLength);
Fabio Utzig6f49c272019-08-23 11:42:58 -0300184 image_index = 0;
185 IMAGES_ITER(image_index) {
186 for (slot = 0; slot < 2; slot++) {
187 area_id = flash_area_id_from_multi_image_slot(image_index, slot);
188 if (flash_area_open(area_id, &fap)) {
189 continue;
190 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800191
Fabio Utzig6f49c272019-08-23 11:42:58 -0300192 flash_area_read(fap, 0, &hdr, sizeof(hdr));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800193
Fabio Utzig6f49c272019-08-23 11:42:58 -0300194 if (hdr.ih_magic != IMAGE_MAGIC ||
195 bootutil_img_validate(NULL, 0, &hdr, fap, tmpbuf, sizeof(tmpbuf),
196 NULL, 0, NULL)) {
197 flash_area_close(fap);
198 continue;
199 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800200 flash_area_close(fap);
Fabio Utzig6f49c272019-08-23 11:42:58 -0300201
202 cbor_encoder_create_map(&images, &image, CborIndefiniteLength);
203
204#if (BOOT_IMAGE_NUMBER > 1)
205 cbor_encode_text_stringz(&image, "image");
206 cbor_encode_int(&image, image_index);
207#endif
208
209 cbor_encode_text_stringz(&image, "slot");
210 cbor_encode_int(&image, slot);
211 cbor_encode_text_stringz(&image, "version");
212
213 bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
214 cbor_encode_text_stringz(&image, (char *)tmpbuf);
215 cbor_encoder_close_container(&images, &image);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800216 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800217 }
218 cbor_encoder_close_container(&bs_rsp, &images);
219 cbor_encoder_close_container(&bs_root, &bs_rsp);
220 boot_serial_output();
221}
222
223/*
224 * Image upload request.
225 */
226static void
227bs_upload(char *buf, int len)
228{
229 CborParser parser;
230 struct cbor_buf_reader reader;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300231 struct CborValue root_value;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800232 struct CborValue value;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300233 uint8_t img_data[512];
234 long long int off = UINT_MAX;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800235 size_t img_blen = 0;
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300236 uint8_t rem_bytes;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300237 long long int data_len = UINT_MAX;
Fabio Utzig6f49c272019-08-23 11:42:58 -0300238 int img_num;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300239 size_t slen;
240 char name_str[8];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800241 const struct flash_area *fap = NULL;
242 int rc;
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200243#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
244 static off_t off_last = -1;
245 struct flash_sector sector;
246#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800247
248 memset(img_data, 0, sizeof(img_data));
Fabio Utzig6f49c272019-08-23 11:42:58 -0300249 img_num = 0;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300250
251 /*
252 * Expected data format.
253 * {
Fabio Utzig6f49c272019-08-23 11:42:58 -0300254 * "image":<image number in a multi-image set (OPTIONAL)>
255 * "data":<image data>
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300256 * "len":<image len>
257 * "off":<current offset of image data>
258 * }
259 */
260
261 /*
262 * Object comes within { ... }
263 */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800264 cbor_buf_reader_init(&reader, (uint8_t *)buf, len);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300265 cbor_parser_init(&reader.r, 0, &parser, &root_value);
Dominik Ermel470e2f32020-01-10 13:28:48 +0000266
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300267 if (!cbor_value_is_container(&root_value)) {
268 goto out_invalid_data;
269 }
270 if (cbor_value_enter_container(&root_value, &value)) {
271 goto out_invalid_data;
272 }
273 while (cbor_value_is_valid(&value)) {
274 /*
275 * Decode key.
276 */
277 if (cbor_value_calculate_string_length(&value, &slen)) {
278 goto out_invalid_data;
279 }
280 if (!cbor_value_is_text_string(&value) ||
281 slen >= sizeof(name_str) - 1) {
282 goto out_invalid_data;
283 }
284 if (cbor_value_copy_text_string(&value, name_str, &slen, &value)) {
285 goto out_invalid_data;
286 }
287 name_str[slen] = '\0';
288 if (!strcmp(name_str, "data")) {
289 /*
290 * Image data
291 */
292 if (value.type != CborByteStringType) {
293 goto out_invalid_data;
294 }
295 if (cbor_value_calculate_string_length(&value, &slen) ||
296 slen >= sizeof(img_data)) {
297 goto out_invalid_data;
298 }
299 if (cbor_value_copy_byte_string(&value, img_data, &slen, &value)) {
300 goto out_invalid_data;
301 }
302 img_blen = slen;
303 } else if (!strcmp(name_str, "off")) {
304 /*
305 * Offset of the data.
306 */
307 if (value.type != CborIntegerType) {
308 goto out_invalid_data;
309 }
310 if (cbor_value_get_int64(&value, &off)) {
311 goto out_invalid_data;
312 }
313 if (cbor_value_advance(&value)) {
314 goto out_invalid_data;
315 }
316 } else if (!strcmp(name_str, "len")) {
317 /*
318 * Length of the image. This should only be present in the first
319 * block of data; when offset is 0.
320 */
321 if (value.type != CborIntegerType) {
322 goto out_invalid_data;
323 }
324 if (cbor_value_get_int64(&value, &data_len)) {
325 goto out_invalid_data;
326 }
327 if (cbor_value_advance(&value)) {
328 goto out_invalid_data;
329 }
Fabio Utzig6f49c272019-08-23 11:42:58 -0300330 } else if (!strcmp(name_str, "image")) {
331 /*
332 * In a multi-image system, image number to upload to, if not
333 * present will upload to slot 0 of image set 0.
334 */
335 if (value.type != CborIntegerType) {
336 goto out_invalid_data;
337 }
338 if (cbor_value_get_int(&value, &img_num)) {
339 goto out_invalid_data;
340 }
341 if (cbor_value_advance(&value)) {
342 goto out_invalid_data;
343 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300344 } else {
345 /*
346 * Unknown keys.
347 */
348 if (cbor_value_advance(&value)) {
349 goto out_invalid_data;
350 }
351 }
352 }
353 if (off == UINT_MAX) {
354 /*
355 * Offset must be set in every block.
356 */
357 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800358 }
359
Fabio Utzig6f49c272019-08-23 11:42:58 -0300360 rc = flash_area_open(flash_area_id_from_multi_image_slot(img_num, 0), &fap);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800361 if (rc) {
362 rc = MGMT_ERR_EINVAL;
363 goto out;
364 }
365
366 if (off == 0) {
367 curr_off = 0;
368 if (data_len > fap->fa_size) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300369 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800370 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200371#ifndef CONFIG_BOOT_ERASE_PROGRESSIVELY
Christopher Collins92ea77f2016-12-12 15:59:26 -0800372 rc = flash_area_erase(fap, 0, fap->fa_size);
373 if (rc) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300374 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800375 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200376#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800377 img_size = data_len;
378 }
379 if (off != curr_off) {
380 rc = 0;
381 goto out;
382 }
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300383 if (curr_off + img_blen < img_size) {
384 rem_bytes = img_blen % flash_area_align(fap);
385 if (rem_bytes) {
386 img_blen -= rem_bytes;
387 }
388 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200389
390#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
391 rc = flash_area_sector_from_off(curr_off + img_blen, &sector);
392 if (rc) {
393 BOOT_LOG_ERR("Unable to determine flash sector size");
394 goto out;
395 }
396 if (off_last != sector.fs_off) {
397 off_last = sector.fs_off;
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200398 BOOT_LOG_INF("Erasing sector at offset 0x%x", sector.fs_off);
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200399 rc = flash_area_erase(fap, sector.fs_off, sector.fs_size);
400 if (rc) {
401 BOOT_LOG_ERR("Error %d while erasing sector", rc);
402 goto out;
403 }
404 }
405#endif
406
407 BOOT_LOG_INF("Writing at 0x%x until 0x%x", curr_off, curr_off + img_blen);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800408 rc = flash_area_write(fap, curr_off, img_data, img_blen);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300409 if (rc == 0) {
410 curr_off += img_blen;
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200411#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
412 if (curr_off == img_size) {
413 /* get the last sector offset */
414 rc = flash_area_sector_from_off(boot_status_off(fap), &sector);
415 if (rc) {
416 BOOT_LOG_ERR("Unable to determine flash sector of"
417 "the image trailer");
418 goto out;
419 }
420 /* Assure that sector for image trailer was erased. */
421 /* Check whether it was erased during previous upload. */
422 if (off_last < sector.fs_off) {
423 BOOT_LOG_INF("Erasing sector at offset 0x%x", sector.fs_off);
424 rc = flash_area_erase(fap, sector.fs_off, sector.fs_size);
425 if (rc) {
426 BOOT_LOG_ERR("Error %d while erasing sector", rc);
427 goto out;
428 }
429 }
430 }
431#endif
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300432 } else {
433 out_invalid_data:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800434 rc = MGMT_ERR_EINVAL;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800435 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200436
Christopher Collins92ea77f2016-12-12 15:59:26 -0800437out:
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200438 BOOT_LOG_INF("RX: 0x%x", rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800439 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
440 cbor_encode_text_stringz(&bs_rsp, "rc");
441 cbor_encode_int(&bs_rsp, rc);
442 if (rc == 0) {
443 cbor_encode_text_stringz(&bs_rsp, "off");
444 cbor_encode_uint(&bs_rsp, curr_off);
445 }
446 cbor_encoder_close_container(&bs_root, &bs_rsp);
447
448 boot_serial_output();
449 flash_area_close(fap);
450}
451
452/*
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300453 * Console echo control/image erase. Send empty response, don't do anything.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800454 */
455static void
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300456bs_empty_rsp(char *buf, int len)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800457{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300458 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
459 cbor_encode_text_stringz(&bs_rsp, "rc");
460 cbor_encode_int(&bs_rsp, 0);
461 cbor_encoder_close_container(&bs_root, &bs_rsp);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800462 boot_serial_output();
463}
464
465/*
466 * Reset, and (presumably) boot to newly uploaded image. Flush console
467 * before restarting.
468 */
Andrzej Puzdrowski268cdd02018-04-10 12:57:54 +0200469static void
Christopher Collins92ea77f2016-12-12 15:59:26 -0800470bs_reset(char *buf, int len)
471{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300472 bs_empty_rsp(buf, len);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800473
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200474#ifdef __ZEPHYR__
475 k_sleep(250);
476 sys_reboot(SYS_REBOOT_COLD);
477#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800478 os_cputime_delay_usecs(250000);
479 hal_system_reset();
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200480#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800481}
482
483/*
484 * Parse incoming line of input from console.
485 * Expect newtmgr protocol with serial transport.
486 */
487void
488boot_serial_input(char *buf, int len)
489{
490 struct nmgr_hdr *hdr;
491
492 hdr = (struct nmgr_hdr *)buf;
493 if (len < sizeof(*hdr) ||
494 (hdr->nh_op != NMGR_OP_READ && hdr->nh_op != NMGR_OP_WRITE) ||
495 (ntohs(hdr->nh_len) < len - sizeof(*hdr))) {
496 return;
497 }
498 bs_hdr = hdr;
499 hdr->nh_group = ntohs(hdr->nh_group);
500
501 buf += sizeof(*hdr);
502 len -= sizeof(*hdr);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300503
Christopher Collins92ea77f2016-12-12 15:59:26 -0800504 bs_writer.bytes_written = 0;
505 cbor_encoder_init(&bs_root, &bs_writer, 0);
506
507 /*
508 * Limited support for commands.
509 */
510 if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
511 switch (hdr->nh_id) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300512 case IMGMGR_NMGR_ID_STATE:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800513 bs_list(buf, len);
514 break;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300515 case IMGMGR_NMGR_ID_UPLOAD:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800516 bs_upload(buf, len);
517 break;
518 default:
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300519 bs_empty_rsp(buf, len);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800520 break;
521 }
522 } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
523 switch (hdr->nh_id) {
524 case NMGR_ID_CONS_ECHO_CTRL:
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300525 bs_empty_rsp(buf, len);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800526 break;
527 case NMGR_ID_RESET:
528 bs_reset(buf, len);
529 break;
530 default:
531 break;
532 }
533 }
534}
535
536static void
537boot_serial_output(void)
538{
539 char *data;
540 int len;
541 uint16_t crc;
542 uint16_t totlen;
543 char pkt_start[2] = { SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
544 char buf[BOOT_SERIAL_OUT_MAX];
545 char encoded_buf[BASE64_ENCODE_SIZE(BOOT_SERIAL_OUT_MAX)];
546
547 data = bs_obuf;
548 len = bs_writer.bytes_written;
549
550 bs_hdr->nh_op++;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300551 bs_hdr->nh_flags = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800552 bs_hdr->nh_len = htons(len);
553 bs_hdr->nh_group = htons(bs_hdr->nh_group);
554
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200555#ifdef __ZEPHYR__
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300556 crc = crc16((u8_t *)bs_hdr, sizeof(*bs_hdr), CRC_CITT_POLYMINAL,
557 CRC16_INITIAL_CRC, false);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200558 crc = crc16(data, len, CRC_CITT_POLYMINAL, crc, true);
559#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800560 crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
561 crc = crc16_ccitt(crc, data, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200562#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800563 crc = htons(crc);
564
Marko Kiiskila149b4572018-06-06 14:18:54 +0300565 boot_uf->write(pkt_start, sizeof(pkt_start));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800566
567 totlen = len + sizeof(*bs_hdr) + sizeof(crc);
568 totlen = htons(totlen);
569
570 memcpy(buf, &totlen, sizeof(totlen));
571 totlen = sizeof(totlen);
572 memcpy(&buf[totlen], bs_hdr, sizeof(*bs_hdr));
573 totlen += sizeof(*bs_hdr);
574 memcpy(&buf[totlen], data, len);
575 totlen += len;
576 memcpy(&buf[totlen], &crc, sizeof(crc));
577 totlen += sizeof(crc);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200578#ifdef __ZEPHYR__
579 size_t enc_len;
Carles Cufi0165be82018-03-26 17:43:51 +0200580 base64_encode(encoded_buf, sizeof(encoded_buf), &enc_len, buf, totlen);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200581 totlen = enc_len;
582#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800583 totlen = base64_encode(buf, totlen, encoded_buf, 1);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200584#endif
Marko Kiiskila149b4572018-06-06 14:18:54 +0300585 boot_uf->write(encoded_buf, totlen);
586 boot_uf->write("\n\r", 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200587 BOOT_LOG_INF("TX");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800588}
589
590/*
591 * Returns 1 if full packet has been received.
592 */
593static int
594boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
595{
596 int rc;
597 uint16_t crc;
598 uint16_t len;
Marko Kiiskilae5aeee42018-12-21 15:00:16 +0200599
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200600#ifdef __ZEPHYR__
601 int err;
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200602 err = base64_decode( &out[*out_off], maxout - *out_off, &rc, in, inlen - 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200603 if (err) {
604 return -1;
605 }
606#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800607 if (*out_off + base64_decode_len(in) >= maxout) {
608 return -1;
609 }
610 rc = base64_decode(in, &out[*out_off]);
611 if (rc < 0) {
612 return -1;
613 }
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200614#endif
Fabio Utzig6f49c272019-08-23 11:42:58 -0300615
Christopher Collins92ea77f2016-12-12 15:59:26 -0800616 *out_off += rc;
Fabio Utzig6f49c272019-08-23 11:42:58 -0300617 if (*out_off <= sizeof(uint16_t)) {
618 return 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800619 }
Fabio Utzig6f49c272019-08-23 11:42:58 -0300620
621 len = ntohs(*(uint16_t *)out);
622 if (len != *out_off - sizeof(uint16_t)) {
623 return 0;
624 }
625
626 if (len > *out_off - sizeof(uint16_t)) {
627 len = *out_off - sizeof(uint16_t);
628 }
629
630 out += sizeof(uint16_t);
631#ifdef __ZEPHYR__
632 crc = crc16(out, len, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true);
633#else
634 crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
635#endif
636 if (crc || len <= sizeof(crc)) {
637 return 0;
638 }
639 *out_off -= sizeof(crc);
640 out[*out_off] = '\0';
641
642 return 1;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800643}
644
645/*
646 * Task which waits reading console, expecting to get image over
647 * serial port.
648 */
649void
Marko Kiiskila149b4572018-06-06 14:18:54 +0300650boot_serial_start(const struct boot_uart_funcs *f)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800651{
652 int rc;
653 int off;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800654 int dec_off;
655 int full_line;
Marko Kiiskila149b4572018-06-06 14:18:54 +0300656 int max_input;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800657
Marko Kiiskila149b4572018-06-06 14:18:54 +0300658 boot_uf = f;
Marko Kiiskila149b4572018-06-06 14:18:54 +0300659 max_input = sizeof(in_buf);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800660
661 off = 0;
662 while (1) {
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200663 rc = f->read(in_buf + off, sizeof(in_buf) - off, &full_line);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800664 if (rc <= 0 && !full_line) {
665 continue;
666 }
667 off += rc;
668 if (!full_line) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300669 if (off == max_input) {
670 /*
671 * Full line, no newline yet. Reset the input buffer.
672 */
673 off = 0;
674 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800675 continue;
676 }
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200677 if (in_buf[0] == SHELL_NLIP_PKT_START1 &&
678 in_buf[1] == SHELL_NLIP_PKT_START2) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800679 dec_off = 0;
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200680 rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
681 } else if (in_buf[0] == SHELL_NLIP_DATA_START1 &&
682 in_buf[1] == SHELL_NLIP_DATA_START2) {
683 rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800684 }
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200685
686 /* serve errors: out of decode memory, or bad encoding */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800687 if (rc == 1) {
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200688 boot_serial_input(&dec_buf[2], dec_off - 2);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800689 }
690 off = 0;
691 }
692}