This is an automated email from the ASF dual-hosted git repository. ccollins pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-mcumgr.git
commit 9f3757c1f5b1938e0a323e5ddb243c21f0c6b1ed Author: Christopher Collins <ccoll...@apache.org> AuthorDate: Wed Jan 17 17:11:06 2018 -0800 mgmt - Code implementing the core `mgmt` layer. The core of mcumgr; facilitates the passing of requests and responses between the generic command handlers and the concrete transports and transfer encodings. --- mgmt/CMakeLists.txt | 8 + mgmt/include/mgmt/endian.h | 58 +++++++ mgmt/include/mgmt/mgmt.h | 388 +++++++++++++++++++++++++++++++++++++++++++++ mgmt/pkg.yml | 29 ++++ mgmt/src/mgmt.c | 170 ++++++++++++++++++++ mgmt/syscfg.yml | 18 +++ 6 files changed, 671 insertions(+) diff --git a/mgmt/CMakeLists.txt b/mgmt/CMakeLists.txt new file mode 100644 index 0000000..ffce8a5 --- /dev/null +++ b/mgmt/CMakeLists.txt @@ -0,0 +1,8 @@ +target_include_directories(MCUMGR INTERFACE + include + port/zephyr/include +) + +zephyr_library_sources( + mgmt/src/mgmt.c +) diff --git a/mgmt/include/mgmt/endian.h b/mgmt/include/mgmt/endian.h new file mode 100644 index 0000000..ad9bd34 --- /dev/null +++ b/mgmt/include/mgmt/endian.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef H_MGMT_ENDIAN_ +#define H_MGMT_ENDIAN_ + +#include <inttypes.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + +#ifndef ntohs +#define ntohs(x) (x) +#endif + +#ifndef htons +#define htons(x) (x) +#endif + +#else +/* Little endian. */ + +#ifndef ntohs +#define ntohs(x) ((uint16_t) \ + ((((x) & 0xff00) >> 8) | \ + (((x) & 0x00ff) << 8))) +#endif + +#ifndef htons +#define htons(x) (ntohs(x)) +#endif + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mgmt/include/mgmt/mgmt.h b/mgmt/include/mgmt/mgmt.h new file mode 100644 index 0000000..549fcdc --- /dev/null +++ b/mgmt/include/mgmt/mgmt.h @@ -0,0 +1,388 @@ +/* + * 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. + */ + +#ifndef H_MGMT_MGMT_ +#define H_MGMT_MGMT_ + +#include <inttypes.h> +#include "cbor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opcodes; encoded in first byte of header. */ +#define MGMT_OP_READ 0 +#define MGMT_OP_READ_RSP 1 +#define MGMT_OP_WRITE 2 +#define MGMT_OP_WRITE_RSP 3 + +/** + * The first 64 groups are reserved for system level mcumgr commands. + * Per-user commands are then defined after group 64. + */ +#define MGMT_GROUP_ID_OS 0 +#define MGMT_GROUP_ID_IMAGE 1 +#define MGMT_GROUP_ID_STATS 2 +#define MGMT_GROUP_ID_CONFIG 3 +#define MGMT_GROUP_ID_LOGS 4 +#define MGMT_GROUP_ID_CRASH 5 +#define MGMT_GROUP_ID_SPLIT 6 +#define MGMT_GROUP_ID_RUN 7 +#define MGMT_GROUP_ID_FS 8 +#define MGMT_GROUP_ID_PERUSER 64 + +/** + * mcumgr error codes. + */ +#define MGMT_ERR_EOK 0 +#define MGMT_ERR_EUNKNOWN 1 +#define MGMT_ERR_ENOMEM 2 +#define MGMT_ERR_EINVAL 3 +#define MGMT_ERR_ETIMEOUT 4 +#define MGMT_ERR_ENOENT 5 +#define MGMT_ERR_EBADSTATE 6 /* Current state disallows command. */ +#define MGMT_ERR_EMSGSIZE 7 /* Response too large. */ +#define MGMT_ERR_ENOTSUP 8 /* Command not supported. */ +#define MGMT_ERR_EPERUSER 256 + +#define MGMT_HDR_SIZE 8 + +struct mgmt_hdr { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + uint8_t nh_op:3; /* MGMT_OP_[...] */ + uint8_t _res1:5; +#endif +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint8_t _res1:5; + uint8_t nh_op:3; /* MGMT_OP_[...] */ +#endif + uint8_t nh_flags; /* Reserved for future flags */ + uint16_t nh_len; /* Length of the payload */ + uint16_t nh_group; /* MGMT_GROUP_ID_[...] */ + uint8_t nh_seq; /* Sequence number */ + uint8_t nh_id; /* Message ID within group */ +}; + +/** @typedef mgmt_alloc_rsp_fn + * @brief Allocates a buffer suitable for holding a response. + * + * If a source buf is provided, its user data is copied into the new buffer. + * + * @param src_buf An optional source buffer to copy user data + * from. + * @param arg Optional streamer argument. + * + * @return Newly-allocated buffer on success + * NULL on failure. + */ +typedef void *mgmt_alloc_rsp_fn(const void *src_buf, void *arg); + +/** @typedef mgmt_trim_front_fn + * @brief Trims data from the front of a buffer. + * + * If the amount to trim exceeds the size of the buffer, the buffer is + * truncated to a length of 0. + * + * @param buf The buffer to trim. + * @param len The number of bytes to remove. + * @param arg Optional streamer argument. + */ +typedef void mgmt_trim_front_fn(void *buf, size_t len, void *arg); + +/** @typedef mgmt_reset_buf_fn + * @brief Resets a buffer to a length of 0. + * + * The buffer's user data remains, but its payload is cleared. + * + * @param buf The buffer to reset. + * @param arg Optional streamer argument. + */ +typedef void mgmt_reset_buf_fn(void *buf, void *arg); + +/** @typedef mgmt_write_at_fn + * @brief Writes data to a CBOR encoder. + * + * Any existing data at the specified offset is overwritten by the new data. + * Any new data that extends past the buffer's current length is appended. + * + * @param writer The encoder to write to. + * @param offset The byte offset to write to, + * @param data The data to write. + * @param len The number of bytes to write. + * @param arg Optional streamer argument. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +typedef int mgmt_write_at_fn(struct cbor_encoder_writer *writer, size_t offset, + const void *data, size_t len, void *arg); + +/** @typedef mgmt_init_reader_fn + * @brief Initializes a CBOR reader with the specified buffer. + * + * @param reader The reader to initialize. + * @param buf The buffer to configure the reader with. + * @param arg Optional streamer argument. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +typedef int mgmt_init_reader_fn(struct cbor_decoder_reader *reader, void *buf, + void *arg); + +/** @typedef mgmt_init_writer_fn + * @brief Initializes a CBOR writer with the specified buffer. + * + * @param writer The writer to initialize. + * @param buf The buffer to configure the writer with. + * @param arg Optional streamer argument. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +typedef int mgmt_init_writer_fn(struct cbor_encoder_writer *writer, void *buf, + void *arg); + +/** @typedef mgmt_init_writer_fn + * @brief Frees the specified buffer. + * + * @param buf The buffer to free. + * @param arg Optional streamer argument. + */ +typedef void mgmt_free_buf_fn(void *buf, void *arg); + +/** + * @brief Configuration for constructing a mgmt_streamer object. + */ +struct mgmt_streamer_cfg { + mgmt_alloc_rsp_fn *alloc_rsp; + mgmt_trim_front_fn *trim_front; + mgmt_reset_buf_fn *reset_buf; + mgmt_write_at_fn *write_at; + mgmt_init_reader_fn *init_reader; + mgmt_init_writer_fn *init_writer; + mgmt_free_buf_fn *free_buf; +}; + +/** + * @brief Decodes requests and encodes responses for any mcumgr protocol. + */ +struct mgmt_streamer { + const struct mgmt_streamer_cfg *cfg; + void *cb_arg; + struct cbor_decoder_reader *reader; + struct cbor_encoder_writer *writer; +}; + +/** + * @brief Context required by command handlers for parsing requests and writing + * responses. + */ +struct mgmt_ctxt { + struct CborEncoder encoder; + struct CborParser parser; + struct CborValue it; +}; + +/** @typedef mgmt_handler_fn + * @brief Processes a request and writes the corresponding response. + * + * A separate handler is required for each supported op-ID pair. + * + * @param cbuf The mcumgr context to use. + * + * @return 0 if a response was successfully encoded, + * MGMT_ERR_[...] code on failure. + */ +typedef int mgmt_handler_fn(struct mgmt_ctxt *cbuf); + +/** + * @brief Read handler and write handler for a single command ID. + */ +struct mgmt_handler { + mgmt_handler_fn *mh_read; + mgmt_handler_fn *mh_write; +}; + +/** + * @brief A collection of handlers for an entire command group. + */ +struct mgmt_group { + /** Points to the next group in the list. */ + struct mgmt_group *mg_next; + + /** Array of handlers; one entry per command ID. */ + const struct mgmt_handler *mg_handlers; + uint16_t mg_handlers_count; + + /* The numeric ID of this group. */ + uint16_t mg_group_id; +}; + +/** + * @brief Uses the specified streamer to allocates a response buffer. + * + * If a source buf is provided, its user data is copied into the new buffer. + * + * @param streamer The streamer providing the callback. + * @param src_buf An optional source buffer to copy user data + * from. + * + * @return Newly-allocated buffer on success + * NULL on failure. + */ +void *mgmt_streamer_alloc_rsp(struct mgmt_streamer *streamer, + const void *src_buf); + +/** + * @brief Uses the specified streamer to trim data from the front of a buffer. + * + * If the amount to trim exceeds the size of the buffer, the buffer is + * truncated to a length of 0. + * + * @param streamer The streamer providing the callback. + * @param buf The buffer to trim. + * @param len The number of bytes to remove. + */ +void mgmt_streamer_trim_front(struct mgmt_streamer *streamer, void *buf, + size_t len); + +/** + * @brief Uses the specified streamer to reset a buffer to a length of 0. + * + * The buffer's user data remains, but its payload is cleared. + * + * @param streamer The streamer providing the callback. + * @param buf The buffer to reset. + */ +void mgmt_streamer_reset_buf(struct mgmt_streamer *streamer, void *buf); + +/** + * @brief Uses the specified streamer to write data to a CBOR encoder. + * + * Any existing data at the specified offset is overwritten by the new data. + * Any new data that extends past the buffer's current length is appended. + * + * @param streamer The streamer providing the callback. + * @param writer The encoder to write to. + * @param offset The byte offset to write to, + * @param data The data to write. + * @param len The number of bytes to write. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int mgmt_streamer_write_at(struct mgmt_streamer *streamer, size_t offset, + const void *data, int len); + +/** + * @brief Uses the specified streamer to initialize a CBOR reader. + * + * @param streamer The streamer providing the callback. + * @param reader The reader to initialize. + * @param buf The buffer to configure the reader with. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int mgmt_streamer_init_reader(struct mgmt_streamer *streamer, void *buf); + +/** + * @brief Uses the specified streamer to initializes a CBOR writer. + * + * @param streamer The streamer providing the callback. + * @param writer The writer to initialize. + * @param buf The buffer to configure the writer with. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int mgmt_streamer_init_writer(struct mgmt_streamer *streamer, void *buf); + +/** + * @brief Uses the specified streamer to free a buffer. + * + * @param streamer The streamer providing the callback. + * @param buf The buffer to free. + */ +void mgmt_streamer_free_buf(struct mgmt_streamer *streamer, void *buf); + +/** + * @brief Registers a full command group. + * + * @param group The group to register. + */ +void mgmt_register_group(struct mgmt_group *group); + +/** + * @brief Finds a registered command handler. + * + * @param group_id The group of the command to find. + * @param command_id The ID of the command to find. + * + * @return The requested command handler on success; + * NULL on failure. + */ +const struct mgmt_handler *mgmt_find_handler(uint16_t group_id, + uint16_t command_id); + +/** + * @brief Encodes a response status into the specified management context. + * + * @param cbuf The management context to encode into. + * @param status The response status to write. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int mgmt_write_rsp_status(struct mgmt_ctxt *cbuf, int status); + +/** + * @brief Initializes a management context object with the specified streamer. + * + * @param cbuf The context object to initialize. + * @param streamer The streamer that will be used with the + * context. + * + * @return 0 on success, MGMT_ERR_[...] code on failure. + */ +int mgmt_ctxt_init(struct mgmt_ctxt *cbuf, struct mgmt_streamer *streamer); + +/** + * @brief Converts a CBOR status code to a MGMT_ERR_[...] code. + * + * @param cbor_status The CBOR status code to convert. + * + * @return The corresponding MGMT_ERR_[,,,] code. + */ +int mgmt_err_from_cbor(int cbor_status); + +/** + * @brief Byte-swaps an mcumgr header from network to host byte order. + * + * @param hdr The mcumgr header to byte-swap. + */ +void mgmt_ntoh_hdr(struct mgmt_hdr *hdr); + +/** + * @brief Byte-swaps an mcumgr header from host to network byte order. + * + * @param hdr The mcumgr header to byte-swap. + */ +void mgmt_hton_hdr(struct mgmt_hdr *hdr); + +#ifdef __cplusplus +} +#endif + +#endif /* MGMT_MGMT_H_ */ diff --git a/mgmt/pkg.yml b/mgmt/pkg.yml new file mode 100644 index 0000000..94839bd --- /dev/null +++ b/mgmt/pkg.yml @@ -0,0 +1,29 @@ +# +# 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. +# + +pkg.name: mgmt +pkg.description: 'System-wide mcumgr management interfaces.' +pkg.author: "Apache Mynewt <d...@mynewt.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - '@apache-mynewt-core/encoding/tinycbor' + - '@apache-mynewt-core/kernel/os' + - '@mynewt-mcumgr/mgmt' diff --git a/mgmt/src/mgmt.c b/mgmt/src/mgmt.c new file mode 100644 index 0000000..ccea65a --- /dev/null +++ b/mgmt/src/mgmt.c @@ -0,0 +1,170 @@ +/* + * 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 <string.h> +#include "cbor.h" +#include "mgmt/endian.h" +#include "mgmt/mgmt.h" + +static struct mgmt_group *mgmt_group_list; +static struct mgmt_group *mgmt_group_list_end; + +void * +mgmt_streamer_alloc_rsp(struct mgmt_streamer *streamer, const void *req) +{ + return streamer->cfg->alloc_rsp(req, streamer->cb_arg); +} + +void +mgmt_streamer_trim_front(struct mgmt_streamer *streamer, void *buf, size_t len) +{ + streamer->cfg->trim_front(buf, len, streamer->cb_arg); +} + +void +mgmt_streamer_reset_buf(struct mgmt_streamer *streamer, void *buf) +{ + streamer->cfg->reset_buf(buf, streamer->cb_arg); +} + +int +mgmt_streamer_write_at(struct mgmt_streamer *streamer, size_t offset, + const void *data, int len) +{ + return streamer->cfg->write_at(streamer->writer, offset, data, len, + streamer->cb_arg); +} + +int +mgmt_streamer_init_reader(struct mgmt_streamer *streamer, void *buf) +{ + return streamer->cfg->init_reader(streamer->reader, buf, streamer->cb_arg); +} + +int +mgmt_streamer_init_writer(struct mgmt_streamer *streamer, void *buf) +{ + return streamer->cfg->init_writer(streamer->writer, buf, streamer->cb_arg); +} + +void +mgmt_streamer_free_buf(struct mgmt_streamer *streamer, void *buf) +{ + streamer->cfg->free_buf(buf, streamer->cb_arg); +} + +void +mgmt_register_group(struct mgmt_group *group) +{ + if (mgmt_group_list_end == NULL) { + mgmt_group_list = group; + } else { + mgmt_group_list_end->mg_next = group; + } + mgmt_group_list_end = group; +} + +static struct mgmt_group * +mgmt_find_group(uint16_t group_id) +{ + struct mgmt_group *group; + + for (group = mgmt_group_list; group != NULL; group = group->mg_next) { + if (group->mg_group_id == group_id) { + return group; + } + } + + return NULL; +} + +const struct mgmt_handler * +mgmt_find_handler(uint16_t group_id, uint16_t command_id) +{ + const struct mgmt_group *group; + + group = mgmt_find_group(group_id); + if (group == NULL) { + return NULL; + } + + if (command_id >= group->mg_handlers_count) { + return NULL; + } + + return &group->mg_handlers[command_id]; +} + +int +mgmt_write_rsp_status(struct mgmt_ctxt *cbuf, int errcode) +{ + int rc; + + rc = cbor_encode_text_stringz(&cbuf->encoder, "rc"); + if (rc != 0) { + return rc; + } + + rc = cbor_encode_int(&cbuf->encoder, errcode); + if (rc != 0) { + return rc; + } + + return 0; +} + +int +mgmt_err_from_cbor(int cbor_status) +{ + switch (cbor_status) { + case CborNoError: return MGMT_ERR_EOK; + case CborErrorOutOfMemory: return MGMT_ERR_ENOMEM; + default: return MGMT_ERR_EUNKNOWN; + } +} + +int +mgmt_ctxt_init(struct mgmt_ctxt *cbuf, struct mgmt_streamer *streamer) +{ + int rc; + + rc = cbor_parser_cust_reader_init(streamer->reader, 0, &cbuf->parser, + &cbuf->it); + if (rc != CborNoError) { + return mgmt_err_from_cbor(rc); + } + + cbor_encoder_cust_writer_init(&cbuf->encoder, streamer->writer, 0); + + return 0; +} + +void +mgmt_ntoh_hdr(struct mgmt_hdr *hdr) +{ + hdr->nh_len = ntohs(hdr->nh_len); + hdr->nh_group = ntohs(hdr->nh_group); +} + +void +mgmt_hton_hdr(struct mgmt_hdr *hdr) +{ + hdr->nh_len = htons(hdr->nh_len); + hdr->nh_group = htons(hdr->nh_group); +} diff --git a/mgmt/syscfg.yml b/mgmt/syscfg.yml new file mode 100644 index 0000000..30ccc02 --- /dev/null +++ b/mgmt/syscfg.yml @@ -0,0 +1,18 @@ +# +# 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. +# -- To stop receiving notification emails like this one, please contact "commits@mynewt.apache.org" <commits@mynewt.apache.org>.