blob: e67e68d1044db8c807e9ebef99cd589335170909 [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>
35#include <serial_adapter/serial_adapter.h>
Carles Cufi0165be82018-03-26 17:43:51 +020036#include <base64.h>
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +020037#include <cbor.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>
Marko Kiiskilace50ab02018-06-06 11:33:33 +030043#include <boot_uart/boot_uart.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020044#include <crc/crc16.h>
45#include <base64/base64.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080046#include <tinycbor/cbor.h>
47#include <tinycbor/cbor_buf_reader.h>
Marko Kiiskilace50ab02018-06-06 11:33:33 +030048
49#define console_write boot_uart_write
50#define console_read boot_uart_read
51
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +020052#endif /* __ZEPHYR__ */
53
Christopher Collins92ea77f2016-12-12 15:59:26 -080054#include <cborattr/cborattr.h>
Andrzej Puzdrowskib788c712018-04-12 12:42:49 +020055#include <flash_map_backend/flash_map_backend.h>
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020056#include <hal/hal_flash.h>
57#include <os/os.h>
58#include <os/os_malloc.h>
Christopher Collins92ea77f2016-12-12 15:59:26 -080059
60#include <bootutil/image.h>
61
62#include "boot_serial/boot_serial.h"
63#include "boot_serial_priv.h"
64
Marko Kiiskilace50ab02018-06-06 11:33:33 +030065#define BOOT_SERIAL_OUT_MAX 80
Christopher Collins92ea77f2016-12-12 15:59:26 -080066
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020067#ifdef __ZEPHYR__
Carles Cufi0165be82018-03-26 17:43:51 +020068/* base64 lib encodes data to null-terminated string */
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +020069#define BASE64_ENCODE_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)
70
71#define CRC16_INITIAL_CRC 0 /* what to seed crc16 with */
72#define CRC_CITT_POLYMINAL 0x1021
73
74#define ntohs(x) sys_be16_to_cpu(x)
75#define htons(x) sys_cpu_to_be16(x)
76
77static char in_buf[CONFIG_BOOT_MAX_LINE_INPUT_LEN + 1];
78static char dec_buf[CONFIG_BOOT_MAX_LINE_INPUT_LEN + 1];
79#endif
80
Christopher Collins92ea77f2016-12-12 15:59:26 -080081static uint32_t curr_off;
82static uint32_t img_size;
83static struct nmgr_hdr *bs_hdr;
84
85static char bs_obuf[BOOT_SERIAL_OUT_MAX];
86
87static int bs_cbor_writer(struct cbor_encoder_writer *, const char *data,
88 int len);
89static void boot_serial_output(void);
90
91static struct cbor_encoder_writer bs_writer = {
92 .write = bs_cbor_writer
93};
94static CborEncoder bs_root;
95static CborEncoder bs_rsp;
96
97int
98bs_cbor_writer(struct cbor_encoder_writer *cew, const char *data, int len)
99{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300100 if (cew->bytes_written + len > sizeof(bs_obuf)) {
101 return CborErrorOutOfMemory;
102 }
103
Christopher Collins92ea77f2016-12-12 15:59:26 -0800104 memcpy(&bs_obuf[cew->bytes_written], data, len);
105 cew->bytes_written += len;
106
107 return 0;
108}
109
110/*
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300111 * Convert version into string without use of snprintf().
Christopher Collins92ea77f2016-12-12 15:59:26 -0800112 */
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300113static int
114u32toa(char *tgt, uint32_t val)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800115{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300116 char *dst;
117 uint32_t d = 1;
118 uint32_t dgt;
119 int n = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800120
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300121 dst = tgt;
122 while (val / d >= 10) {
123 d *= 10;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800124 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300125 while (d) {
126 dgt = val / d;
127 val %= d;
128 d /= 10;
129 if (n || dgt > 0 || d == 0) {
130 *dst++ = dgt + '0';
131 ++n;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800132 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800133 }
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300134 *dst = '\0';
135
136 return dst - tgt;
137}
138
139/*
140 * dst has to be able to fit "255.255.65535.4294967295" (25 characters).
141 */
142static void
143bs_list_img_ver(char *dst, int maxlen, struct image_version *ver)
144{
145 int off;
146
147 off = u32toa(dst, ver->iv_major);
148 dst[off++] = '.';
149 off += u32toa(dst + off, ver->iv_minor);
150 dst[off++] = '.';
151 off += u32toa(dst + off, ver->iv_revision);
152 dst[off++] = '.';
153 off += u32toa(dst + off, ver->iv_build_num);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800154}
155
156/*
157 * List images.
158 */
159static void
160bs_list(char *buf, int len)
161{
162 CborEncoder images;
163 CborEncoder image;
164 struct image_header hdr;
165 uint8_t tmpbuf[64];
166 int i, area_id;
167 const struct flash_area *fap;
168
169 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
170 cbor_encode_text_stringz(&bs_rsp, "images");
171 cbor_encoder_create_array(&bs_rsp, &images, CborIndefiniteLength);
172 for (i = 0; i < 2; i++) {
173 area_id = flash_area_id_from_image_slot(i);
174 if (flash_area_open(area_id, &fap)) {
175 continue;
176 }
177
178 flash_area_read(fap, 0, &hdr, sizeof(hdr));
179
180 if (hdr.ih_magic != IMAGE_MAGIC ||
181 bootutil_img_validate(&hdr, fap, tmpbuf, sizeof(tmpbuf),
182 NULL, 0, NULL)) {
183 flash_area_close(fap);
184 continue;
185 }
186 flash_area_close(fap);
187
188 cbor_encoder_create_map(&images, &image, CborIndefiniteLength);
189 cbor_encode_text_stringz(&image, "slot");
190 cbor_encode_int(&image, i);
191 cbor_encode_text_stringz(&image, "version");
192
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300193 bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800194 cbor_encode_text_stringz(&image, (char *)tmpbuf);
195 cbor_encoder_close_container(&images, &image);
196 }
197 cbor_encoder_close_container(&bs_rsp, &images);
198 cbor_encoder_close_container(&bs_root, &bs_rsp);
199 boot_serial_output();
200}
201
202/*
203 * Image upload request.
204 */
205static void
206bs_upload(char *buf, int len)
207{
208 CborParser parser;
209 struct cbor_buf_reader reader;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300210 struct CborValue root_value;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800211 struct CborValue value;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300212 uint8_t img_data[512];
213 long long int off = UINT_MAX;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800214 size_t img_blen = 0;
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300215 uint8_t rem_bytes;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300216 long long int data_len = UINT_MAX;
217 size_t slen;
218 char name_str[8];
Christopher Collins92ea77f2016-12-12 15:59:26 -0800219 const struct flash_area *fap = NULL;
220 int rc;
221
222 memset(img_data, 0, sizeof(img_data));
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300223
224 /*
225 * Expected data format.
226 * {
227 * "data":<img_data>
228 * "len":<image len>
229 * "off":<current offset of image data>
230 * }
231 */
232
233 /*
234 * Object comes within { ... }
235 */
Christopher Collins92ea77f2016-12-12 15:59:26 -0800236 cbor_buf_reader_init(&reader, (uint8_t *)buf, len);
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +0200237#ifdef __ZEPHYR__
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300238 cbor_parser_cust_reader_init(&reader.r, 0, &parser, &root_value);
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +0200239#else
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300240 cbor_parser_init(&reader.r, 0, &parser, &root_value);
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +0200241#endif
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300242 if (!cbor_value_is_container(&root_value)) {
243 goto out_invalid_data;
244 }
245 if (cbor_value_enter_container(&root_value, &value)) {
246 goto out_invalid_data;
247 }
248 while (cbor_value_is_valid(&value)) {
249 /*
250 * Decode key.
251 */
252 if (cbor_value_calculate_string_length(&value, &slen)) {
253 goto out_invalid_data;
254 }
255 if (!cbor_value_is_text_string(&value) ||
256 slen >= sizeof(name_str) - 1) {
257 goto out_invalid_data;
258 }
259 if (cbor_value_copy_text_string(&value, name_str, &slen, &value)) {
260 goto out_invalid_data;
261 }
262 name_str[slen] = '\0';
263 if (!strcmp(name_str, "data")) {
264 /*
265 * Image data
266 */
267 if (value.type != CborByteStringType) {
268 goto out_invalid_data;
269 }
270 if (cbor_value_calculate_string_length(&value, &slen) ||
271 slen >= sizeof(img_data)) {
272 goto out_invalid_data;
273 }
274 if (cbor_value_copy_byte_string(&value, img_data, &slen, &value)) {
275 goto out_invalid_data;
276 }
277 img_blen = slen;
278 } else if (!strcmp(name_str, "off")) {
279 /*
280 * Offset of the data.
281 */
282 if (value.type != CborIntegerType) {
283 goto out_invalid_data;
284 }
285 if (cbor_value_get_int64(&value, &off)) {
286 goto out_invalid_data;
287 }
288 if (cbor_value_advance(&value)) {
289 goto out_invalid_data;
290 }
291 } else if (!strcmp(name_str, "len")) {
292 /*
293 * Length of the image. This should only be present in the first
294 * block of data; when offset is 0.
295 */
296 if (value.type != CborIntegerType) {
297 goto out_invalid_data;
298 }
299 if (cbor_value_get_int64(&value, &data_len)) {
300 goto out_invalid_data;
301 }
302 if (cbor_value_advance(&value)) {
303 goto out_invalid_data;
304 }
305 } else {
306 /*
307 * Unknown keys.
308 */
309 if (cbor_value_advance(&value)) {
310 goto out_invalid_data;
311 }
312 }
313 }
314 if (off == UINT_MAX) {
315 /*
316 * Offset must be set in every block.
317 */
318 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800319 }
320
Christopher Collins92ea77f2016-12-12 15:59:26 -0800321 rc = flash_area_open(flash_area_id_from_image_slot(0), &fap);
322 if (rc) {
323 rc = MGMT_ERR_EINVAL;
324 goto out;
325 }
326
327 if (off == 0) {
328 curr_off = 0;
329 if (data_len > fap->fa_size) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300330 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800331 }
332 rc = flash_area_erase(fap, 0, fap->fa_size);
333 if (rc) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300334 goto out_invalid_data;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800335 }
336 img_size = data_len;
337 }
338 if (off != curr_off) {
339 rc = 0;
340 goto out;
341 }
Fabio Utzig30f6b2a2018-03-29 16:18:53 -0300342 if (curr_off + img_blen < img_size) {
343 rem_bytes = img_blen % flash_area_align(fap);
344 if (rem_bytes) {
345 img_blen -= rem_bytes;
346 }
347 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800348 rc = flash_area_write(fap, curr_off, img_data, img_blen);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300349 if (rc == 0) {
350 curr_off += img_blen;
351 } else {
352 out_invalid_data:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800353 rc = MGMT_ERR_EINVAL;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800354 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800355out:
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200356 BOOT_LOG_INF("RX: 0x%x", rc);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800357 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
358 cbor_encode_text_stringz(&bs_rsp, "rc");
359 cbor_encode_int(&bs_rsp, rc);
360 if (rc == 0) {
361 cbor_encode_text_stringz(&bs_rsp, "off");
362 cbor_encode_uint(&bs_rsp, curr_off);
363 }
364 cbor_encoder_close_container(&bs_root, &bs_rsp);
365
366 boot_serial_output();
367 flash_area_close(fap);
368}
369
370/*
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300371 * Console echo control/image erase. Send empty response, don't do anything.
Christopher Collins92ea77f2016-12-12 15:59:26 -0800372 */
373static void
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300374bs_empty_rsp(char *buf, int len)
Christopher Collins92ea77f2016-12-12 15:59:26 -0800375{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300376 cbor_encoder_create_map(&bs_root, &bs_rsp, CborIndefiniteLength);
377 cbor_encode_text_stringz(&bs_rsp, "rc");
378 cbor_encode_int(&bs_rsp, 0);
379 cbor_encoder_close_container(&bs_root, &bs_rsp);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800380 boot_serial_output();
381}
382
383/*
384 * Reset, and (presumably) boot to newly uploaded image. Flush console
385 * before restarting.
386 */
Andrzej Puzdrowski268cdd02018-04-10 12:57:54 +0200387static void
Christopher Collins92ea77f2016-12-12 15:59:26 -0800388bs_reset(char *buf, int len)
389{
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300390 bs_empty_rsp(buf, len);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800391
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200392#ifdef __ZEPHYR__
393 k_sleep(250);
394 sys_reboot(SYS_REBOOT_COLD);
395#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800396 os_cputime_delay_usecs(250000);
397 hal_system_reset();
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200398#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800399}
400
401/*
402 * Parse incoming line of input from console.
403 * Expect newtmgr protocol with serial transport.
404 */
405void
406boot_serial_input(char *buf, int len)
407{
408 struct nmgr_hdr *hdr;
409
410 hdr = (struct nmgr_hdr *)buf;
411 if (len < sizeof(*hdr) ||
412 (hdr->nh_op != NMGR_OP_READ && hdr->nh_op != NMGR_OP_WRITE) ||
413 (ntohs(hdr->nh_len) < len - sizeof(*hdr))) {
414 return;
415 }
416 bs_hdr = hdr;
417 hdr->nh_group = ntohs(hdr->nh_group);
418
419 buf += sizeof(*hdr);
420 len -= sizeof(*hdr);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300421
Christopher Collins92ea77f2016-12-12 15:59:26 -0800422 bs_writer.bytes_written = 0;
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +0200423#ifdef __ZEPHYR__
424 cbor_encoder_cust_writer_init(&bs_root, &bs_writer, 0);
425#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800426 cbor_encoder_init(&bs_root, &bs_writer, 0);
Andrzej Puzdrowski386b5922018-04-06 19:26:24 +0200427#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800428
429 /*
430 * Limited support for commands.
431 */
432 if (hdr->nh_group == MGMT_GROUP_ID_IMAGE) {
433 switch (hdr->nh_id) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300434 case IMGMGR_NMGR_ID_STATE:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800435 bs_list(buf, len);
436 break;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300437 case IMGMGR_NMGR_ID_UPLOAD:
Christopher Collins92ea77f2016-12-12 15:59:26 -0800438 bs_upload(buf, len);
439 break;
440 default:
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300441 bs_empty_rsp(buf, len);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800442 break;
443 }
444 } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) {
445 switch (hdr->nh_id) {
446 case NMGR_ID_CONS_ECHO_CTRL:
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300447 bs_empty_rsp(buf, len);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800448 break;
449 case NMGR_ID_RESET:
450 bs_reset(buf, len);
451 break;
452 default:
453 break;
454 }
455 }
456}
457
458static void
459boot_serial_output(void)
460{
461 char *data;
462 int len;
463 uint16_t crc;
464 uint16_t totlen;
465 char pkt_start[2] = { SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2 };
466 char buf[BOOT_SERIAL_OUT_MAX];
467 char encoded_buf[BASE64_ENCODE_SIZE(BOOT_SERIAL_OUT_MAX)];
468
469 data = bs_obuf;
470 len = bs_writer.bytes_written;
471
472 bs_hdr->nh_op++;
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300473 bs_hdr->nh_flags = 0;
Christopher Collins92ea77f2016-12-12 15:59:26 -0800474 bs_hdr->nh_len = htons(len);
475 bs_hdr->nh_group = htons(bs_hdr->nh_group);
476
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200477#ifdef __ZEPHYR__
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300478 crc = crc16((u8_t *)bs_hdr, sizeof(*bs_hdr), CRC_CITT_POLYMINAL,
479 CRC16_INITIAL_CRC, false);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200480 crc = crc16(data, len, CRC_CITT_POLYMINAL, crc, true);
481#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800482 crc = crc16_ccitt(CRC16_INITIAL_CRC, bs_hdr, sizeof(*bs_hdr));
483 crc = crc16_ccitt(crc, data, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200484#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800485 crc = htons(crc);
486
487 console_write(pkt_start, sizeof(pkt_start));
488
489 totlen = len + sizeof(*bs_hdr) + sizeof(crc);
490 totlen = htons(totlen);
491
492 memcpy(buf, &totlen, sizeof(totlen));
493 totlen = sizeof(totlen);
494 memcpy(&buf[totlen], bs_hdr, sizeof(*bs_hdr));
495 totlen += sizeof(*bs_hdr);
496 memcpy(&buf[totlen], data, len);
497 totlen += len;
498 memcpy(&buf[totlen], &crc, sizeof(crc));
499 totlen += sizeof(crc);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200500#ifdef __ZEPHYR__
501 size_t enc_len;
Carles Cufi0165be82018-03-26 17:43:51 +0200502 base64_encode(encoded_buf, sizeof(encoded_buf), &enc_len, buf, totlen);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200503 totlen = enc_len;
504#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800505 totlen = base64_encode(buf, totlen, encoded_buf, 1);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200506#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800507 console_write(encoded_buf, totlen);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300508 console_write("\n\r", 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200509 BOOT_LOG_INF("TX");
Christopher Collins92ea77f2016-12-12 15:59:26 -0800510}
511
512/*
513 * Returns 1 if full packet has been received.
514 */
515static int
516boot_serial_in_dec(char *in, int inlen, char *out, int *out_off, int maxout)
517{
518 int rc;
519 uint16_t crc;
520 uint16_t len;
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200521#ifdef __ZEPHYR__
522 int err;
Carles Cufi0165be82018-03-26 17:43:51 +0200523 err = base64_decode( &out[*out_off], maxout, &rc, in, inlen - 2);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200524 if (err) {
525 return -1;
526 }
527#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800528 if (*out_off + base64_decode_len(in) >= maxout) {
529 return -1;
530 }
531 rc = base64_decode(in, &out[*out_off]);
532 if (rc < 0) {
533 return -1;
534 }
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200535#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800536 *out_off += rc;
537
538 if (*out_off > sizeof(uint16_t)) {
539 len = ntohs(*(uint16_t *)out);
540
541 len = min(len, *out_off - sizeof(uint16_t));
542 out += sizeof(uint16_t);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200543#ifdef __ZEPHYR__
544 crc = crc16(out, len, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true);
545#else
Christopher Collins92ea77f2016-12-12 15:59:26 -0800546 crc = crc16_ccitt(CRC16_INITIAL_CRC, out, len);
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200547#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800548 if (crc || len <= sizeof(crc)) {
549 return 0;
550 }
551 *out_off -= sizeof(crc);
552 out[*out_off] = '\0';
553
554 return 1;
555 }
556 return 0;
557}
558
559/*
560 * Task which waits reading console, expecting to get image over
561 * serial port.
562 */
563void
564boot_serial_start(int max_input)
565{
566 int rc;
567 int off;
568 char *buf;
569 char *dec;
570 int dec_off;
571 int full_line;
572
Andrzej Puzdrowski8e96b832017-09-08 16:49:14 +0200573#ifdef __ZEPHYR__
574 rc = boot_console_init();
575 buf = in_buf;
576 dec = dec_buf;
577 assert(max_input <= sizeof(in_buf) && max_input <= sizeof(dec_buf));
578#else
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300579 rc = boot_uart_open();
Christopher Collins92ea77f2016-12-12 15:59:26 -0800580 assert(rc == 0);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300581
Christopher Collins92ea77f2016-12-12 15:59:26 -0800582 buf = os_malloc(max_input);
583 dec = os_malloc(max_input);
Christopher Collins92ea77f2016-12-12 15:59:26 -0800584 assert(buf && dec);
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300585#endif
Christopher Collins92ea77f2016-12-12 15:59:26 -0800586
587 off = 0;
588 while (1) {
589 rc = console_read(buf + off, max_input - off, &full_line);
590 if (rc <= 0 && !full_line) {
591 continue;
592 }
593 off += rc;
594 if (!full_line) {
Marko Kiiskilace50ab02018-06-06 11:33:33 +0300595 if (off == max_input) {
596 /*
597 * Full line, no newline yet. Reset the input buffer.
598 */
599 off = 0;
600 }
Christopher Collins92ea77f2016-12-12 15:59:26 -0800601 continue;
602 }
603 if (buf[0] == SHELL_NLIP_PKT_START1 &&
604 buf[1] == SHELL_NLIP_PKT_START2) {
605 dec_off = 0;
606 rc = boot_serial_in_dec(&buf[2], off - 2, dec, &dec_off, max_input);
607 } else if (buf[0] == SHELL_NLIP_DATA_START1 &&
608 buf[1] == SHELL_NLIP_DATA_START2) {
609 rc = boot_serial_in_dec(&buf[2], off - 2, dec, &dec_off, max_input);
610 }
611 if (rc == 1) {
612 boot_serial_input(&dec[2], dec_off - 2);
613 }
614 off = 0;
615 }
616}