2019-03-26 14:24:36 -04:00
|
|
|
//
|
|
|
|
// Created by nock on 26/03/19.
|
|
|
|
//
|
|
|
|
|
2019-05-01 12:25:19 -04:00
|
|
|
#include <errno.h>
|
2019-03-26 14:24:36 -04:00
|
|
|
#include <stdio.h>
|
2019-05-01 12:25:19 -04:00
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2019-05-02 08:48:43 -04:00
|
|
|
#include <netinet/in.h>
|
2019-05-02 12:54:43 -04:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/stat.h>
|
2019-05-08 11:53:08 -04:00
|
|
|
#include <math.h>
|
2019-05-01 12:25:19 -04:00
|
|
|
|
2019-05-02 08:48:43 -04:00
|
|
|
#include "base64.h"
|
2019-05-02 12:54:43 -04:00
|
|
|
#include "crc.h"
|
2019-06-18 13:43:05 -04:00
|
|
|
#include "error.h"
|
2019-06-04 12:20:14 -04:00
|
|
|
#include "fixkey-msg.h"
|
|
|
|
#include "fixkey-payload.h"
|
|
|
|
#include "gpio.h"
|
2019-03-26 14:24:36 -04:00
|
|
|
#include "image.h"
|
2019-05-01 12:25:19 -04:00
|
|
|
#include "nmgr.h"
|
2019-05-08 11:53:08 -04:00
|
|
|
#include "timer.h"
|
2019-06-04 12:20:14 -04:00
|
|
|
#include "serial_util.h"
|
2019-05-08 10:47:29 -04:00
|
|
|
#include <tinycbor/cbor.h>
|
2019-05-07 12:19:42 -04:00
|
|
|
|
|
|
|
#ifdef DO_UPLOAD_SHA
|
2019-05-03 23:14:14 -04:00
|
|
|
#include "sha256.h"
|
2019-05-07 12:19:42 -04:00
|
|
|
#endif
|
2019-05-02 08:48:43 -04:00
|
|
|
|
2019-06-18 14:44:47 -04:00
|
|
|
|
|
|
|
/* These values produce output identical to mcumgr *if* DO_UPLOAD_SHA is defined */
|
|
|
|
#define IMAGE_CHUNK_SIZE 124 // 124 for identical output to newtmgr
|
|
|
|
#define MACRO_CHUNK_SIZE 302 // 302 ""
|
|
|
|
|
|
|
|
/* Fast mode doesn't support original EM bootloader, but is much faster with later bootloaders */
|
|
|
|
#define IMAGE_CHUNK_SIZE_FAST 216
|
|
|
|
#define MACRO_CHUNK_SIZE_FAST 432
|
2019-05-02 12:54:43 -04:00
|
|
|
|
2019-05-21 11:46:50 -04:00
|
|
|
/*
|
|
|
|
* Larger values above greatly increase speed, but seem to break older
|
|
|
|
* versions of mcuboot (like the one shipped with inital EM firmware)
|
|
|
|
*/
|
|
|
|
|
2019-05-02 12:54:43 -04:00
|
|
|
#define CRC16_INITIAL_CRC 0 /* what to seed crc16 with */
|
|
|
|
#define CRC_CITT_POLYMINAL 0x1021
|
|
|
|
|
2019-05-02 08:48:43 -04:00
|
|
|
static int serial_fd = -1;
|
2019-05-01 12:25:19 -04:00
|
|
|
|
2019-06-18 14:44:47 -04:00
|
|
|
static bool g_fast_mode = false;
|
|
|
|
|
|
|
|
void image_set_fast_mode(void) {
|
|
|
|
g_fast_mode = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool image_get_fast_mode(void) {
|
|
|
|
return g_fast_mode;
|
|
|
|
}
|
|
|
|
|
2019-05-01 12:25:19 -04:00
|
|
|
void image_help(void){
|
2019-06-18 13:43:05 -04:00
|
|
|
BAIL_OUT(ERR_USAGE);
|
2019-05-01 12:25:19 -04:00
|
|
|
}
|
|
|
|
|
2019-05-07 12:19:42 -04:00
|
|
|
static char *hex(unsigned char in) {
|
2019-05-01 12:25:19 -04:00
|
|
|
static char out[3] = {0};
|
|
|
|
static char lookup[] = {
|
|
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
|
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
|
|
|
};
|
|
|
|
out[0] = lookup[in >> 4];
|
|
|
|
out[1] = lookup[in & 0xf];
|
|
|
|
out[2] = 0;
|
|
|
|
return out;
|
|
|
|
}
|
2019-03-26 14:24:36 -04:00
|
|
|
|
2019-05-03 13:06:01 -04:00
|
|
|
static void read_response(uint8_t *dest, size_t *len) {
|
|
|
|
static uint8_t buf[BOOT_SERIAL_IN_MAX*2] = {0};
|
|
|
|
static uint8_t *p = buf;
|
2019-05-08 11:53:08 -04:00
|
|
|
timer_start(3);
|
2019-05-03 13:06:01 -04:00
|
|
|
while (true) {
|
|
|
|
int bytes_read = read(serial_fd, p, BOOT_SERIAL_IN_MAX);
|
|
|
|
if (bytes_read < 0) {
|
|
|
|
if (errno == EAGAIN) {
|
2019-05-08 11:53:08 -04:00
|
|
|
if (timer_expired()) {
|
2019-06-18 13:43:05 -04:00
|
|
|
BAIL_OUT(ERR_TIMEOUT);
|
2019-05-08 11:53:08 -04:00
|
|
|
}
|
2019-06-18 15:07:14 -04:00
|
|
|
usleep(5000);
|
2019-05-03 13:06:01 -04:00
|
|
|
continue;
|
|
|
|
}
|
2019-06-18 13:43:05 -04:00
|
|
|
BAIL_OUT(ERR_SERIAL_PORT);
|
2019-05-03 13:06:01 -04:00
|
|
|
}
|
|
|
|
p += bytes_read;
|
|
|
|
uint8_t *nl_p = memchr(buf, '\n', p-buf);
|
|
|
|
if (nl_p) {
|
|
|
|
*len = nl_p - buf;
|
|
|
|
memcpy(dest, buf, *len);
|
|
|
|
uint16_t new_buf_len = p - nl_p;
|
2019-05-08 12:27:33 -04:00
|
|
|
if (new_buf_len) {
|
|
|
|
p = buf;
|
|
|
|
return;
|
|
|
|
}
|
2019-05-03 13:06:01 -04:00
|
|
|
memcpy(buf, nl_p+1, new_buf_len);
|
|
|
|
p = buf+new_buf_len;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-02 08:48:43 -04:00
|
|
|
static void hex_print(char *in, size_t len) {
|
|
|
|
char tmp[len*2+1];
|
|
|
|
tmp[len] = 0;
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
strcat(tmp, hex(in[i]));
|
|
|
|
}
|
|
|
|
printf("%s\n", tmp);
|
|
|
|
}
|
|
|
|
|
2019-05-07 12:19:42 -04:00
|
|
|
static void printlen(void *src, size_t len){
|
|
|
|
uint8_t *p = src;
|
2019-05-02 08:48:43 -04:00
|
|
|
for (size_t i = 0; i < len; i++) {
|
2019-05-08 06:11:57 -04:00
|
|
|
//fprintf(stderr, "printlen: %u %s %c\n", i, hex(p[i]), p[i]);
|
2019-05-07 12:19:42 -04:00
|
|
|
putchar(p[i]);
|
2019-05-02 08:48:43 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-18 13:43:05 -04:00
|
|
|
static bool assert_pkt_start(uint8_t const *buf){
|
|
|
|
return (buf[0] == SHELL_NLIP_PKT_START1 && buf[1] == SHELL_NLIP_PKT_START2);
|
2019-05-02 08:48:43 -04:00
|
|
|
}
|
|
|
|
|
2019-06-18 13:43:05 -04:00
|
|
|
#define cbor_require_type(it, type) _cbor_require_type(it, type, __FUNCTION__, __FILE__, __LINE__)
|
|
|
|
static void _cbor_require_type(CborValue *it, CborType type, const char *function, const char *file, unsigned line) {
|
2019-05-02 08:48:43 -04:00
|
|
|
CborType actual_type = cbor_value_get_type(it);
|
|
|
|
if (actual_type != type) {
|
2019-06-18 13:43:05 -04:00
|
|
|
_bail_out(ERR_CBOR_TYPE, function, file, line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define cbor_ensure_success(cbor_err) _cbor_ensure_success(cbor_err, __FUNCTION__, __FILE__, __LINE__)
|
|
|
|
static inline void _cbor_ensure_success(CborError err, const char *function, const char *file, unsigned line) {
|
|
|
|
if (err != CborNoError) {
|
|
|
|
_bail_out(ERR_CBOR, function, file, line);
|
2019-05-02 08:48:43 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-04 12:20:14 -04:00
|
|
|
static char *get_version(void) {
|
2019-06-04 12:20:14 -04:00
|
|
|
serial_flush(serial_fd);
|
2019-05-02 08:48:43 -04:00
|
|
|
int rc = write(serial_fd, IMAGE_LIST_CMD, sizeof(IMAGE_LIST_CMD) - 1);
|
|
|
|
if (rc < sizeof(IMAGE_LIST_CMD) - 1) {
|
2019-06-18 13:57:58 -04:00
|
|
|
BAIL_OUT(ERR_SERIAL_PORT);
|
2019-05-02 08:48:43 -04:00
|
|
|
}
|
|
|
|
uint8_t tmp[BOOT_SERIAL_IN_MAX];
|
2019-05-03 13:06:01 -04:00
|
|
|
size_t in_len;
|
|
|
|
|
|
|
|
read_response(tmp, &in_len);
|
2019-05-02 08:48:43 -04:00
|
|
|
|
|
|
|
// Process the response
|
|
|
|
CborParser parser;
|
|
|
|
CborValue it;
|
|
|
|
|
2019-05-03 13:06:01 -04:00
|
|
|
// Validate packet start marker
|
2019-06-18 13:43:05 -04:00
|
|
|
if (in_len < 2 || !assert_pkt_start(tmp)) {
|
|
|
|
BAIL_OUT(ERR_INVALID_PACKET);
|
2019-05-02 12:54:43 -04:00
|
|
|
}
|
2019-05-03 13:06:01 -04:00
|
|
|
|
|
|
|
// Decode the payload
|
|
|
|
size_t out_len;
|
2019-05-02 08:48:43 -04:00
|
|
|
uint8_t *decoded_buf = base64_decode(tmp+2, in_len-2, &out_len);
|
|
|
|
|
2019-05-02 12:54:43 -04:00
|
|
|
if (!decoded_buf) {
|
2019-06-18 13:43:05 -04:00
|
|
|
BAIL_OUT(ERR_BASE64_DECODE);
|
2019-05-02 12:54:43 -04:00
|
|
|
}
|
|
|
|
|
2019-05-02 08:48:43 -04:00
|
|
|
// Unclear why this would be useful in a line oriented (cannonical mode) program
|
2019-05-03 13:06:01 -04:00
|
|
|
uint16_t pkt_len = ntohs(*(uint16_t *)decoded_buf);
|
|
|
|
uint16_t crc = crc16(decoded_buf+sizeof(pkt_len), pkt_len, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true);
|
|
|
|
if (crc) {
|
2019-06-18 13:43:05 -04:00
|
|
|
BAIL_OUT(ERR_BAD_CRC);
|
2019-05-03 13:06:01 -04:00
|
|
|
}
|
2019-05-02 08:48:43 -04:00
|
|
|
|
2019-06-18 13:43:05 -04:00
|
|
|
uint8_t *p = decoded_buf + sizeof(pkt_len) + sizeof(struct nmgr_hdr);
|
|
|
|
cbor_ensure_success(
|
|
|
|
cbor_parser_init(p, out_len, 0, &parser, &it));
|
2019-05-02 08:48:43 -04:00
|
|
|
cbor_require_type(&it, CborMapType);
|
|
|
|
CborValue map;
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_value_enter_container(&it, &map));
|
2019-05-02 08:48:43 -04:00
|
|
|
cbor_require_type(&map, CborTextStringType);
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_value_advance(&map));
|
2019-05-02 08:48:43 -04:00
|
|
|
cbor_require_type(&map, CborArrayType);
|
|
|
|
CborValue img_array;
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_value_enter_container(&map, &img_array));
|
2019-05-02 08:48:43 -04:00
|
|
|
|
2019-05-03 13:06:01 -04:00
|
|
|
char *version = NULL;
|
2019-05-02 08:48:43 -04:00
|
|
|
while (!cbor_value_at_end(&img_array)) {
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_require_type(&img_array, CborMapType);
|
2019-05-02 08:48:43 -04:00
|
|
|
CborValue version_tag;
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(
|
|
|
|
cbor_value_map_find_value(&img_array, "version", &version_tag));
|
|
|
|
|
2019-05-03 13:06:01 -04:00
|
|
|
if (cbor_value_get_type(&version_tag) == CborInvalidType) {
|
2019-05-02 08:48:43 -04:00
|
|
|
cbor_value_advance(&img_array);
|
|
|
|
continue;
|
2019-05-01 12:25:19 -04:00
|
|
|
}
|
2019-05-02 08:48:43 -04:00
|
|
|
size_t len;
|
|
|
|
cbor_value_dup_text_string(&version_tag, &version, &len, NULL);
|
2019-05-03 13:06:01 -04:00
|
|
|
break;
|
|
|
|
}
|
2019-05-02 08:48:43 -04:00
|
|
|
free(decoded_buf);
|
2019-06-04 12:20:14 -04:00
|
|
|
return version;
|
2019-05-02 08:48:43 -04:00
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:47 -04:00
|
|
|
static void wrap_and_send_pkt(uint8_t *data, size_t len, bool fast_mode) {
|
2019-06-18 13:43:05 -04:00
|
|
|
assert(data != NULL);
|
|
|
|
assert(len != 0);
|
2019-05-07 12:19:42 -04:00
|
|
|
static uint8_t seq = 67;
|
2019-05-03 13:06:01 -04:00
|
|
|
uint8_t b64_buf[BOOT_SERIAL_OUT_MAX*2];
|
2019-05-07 12:19:42 -04:00
|
|
|
uint16_t tot_len = 2 + len + sizeof(struct nmgr_hdr) + 2; // +2 is len +2 is crc
|
|
|
|
uint16_t net_len = htons(tot_len-2); // tot_len doesn't include the len field
|
|
|
|
|
2019-05-03 23:14:14 -04:00
|
|
|
struct nmgr_hdr hdr = {0};
|
2019-05-02 12:54:43 -04:00
|
|
|
hdr.nh_op = NMGR_OP_WRITE;
|
|
|
|
hdr.nh_group = htons(MGMT_GROUP_ID_IMAGE);
|
|
|
|
hdr.nh_id = IMGMGR_NMGR_ID_UPLOAD;
|
2019-05-03 23:14:14 -04:00
|
|
|
hdr.nh_seq = seq++;
|
2019-05-07 12:19:42 -04:00
|
|
|
hdr.nh_len = htons(len);
|
2019-05-02 12:54:43 -04:00
|
|
|
|
2019-05-07 12:19:42 -04:00
|
|
|
memcpy(b64_buf, &net_len, sizeof(net_len));
|
2019-05-02 12:54:43 -04:00
|
|
|
|
2019-05-07 12:19:42 -04:00
|
|
|
#define HDR_OFFSET 2
|
|
|
|
#define DATA_OFFSET (HDR_OFFSET+sizeof(struct nmgr_hdr))
|
|
|
|
#define CRC_OFFSET(len) (DATA_OFFSET+len)
|
2019-05-03 23:14:14 -04:00
|
|
|
|
2019-05-07 12:19:42 -04:00
|
|
|
memcpy(b64_buf+HDR_OFFSET, &hdr, sizeof(struct nmgr_hdr));
|
|
|
|
memcpy(b64_buf+DATA_OFFSET, data, len);
|
2019-05-03 23:14:14 -04:00
|
|
|
|
2019-05-07 12:19:42 -04:00
|
|
|
uint16_t crc = crc16(b64_buf+HDR_OFFSET, tot_len-4, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true);
|
|
|
|
crc = htons(crc);
|
|
|
|
memcpy(b64_buf+CRC_OFFSET(len), &crc, sizeof(crc));
|
2019-05-02 12:54:43 -04:00
|
|
|
|
|
|
|
size_t out_len;
|
|
|
|
uint8_t *out_buf = base64_encode(b64_buf, tot_len, &out_len);
|
|
|
|
|
2019-05-07 12:19:42 -04:00
|
|
|
uint8_t *pos = out_buf;
|
2019-05-03 13:06:01 -04:00
|
|
|
while (pos < out_buf+out_len) {
|
|
|
|
uint8_t start_pkt[] = {SHELL_NLIP_PKT_START1, SHELL_NLIP_PKT_START2};
|
|
|
|
uint8_t start_data[] = {SHELL_NLIP_DATA_START1, SHELL_NLIP_DATA_START2};
|
2019-05-02 12:54:43 -04:00
|
|
|
|
2019-05-03 13:06:01 -04:00
|
|
|
if (pos == out_buf) {
|
|
|
|
write(serial_fd, start_pkt, sizeof(start_pkt));
|
|
|
|
} else {
|
2019-06-18 15:07:14 -04:00
|
|
|
if (!fast_mode) {
|
|
|
|
usleep(20000);
|
|
|
|
}
|
2019-05-03 13:06:01 -04:00
|
|
|
write(serial_fd, start_data, sizeof(start_data));
|
|
|
|
}
|
2019-05-02 12:54:43 -04:00
|
|
|
|
2019-05-03 13:06:01 -04:00
|
|
|
size_t remaining = out_buf + out_len - pos;
|
2019-06-18 14:44:47 -04:00
|
|
|
size_t to_write;
|
|
|
|
if (fast_mode) {
|
|
|
|
to_write = remaining > IMAGE_CHUNK_SIZE_FAST ? IMAGE_CHUNK_SIZE_FAST : remaining;
|
|
|
|
} else {
|
|
|
|
to_write = remaining > IMAGE_CHUNK_SIZE ? IMAGE_CHUNK_SIZE : remaining;
|
|
|
|
}
|
|
|
|
|
2019-05-03 13:06:01 -04:00
|
|
|
write(serial_fd, pos, to_write);
|
|
|
|
write(serial_fd, "\n", 1);
|
2019-05-07 12:19:42 -04:00
|
|
|
pos += to_write;
|
2019-05-03 13:06:01 -04:00
|
|
|
}
|
2019-05-02 12:54:43 -04:00
|
|
|
free(out_buf);
|
2019-05-03 13:06:01 -04:00
|
|
|
fsync(serial_fd);
|
2019-05-02 12:54:43 -04:00
|
|
|
}
|
|
|
|
|
2019-06-18 14:44:47 -04:00
|
|
|
void do_upload(char *filename, bool fast_mode){
|
2019-06-04 12:20:14 -04:00
|
|
|
serial_flush(serial_fd);
|
2019-06-04 12:20:14 -04:00
|
|
|
size_t pos = 0, len;
|
|
|
|
uint8_t const *payload;
|
|
|
|
if (filename) {
|
|
|
|
int fd = open(filename, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
fprintf(stderr, "Failed to open \"%s\": %s\n", filename, strerror(errno));
|
2019-06-18 13:43:05 -04:00
|
|
|
exit(ERR_SERIAL_PORT);
|
2019-06-04 12:20:14 -04:00
|
|
|
}
|
2019-05-02 12:54:43 -04:00
|
|
|
|
2019-06-04 12:20:14 -04:00
|
|
|
struct stat st;
|
|
|
|
fstat(fd, &st);
|
|
|
|
len = st.st_size;
|
2019-06-04 12:20:14 -04:00
|
|
|
|
2019-06-04 12:20:14 -04:00
|
|
|
uint8_t *payload_mut = calloc(1, len);
|
|
|
|
if (!payload_mut) {
|
2019-06-18 13:43:05 -04:00
|
|
|
BAIL_OUT(ERR_MEMORY);
|
2019-06-04 12:20:14 -04:00
|
|
|
}
|
2019-06-04 12:20:14 -04:00
|
|
|
|
2019-06-04 12:20:14 -04:00
|
|
|
size_t bytes_read = 0;
|
|
|
|
while (bytes_read < len) {
|
|
|
|
errno = 0;
|
|
|
|
int r = read(fd, &payload_mut[bytes_read], len);
|
|
|
|
if (r < 0 && errno != EAGAIN) {
|
2019-06-18 13:43:05 -04:00
|
|
|
BAIL_OUT(ERR_IO);
|
2019-06-04 12:20:14 -04:00
|
|
|
}
|
|
|
|
bytes_read += r;
|
|
|
|
}
|
|
|
|
payload = payload_mut;
|
|
|
|
} else {
|
|
|
|
payload = fixkey_payload_bin;
|
|
|
|
len = fixkey_payload_len;
|
|
|
|
}
|
2019-05-08 11:53:08 -04:00
|
|
|
|
2019-06-18 14:44:47 -04:00
|
|
|
size_t base_chunk_len;
|
|
|
|
if (fast_mode) {
|
|
|
|
base_chunk_len = MACRO_CHUNK_SIZE_FAST;
|
|
|
|
} else {
|
|
|
|
base_chunk_len = MACRO_CHUNK_SIZE;
|
|
|
|
}
|
2019-05-02 12:54:43 -04:00
|
|
|
while (pos < len){
|
2019-05-07 12:19:42 -04:00
|
|
|
size_t data_chunk_len;
|
|
|
|
if (pos == 0) {
|
2019-06-18 14:44:47 -04:00
|
|
|
data_chunk_len = base_chunk_len;
|
2019-05-07 12:19:42 -04:00
|
|
|
} else {
|
2019-06-18 14:44:47 -04:00
|
|
|
data_chunk_len = base_chunk_len + 45;
|
2019-05-07 12:19:42 -04:00
|
|
|
}
|
2019-05-02 12:54:43 -04:00
|
|
|
CborEncoder root, map;
|
2019-05-03 13:06:01 -04:00
|
|
|
uint8_t cbor_buf[BOOT_SERIAL_OUT_MAX*2];
|
|
|
|
cbor_encoder_init(&root, cbor_buf, BOOT_SERIAL_OUT_MAX*2, 0);
|
2019-05-08 06:14:59 -04:00
|
|
|
#ifdef DO_UPLOAD_SHA
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_encoder_create_map(&root, &map, pos == 0 ? 4 : 2));
|
2019-05-08 06:14:59 -04:00
|
|
|
#else
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_encoder_create_map(&root, &map, pos == 0 ? 3 : 2));
|
2019-05-08 06:14:59 -04:00
|
|
|
#endif
|
2019-05-02 12:54:43 -04:00
|
|
|
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_encode_text_stringz(&map, "data"));
|
2019-06-04 12:20:14 -04:00
|
|
|
|
|
|
|
// Most packets will be `data_chunk_len`, but not the last one
|
|
|
|
size_t actual_size = len - pos > data_chunk_len ? data_chunk_len : len - pos;
|
|
|
|
|
2019-06-18 14:08:35 -04:00
|
|
|
cbor_ensure_success(cbor_encode_byte_string(&map, &payload[pos], actual_size));
|
2019-05-03 13:06:01 -04:00
|
|
|
|
|
|
|
if (pos == 0) {
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_encode_text_stringz(&map, "len"));
|
|
|
|
cbor_ensure_success(cbor_encode_uint(&map, len));
|
2019-05-03 13:06:01 -04:00
|
|
|
}
|
|
|
|
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_encode_text_stringz(&map, "off"));
|
|
|
|
cbor_ensure_success(cbor_encode_uint(&map, pos));
|
2019-05-03 13:06:01 -04:00
|
|
|
|
2019-05-08 06:14:59 -04:00
|
|
|
#ifdef DO_UPLOAD_SHA
|
2019-05-07 12:19:42 -04:00
|
|
|
if (pos == 0) {
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_encode_text_stringz(&map, "sha"));
|
2019-05-07 12:19:42 -04:00
|
|
|
SHA256_CTX sha_ctx;
|
|
|
|
sha256_init(&sha_ctx);
|
2019-06-04 12:20:14 -04:00
|
|
|
sha256_update(&sha_ctx, payload, len);
|
2019-05-07 12:19:42 -04:00
|
|
|
uint8_t sha[32];
|
|
|
|
sha256_final(&sha_ctx, (BYTE *)&sha);
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_encode_byte_string(&map, sha, 32));
|
2019-05-07 12:19:42 -04:00
|
|
|
}
|
2019-05-08 06:14:59 -04:00
|
|
|
#endif /* DO_UPLOAD_SHA */
|
2019-05-03 23:14:14 -04:00
|
|
|
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_encoder_close_container(&root, &map));
|
2019-05-07 12:19:42 -04:00
|
|
|
size_t cbor_size = cbor_encoder_get_buffer_size(&root, cbor_buf);
|
|
|
|
|
2019-06-18 14:44:47 -04:00
|
|
|
wrap_and_send_pkt(cbor_buf, cbor_size, fast_mode);
|
2019-05-02 12:54:43 -04:00
|
|
|
|
2019-05-21 08:45:47 -04:00
|
|
|
uint8_t resp_buf[BOOT_SERIAL_IN_MAX*2];
|
2019-05-03 13:06:01 -04:00
|
|
|
size_t in_len;
|
|
|
|
read_response(resp_buf, &in_len);
|
2019-05-02 12:54:43 -04:00
|
|
|
|
2019-05-07 12:19:42 -04:00
|
|
|
size_t out_len;
|
|
|
|
uint8_t *out = base64_decode(resp_buf+2, in_len-2, &out_len);
|
|
|
|
|
2019-06-18 13:43:05 -04:00
|
|
|
if (out == NULL) {
|
|
|
|
BAIL_OUT(ERR_BASE64_DECODE);
|
|
|
|
}
|
|
|
|
|
2019-05-07 12:19:42 -04:00
|
|
|
uint16_t l;
|
|
|
|
memcpy(&l, out, sizeof(l));
|
|
|
|
l = ntohs(l);
|
|
|
|
|
|
|
|
if (crc16(out+2, l, CRC_CITT_POLYMINAL, CRC16_INITIAL_CRC, true)) {
|
2019-06-18 13:43:05 -04:00
|
|
|
BAIL_OUT(ERR_BAD_CRC);
|
2019-05-02 12:54:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
CborParser parser;
|
|
|
|
CborValue it, rc;
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(
|
|
|
|
cbor_parser_init(out+sizeof(struct nmgr_hdr)+2, out_len-sizeof(struct nmgr_hdr)-2, 0, &parser, &it));
|
2019-05-02 12:54:43 -04:00
|
|
|
cbor_require_type(&it, CborMapType);
|
|
|
|
if (cbor_value_map_find_value(&it, "rc", &rc)) {
|
2019-06-18 13:43:05 -04:00
|
|
|
BAIL_OUT(ERR_NO_RESPONSE_CODE);
|
2019-05-02 12:54:43 -04:00
|
|
|
}
|
|
|
|
int r;
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_value_get_int(&rc, &r));
|
2019-05-07 12:19:42 -04:00
|
|
|
if (r) {
|
2019-06-18 13:43:05 -04:00
|
|
|
BAIL_OUT(ERR_CLIENT_REPORTED);
|
2019-05-02 12:54:43 -04:00
|
|
|
}
|
|
|
|
if (cbor_value_map_find_value(&it, "off", &rc)) {
|
|
|
|
fprintf(stderr, "Failed to find an offset in the response %s:%d\n", __FILE__, __LINE__);
|
|
|
|
} else {
|
2019-06-18 13:43:05 -04:00
|
|
|
cbor_ensure_success(cbor_value_get_int(&rc, &r));
|
2019-05-08 11:53:08 -04:00
|
|
|
uint8_t percent_complete = round(((double)r/len)*100);
|
2019-06-18 13:43:05 -04:00
|
|
|
printf("\033[80D%d/%lu Written (%d%%)", r, len, percent_complete);
|
2019-05-08 11:53:08 -04:00
|
|
|
fflush(stdout);
|
2019-05-02 12:54:43 -04:00
|
|
|
}
|
|
|
|
pos += actual_size;
|
2019-05-07 12:19:42 -04:00
|
|
|
free(out);
|
2019-05-02 12:54:43 -04:00
|
|
|
}
|
2019-06-04 12:20:14 -04:00
|
|
|
printf("\n");
|
2019-05-02 08:48:43 -04:00
|
|
|
}
|
|
|
|
|
2019-06-04 12:20:14 -04:00
|
|
|
void fix_and_upload(char *filename) {
|
|
|
|
char *version = get_version();
|
2019-06-04 12:20:14 -04:00
|
|
|
if (version && !strcmp(version, "0.3.2.0") ) {
|
2019-06-04 12:20:14 -04:00
|
|
|
// Upload bootloader update payload
|
|
|
|
printf("Bootloader update required, uploading...\n");
|
2019-06-18 14:44:47 -04:00
|
|
|
do_upload(NULL, false);
|
2019-06-04 12:20:14 -04:00
|
|
|
|
|
|
|
// Reset into controller
|
2019-06-04 12:20:14 -04:00
|
|
|
printf("Starting Controller\n");
|
2019-06-04 12:20:14 -04:00
|
|
|
gpio_ble_req_controller();
|
2019-06-04 12:20:14 -04:00
|
|
|
sleep(1);
|
2019-06-04 12:20:14 -04:00
|
|
|
|
|
|
|
// Update bootloader
|
2019-06-04 12:20:14 -04:00
|
|
|
printf("Triggering bootloader upgrade\n");
|
2019-06-04 12:20:14 -04:00
|
|
|
write(serial_fd, fixkey_msg, sizeof(fixkey_msg));
|
2019-06-04 12:20:14 -04:00
|
|
|
sleep(3);
|
2019-06-04 12:20:14 -04:00
|
|
|
|
|
|
|
// Reset into new bootloader
|
2019-06-04 12:20:14 -04:00
|
|
|
printf("Reseting into new bootloader\n");
|
2019-06-04 12:20:14 -04:00
|
|
|
gpio_ble_req_bootloader();
|
2019-06-04 12:20:14 -04:00
|
|
|
usleep(50000);
|
2019-06-04 12:20:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Do the update
|
|
|
|
printf("Writing %s into slot 1\n", filename);
|
2019-06-18 14:44:47 -04:00
|
|
|
do_upload(filename, image_get_fast_mode());
|
2019-06-04 12:20:14 -04:00
|
|
|
}
|
|
|
|
|
2019-05-02 08:48:43 -04:00
|
|
|
void image_main(int fd, int argc, char **argv){
|
2019-06-04 12:20:14 -04:00
|
|
|
gpio_ble_req_bootloader();
|
2019-05-02 08:48:43 -04:00
|
|
|
serial_fd = fd;
|
|
|
|
if (argc < 1) {
|
|
|
|
image_help();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!strcmp(argv[0], "version")) {
|
2019-06-04 12:20:14 -04:00
|
|
|
char *version = get_version();
|
2019-06-04 12:20:14 -04:00
|
|
|
|
|
|
|
if (version) {
|
|
|
|
printf("%s\n", version);
|
|
|
|
free(version);
|
|
|
|
} else {
|
|
|
|
printf("No application image found.\n");
|
|
|
|
}
|
2019-05-02 08:48:43 -04:00
|
|
|
} else if (!strcmp(argv[0], "upload")) {
|
2019-05-02 12:54:43 -04:00
|
|
|
if (argc < 2) {
|
|
|
|
fprintf(stderr, "umcumgr image upload <binary file>\n");
|
|
|
|
}
|
2019-06-04 12:20:14 -04:00
|
|
|
fix_and_upload(argv[1]);
|
2019-05-01 12:25:19 -04:00
|
|
|
} else {
|
|
|
|
image_help();
|
|
|
|
}
|
2019-06-04 12:20:14 -04:00
|
|
|
gpio_ble_req_controller();
|
2019-03-26 14:24:36 -04:00
|
|
|
}
|