You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2017/12/13 18:47:48 UTC

[mynewt-mcumgr] branch master updated: Initial implementation: mgmt, newtmgr

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


The following commit(s) were added to refs/heads/master by this push:
     new 46c0a53  Initial implementation: mgmt, newtmgr
46c0a53 is described below

commit 46c0a53084f1b1c7007abe322d110c75c8fa0828
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Dec 7 17:03:11 2017 -0800

    Initial implementation: mgmt, newtmgr
---
 .gitignore                                         |  37 +++
 mgmt/include/mgmt/mgmt.h                           | 166 ++++++++++
 mgmt/pkg.yml                                       |  29 ++
 mgmt/port/mynewt/include/mynewt_mgmt/mynewt_mgmt.h |  37 +++
 mgmt/port/mynewt/pkg.yml                           |  27 ++
 mgmt/src/mgmt.c                                    | 156 +++++++++
 mgmt/syscfg.yml                                    |  18 ++
 newtmgr/include/newtmgr/newtmgr.h                  |  48 +++
 newtmgr/pkg.yml                                    |  41 +++
 .../mynewt/include/mynewt_newtmgr/mynewt_newtmgr.h |  66 ++++
 newtmgr/port/mynewt/pkg.yml                        |  30 ++
 newtmgr/port/mynewt/src/mynewt_nmgr.c              | 273 ++++++++++++++++
 newtmgr/src/newtmgr.c                              | 353 +++++++++++++++++++++
 13 files changed, 1281 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..91be3d8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+.app.db
+.app
+bin
+obj
+tags
+.gdb_history
+.gdb_out
+.gdb_cmds
+.gdbinit
+*~
+.DS_Store
+*.swp
+*.swo
+*.bak
+docs/html
+docs/latex
+cscope.*
+*.tags
diff --git a/mgmt/include/mgmt/mgmt.h b/mgmt/include/mgmt/mgmt.h
new file mode 100644
index 0000000..b2c5dd1
--- /dev/null
+++ b/mgmt/include/mgmt/mgmt.h
@@ -0,0 +1,166 @@
+/*
+ * 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 "tinycbor/cbor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* MTU for newtmgr responses */
+#define MGMT_MAX_MTU 1024
+
+#define NMGR_OP_READ            (0)
+#define NMGR_OP_READ_RSP        (1)
+#define NMGR_OP_WRITE           (2)
+#define NMGR_OP_WRITE_RSP       (3)
+
+/* First 64 groups are reserved for system level newtmgr 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)
+
+/**
+ * Newtmgr 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_EPERUSER   (256)
+
+#define NMGR_HDR_SIZE           (8)
+
+struct nmgr_hdr {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+    uint8_t  nh_op:3;           /* NMGR_OP_XXX */
+    uint8_t  _res1:5;
+#endif
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+    uint8_t  _res1:5;
+    uint8_t  nh_op:3;           /* NMGR_OP_XXX */
+#endif
+    uint8_t  nh_flags;          /* reserved for future flags */
+    uint16_t nh_len;            /* length of the payload */
+    uint16_t nh_group;          /* NMGR_GROUP_XXX */
+    uint8_t  nh_seq;            /* sequence number */
+    uint8_t  nh_id;             /* message ID within group */
+};
+
+typedef void *mgmt_alloc_rsp_fn(const void *req, void *arg);
+typedef int mgmt_trim_front_fn(void *buf, int len, void *arg);
+typedef void mgmt_reset_buf_fn(void *buf, void *arg);
+typedef int mgmt_write_at_fn(struct cbor_encoder_writer *writer, int offset,
+                             const void *data, int len, void *arg);
+typedef int mgmt_init_reader_fn(struct cbor_decoder_reader *reader, void *buf,
+                                void *arg);
+typedef int mgmt_init_writer_fn(struct cbor_encoder_writer *writer, void *buf,
+                                void *arg);
+typedef void mgmt_free_buf_fn(void *buf, void *arg);
+
+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;
+};
+
+/** Decodes requests and encodes responses. */
+struct mgmt_streamer {
+    const struct mgmt_streamer_cfg *cfg;
+    void *cb_arg;
+    struct cbor_decoder_reader *reader;
+    struct cbor_encoder_writer *writer;
+};
+
+/**
+ * Context required by command handlers for parsing requests and writing
+ * responses.
+ */
+struct mgmt_cbuf {
+    struct CborEncoder encoder;
+    struct CborParser parser;
+    struct CborValue it;
+};
+
+typedef int mgmt_handler_fn(struct mgmt_cbuf *cbuf);
+
+/** Read and write handlers for a single command ID. */
+struct mgmt_handler {
+    mgmt_handler_fn *mh_read;
+    mgmt_handler_fn *mh_write;
+};
+
+/** A collection of handlers for every command in a single group. */
+struct mgmt_group {
+    const struct mgmt_handler *mg_handlers;
+    uint16_t mg_handlers_count;
+    uint16_t mg_group_id;
+    struct mgmt_group *mg_next;
+};
+
+#define MGMT_GROUP_SET_HANDLERS(group__, handlers__) do {   \
+    (group__)->mg_handlers = (handlers__);                  \
+    (group__)->mg_handlers_count =                          \
+        sizeof (handlers__) / sizeof (handlers__)[0];       \
+} while (0)
+
+void *mgmt_streamer_alloc_rsp(struct mgmt_streamer *streamer, const void *req);
+int mgmt_streamer_trim_front(struct mgmt_streamer *streamer, void *buf,
+                             int len);
+void mgmt_streamer_reset_buf(struct mgmt_streamer *streamer, void *buf);
+int mgmt_streamer_write_at(struct mgmt_streamer *streamer, int offset,
+                           const void *data, int len);
+int mgmt_streamer_init_reader(struct mgmt_streamer *streamer, void *buf);
+int mgmt_streamer_init_writer(struct mgmt_streamer *streamer, void *buf);
+void mgmt_streamer_free_buf(struct mgmt_streamer *streamer, void *buf);
+
+int mgmt_group_register(struct mgmt_group *group);
+int mgmt_cbuf_setoerr(struct mgmt_cbuf *cbuf, int errcode);
+const struct mgmt_handler *mgmt_find_handler(uint16_t group_id,
+                                             uint16_t command_id);
+int mgmt_err_from_cbor(int cbor_status);
+int mgmt_cbuf_init(struct mgmt_cbuf *cbuf, struct mgmt_streamer *streamer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MGMT_MGMT_H_ */
diff --git a/mgmt/pkg.yml b/mgmt/pkg.yml
new file mode 100644
index 0000000..7059910
--- /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/mgmt
+pkg.description: System-wide management interfaces.
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - encoding/tinycbor
+    - kernel/os
+    - mgmt/mgmt/port/mynewt
diff --git a/mgmt/port/mynewt/include/mynewt_mgmt/mynewt_mgmt.h b/mgmt/port/mynewt/include/mynewt_mgmt/mynewt_mgmt.h
new file mode 100644
index 0000000..2dfaa2c
--- /dev/null
+++ b/mgmt/port/mynewt/include/mynewt_mgmt/mynewt_mgmt.h
@@ -0,0 +1,37 @@
+/*
+ * 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_MYNEWT_MGMT_
+#define H_MYNEWT_MGMT_
+
+#include "mgmt/mgmt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_eventq *mgmt_evq_get(void);
+void mgmt_evq_set(struct os_eventq *evq);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/mgmt/port/mynewt/pkg.yml b/mgmt/port/mynewt/pkg.yml
new file mode 100644
index 0000000..048acfc
--- /dev/null
+++ b/mgmt/port/mynewt/pkg.yml
@@ -0,0 +1,27 @@
+#
+# 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/mgmt/port/mynewt
+pkg.description: XXX
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - kernel/os
diff --git a/mgmt/src/mgmt.c b/mgmt/src/mgmt.c
new file mode 100644
index 0000000..1acb60f
--- /dev/null
+++ b/mgmt/src/mgmt.c
@@ -0,0 +1,156 @@
+/*
+ * 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 "tinycbor/cbor.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);
+}
+
+int
+mgmt_streamer_trim_front(struct mgmt_streamer *streamer, void *buf, int len)
+{
+    return 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, int 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);
+}
+
+int
+mgmt_group_register(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;
+
+    return 0;
+}
+
+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_cbuf_setoerr(struct mgmt_cbuf *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_cbuf_init(struct mgmt_cbuf *cbuf, struct mgmt_streamer *streamer)
+{
+    int rc;
+
+    rc = cbor_parser_init(streamer->reader, 0, &cbuf->parser, &cbuf->it);
+    if (rc != CborNoError) {
+        return mgmt_err_from_cbor(rc);
+    }
+
+    cbor_encoder_init(&cbuf->encoder, streamer->writer, 0);
+
+    return 0;
+}
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.
+#
diff --git a/newtmgr/include/newtmgr/newtmgr.h b/newtmgr/include/newtmgr/newtmgr.h
new file mode 100644
index 0000000..23ae190
--- /dev/null
+++ b/newtmgr/include/newtmgr/newtmgr.h
@@ -0,0 +1,48 @@
+/*
+ * 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 _NEWTMGR_H_
+#define _NEWTMGR_H_
+
+#include "mgmt/mgmt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mynewt_nmgr_transport;
+struct nmgr_streamer;
+struct nmgr_hdr;
+typedef int nmgr_tx_rsp_fn(struct nmgr_streamer *ns, void *buf, void *arg);
+
+struct nmgr_streamer {
+    struct mgmt_streamer ns_base;
+    nmgr_tx_rsp_fn *ns_tx_rsp;
+};
+
+void nmgr_ntoh_hdr(struct nmgr_hdr *hdr);
+int nmgr_handle_single_payload(struct mgmt_cbuf *cbuf,
+                               const struct nmgr_hdr *req_hdr);
+int nmgr_process_single_packet(struct nmgr_streamer *streamer, void *req);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETMGR_H */
diff --git a/newtmgr/pkg.yml b/newtmgr/pkg.yml
new file mode 100644
index 0000000..2d48007
--- /dev/null
+++ b/newtmgr/pkg.yml
@@ -0,0 +1,41 @@
+#
+# 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/newtmgr
+pkg.description: Server-side newtmgr functionality.
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - encoding/cborattr
+    - kernel/os
+    - mgmt/mgmt
+    - mgmt/newtmgr/nmgr_os
+    - mgmt/newtmgr/port/mynewt
+    - util/mem
+
+pkg.deps.NEWTMGR_BLE_HOST:
+    - mgmt/newtmgr/transport/ble
+
+pkg.apis:
+    - newtmgr
+
+pkg.init:
+    nmgr_pkg_init: 500
diff --git a/newtmgr/port/mynewt/include/mynewt_newtmgr/mynewt_newtmgr.h b/newtmgr/port/mynewt/include/mynewt_newtmgr/mynewt_newtmgr.h
new file mode 100644
index 0000000..0317ef5
--- /dev/null
+++ b/newtmgr/port/mynewt/include/mynewt_newtmgr/mynewt_newtmgr.h
@@ -0,0 +1,66 @@
+/*
+ * 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_MYNEWT_NEWTMGR_
+#define H_MYNEWT_NEWTMGR_
+
+#include <inttypes.h>
+#include "mgmt/mgmt.h"
+#include "os/os_mbuf.h"
+struct mynewt_nmgr_transport;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Transmit function.  The supplied mbuf is always consumed, regardless of
+ * return code.
+ */
+typedef int mynewt_nmgr_transport_out_fn(struct mynewt_nmgr_transport *mnt,
+                                         struct os_mbuf *m);
+
+/**
+ * MTU query function.  The supplied mbuf should contain a request received
+ * from the peer whose MTU is being queried.  This function takes an mbuf
+ * parameter because some transports store connection-specific information in
+ * the mbuf user header (e.g., the BLE transport stores the connection handle).
+ *
+ * @return                      The transport's MTU;
+ *                              0 if transmission is currently not possible.
+ */
+typedef uint16_t mynewt_nmgr_transport_get_mtu_fn(struct os_mbuf *m);
+
+struct mynewt_nmgr_transport {
+    struct os_mqueue mnt_imq;
+    mynewt_nmgr_transport_out_fn *mnt_output;
+    mynewt_nmgr_transport_get_mtu_fn *mnt_get_mtu;
+};
+
+int mynewt_nmgr_transport_init(struct mynewt_nmgr_transport *mnt,
+                               mynewt_nmgr_transport_out_fn *output_func,
+                               mynewt_nmgr_transport_get_mtu_fn *get_mtu_func);
+
+int mynewt_nmgr_rx_req(struct mynewt_nmgr_transport *mnt, struct os_mbuf *req);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_MYNEWT_NETMGR_ */
diff --git a/newtmgr/port/mynewt/pkg.yml b/newtmgr/port/mynewt/pkg.yml
new file mode 100644
index 0000000..bb90250
--- /dev/null
+++ b/newtmgr/port/mynewt/pkg.yml
@@ -0,0 +1,30 @@
+#
+# 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/newtmgr/port/mynewt
+pkg.description: Server-side newtmgr functionality.
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - kernel/os
+    - mgmt/mgmt
+    - mgmt/mgmt_os
+    - util/mem
diff --git a/newtmgr/port/mynewt/src/mynewt_nmgr.c b/newtmgr/port/mynewt/src/mynewt_nmgr.c
new file mode 100644
index 0000000..7e90e7b
--- /dev/null
+++ b/newtmgr/port/mynewt/src/mynewt_nmgr.c
@@ -0,0 +1,273 @@
+#include "sysinit/sysinit.h"
+
+#include "os/os.h"
+#include "mynewt_mgmt/mynewt_mgmt.h"
+#include "newtmgr/newtmgr.h"
+#include "mgmt_os/mgmt_os.h"
+#include "mem/mem.h"
+#include "tinycbor/cbor_mbuf_reader.h"
+#include "tinycbor/cbor_mbuf_writer.h"
+#include "mynewt_newtmgr/mynewt_newtmgr.h"
+
+/* Shared queue that newtmgr uses for work items. */
+struct os_eventq *nmgr_evq;
+
+static mgmt_alloc_rsp_fn mynewt_nmgr_alloc_rsp;
+static mgmt_trim_front_fn mynewt_nmgr_trim_front;
+static mgmt_reset_buf_fn mynewt_nmgr_reset_buf;
+static mgmt_write_at_fn mynewt_nmgr_write_at;
+static mgmt_init_reader_fn mynewt_nmgr_init_reader;
+static mgmt_init_writer_fn mynewt_nmgr_init_writer;
+static mgmt_free_buf_fn mynewt_nmgr_free_buf;
+static nmgr_tx_rsp_fn mynewt_nmgr_tx_rsp;
+
+static const struct mgmt_streamer_cfg mynewt_nmgr_cbor_cfg = {
+    .alloc_rsp = mynewt_nmgr_alloc_rsp,
+    .trim_front = mynewt_nmgr_trim_front,
+    .reset_buf = mynewt_nmgr_reset_buf,
+    .write_at = mynewt_nmgr_write_at,
+    .init_reader = mynewt_nmgr_init_reader,
+    .init_writer = mynewt_nmgr_init_writer,
+    .free_buf = mynewt_nmgr_free_buf,
+};
+
+/**
+ * Allocates an mbuf to contain an outgoing response fragment.
+ */
+static struct os_mbuf *
+mynewt_nmgr_rsp_frag_alloc(uint16_t frag_size, void *arg)
+{
+    struct os_mbuf *src_rsp;
+    struct os_mbuf *frag;
+
+    /* We need to duplicate the user header from the source response, as that
+     * is where transport-specific information is stored.
+     */
+    src_rsp = arg;
+
+    frag = os_msys_get_pkthdr(frag_size, OS_MBUF_USRHDR_LEN(src_rsp));
+    if (frag != NULL) {
+        /* Copy the user header from the response into the fragment mbuf. */
+        memcpy(OS_MBUF_USRHDR(frag), OS_MBUF_USRHDR(src_rsp),
+               OS_MBUF_USRHDR_LEN(src_rsp));
+    }
+
+    return frag;
+}
+
+static void *
+mynewt_nmgr_alloc_rsp(const void *req, void *arg)
+{
+    const struct os_mbuf *om_req;
+    struct os_mbuf *om_rsp;
+
+    om_req = req;
+    om_rsp = os_msys_get_pkthdr(512, OS_MBUF_USRHDR_LEN(om_req));
+    if (om_rsp == NULL) {
+        return NULL;
+    }
+
+    /* Copy the request user header into the response. */
+    memcpy(OS_MBUF_USRHDR(om_rsp),
+           OS_MBUF_USRHDR(om_req),
+           OS_MBUF_USRHDR_LEN(om_req));
+
+    return om_rsp;
+}
+
+static int
+mynewt_nmgr_trim_front(void *buf, int len, void *arg)
+{
+    struct os_mbuf *om;
+
+    om = buf;
+    os_mbuf_adj(om, len);
+    return 0;
+}
+
+static void
+mynewt_nmgr_reset_buf(void *buf, void *arg)
+{
+    struct os_mbuf *om;
+
+    om = buf;
+    os_mbuf_adj(om, -OS_MBUF_PKTLEN(om));
+}
+
+static int
+mynewt_nmgr_write_at(struct cbor_encoder_writer *writer, int offset,
+                     const void *data, int len, void *arg)
+{
+    struct cbor_mbuf_writer *mw;
+    int rc;
+
+    mw = (struct cbor_mbuf_writer *)writer;
+    rc = os_mbuf_copyinto(mw->m, offset, data, len);
+    if (rc != 0) {
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    return 0;
+}
+
+static int
+mynewt_nmgr_init_reader(struct cbor_decoder_reader *reader, void *buf,
+                        void *arg)
+{
+    struct cbor_mbuf_reader *mr;
+
+    mr = (struct cbor_mbuf_reader *)reader;
+    cbor_mbuf_reader_init(mr, buf, 0);
+
+    return 0;
+}
+
+static int
+mynewt_nmgr_init_writer(struct cbor_encoder_writer *writer, void *buf,
+                        void *arg)
+{
+    struct cbor_mbuf_writer *mw;
+
+    mw = (struct cbor_mbuf_writer *)writer;
+    cbor_mbuf_writer_init(mw, buf);
+
+    return 0;
+}
+
+static int
+mynewt_nmgr_tx_rsp(struct nmgr_streamer *ns, void *rsp, void *arg)
+{
+    struct mynewt_nmgr_transport *mnt;
+    struct os_mbuf *om_rsp;
+    struct os_mbuf *frag;
+    uint16_t mtu;
+    int rc;
+
+    mnt = arg;
+    om_rsp = rsp;
+
+    mtu = mnt->mnt_get_mtu(rsp);
+    if (mtu == 0) {
+        /* The transport cannot support a transmission right now. */
+        return MGMT_ERR_EUNKNOWN;
+    }
+
+    while (om_rsp != NULL) {
+        frag = mem_split_frag(&om_rsp, mtu, mynewt_nmgr_rsp_frag_alloc,
+                              om_rsp);
+        if (frag == NULL) {
+            return MGMT_ERR_ENOMEM;
+        }
+
+        rc = mnt->mnt_output(mnt, frag);
+        if (rc != 0) {
+            /* Output function already freed mbuf. */
+            return MGMT_ERR_EUNKNOWN;
+        }
+    }
+
+    return MGMT_ERR_EOK;
+}
+
+static void
+mynewt_nmgr_free_buf(void *buf, void *arg)
+{
+    os_mbuf_free_chain(buf);
+}
+
+static void
+mynewt_nmgr_process(struct mynewt_nmgr_transport *mnt)
+{
+    struct cbor_mbuf_reader reader;
+    struct cbor_mbuf_writer writer;
+    struct nmgr_streamer streamer;
+    struct os_mbuf *req;
+    int rc;
+
+    streamer = (struct nmgr_streamer) {
+        .ns_base = {
+            .cfg = &mynewt_nmgr_cbor_cfg,
+            .reader = &reader.r,
+            .writer = &writer.enc,
+            .cb_arg = mnt,
+        },
+        .ns_tx_rsp = mynewt_nmgr_tx_rsp,
+    };
+
+    while (1) {
+        req = os_mqueue_get(&mnt->mnt_imq);
+        if (req == NULL) {
+            break;
+        }
+
+        rc = nmgr_process_single_packet(&streamer, req);
+        if (rc != 0) {
+            break;
+        }
+    }
+}
+
+static void
+mynewt_nmgr_event_data_in(struct os_event *ev)
+{
+    mynewt_nmgr_process(ev->ev_arg);
+}
+
+int
+mynewt_nmgr_transport_init(struct mynewt_nmgr_transport *mnt,
+                           mynewt_nmgr_transport_out_fn *output_func,
+                           mynewt_nmgr_transport_get_mtu_fn *get_mtu_func)
+{
+    int rc;
+
+    *mnt = (struct mynewt_nmgr_transport) {
+        .mnt_output = output_func,
+        .mnt_get_mtu = get_mtu_func,
+    };
+
+    rc = os_mqueue_init(&mnt->mnt_imq, mynewt_nmgr_event_data_in, mnt);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+mynewt_nmgr_rx_req(struct mynewt_nmgr_transport *mnt, struct os_mbuf *req)
+{
+    int rc;
+
+    rc = os_mqueue_put(&mnt->mnt_imq, mgmt_evq_get(), req);
+    if (rc != 0) {
+        os_mbuf_free_chain(req);
+    }
+
+    return rc;
+}
+
+struct os_eventq *
+mgmt_evq_get(void)
+{
+    return nmgr_evq;
+}
+
+void
+mgmt_evq_set(struct os_eventq *evq)
+{
+    nmgr_evq = evq;
+}
+
+void
+nmgr_pkg_init(void)
+{
+    int rc;
+
+    /* Ensure this function only gets called by sysinit. */
+    SYSINIT_ASSERT_ACTIVE();
+
+    rc = mgmt_os_group_register();
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+    mgmt_evq_set(os_eventq_dflt_get());
+}
diff --git a/newtmgr/src/newtmgr.c b/newtmgr/src/newtmgr.c
new file mode 100644
index 0000000..5266cd7
--- /dev/null
+++ b/newtmgr/src/newtmgr.c
@@ -0,0 +1,353 @@
+/*
+ * 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 <assert.h>
+#include <string.h>
+
+#include "mgmt/mgmt.h"
+#include "newtmgr/newtmgr.h"
+#include "tinycbor/cbor.h"
+#include "tinycbor/cbor_mbuf_writer.h"
+#include "tinycbor/cbor_mbuf_reader.h"
+
+#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
+
+static int
+nmgr_align4(int x)
+{
+    int rem;
+
+    rem = x % 4;
+    if (rem == 0) {
+        return x;
+    } else {
+        return x - rem + 4;
+    }
+}
+
+static uint8_t
+nmgr_rsp_op(uint8_t req_op)
+{
+    if (req_op == NMGR_OP_READ) {
+        return NMGR_OP_READ_RSP;
+    } else {
+        return NMGR_OP_WRITE_RSP;
+    }
+}
+
+void
+nmgr_ntoh_hdr(struct nmgr_hdr *hdr)
+{
+    hdr->nh_len = ntohs(hdr->nh_len);
+    hdr->nh_group = ntohs(hdr->nh_group);
+}
+
+static void
+nmgr_hton_hdr(struct nmgr_hdr *hdr)
+{
+    hdr->nh_len = htons(hdr->nh_len);
+    hdr->nh_group = htons(hdr->nh_group);
+}
+
+static void
+nmgr_init_rsp_hdr(const struct nmgr_hdr *req_hdr, struct nmgr_hdr *rsp_hdr)
+{
+    *rsp_hdr = (struct nmgr_hdr) {
+        .nh_len = 0,
+        .nh_flags = 0,
+        .nh_op = nmgr_rsp_op(req_hdr->nh_op),
+        .nh_group = req_hdr->nh_group,
+        .nh_seq = req_hdr->nh_seq,
+        .nh_id = req_hdr->nh_id,
+    };
+}
+
+static int
+nmgr_read_hdr(struct nmgr_streamer *streamer, struct nmgr_hdr *hdr)
+{
+    struct mgmt_streamer *base;
+
+    base = &streamer->ns_base;
+
+    if (base->reader->message_size < sizeof *hdr) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    base->reader->cpy(base->reader, (char *)hdr, 0, sizeof *hdr);
+    return 0;
+}
+
+static int
+nmgr_write_hdr(struct nmgr_streamer *streamer, const struct nmgr_hdr *hdr)
+{
+    int rc;
+
+    rc = mgmt_streamer_write_at(&streamer->ns_base, 0, hdr, sizeof *hdr);
+    return mgmt_err_from_cbor(rc);
+}
+
+static int
+nmgr_build_err_rsp(struct nmgr_streamer *streamer,
+                   const struct nmgr_hdr *req_hdr,
+                   int status)
+{
+    struct CborEncoder map;
+    struct mgmt_cbuf cbuf;
+    struct nmgr_hdr rsp_hdr;
+    int rc;
+
+    rc = mgmt_cbuf_init(&cbuf, &streamer->ns_base);
+    if (rc != 0) {
+        return rc;
+    }
+
+    nmgr_init_rsp_hdr(req_hdr, &rsp_hdr);
+    rc = nmgr_write_hdr(streamer, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = cbor_encoder_create_map(&cbuf.encoder, &map, CborIndefiniteLength);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = mgmt_cbuf_setoerr(&cbuf, status);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = cbor_encoder_close_container(&cbuf.encoder, &map);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rsp_hdr.nh_len = htons(cbor_encode_bytes_written(&cbuf.encoder));
+    rc = nmgr_write_hdr(streamer, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+nmgr_handle_single_payload(struct mgmt_cbuf *cbuf,
+                           const struct nmgr_hdr *req_hdr)
+{
+    const struct mgmt_handler *handler;
+    struct CborEncoder payload_encoder;
+    int rc;
+
+    handler = mgmt_find_handler(req_hdr->nh_group, req_hdr->nh_id);
+    if (!handler) {
+        return MGMT_ERR_ENOENT;
+    }
+
+    /* Begin response payload.  Response fields are inserted into the root
+     * map as key value pairs.
+     */
+    rc = cbor_encoder_create_map(&cbuf->encoder, &payload_encoder,
+                                 CborIndefiniteLength);
+    rc = mgmt_err_from_cbor(rc);
+    if (rc != 0) {
+        return rc;
+    }
+
+    if (req_hdr->nh_op == NMGR_OP_READ) {
+        if (handler->mh_read) {
+            rc = handler->mh_read(cbuf);
+        } else {
+            rc = MGMT_ERR_ENOENT;
+        }
+    } else if (req_hdr->nh_op == NMGR_OP_WRITE) {
+        if (handler->mh_write) {
+            rc = handler->mh_write(cbuf);
+        } else {
+            rc = MGMT_ERR_ENOENT;
+        }
+    } else {
+        rc = MGMT_ERR_EINVAL;
+    }
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* End response payload. */
+    rc = cbor_encoder_close_container(&cbuf->encoder, &payload_encoder);
+    rc = mgmt_err_from_cbor(rc);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+
+static int
+nmgr_handle_single_req(struct nmgr_streamer *streamer,
+                       const struct nmgr_hdr *req_hdr)
+{
+    struct mgmt_cbuf cbuf;
+    struct nmgr_hdr rsp_hdr;
+    int rc;
+
+    rc = mgmt_cbuf_init(&cbuf, &streamer->ns_base);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* Build response header a priori, then pass to the handlers to fill out
+     * the response data and adjust length and flags.
+     */
+    nmgr_init_rsp_hdr(req_hdr, &rsp_hdr);
+    rc = nmgr_write_hdr(streamer, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = nmgr_handle_single_payload(&cbuf, req_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rsp_hdr.nh_len = cbor_encode_bytes_written(&cbuf.encoder);
+    nmgr_hton_hdr(&rsp_hdr);
+    rc = nmgr_write_hdr(streamer, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static void
+nmgr_on_err(struct nmgr_streamer *streamer,
+            const struct nmgr_hdr *req_hdr,
+            void *req,
+            void *rsp,
+            int status)
+{
+    int rc;
+
+    if (rsp == NULL) {
+        rsp = req;
+        req = NULL;
+    }
+
+    mgmt_streamer_reset_buf(&streamer->ns_base, rsp);
+    mgmt_streamer_init_writer(&streamer->ns_base, rsp);
+
+    rc = nmgr_build_err_rsp(streamer, req_hdr, status);
+    if (rc == 0) {
+        streamer->ns_tx_rsp(streamer, rsp, streamer->ns_base.cb_arg);
+        rsp = NULL;
+    }
+
+    mgmt_streamer_free_buf(&streamer->ns_base, req);
+    mgmt_streamer_free_buf(&streamer->ns_base, rsp);
+}
+
+int
+nmgr_process_single_packet(struct nmgr_streamer *streamer, void *req)
+{
+    struct nmgr_hdr req_hdr;
+    void *rsp;
+    bool valid_hdr;
+    int rc;
+
+    rsp = NULL;
+    valid_hdr = true;
+
+    while (1) {
+        rc = mgmt_streamer_init_reader(&streamer->ns_base, req);
+        if (rc != 0) {
+            valid_hdr = false;
+            break;
+        }
+
+        rc = nmgr_read_hdr(streamer, &req_hdr);
+        if (rc != 0) {
+            valid_hdr = false;
+            break;
+        }
+        nmgr_ntoh_hdr(&req_hdr);
+        rc = mgmt_streamer_trim_front(&streamer->ns_base, req, NMGR_HDR_SIZE);
+        assert(rc == 0);
+
+        rsp = mgmt_streamer_alloc_rsp(&streamer->ns_base, req);
+        if (rsp == NULL) {
+            rc = MGMT_ERR_ENOMEM;
+            break;
+        }
+
+        rc = mgmt_streamer_init_writer(&streamer->ns_base, rsp);
+        if (rc != 0) {
+            break;
+        }
+
+        rc = nmgr_handle_single_req(streamer, &req_hdr);
+        if (rc != 0) {
+            break;
+        }
+
+        rc = streamer->ns_tx_rsp(streamer, rsp, streamer->ns_base.cb_arg);
+        rsp = NULL;
+        if (rc != 0) {
+            break;
+        }
+
+        /* Trim processed request to free up space for subsequent responses. */
+        rc = mgmt_streamer_trim_front(&streamer->ns_base, req,
+                                      nmgr_align4(req_hdr.nh_len));
+        assert(rc == 0);
+    }
+
+    if (rc != 0 && valid_hdr) {
+        nmgr_on_err(streamer, &req_hdr, req, rsp, rc);
+        return rc;
+    }
+
+    mgmt_streamer_free_buf(&streamer->ns_base, req);
+    mgmt_streamer_free_buf(&streamer->ns_base, rsp);
+    return 0;
+}

-- 
To stop receiving notification emails like this one, please contact
['"commits@mynewt.apache.org" <co...@mynewt.apache.org>'].