blob: 84681de2daf7a225104121ad4cc5964aed6214ef [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "os/mynewt.h"
#if MYNEWT_VAL(FS_NMGR)
#include <limits.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "bootutil/image.h"
#include "fs/fs.h"
#include "cborattr/cborattr.h"
#include "bsp/bsp.h"
#include "mgmt/mgmt.h"
#include "fs/fs.h"
#include "fs_priv.h"
static struct {
struct {
uint32_t off;
uint32_t size;
const struct flash_area *fa;
struct fs_file *file;
} upload;
} fs_nmgr_state;
static int fs_nmgr_file_download(struct mgmt_cbuf *cb);
static int fs_nmgr_file_upload(struct mgmt_cbuf *cb);
static const struct mgmt_handler fs_nmgr_handlers[] = {
[FS_NMGR_ID_FILE] = {
.mh_read = fs_nmgr_file_download,
.mh_write = fs_nmgr_file_upload
},
};
#define FS_NMGR_HANDLER_CNT \
sizeof(fs_nmgr_handlers) / sizeof(fs_nmgr_handlers[0])
static struct mgmt_group fs_nmgr_group = {
.mg_handlers = fs_nmgr_handlers,
.mg_handlers_count = FS_NMGR_HANDLER_CNT,
.mg_group_id = MGMT_GROUP_ID_FS,
};
static int
fs_nmgr_file_download(struct mgmt_cbuf *cb)
{
long long unsigned int off = UINT_MAX;
char tmp_str[FS_NMGR_MAX_NAME + 1];
uint8_t img_data[MYNEWT_VAL(FS_UPLOAD_MAX_CHUNK_SIZE)];
const struct cbor_attr_t dload_attr[3] = {
[0] = {
.attribute = "off",
.type = CborAttrUnsignedIntegerType,
.addr.uinteger = &off
},
[1] = {
.attribute = "name",
.type = CborAttrTextStringType,
.addr.string = tmp_str,
.len = sizeof(tmp_str)
},
[2] = { 0 },
};
int rc;
uint32_t out_len;
struct fs_file *file;
CborError g_err = CborNoError;
rc = cbor_read_object(&cb->it, dload_attr);
if (rc || off == UINT_MAX) {
return MGMT_ERR_EINVAL;
}
rc = fs_open(tmp_str, FS_ACCESS_READ, &file);
if (rc || !file) {
return MGMT_ERR_ENOMEM;
}
rc = fs_seek(file, off);
if (rc) {
rc = MGMT_ERR_EUNKNOWN;
goto err_close;
}
rc = fs_read(file, 32, img_data, &out_len);
if (rc) {
rc = MGMT_ERR_EUNKNOWN;
goto err_close;
}
g_err |= cbor_encode_text_stringz(&cb->encoder, "off");
g_err |= cbor_encode_uint(&cb->encoder, off);
g_err |= cbor_encode_text_stringz(&cb->encoder, "data");
g_err |= cbor_encode_byte_string(&cb->encoder, img_data, out_len);
g_err |= cbor_encode_text_stringz(&cb->encoder, "rc");
g_err |= cbor_encode_int(&cb->encoder, MGMT_ERR_EOK);
if (off == 0) {
rc = fs_filelen(file, &out_len);
g_err |= cbor_encode_text_stringz(&cb->encoder, "len");
g_err |= cbor_encode_uint(&cb->encoder, out_len);
}
fs_close(file);
if (g_err) {
return MGMT_ERR_ENOMEM;
}
return 0;
err_close:
fs_close(file);
return rc;
}
static int
fs_nmgr_file_upload(struct mgmt_cbuf *cb)
{
uint8_t img_data[MYNEWT_VAL(FS_UPLOAD_MAX_CHUNK_SIZE)];
char file_name[FS_NMGR_MAX_NAME + 1];
size_t img_len;
long long unsigned int off = UINT_MAX;
long long unsigned int size = UINT_MAX;
const struct cbor_attr_t off_attr[5] = {
[0] = {
.attribute = "off",
.type = CborAttrUnsignedIntegerType,
.addr.uinteger = &off,
.nodefault = true
},
[1] = {
.attribute = "data",
.type = CborAttrByteStringType,
.addr.bytestring.data = img_data,
.addr.bytestring.len = &img_len,
.len = sizeof(img_data)
},
[2] = {
.attribute = "len",
.type = CborAttrUnsignedIntegerType,
.addr.uinteger = &size,
.nodefault = true
},
[3] = {
.attribute = "name",
.type = CborAttrTextStringType,
.addr.string = file_name,
.len = sizeof(file_name)
},
[4] = { 0 },
};
CborError g_err = CborNoError;
int rc;
rc = cbor_read_object(&cb->it, off_attr);
if (rc || off == UINT_MAX) {
return MGMT_ERR_EINVAL;
}
if (off == 0) {
/*
* New upload.
*/
fs_nmgr_state.upload.off = 0;
fs_nmgr_state.upload.size = size;
if (!strlen(file_name)) {
return MGMT_ERR_EINVAL;
}
if (fs_nmgr_state.upload.file) {
fs_close(fs_nmgr_state.upload.file);
fs_nmgr_state.upload.file = NULL;
}
rc = fs_open(file_name, FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE,
&fs_nmgr_state.upload.file);
if (rc) {
return MGMT_ERR_EINVAL;
}
} else if (off != fs_nmgr_state.upload.off) {
/*
* Invalid offset. Drop the data, and respond with the offset we're
* expecting data for.
*/
goto out;
}
if (!fs_nmgr_state.upload.file) {
return MGMT_ERR_EINVAL;
}
if (img_len) {
rc = fs_write(fs_nmgr_state.upload.file, img_data, img_len);
if (rc) {
rc = MGMT_ERR_EINVAL;
goto err_close;
}
fs_nmgr_state.upload.off += img_len;
if (fs_nmgr_state.upload.size == fs_nmgr_state.upload.off) {
/* Done */
fs_close(fs_nmgr_state.upload.file);
fs_nmgr_state.upload.file = NULL;
}
}
out:
g_err |= cbor_encode_text_stringz(&cb->encoder, "rc");
g_err |= cbor_encode_int(&cb->encoder, MGMT_ERR_EOK);
g_err |= cbor_encode_text_stringz(&cb->encoder, "off");
g_err |= cbor_encode_uint(&cb->encoder, fs_nmgr_state.upload.off);
if (g_err) {
return MGMT_ERR_ENOMEM;
}
return 0;
err_close:
fs_close(fs_nmgr_state.upload.file);
fs_nmgr_state.upload.file = NULL;
return rc;
}
int
fs_nmgr_init(void)
{
int rc;
rc = mgmt_group_register(&fs_nmgr_group);
return rc;
}
#endif