blob: 32b3eb1c6bf6cb54a25d68c5c07a69066170db09 [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__
30#include <misc/reboot.h>
31#include <misc/byteorder.h>
32#include <misc/__assert.h>
33#include <flash.h>
34#include <crc16.h>
Carles Cufi0165be82018-03-26 17:43:51 +020035#include <base64.h>
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +020036#include <cbor.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020037#else
Christopher Collins92ea77f2016-12-12 15:59:26 -080038#include <bsp/bsp.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080039#include <hal/hal_system.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080040#include <os/endian.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080041#include <os/os_cputime.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020042#include <crc/crc16.h>
43#include <base64/base64.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080044#include <tinycbor/cbor.h>
45#include <tinycbor/cbor_buf_reader.h>
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +020046#endif /* __ZEPHYR__ */
47
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +020048#include <flash_map_backend/flash_map_backend.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020049#include <hal/hal_flash.h>
50#include <os/os.h>
51#include <os/os_malloc.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080052
53#include <bootutil/image.h>
54
55#include "boot_serial/boot_serial.h"
56#include "boot_serial_priv.h"
57
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +020058#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
59#include "bootutil_priv.h"
60#endif
61
Marko Kiiskila149b4572018-06-06 14:18:54 +030062#define BOOT_SERIAL_INPUT_MAX 512
Marko Kiiskilace50ab02018-06-06 11:33:33 +030063#define BOOT_SERIAL_OUT_MAX 80
Christopher Collins92ea77f2016-12-12 15:59:26 -080064
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020065#ifdef __ZEPHYR__
Carles Cufi0165be82018-03-26 17:43:51 +020066/* base64 lib encodes data to null-terminated string */
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020067#define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
68
69#define CRC16_INITIAL_CRC 0 /* what to seed crc16 with */
70#define CRC_CITT_POLYMINAL 0x1021
71
72#define ntohs(x) sys_be16_to_cpu(x)
73#define htons(x) sys_cpu_to_be16(x)
74
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020075#endif
Marko Kiiskila149b4572018-06-06 14:18:54 +030076static char in_buf[BOOT_SERIAL_INPUT_MAX + 1];
77static char dec_buf[BOOT_SERIAL_INPUT_MAX + 1];
Marko Kiiskila8b1ce3a2018-06-14 13:20:46 -070078const struct boot_uart_funcs *boot_uf;
Christopher Collins92ea77f2016-12-12 15:59:26 -080079static uint32_t curr_off;
80static uint32_t img_size;
81static struct nmgr_hdr *bs_hdr;
82
83static char bs_obuf[BOOT_SERIAL_OUT_MAX];
84
85static int bs_cbor_writer(struct cbor_encoder_writer *, const char *data,
86 int len);
87static void boot_serial_output(void);
88
89static struct cbor_encoder_writer bs_writer = {
90 .write = bs_cbor_writer
91};
92static CborEncoder bs_root;
93static CborEncoder bs_rsp;
94
95int
96bs_cbor_writer(struct cbor_encoder_writer *cew, const char *data, int len)
97{
Marko Kiiskilace50ab02018-06-06 11:33:33 +030098 if (cew->bytes_written + len > sizeof(bs_obuf)) {
99 return CborErrorOutOfMemory;
100 }
101
Christopher Collins92ea77f2016-12-12 15:59:26 -0800102 memcpy(&bs_obuf[cew->bytes_written], data, len);
103 cew->bytes_written += len;
104
105 return 0;
106}
107
108/*
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300109 * Convert version into string without use of snprintf().
Christopher Collins92ea77f2016-12-12 15:59:26 -0800110 */
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300111static int
112u32toa(char *tgt, uint32_t val)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800113{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300114 char *dst;
115 uint32_t d = 1;
116 uint32_t dgt;
117 int n = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800118
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300119 dst = tgt;
120 while (val / d >= 10) {
121 d *= 10;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800122 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300123 while (d) {
124 dgt = val / d;
125 val %= d;
126 d /= 10;
127 if (n || dgt > 0 || d == 0) {
128 *dst++ = dgt + '0';
129 ++n;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800130 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800131 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300132 *dst = '\0';
133
134 return dst - tgt;
135}
136
137/*
138 * dst has to be able to fit "255.255.65535.4294967295" (25 characters).
139 */
140static void
141bs_list_img_ver(char *dst, int maxlen, struct image_version *ver)
142{
143 int off;
144
145 off = u32toa(dst, ver->iv_major);
146 dst[off++] = '.';
147 off += u32toa(dst + off, ver->iv_minor);
148 dst[off++] = '.';
149 off += u32toa(dst + off, ver->iv_revision);
150 dst[off++] = '.';
151 off += u32toa(dst + off, ver->iv_build_num);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800152}
153
154/*
155 * List images.
156 */
157static void
158bs_list(char *buf, int len)
159{
160 CborEncoder images;
161 CborEncoder image;
162 struct image_header hdr;
163 uint8_t tmpbuf[64];
164 int i, area_id;
165 const struct flash_area *fap;
166
167 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
168 cbor_encode_text_stringz(&bs_rsp, "images");
169 cbor_encoder_create_array(&bs_rsp, &images, CborIndefiniteLength);
170 for (i = 0; i < 2; i++) {
171 area_id = flash_area_id_from_image_slot(i);
172 if (flash_area_open(area_id, &fap)) {
173 continue;
174 }
175
176 flash_area_read(fap, 0, &hdr, sizeof(hdr));
177
178 if (hdr.ih_magic != IMAGE_MAGIC ||
179 bootutil_img_validate(&hdr, fap, tmpbuf, sizeof(tmpbuf),
180 NULL, 0, NULL)) {
181 flash_area_close(fap);
182 continue;
183 }
184 flash_area_close(fap);
185
186 cbor_encoder_create_map(&images, &image, CborIndefiniteLength);
187 cbor_encode_text_stringz(&image, "slot");
188 cbor_encode_int(&image, i);
189 cbor_encode_text_stringz(&image, "version");
190
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300191 bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800192 cbor_encode_text_stringz(&image, (char *)tmpbuf);
193 cbor_encoder_close_container(&images, &image);
194 }
195 cbor_encoder_close_container(&bs_rsp, &images);
196 cbor_encoder_close_container(&bs_root, &bs_rsp);
197 boot_serial_output();
198}
199
200/*
201 * Image upload request.
202 */
203static void
204bs_upload(char *buf, int len)
205{
206 CborParser parser;
207 struct cbor_buf_reader reader;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300208 struct CborValue root_value;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800209 struct CborValue value;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300210 uint8_t img_data[512];
211 long long int off = UINT_MAX;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800212 size_t img_blen = 0;
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300213 uint8_t rem_bytes;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300214 long long int data_len = UINT_MAX;
215 size_t slen;
216 char name_str[8];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800217 const struct flash_area *fap = NULL;
218 int rc;
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200219#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
220 static off_t off_last = -1;
221 struct flash_sector sector;
222#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800223
224 memset(img_data, 0, sizeof(img_data));
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300225
226 /*
227 * Expected data format.
228 * {
229 * "data":<img_data>
230 * "len":<image len>
231 * "off":<current offset of image data>
232 * }
233 */
234
235 /*
236 * Object comes within { ... }
237 */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800238 cbor_buf_reader_init(&reader, (uint8_t *)buf, len);
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +0200239#ifdef __ZEPHYR__
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300240 cbor_parser_cust_reader_init(&reader.r, 0, &parser, &root_value);
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +0200241#else
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300242 cbor_parser_init(&reader.r, 0, &parser, &root_value);
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +0200243#endif
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300244 if (!cbor_value_is_container(&root_value)) {
245 goto out_invalid_data;
246 }
247 if (cbor_value_enter_container(&root_value, &value)) {
248 goto out_invalid_data;
249 }
250 while (cbor_value_is_valid(&value)) {
251 /*
252 * Decode key.
253 */
254 if (cbor_value_calculate_string_length(&value, &slen)) {
255 goto out_invalid_data;
256 }
257 if (!cbor_value_is_text_string(&value) ||
258 slen >= sizeof(name_str) - 1) {
259 goto out_invalid_data;
260 }
261 if (cbor_value_copy_text_string(&value, name_str, &slen, &value)) {
262 goto out_invalid_data;
263 }
264 name_str[slen] = '\0';
265 if (!strcmp(name_str, "data")) {
266 /*
267 * Image data
268 */
269 if (value.type != CborByteStringType) {
270 goto out_invalid_data;
271 }
272 if (cbor_value_calculate_string_length(&value, &slen) ||
273 slen >= sizeof(img_data)) {
274 goto out_invalid_data;
275 }
276 if (cbor_value_copy_byte_string(&value, img_data, &slen, &value)) {
277 goto out_invalid_data;
278 }
279 img_blen = slen;
280 } else if (!strcmp(name_str, "off")) {
281 /*
282 * Offset of the data.
283 */
284 if (value.type != CborIntegerType) {
285 goto out_invalid_data;
286 }
287 if (cbor_value_get_int64(&value, &off)) {
288 goto out_invalid_data;
289 }
290 if (cbor_value_advance(&value)) {
291 goto out_invalid_data;
292 }
293 } else if (!strcmp(name_str, "len")) {
294 /*
295 * Length of the image. This should only be present in the first
296 * block of data; when offset is 0.
297 */
298 if (value.type != CborIntegerType) {
299 goto out_invalid_data;
300 }
301 if (cbor_value_get_int64(&value, &data_len)) {
302 goto out_invalid_data;
303 }
304 if (cbor_value_advance(&value)) {
305 goto out_invalid_data;
306 }
307 } else {
308 /*
309 * Unknown keys.
310 */
311 if (cbor_value_advance(&value)) {
312 goto out_invalid_data;
313 }
314 }
315 }
316 if (off == UINT_MAX) {
317 /*
318 * Offset must be set in every block.
319 */
320 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800321 }
322
Christopher Collins92ea77f2016-12-12 15:59:26 -0800323 rc = flash_area_open(flash_area_id_from_image_slot(0), &fap);
324 if (rc) {
325 rc = MGMT_ERR_EINVAL;
326 goto out;
327 }
328
329 if (off == 0) {
330 curr_off = 0;
331 if (data_len > fap->fa_size) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300332 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800333 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200334#ifndef CONFIG_BOOT_ERASE_PROGRESSIVELY
Christopher Collins92ea77f2016-12-12 15:59:26 -0800335 rc = flash_area_erase(fap, 0, fap->fa_size);
336 if (rc) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300337 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800338 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200339#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800340 img_size = data_len;
341 }
342 if (off != curr_off) {
343 rc = 0;
344 goto out;
345 }
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300346 if (curr_off + img_blen < img_size) {
347 rem_bytes = img_blen % flash_area_align(fap);
348 if (rem_bytes) {
349 img_blen -= rem_bytes;
350 }
351 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200352
353#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
354 rc = flash_area_sector_from_off(curr_off + img_blen, &sector);
355 if (rc) {
356 BOOT_LOG_ERR("Unable to determine flash sector size");
357 goto out;
358 }
359 if (off_last != sector.fs_off) {
360 off_last = sector.fs_off;
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200361 BOOT_LOG_INF("Erasing sector at offset 0x%x", sector.fs_off);
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200362 rc = flash_area_erase(fap, sector.fs_off, sector.fs_size);
363 if (rc) {
364 BOOT_LOG_ERR("Error %d while erasing sector", rc);
365 goto out;
366 }
367 }
368#endif
369
370 BOOT_LOG_INF("Writing at 0x%x until 0x%x", curr_off, curr_off + img_blen);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800371 rc = flash_area_write(fap, curr_off, img_data, img_blen);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300372 if (rc == 0) {
373 curr_off += img_blen;
Andrzej Puzdrowskic2e30cf2018-07-20 16:19:09 +0200374#ifdef CONFIG_BOOT_ERASE_PROGRESSIVELY
375 if (curr_off == img_size) {
376 /* get the last sector offset */
377 rc = flash_area_sector_from_off(boot_status_off(fap), &sector);
378 if (rc) {
379 BOOT_LOG_ERR("Unable to determine flash sector of"
380 "the image trailer");
381 goto out;
382 }
383 /* Assure that sector for image trailer was erased. */
384 /* Check whether it was erased during previous upload. */
385 if (off_last < sector.fs_off) {
386 BOOT_LOG_INF("Erasing sector at offset 0x%x", sector.fs_off);
387 rc = flash_area_erase(fap, sector.fs_off, sector.fs_size);
388 if (rc) {
389 BOOT_LOG_ERR("Error %d while erasing sector", rc);
390 goto out;
391 }
392 }
393 }
394#endif
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300395 } else {
396 out_invalid_data:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800397 rc = MGMT_ERR_EINVAL;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800398 }
Emanuele Di Santo205c8c62018-07-20 11:42:31 +0200399
Christopher Collins92ea77f2016-12-12 15:59:26 -0800400out:
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200401 BOOT_LOG_INF("RX: 0x%x", rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800402 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
403 cbor_encode_text_stringz(&bs_rsp, "rc");
404 cbor_encode_int(&bs_rsp, rc);
405 if (rc == 0) {
406 cbor_encode_text_stringz(&bs_rsp, "off");
407 cbor_encode_uint(&bs_rsp, curr_off);
408 }
409 cbor_encoder_close_container(&bs_root, &bs_rsp);
410
411 boot_serial_output();
412 flash_area_close(fap);
413}
414
415/*
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300416 * Console echo control/image erase. Send empty response, don't do anything.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800417 */
418static void
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300419bs_empty_rsp(char *buf, int len)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800420{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300421 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
422 cbor_encode_text_stringz(&bs_rsp, "rc");
423 cbor_encode_int(&bs_rsp, 0);
424 cbor_encoder_close_container(&bs_root, &bs_rsp);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800425 boot_serial_output();
426}
427
428/*
429 * Reset, and (presumably) boot to newly uploaded image. Flush console
430 * before restarting.
431 */
Andrzej Puzdrowski268cdd02018-04-10 12:57:54 +0200432static void
Christopher Collins92ea77f2016-12-12 15:59:26 -0800433bs_reset(char *buf, int len)
434{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300435 bs_empty_rsp(buf, len);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800436
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200437#ifdef __ZEPHYR__
438 k_sleep(250);
439 sys_reboot(SYS_REBOOT_COLD);
440#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800441 os_cputime_delay_usecs(250000);
442 hal_system_reset();
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200443#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800444}
445
446/*
447 * Parse incoming line of input from console.
448 * Expect newtmgr protocol with serial transport.
449 */
450void
451boot_serial_input(char *buf, int len)
452{
453 struct nmgr_hdr *hdr;
454
455 hdr = (struct nmgr_hdr *)buf;
456 if (len < sizeof(*hdr) ||
457 (hdr->nh_op != NMGR_OP_READ && hdr->nh_op != NMGR_OP_WRITE) ||
458 (ntohs(hdr->nh_len) < len - sizeof(*hdr))) {
459 return;
460 }
461 bs_hdr = hdr;
462 hdr->nh_group = ntohs(hdr->nh_group);
463
464 buf += sizeof(*hdr);
465 len -= sizeof(*hdr);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300466
Christopher Collins92ea77f2016-12-12 15:59:26 -0800467 bs_writer.bytes_written = 0;
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +0200468#ifdef __ZEPHYR__
469 cbor_encoder_cust_writer_init(&bs_root, &bs_writer, 0);
470#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800471 cbor_encoder_init(&bs_root, &bs_writer, 0);
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +0200472#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800473
474 /*
475 * Limited support for commands.
476 */
477 if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
478 switch (hdr->nh_id) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300479 case IMGMGR_NMGR_ID_STATE:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800480 bs_list(buf, len);
481 break;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300482 case IMGMGR_NMGR_ID_UPLOAD:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800483 bs_upload(buf, len);
484 break;
485 default:
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300486 bs_empty_rsp(buf, len);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800487 break;
488 }
489 } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
490 switch (hdr->nh_id) {
491 case NMGR_ID_CONS_ECHO_CTRL:
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300492 bs_empty_rsp(buf, len);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800493 break;
494 case NMGR_ID_RESET:
495 bs_reset(buf, len);
496 break;
497 default:
498 break;
499 }
500 }
501}
502
503static void
504boot_serial_output(void)
505{
506 char *data;
507 int len;
508 uint16_t crc;
509 uint16_t totlen;
510 char pkt_start[2] = { SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
511 char buf[BOOT_SERIAL_OUT_MAX];
512 char encoded_buf[BASE64_ENCODE_SIZE(BOOT_SERIAL_OUT_MAX)];
513
514 data = bs_obuf;
515 len = bs_writer.bytes_written;
516
517 bs_hdr->nh_op++;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300518 bs_hdr->nh_flags = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800519 bs_hdr->nh_len = htons(len);
520 bs_hdr->nh_group = htons(bs_hdr->nh_group);
521
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200522#ifdef __ZEPHYR__
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300523 crc = crc16((u8_t *)bs_hdr, sizeof(*bs_hdr), CRC_CITT_POLYMINAL,
524 CRC16_INITIAL_CRC, false);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200525 crc = crc16(data, len, CRC_CITT_POLYMINAL, crc, true);
526#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800527 crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
528 crc = crc16_ccitt(crc, data, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200529#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800530 crc = htons(crc);
531
Marko Kiiskila149b4572018-06-06 14:18:54 +0300532 boot_uf->write(pkt_start, sizeof(pkt_start));
Christopher Collins92ea77f2016-12-12 15:59:26 -0800533
534 totlen = len + sizeof(*bs_hdr) + sizeof(crc);
535 totlen = htons(totlen);
536
537 memcpy(buf, &totlen, sizeof(totlen));
538 totlen = sizeof(totlen);
539 memcpy(&buf[totlen], bs_hdr, sizeof(*bs_hdr));
540 totlen += sizeof(*bs_hdr);
541 memcpy(&buf[totlen], data, len);
542 totlen += len;
543 memcpy(&buf[totlen], &crc, sizeof(crc));
544 totlen += sizeof(crc);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200545#ifdef __ZEPHYR__
546 size_t enc_len;
Carles Cufi0165be82018-03-26 17:43:51 +0200547 base64_encode(encoded_buf, sizeof(encoded_buf), &enc_len, buf, totlen);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200548 totlen = enc_len;
549#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800550 totlen = base64_encode(buf, totlen, encoded_buf, 1);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200551#endif
Marko Kiiskila149b4572018-06-06 14:18:54 +0300552 boot_uf->write(encoded_buf, totlen);
553 boot_uf->write("\n\r", 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200554 BOOT_LOG_INF("TX");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800555}
556
557/*
558 * Returns 1 if full packet has been received.
559 */
560static int
561boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
562{
563 int rc;
564 uint16_t crc;
565 uint16_t len;
Marko Kiiskilae5aeee42018-12-21 15:00:16 +0200566
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200567#ifdef __ZEPHYR__
568 int err;
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200569 err = base64_decode( &out[*out_off], maxout - *out_off, &rc, in, inlen - 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200570 if (err) {
571 return -1;
572 }
573#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800574 if (*out_off + base64_decode_len(in) >= maxout) {
575 return -1;
576 }
577 rc = base64_decode(in, &out[*out_off]);
578 if (rc < 0) {
579 return -1;
580 }
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200581#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800582 *out_off += rc;
583
584 if (*out_off > sizeof(uint16_t)) {
585 len = ntohs(*(uint16_t *)out);
Marko Kiiskilae5aeee42018-12-21 15:00:16 +0200586 if (len != *out_off - sizeof(uint16_t)) {
587 return 0;
588 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800589 len = min(len, *out_off - sizeof(uint16_t));
590 out += sizeof(uint16_t);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200591#ifdef __ZEPHYR__
592 crc = crc16(out, len, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true);
593#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800594 crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200595#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800596 if (crc || len <= sizeof(crc)) {
597 return 0;
598 }
599 *out_off -= sizeof(crc);
600 out[*out_off] = '\0';
601
602 return 1;
603 }
604 return 0;
605}
606
607/*
608 * Task which waits reading console, expecting to get image over
609 * serial port.
610 */
611void
Marko Kiiskila149b4572018-06-06 14:18:54 +0300612boot_serial_start(const struct boot_uart_funcs *f)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800613{
614 int rc;
615 int off;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800616 int dec_off;
617 int full_line;
Marko Kiiskila149b4572018-06-06 14:18:54 +0300618 int max_input;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800619
Marko Kiiskila149b4572018-06-06 14:18:54 +0300620 boot_uf = f;
Marko Kiiskila149b4572018-06-06 14:18:54 +0300621 max_input = sizeof(in_buf);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800622
623 off = 0;
624 while (1) {
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200625 rc = f->read(in_buf + off, sizeof(in_buf) - off, &full_line);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800626 if (rc <= 0 && !full_line) {
627 continue;
628 }
629 off += rc;
630 if (!full_line) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300631 if (off == max_input) {
632 /*
633 * Full line, no newline yet. Reset the input buffer.
634 */
635 off = 0;
636 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800637 continue;
638 }
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200639 if (in_buf[0] == SHELL_NLIP_PKT_START1 &&
640 in_buf[1] == SHELL_NLIP_PKT_START2) {
Christopher Collins92ea77f2016-12-12 15:59:26 -0800641 dec_off = 0;
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200642 rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
643 } else if (in_buf[0] == SHELL_NLIP_DATA_START1 &&
644 in_buf[1] == SHELL_NLIP_DATA_START2) {
645 rc = boot_serial_in_dec(&in_buf[2], off - 2, dec_buf, &dec_off, max_input);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800646 }
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200647
648 /* serve errors: out of decode memory, or bad encoding */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800649 if (rc == 1) {
Andrzej Puzdrowskiec1e4d12018-06-18 14:36:14 +0200650 boot_serial_input(&dec_buf[2], dec_off - 2);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800651 }
652 off = 0;
653 }
654}