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/08 00:56:06 UTC

[mynewt-mcumgr] 01/02: initial commit

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 63166fd4cea4b98dea110185a5467a9612dc15f0
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Dec 7 12:41:12 2017 -0800

    initial commit
---
 .gitignore                                         |  37 ++
 mgmt/mgmt/include/mgmt/mgmt.h                      | 139 ++++++++
 mgmt/mgmt/pkg.yml                                  |  28 ++
 mgmt/mgmt/src/mgmt.c                               | 112 ++++++
 mgmt/mgmt/syscfg.yml                               |  18 +
 mgmt/newtmgr/include/newtmgr/newtmgr.h             |  74 ++++
 mgmt/newtmgr/nmgr_os/include/nmgr_os/nmgr_os.h     |  43 +++
 mgmt/newtmgr/nmgr_os/pkg.yml                       |  38 ++
 mgmt/newtmgr/nmgr_os/src/newtmgr_os.c              | 346 ++++++++++++++++++
 mgmt/newtmgr/nmgr_os/syscfg.yml                    |  23 ++
 mgmt/newtmgr/pkg.yml                               |  40 +++
 mgmt/newtmgr/src/mynewt_nmgr.c                     | 182 ++++++++++
 mgmt/newtmgr/src/newtmgr.c                         | 205 +++++++++++
 .../transport/ble/include/nmgrble/newtmgr_ble.h    |  42 +++
 mgmt/newtmgr/transport/ble/pkg.yml                 |  35 ++
 mgmt/newtmgr/transport/ble/src/newtmgr_ble.c       | 242 +++++++++++++
 mgmt/newtmgr/transport/nmgr_shell/pkg.yml          |  34 ++
 mgmt/newtmgr/transport/nmgr_shell/src/nmgr_shell.c |  71 ++++
 mgmt/newtmgr/transport/nmgr_uart/pkg.yml           |  35 ++
 mgmt/newtmgr/transport/nmgr_uart/src/nmgr_uart.c   | 389 +++++++++++++++++++++
 mgmt/newtmgr/transport/nmgr_uart/syscfg.yml        |  28 ++
 21 files changed, 2161 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/mgmt/include/mgmt/mgmt.h b/mgmt/mgmt/include/mgmt/mgmt.h
new file mode 100644
index 0000000..0313736
--- /dev/null
+++ b/mgmt/mgmt/include/mgmt/mgmt.h
@@ -0,0 +1,139 @@
+/*
+ * 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 _MGMT_MGMT_H_
+#define _MGMT_MGMT_H_
+
+#include <inttypes.h>
+
+#include <os/queue.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* MTU for newtmgr responses */
+#define MGMT_MAX_MTU 1024
+
+#ifndef STR
+/* Stringification of constants */
+#define STR(x) #x
+#endif
+
+#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_DEFAULT   (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;          /* XXX 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 int mgmt_reader_trim_front_fn(struct cbor_decoder_reader *reader,
+                                      int len);
+typedef int mgmt_writer_write_at_fn(struct cbor_encoder_writer *writer,
+                                    int offset, const void *data, int len);
+
+/* XXX: Bad name */
+struct mgmt_cbor_cfg {
+    mgmt_reader_trim_front_fn *trim_front;
+    mgmt_writer_write_at_fn *write_at;
+
+    struct cbor_decoder_reader *reader;
+    struct cbor_encoder_writer *writer;
+};
+
+struct mgmt_cbuf {
+    struct CborEncoder encoder;
+    struct CborParser parser;
+    struct CborValue it;
+};
+
+typedef int (*mgmt_handler_func_t)(struct mgmt_cbuf *);
+
+struct mgmt_handler {
+    mgmt_handler_func_t mh_read;
+    mgmt_handler_func_t mh_write;
+};
+
+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)       \
+    (__group)->mg_handlers = (__handlers);                 \
+    (__group)->mg_handlers_count = (sizeof((__handlers)) / \
+            sizeof(struct mgmt_handler));
+
+int mgmt_group_register(struct mgmt_group *group);
+int mgmt_cbuf_setoerr(struct mgmt_cbuf *njb, int errcode);
+const struct mgmt_handler *mgmt_find_handler(uint16_t group_id,
+  uint16_t handler_id);
+int mgmt_err_from_cbor(int cbor_status);
+int mgmt_cbuf_init(struct mgmt_cbuf *cbuf, struct mgmt_cbor_cfg *cfg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MGMT_MGMT_H_ */
diff --git a/mgmt/mgmt/pkg.yml b/mgmt/mgmt/pkg.yml
new file mode 100644
index 0000000..2361166
--- /dev/null
+++ b/mgmt/mgmt/pkg.yml
@@ -0,0 +1,28 @@
+#
+# 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:
+    - kernel/os
+    - encoding/tinycbor
diff --git a/mgmt/mgmt/src/mgmt.c b/mgmt/mgmt/src/mgmt.c
new file mode 100644
index 0000000..ab0cb8a
--- /dev/null
+++ b/mgmt/mgmt/src/mgmt.c
@@ -0,0 +1,112 @@
+/*
+ * 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 <os/os.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_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;
+}
+
+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 handler_id)
+{
+    struct mgmt_group *group;
+    const struct mgmt_handler *handler;
+
+    group = mgmt_find_group(group_id);
+    if (group == NULL) {
+        return NULL;
+    }
+
+    if (handler_id >= group->mg_handlers_count) {
+        return NULL;
+    }
+
+    return &group->mg_handlers[handler_id];
+}
+
+int
+mgmt_cbuf_setoerr(struct CborEncoder *encoder, int errcode)
+{
+    int rc;
+
+    rc = cbor_encode_text_stringz(encoder, "rc");
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = cbor_encode_int(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_cbor_cfg *cfg)
+{
+    int rc;
+
+    rc = cbor_parser_init(cfg->reader, 0, &cbuf->parser, &cbuf->it);
+    if (rc != CborNoError) {
+        return mgmt_err_from_cbor(rc);
+    }
+
+    cbor_encoder_init(&cbuf->encoder, cfg->writer, 0);
+
+    return 0;
+}
diff --git a/mgmt/mgmt/syscfg.yml b/mgmt/mgmt/syscfg.yml
new file mode 100644
index 0000000..30ccc02
--- /dev/null
+++ b/mgmt/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/mgmt/newtmgr/include/newtmgr/newtmgr.h b/mgmt/newtmgr/include/newtmgr/newtmgr.h
new file mode 100644
index 0000000..b01d962
--- /dev/null
+++ b/mgmt/newtmgr/include/newtmgr/newtmgr.h
@@ -0,0 +1,74 @@
+/*
+ * 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 <tinycbor/cbor.h>
+#include <inttypes.h>
+#include <os/os.h>
+#include <os/endian.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nmgr_transport;
+struct mgmt_cbor_cfg;
+
+/**
+ * Transmit function.  The supplied mbuf is always consumed, regardless of
+ * return code.
+ */
+typedef int (*nmgr_transport_out_func_t)(struct nmgr_transport *nt,
+        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 (*nmgr_transport_get_mtu_func_t)(struct os_mbuf *m);
+
+struct nmgr_transport {
+    nmgr_transport_out_func_t nt_output;
+};
+
+struct mynewt_nmgr_transport {
+    struct nmgr_transport mnt_xport;
+    struct os_mqueue mnt_imq;
+};
+
+int mynewt_nmgr_transport_init(struct mynewt_nmgr_transport *mnt,
+                               nmgr_transport_out_func_t output_func);
+
+int nmgr_build_err_rsp(struct mgmt_cbor_cfg *cfg,
+                       const struct nmgr_hdr *req_hdr,
+                       int status);
+int nmgr_handle_single_req(struct mgmt_cbor_cfg *cfg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETMGR_H */
diff --git a/mgmt/newtmgr/nmgr_os/include/nmgr_os/nmgr_os.h b/mgmt/newtmgr/nmgr_os/include/nmgr_os/nmgr_os.h
new file mode 100644
index 0000000..6c3460f
--- /dev/null
+++ b/mgmt/newtmgr/nmgr_os/include/nmgr_os/nmgr_os.h
@@ -0,0 +1,43 @@
+/*
+ * 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 _NMGR_OS_H_
+#define _NMGR_OS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Id's for OS group commands
+ */
+#define NMGR_ID_ECHO            0
+#define NMGR_ID_CONS_ECHO_CTRL  1
+#define NMGR_ID_TASKSTATS       2
+#define NMGR_ID_MPSTATS         3
+#define NMGR_ID_DATETIME_STR    4
+#define NMGR_ID_RESET           5
+
+int nmgr_os_groups_register(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NMGR_OS_H_ */
diff --git a/mgmt/newtmgr/nmgr_os/pkg.yml b/mgmt/newtmgr/nmgr_os/pkg.yml
new file mode 100644
index 0000000..6c39c16
--- /dev/null
+++ b/mgmt/newtmgr/nmgr_os/pkg.yml
@@ -0,0 +1,38 @@
+#
+# 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/nmgr_os
+pkg.description: Default newtmgr command.
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+    - hw/hal
+    - time/datetime
+    - kernel/os
+    - mgmt/mgmt
+    - encoding/tinycbor
+    - encoding/cborattr
+
+pkg.deps.LOG_SOFT_RESET:
+    - sys/reboot
+
+pkg.req_apis:
+    - newtmgr
diff --git a/mgmt/newtmgr/nmgr_os/src/newtmgr_os.c b/mgmt/newtmgr/nmgr_os/src/newtmgr_os.c
new file mode 100644
index 0000000..b2ebc37
--- /dev/null
+++ b/mgmt/newtmgr/nmgr_os/src/newtmgr_os.c
@@ -0,0 +1,346 @@
+/*
+ * 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 <syscfg/syscfg.h>
+
+#include <os/os.h>
+#include <os/endian.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <hal/hal_system.h>
+#include <hal/hal_watchdog.h>
+
+#include <mgmt/mgmt.h>
+
+#include <console/console.h>
+#include <datetime/datetime.h>
+
+#if MYNEWT_VAL(LOG_SOFT_RESET)
+#include <reboot/log_reboot.h>
+#endif
+
+#include "nmgr_os/nmgr_os.h"
+
+#include <tinycbor/cbor.h>
+#include <cborattr/cborattr.h>
+
+static struct os_callout nmgr_reset_callout;
+
+static int nmgr_def_echo(struct mgmt_cbuf *);
+static int nmgr_def_console_echo(struct mgmt_cbuf *);
+static int nmgr_def_taskstat_read(struct mgmt_cbuf *njb);
+static int nmgr_def_mpstat_read(struct mgmt_cbuf *njb);
+static int nmgr_datetime_get(struct mgmt_cbuf *njb);
+static int nmgr_datetime_set(struct mgmt_cbuf *njb);
+static int nmgr_reset(struct mgmt_cbuf *njb);
+
+static const struct mgmt_handler nmgr_def_group_handlers[] = {
+    [NMGR_ID_ECHO] = {
+        nmgr_def_echo, nmgr_def_echo
+    },
+    [NMGR_ID_CONS_ECHO_CTRL] = {
+        nmgr_def_console_echo, nmgr_def_console_echo
+    },
+    [NMGR_ID_TASKSTATS] = {
+        nmgr_def_taskstat_read, NULL
+    },
+    [NMGR_ID_MPSTATS] = {
+        nmgr_def_mpstat_read, NULL
+    },
+    [NMGR_ID_DATETIME_STR] = {
+        nmgr_datetime_get, nmgr_datetime_set
+    },
+    [NMGR_ID_RESET] = {
+        NULL, nmgr_reset
+    },
+};
+
+#define NMGR_DEF_GROUP_SZ                                               \
+    (sizeof(nmgr_def_group_handlers) / sizeof(nmgr_def_group_handlers[0]))
+
+static struct mgmt_group nmgr_def_group = {
+    .mg_handlers = (struct mgmt_handler *)nmgr_def_group_handlers,
+    .mg_handlers_count = NMGR_DEF_GROUP_SZ,
+    .mg_group_id = MGMT_GROUP_ID_DEFAULT
+};
+
+static int
+nmgr_def_echo(struct mgmt_cbuf *cb)
+{
+    char echo_buf[128] = {'\0'};
+    CborError g_err = CborNoError;
+
+    struct cbor_attr_t attrs[2] = {
+        [0] = {
+            .attribute = "d",
+            .type = CborAttrTextStringType,
+            .addr.string = echo_buf,
+            .nodefault = 1,
+            .len = sizeof(echo_buf),
+        },
+        [1] = {
+            .attribute = NULL
+        }
+    };
+
+    g_err |= cbor_encode_text_stringz(&cb->encoder, "r");
+    g_err |= cbor_read_object(&cb->it, attrs);
+    g_err |= cbor_encode_text_string(&cb->encoder, echo_buf, strlen(echo_buf));
+
+    if (g_err) {
+        return MGMT_ERR_ENOMEM;
+    }
+    return (0);
+}
+
+static int
+nmgr_def_console_echo(struct mgmt_cbuf *cb)
+{
+    long long int echo_on = 1;
+    int rc;
+    struct cbor_attr_t attrs[2] = {
+        [0] = {
+            .attribute = "echo",
+            .type = CborAttrIntegerType,
+            .addr.integer = &echo_on,
+            .nodefault = 1
+        },
+        [1] = { 0 },
+    };
+
+    rc = cbor_read_object(&cb->it, attrs);
+    if (rc) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    if (echo_on) {
+        console_echo(1);
+    } else {
+        console_echo(0);
+    }
+    return (0);
+}
+
+static int
+nmgr_def_taskstat_read(struct mgmt_cbuf *cb)
+{
+    struct os_task *prev_task;
+    struct os_task_info oti;
+    CborError g_err = CborNoError;
+    CborEncoder tasks;
+    CborEncoder task;
+
+    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, "tasks");
+    g_err |= cbor_encoder_create_map(&cb->encoder, &tasks,
+                                     CborIndefiniteLength);
+
+    prev_task = NULL;
+    while (1) {
+        prev_task = os_task_info_get_next(prev_task, &oti);
+        if (prev_task == NULL) {
+            break;
+        }
+
+        g_err |= cbor_encode_text_stringz(&tasks, oti.oti_name);
+        g_err |= cbor_encoder_create_map(&tasks, &task, CborIndefiniteLength);
+        g_err |= cbor_encode_text_stringz(&task, "prio");
+        g_err |= cbor_encode_uint(&task, oti.oti_prio);
+        g_err |= cbor_encode_text_stringz(&task, "tid");
+        g_err |= cbor_encode_uint(&task, oti.oti_taskid);
+        g_err |= cbor_encode_text_stringz(&task, "state");
+        g_err |= cbor_encode_uint(&task, oti.oti_state);
+        g_err |= cbor_encode_text_stringz(&task, "stkuse");
+        g_err |= cbor_encode_uint(&task, oti.oti_stkusage);
+        g_err |= cbor_encode_text_stringz(&task, "stksiz");
+        g_err |= cbor_encode_uint(&task, oti.oti_stksize);
+        g_err |= cbor_encode_text_stringz(&task, "cswcnt");
+        g_err |= cbor_encode_uint(&task, oti.oti_cswcnt);
+        g_err |= cbor_encode_text_stringz(&task, "runtime");
+        g_err |= cbor_encode_uint(&task, oti.oti_runtime);
+        g_err |= cbor_encode_text_stringz(&task, "last_checkin");
+        g_err |= cbor_encode_uint(&task, oti.oti_last_checkin);
+        g_err |= cbor_encode_text_stringz(&task, "next_checkin");
+        g_err |= cbor_encode_uint(&task, oti.oti_next_checkin);
+        g_err |= cbor_encoder_close_container(&tasks, &task);
+    }
+    g_err |= cbor_encoder_close_container(&cb->encoder, &tasks);
+
+    if (g_err) {
+        return MGMT_ERR_ENOMEM;
+    }
+    return (0);
+}
+
+static int
+nmgr_def_mpstat_read(struct mgmt_cbuf *cb)
+{
+    struct os_mempool *prev_mp;
+    struct os_mempool_info omi;
+    CborError g_err = CborNoError;
+    CborEncoder pools;
+    CborEncoder pool;
+
+    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, "mpools");
+    g_err |= cbor_encoder_create_map(&cb->encoder, &pools,
+                                     CborIndefiniteLength);
+
+    prev_mp = NULL;
+    while (1) {
+        prev_mp = os_mempool_info_get_next(prev_mp, &omi);
+        if (prev_mp == NULL) {
+            break;
+        }
+
+        g_err |= cbor_encode_text_stringz(&pools, omi.omi_name);
+        g_err |= cbor_encoder_create_map(&pools, &pool, CborIndefiniteLength);
+        g_err |= cbor_encode_text_stringz(&pool, "blksiz");
+        g_err |= cbor_encode_uint(&pool, omi.omi_block_size);
+        g_err |= cbor_encode_text_stringz(&pool, "nblks");
+        g_err |= cbor_encode_uint(&pool, omi.omi_num_blocks);
+        g_err |= cbor_encode_text_stringz(&pool, "nfree");
+        g_err |= cbor_encode_uint(&pool, omi.omi_num_free);
+        g_err |= cbor_encode_text_stringz(&pool, "min");
+        g_err |= cbor_encode_uint(&pool, omi.omi_min_free);
+        g_err |= cbor_encoder_close_container(&pools, &pool);
+    }
+
+    g_err |= cbor_encoder_close_container(&cb->encoder, &pools);
+
+    if (g_err) {
+        return MGMT_ERR_ENOMEM;
+    }
+    return (0);
+}
+
+static int
+nmgr_datetime_get(struct mgmt_cbuf *cb)
+{
+    struct os_timeval tv;
+    struct os_timezone tz;
+    char buf[DATETIME_BUFSIZE];
+    int rc;
+    CborError g_err = CborNoError;
+
+    g_err |= cbor_encode_text_stringz(&cb->encoder, "rc");
+    g_err |= cbor_encode_int(&cb->encoder, MGMT_ERR_EOK);
+
+    /* Display the current datetime */
+    rc = os_gettimeofday(&tv, &tz);
+    assert(rc == 0);
+    rc = datetime_format(&tv, &tz, buf, DATETIME_BUFSIZE);
+    if (rc) {
+        rc = MGMT_ERR_EINVAL;
+        goto err;
+    }
+    g_err |= cbor_encode_text_stringz(&cb->encoder, "datetime");
+    g_err |= cbor_encode_text_stringz(&cb->encoder, buf);
+
+    if (g_err) {
+        return MGMT_ERR_ENOMEM;
+    }
+    return 0;
+
+err:
+    return (rc);
+}
+
+static int
+nmgr_datetime_set(struct mgmt_cbuf *cb)
+{
+    struct os_timeval tv;
+    struct os_timezone tz;
+    char buf[DATETIME_BUFSIZE];
+    int rc = 0;
+    const struct cbor_attr_t datetime_write_attr[] = {
+        [0] = {
+            .attribute = "datetime",
+            .type = CborAttrTextStringType,
+            .addr.string = buf,
+            .len = sizeof(buf),
+        },
+        { 0 },
+    };
+
+    rc = cbor_read_object(&cb->it, datetime_write_attr);
+    if (rc) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    /* Set the current datetime */
+    rc = datetime_parse(buf, &tv, &tz);
+    if (!rc) {
+        rc = os_settimeofday(&tv, &tz);
+        if (rc) {
+          return MGMT_ERR_EINVAL;
+        }
+    } else {
+        return MGMT_ERR_EINVAL;
+    }
+
+    rc = mgmt_cbuf_setoerr(cb, 0);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static void
+nmgr_reset_tmo(struct os_event *ev)
+{
+    /*
+     * Tickle watchdog just before re-entering bootloader.
+     * Depending on what system has been doing lately, watchdog
+     * timer might be close to firing.
+     */
+    hal_watchdog_tickle();
+    hal_system_reset();
+}
+
+static int
+nmgr_reset(struct mgmt_cbuf *cb)
+{
+    int rc;
+
+    os_callout_init(&nmgr_reset_callout, mgmt_evq_get(), nmgr_reset_tmo, NULL);
+
+#if MYNEWT_VAL(LOG_SOFT_RESET)
+    log_reboot(HAL_RESET_REQUESTED);
+#endif
+    os_callout_reset(&nmgr_reset_callout, OS_TICKS_PER_SEC / 4);
+
+    rc = mgmt_cbuf_setoerr(cb, 0);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+nmgr_os_groups_register(void)
+{
+    return mgmt_group_register(&nmgr_def_group);
+}
+
diff --git a/mgmt/newtmgr/nmgr_os/syscfg.yml b/mgmt/newtmgr/nmgr_os/syscfg.yml
new file mode 100644
index 0000000..78caaf0
--- /dev/null
+++ b/mgmt/newtmgr/nmgr_os/syscfg.yml
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+
+syscfg.defs:
+    LOG_SOFT_RESET:
+        description: 'Log soft restarts'
+        value: 1
diff --git a/mgmt/newtmgr/pkg.yml b/mgmt/newtmgr/pkg.yml
new file mode 100644
index 0000000..6f73873
--- /dev/null
+++ b/mgmt/newtmgr/pkg.yml
@@ -0,0 +1,40 @@
+#
+# 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
+    - util/mem
+
+pkg.deps.NEWTMGR_BLE_HOST:
+    - mgmt/newtmgr/transport/ble
+
+pkg.apis:
+    - newtmgr
+
+pkg.init:
+    nmgr_pkg_init: 500
diff --git a/mgmt/newtmgr/src/mynewt_nmgr.c b/mgmt/newtmgr/src/mynewt_nmgr.c
new file mode 100644
index 0000000..cdd9eac
--- /dev/null
+++ b/mgmt/newtmgr/src/mynewt_nmgr.c
@@ -0,0 +1,182 @@
+#include "os/os.h"
+#include "mgmt/mgmt.h"
+#include "mem/mem.h"
+
+static mgmt_reader_trim_front_fn mynewt_nmgr_trim_front;
+static mgmt_reader_trim_back_fn mynewt_nmgr_trim_back;
+static mgmt_reader_write_at_fn mynewt_nmgr_write_at;
+
+static struct mgmt_cbor_cfg mynewt_nmgr_cbor_cfg = {
+    .mr.trim_front = mynewt_nmgr_trim_front,
+    .mw.trim_back = mynewt_nmgr_trim_back,
+    .mw.write_at = mynewt_nmgr_write_at,
+};
+
+/**
+ * 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;
+}
+
+/**
+ * Sends a newtmgr response, fragmenting it as needed.  The supplied response
+ * mbuf is consumed on success and in some failure cases.  If the mbuf is
+ * consumed, the supplied pointer is set to NULL.
+ *
+ * This function prefers not to consume the supplied mbuf on failure.  The
+ * reason for this is to allow the caller to reuse the mbuf for an error
+ * response.
+ */
+static int
+mynewt_nmgr_rsp_tx(struct mynewt_nmgr_transport *mnt, struct os_mbuf **rsp,
+                   uint16_t mtu)
+{
+    struct os_mbuf *frag;
+    int rc;
+
+    while (*rsp != NULL) {
+        frag = mem_split_frag(rsp, mtu, nmgr_rsp_frag_alloc, *rsp);
+        if (frag == NULL) {
+            return MGMT_ERR_ENOMEM;
+        }
+
+        rc = mnt->mnt_xport.nt_output(&mnt->mnt_xport, frag);
+        if (rc != 0) {
+            /* Output function already freed mbuf. */
+            return MGMT_ERR_EUNKNOWN;
+        }
+    }
+
+    return MGMT_ERR_EOK;
+}
+
+static int
+mynewt_nmgr_process_single_packet(struct mynewt_nmgr_transport *mnt,
+                                  struct os_mbuf *req)
+{
+    struct nmgr_hdr req_hdr;
+    struct os_mbuf *rsp;
+    int err_rc;
+    int rc;
+
+    cbor_mbuf_reader_init(mynewt_nmgr_cbor_cfg.reader, req, 0);
+
+    while (1) {
+        rc = nmgr_read_hdr(&mynewt_nmgr_cbor_cfg, &req_hdr);
+        if (rc != 0) {
+            rc = 0;
+            goto done;
+        }
+
+        rsp = os_msys_get_pkthdr(512, OS_MBUF_USRHDR_LEN(req));
+        if (rsp == NULL) {
+            rc = MGMT_ERR_ENOMEM;
+            goto done;
+        }
+
+        cbor_mbuf_writer_init(mynewt_nmgr_cbor_cfg.writer, rsp);
+
+        rc = nmgr_handle_single_req(&mynewt_nmgr_cbor_cfg, &req_hdr)
+        if (rc != 0) {
+            goto done;
+        }
+
+        os_mbuf_adj(req, sizeof *req_hdr + OS_ALIGN(req_hdr.nh_len, 4));
+
+        if (OS_MBUF_PKTLEN(rsp) > 0) {
+            rc = mynewt_nmgr_rsp_tx(mnt, &rsp, 65535 /* XXX */);
+            if (rc != 0) {
+                goto done;
+            }
+        }
+    }
+
+    rc = 0;
+
+done:
+    if (rc != 0) {
+        if (rsp == NULL) {
+            rsp = req;
+            req = NULL;
+        }
+
+        os_mbuf_adj(rsp, OS_MBUF_PKTLEN(rsp));
+        cbor_mbuf_writer_init(mynewt_nmgr_cbor_cfg.writer, rsp);
+
+        err_rc = nmgr_build_err_rsp(&mynewt_nmgr_cbor_cfg, &req_hdr, rc);
+        if (err_rc == 0) {
+            err_rc = mynewt_nmgr_rsp_tx(mnt, &rsp, 65535 /* XXX */);
+            rsp = NULL;
+        }
+    }
+
+    os_mbuf_free_chain(req);
+    os_mbuf_free_chain(rsp);
+
+    return rc;
+}
+
+static void
+mynewt_nmgr_process(struct mynewt_nmgr_transport *mnt)
+{
+    struct cbor_mbuf_reader reader;
+    struct cbor_mbuf_writer writer;
+    struct os_mbuf *rsp;
+    struct os_mbuf *req;
+    int rc;
+
+    mynewt_nmgr_cbor_cfg.reader = &reader;
+    mynewt_nmgr_cbor_cfg.writer = &writer;
+
+    while (1) {
+        req = os_mqueue_get(&mnt->mnt_imq);
+        if (req == NULL) {
+            break;
+        }
+
+        rc = mynewt_nmgr_process_single_packet(mnt, 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,
+                           nmgr_transport_out_func_t output_func)
+{
+    int rc;
+
+    mnt->mnt_xport.nt_output = output_func;
+
+    rc = os_mqueue_init(&mnt->nt_imq, mynewt_nmgr_event_data_in, mnt);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
diff --git a/mgmt/newtmgr/src/newtmgr.c b/mgmt/newtmgr/src/newtmgr.c
new file mode 100644
index 0000000..cdd1c22
--- /dev/null
+++ b/mgmt/newtmgr/src/newtmgr.c
@@ -0,0 +1,205 @@
+/*
+ * 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 "syscfg/syscfg.h"
+#include "sysinit/sysinit.h"
+#include "os/os.h"
+#include "os/endian.h" /* XXX */
+
+#include "mgmt/mgmt.h"
+
+#include "newtmgr/newtmgr.h"
+
+#include "tinycbor/cbor.h"
+#include "tinycbor/cbor_mbuf_writer.h"
+#include "tinycbor/cbor_mbuf_reader.h"
+
+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;
+    }
+}
+
+static 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->nh_len = 0;
+    rsp_hdr->nh_flags = 0;
+    rsp_hdr->nh_op = nmgr_rsp_op(req_hdr->nh_op);
+    rsp_hdr->nh_group = req_hdr->nh_group;
+    rsp_hdr->nh_seq = req_hdr->nh_seq;
+    rsp_hdr->nh_id = req_hdr->nh_id;
+}
+
+static int
+nmgr_read_hdr(struct mgmt_cbor_cfg *cfg, struct nmgr_hdr *hdr)
+{
+    if (cfg->reader->message_size < sizeof *hdr) {
+        return MGMT_ERR_EINVAL;
+    }
+
+    cfg->reader->cpy(cfg->reader, (char *)hdr, 0, sizeof *hdr);
+    return 0;
+}
+
+static int
+nmgr_write_hdr(struct mgmt_cbor_cfg *cfg, const struct nmgr_hdr *hdr)
+{
+    rc = cfg->write_at(cfg->writer, 0, hdr, sizeof *hdr);
+    return mgmt_err_from_cbor(rc);
+}
+
+int
+nmgr_build_err_rsp(struct mgmt_cbor_cfg *cfg, 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, cfg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    nmgr_init_rsp_hdr(req_hdr, &rsp_hdr);
+    rc = nmgr_write_hdr(cfg, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = cbor_encoder_create_map(encoder, &map, CborIndefiniteLength);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = mgmt_cbuf_setoerr(encoder, status);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = cbor_encoder_close_container(encoder, &map);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rsp_hdr.nh_len = htons(cbor_encode_bytes_written(encoder));
+    rc = nmgr_write_hdr(cfg, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+nmgr_handle_single_req(struct mgmt_cbor_cfg *cfg,
+                       const struct nmgr_hdr *req_hdr)
+{
+    struct CborEncoder payload_encoder;
+    struct mgmt_cbuf cbuf;
+    struct nmgr_hdr rsp_hdr;
+    int rc;
+
+    rc = mgmt_cbuf_init(&cbuf, cfg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    handler = mgmt_find_handler(req_hdr->nh_group, req_hdr->nh_id);
+    if (!handler) {
+        return MGMT_ERR_ENOENT;
+    }
+
+    /* 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(cfg, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* 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;
+    }
+
+    rsp_hdr.nh_len = cbor_encode_bytes_written(&cbuf.encoder);
+    nmgr_hton_hdr(&rsp_hdr);
+    rc = nmgr_write_hdr(cfg, &rsp_hdr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
diff --git a/mgmt/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h b/mgmt/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h
new file mode 100644
index 0000000..4666d04
--- /dev/null
+++ b/mgmt/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h
@@ -0,0 +1,42 @@
+/*
+ * 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_BLE_H_
+#define _NEWTMGR_BLE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nmgr_hdr;
+
+int
+nmgr_ble_proc_mq_evt(struct os_event *ev);
+
+int
+nmgr_ble_gatt_svr_init(void);
+
+void
+nmgr_ble_update_rsp_len(struct os_mbuf *req, uint16_t *len, uint8_t *flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETMGR_H */
diff --git a/mgmt/newtmgr/transport/ble/pkg.yml b/mgmt/newtmgr/transport/ble/pkg.yml
new file mode 100644
index 0000000..af3dc32
--- /dev/null
+++ b/mgmt/newtmgr/transport/ble/pkg.yml
@@ -0,0 +1,35 @@
+#
+# 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/transport/ble
+pkg.description: BLE transport newtmgr functionality.
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+    - ble
+    - bluetooth
+
+pkg.deps:
+    - kernel/os
+    - mgmt/mgmt
+    - mgmt/newtmgr
+    - net/nimble/host
+
+pkg.init:
+    newtmgr_ble_pkg_init: 501
diff --git a/mgmt/newtmgr/transport/ble/src/newtmgr_ble.c b/mgmt/newtmgr/transport/ble/src/newtmgr_ble.c
new file mode 100644
index 0000000..907e1c7
--- /dev/null
+++ b/mgmt/newtmgr/transport/ble/src/newtmgr_ble.c
@@ -0,0 +1,242 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include "sysinit/sysinit.h"
+#include "host/ble_hs.h"
+#include "mgmt/mgmt.h"
+#include "newtmgr/newtmgr.h"
+#include "os/endian.h"
+#include "console/console.h"
+
+/* nmgr ble mqueue */
+struct os_mqueue nmgr_ble_mq;
+
+/* ble nmgr transport */
+struct nmgr_transport ble_nt;
+
+/* ble nmgr attr handle */
+uint16_t g_ble_nmgr_attr_handle;
+
+/**
+ * The vendor specific "newtmgr" service consists of one write no-rsp
+ * characteristic for newtmgr requests: a single-byte characteristic that can
+ * only accepts write-without-response commands.  The contents of each write
+ * command contains an NMP request.  NMP responses are sent back in the form of
+ * unsolicited notifications from the same characteristic.
+ */
+
+/* {8D53DC1D-1DB7-4CD3-868B-8A527460AA84} */
+static const ble_uuid128_t gatt_svr_svc_newtmgr =
+    BLE_UUID128_INIT(0x84, 0xaa, 0x60, 0x74, 0x52, 0x8a, 0x8b, 0x86,
+                     0xd3, 0x4c, 0xb7, 0x1d, 0x1d, 0xdc, 0x53, 0x8d);
+
+/* {DA2E7828-FBCE-4E01-AE9E-261174997C48} */
+static const ble_uuid128_t gatt_svr_chr_newtmgr =
+    BLE_UUID128_INIT(0x48, 0x7c, 0x99, 0x74, 0x11, 0x26, 0x9e, 0xae,
+                     0x01, 0x4e, 0xce, 0xfb, 0x28, 0x78, 0x2e, 0xda);
+
+static int
+gatt_svr_chr_access_newtmgr(uint16_t conn_handle, uint16_t attr_handle,
+                            struct ble_gatt_access_ctxt *ctxt, void *arg);
+
+static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
+    {
+        /* Service: newtmgr */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid = &gatt_svr_svc_newtmgr.u,
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            /* Characteristic: Write No Rsp */
+            .uuid = &gatt_svr_chr_newtmgr.u,
+            .access_cb = gatt_svr_chr_access_newtmgr,
+            .flags = BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_NOTIFY,
+            .val_handle = &g_ble_nmgr_attr_handle,
+        }, {
+            0, /* No more characteristics in this service */
+        } },
+    },
+
+    {
+        0, /* No more services */
+    },
+};
+
+static int
+gatt_svr_chr_access_newtmgr(uint16_t conn_handle, uint16_t attr_handle,
+                            struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    int rc;
+    struct os_mbuf *m_req;
+
+    switch (ctxt->op) {
+        case BLE_GATT_ACCESS_OP_WRITE_CHR:
+            /* Try to reuse the BLE packet mbuf as the newtmgr request.  This
+             * requires a two-byte usrhdr to hold the BLE connection handle so
+             * that the newtmgr response can be sent to the correct peer.  If
+             * it is not possible to reuse the mbuf, then allocate a new one
+             * and copy the request contents.
+             */
+            if (OS_MBUF_USRHDR_LEN(ctxt->om) >= sizeof (conn_handle)) {
+                /* Sufficient usrhdr space already present. */
+                m_req = ctxt->om;
+                ctxt->om = NULL;
+            } else if (OS_MBUF_LEADINGSPACE(ctxt->om) >=
+                       sizeof (conn_handle)) {
+
+                /* Usrhdr isn't present, but there is enough leading space to
+                 * add one.
+                 */
+                m_req = ctxt->om;
+                ctxt->om = NULL;
+
+                m_req->om_pkthdr_len += sizeof (conn_handle);
+            } else {
+                /* The mbuf can't be reused.  Allocate a new one and perform a
+                 * copy.  Don't set ctxt->om to NULL; let the NimBLE host free
+                 * it.
+                 */
+                m_req = os_msys_get_pkthdr(OS_MBUF_PKTLEN(ctxt->om),
+                                           sizeof (conn_handle));
+                if (!m_req) {
+                    return BLE_ATT_ERR_INSUFFICIENT_RES;
+                }
+                rc = os_mbuf_appendfrom(m_req, ctxt->om, 0,
+                                        OS_MBUF_PKTLEN(ctxt->om));
+                if (rc) {
+                    return BLE_ATT_ERR_INSUFFICIENT_RES;
+                }
+            }
+
+            /* Write the connection handle to the newtmgr request usrhdr.  This
+             * is necessary so that we later know who to send the newtmgr
+             * response to.
+             */
+            memcpy(OS_MBUF_USRHDR(m_req), &conn_handle, sizeof(conn_handle));
+
+            rc = nmgr_rx_req(&ble_nt, m_req);
+            if (rc != 0) {
+                return BLE_ATT_ERR_UNLIKELY;
+            }
+            return 0;
+
+        default:
+            assert(0);
+            return BLE_ATT_ERR_UNLIKELY;
+    }
+}
+
+uint16_t
+nmgr_ble_get_mtu(struct os_mbuf *req) {
+
+    uint16_t conn_handle;
+    uint16_t mtu;
+
+    memcpy(&conn_handle, OS_MBUF_USRHDR(req), sizeof (conn_handle));
+    mtu = ble_att_mtu(conn_handle);
+    if (!mtu) {
+        /* No longer connected. */
+        return 0;
+    }
+
+    /* 3 is the number of bytes for ATT notification base */
+    mtu = mtu - 3;
+
+    return (mtu);
+}
+
+/**
+ * Nmgr ble process mqueue event
+ * Gets an event from the nmgr mqueue and does a notify with the response
+ *
+ * @param eventq
+ * @return 0 on success; non-zero on failure
+ */
+
+static void
+nmgr_ble_event_data_in(struct os_event *ev)
+{
+    struct os_mbuf *m_resp;
+    uint16_t conn_handle;
+
+    while ((m_resp = os_mqueue_get(&nmgr_ble_mq)) != NULL) {
+        assert(OS_MBUF_USRHDR_LEN(m_resp) >= sizeof (conn_handle));
+        memcpy(&conn_handle, OS_MBUF_USRHDR(m_resp), sizeof (conn_handle));
+        ble_gattc_notify_custom(conn_handle, g_ble_nmgr_attr_handle,
+                                m_resp);
+    }
+}
+
+static int
+nmgr_ble_out(struct nmgr_transport *nt, struct os_mbuf *om)
+{
+    int rc;
+
+    rc = os_mqueue_put(&nmgr_ble_mq, mgmt_evq_get(), om);
+    if (rc != 0) {
+        goto err;
+    }
+
+    return (0);
+err:
+    os_mbuf_free_chain(om);
+    return (rc);
+}
+
+/**
+ * Nmgr ble GATT server initialization
+ *
+ * @param eventq
+ * @return 0 on success; non-zero on failure
+ */
+int
+nmgr_ble_gatt_svr_init(void)
+{
+    int rc;
+
+    rc = ble_gatts_count_cfg(gatt_svr_svcs);
+    if (rc != 0) {
+        goto err;
+    }
+
+    rc = ble_gatts_add_svcs(gatt_svr_svcs);
+    if (rc != 0) {
+        return rc;
+    }
+
+    os_mqueue_init(&nmgr_ble_mq, &nmgr_ble_event_data_in, NULL);
+
+    rc = nmgr_transport_init(&ble_nt, nmgr_ble_out, nmgr_ble_get_mtu);
+
+err:
+    return rc;
+}
+
+void
+newtmgr_ble_pkg_init(void)
+{
+    int rc;
+
+    /* Ensure this function only gets called by sysinit. */
+    SYSINIT_ASSERT_ACTIVE();
+
+    rc = nmgr_ble_gatt_svr_init();
+    SYSINIT_PANIC_ASSERT(rc == 0);
+}
diff --git a/mgmt/newtmgr/transport/nmgr_shell/pkg.yml b/mgmt/newtmgr/transport/nmgr_shell/pkg.yml
new file mode 100644
index 0000000..2a859cb
--- /dev/null
+++ b/mgmt/newtmgr/transport/nmgr_shell/pkg.yml
@@ -0,0 +1,34 @@
+#
+# 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/transport/nmgr_shell
+pkg.description: Newtmgr transport over shell
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+    - newtmgr
+    - shell
+
+pkg.deps:
+    - kernel/os
+    - sys/shell
+    - mgmt/newtmgr
+
+pkg.init:
+    nmgr_shell_pkg_init: 501
diff --git a/mgmt/newtmgr/transport/nmgr_shell/src/nmgr_shell.c b/mgmt/newtmgr/transport/nmgr_shell/src/nmgr_shell.c
new file mode 100644
index 0000000..c57e9b1
--- /dev/null
+++ b/mgmt/newtmgr/transport/nmgr_shell/src/nmgr_shell.c
@@ -0,0 +1,71 @@
+/*
+ * 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 <inttypes.h>
+#include <assert.h>
+
+#include <sysinit/sysinit.h>
+#include <shell/shell.h>
+#include <mgmt/mgmt.h>
+#include <newtmgr/newtmgr.h>
+
+static struct nmgr_transport nmgr_shell_transport;
+
+static uint16_t
+nmgr_shell_get_mtu(struct os_mbuf *m)
+{
+    return MGMT_MAX_MTU;
+}
+
+static int
+nmgr_shell_out(struct nmgr_transport *nt, struct os_mbuf *m)
+{
+    int rc;
+
+    rc = shell_nlip_output(m);
+    if (rc != 0) {
+        goto err;
+    }
+
+    return (0);
+err:
+    os_mbuf_free_chain(m);
+    return (rc);
+}
+
+static int
+nmgr_shell_in(struct os_mbuf *m, void *arg)
+{
+    return nmgr_rx_req(&nmgr_shell_transport, m);
+}
+
+void
+nmgr_shell_pkg_init(void)
+{
+    int rc;
+
+    /* Ensure this function only gets called by sysinit. */
+    SYSINIT_ASSERT_ACTIVE();
+
+    rc = nmgr_transport_init(&nmgr_shell_transport, nmgr_shell_out,
+      nmgr_shell_get_mtu);
+    assert(rc == 0);
+
+    rc = shell_nlip_input_register(nmgr_shell_in, &nmgr_shell_transport);
+    assert(rc == 0);
+}
diff --git a/mgmt/newtmgr/transport/nmgr_uart/pkg.yml b/mgmt/newtmgr/transport/nmgr_uart/pkg.yml
new file mode 100644
index 0000000..9e62a32
--- /dev/null
+++ b/mgmt/newtmgr/transport/nmgr_uart/pkg.yml
@@ -0,0 +1,35 @@
+#
+# 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/transport/nmgr_uart
+pkg.description: Newtmgr transport over raw UART
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+    - newtmgr
+    - uart
+
+pkg.deps:
+    - kernel/os
+    - hw/drivers/uart
+    - mgmt/newtmgr
+    - util/crc
+
+pkg.init:
+    nmgr_uart_pkg_init: 501
diff --git a/mgmt/newtmgr/transport/nmgr_uart/src/nmgr_uart.c b/mgmt/newtmgr/transport/nmgr_uart/src/nmgr_uart.c
new file mode 100644
index 0000000..4465079
--- /dev/null
+++ b/mgmt/newtmgr/transport/nmgr_uart/src/nmgr_uart.c
@@ -0,0 +1,389 @@
+/*
+ * 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 <inttypes.h>
+#include <assert.h>
+
+#include <syscfg/syscfg.h>
+#include <sysinit/sysinit.h>
+#include <bsp/bsp.h>
+
+#include <os/os.h>
+#include <mgmt/mgmt.h>
+#include <newtmgr/newtmgr.h>
+#include <uart/uart.h>
+
+#include <crc/crc16.h>
+#include <base64/base64.h>
+
+#define SHELL_NLIP_PKT          0x0609
+#define SHELL_NLIP_DATA         0x0414
+#define SHELL_NLIP_MAX_FRAME    128
+
+#define NUS_EV_TO_STATE(ptr)                                            \
+    (struct nmgr_uart_state *)((uint8_t *)ptr -                         \
+      (int)&(((struct nmgr_uart_state *)0)->nus_cb_ev))
+
+struct nmgr_uart_state {
+    struct nmgr_transport nus_transport; /* keep first in struct */
+    struct os_event nus_cb_ev;
+    struct uart_dev *nus_dev;
+    struct os_mbuf *nus_tx;
+    int nus_tx_off;
+    struct os_mbuf_pkthdr *nus_rx_pkt;
+    struct os_mbuf_pkthdr *nus_rx_q;
+    struct os_mbuf_pkthdr *nus_rx;
+};
+
+/*
+ * Header for frames arriving over serial.
+ */
+struct nmgr_ser_hdr {
+    uint16_t nsh_seq;
+    uint16_t nsh_len;
+};
+
+static struct nmgr_uart_state nmgr_uart_state;
+
+static uint16_t
+nmgr_uart_mtu(struct os_mbuf *m)
+{
+    return MGMT_MAX_MTU;
+}
+
+/*
+ * Called by mgmt to queue packet out to UART.
+ */
+static int
+nmgr_uart_out(struct nmgr_transport *nt, struct os_mbuf *m)
+{
+    struct nmgr_uart_state *nus = (struct nmgr_uart_state *)nt;
+    struct os_mbuf_pkthdr *mpkt;
+    struct os_mbuf *n;
+    uint16_t tmp_buf[6];
+    char *dst;
+    int off;
+    int boff;
+    int slen;
+    int sr;
+    int rc;
+    int last;
+    int tx_sz;
+
+    assert(OS_MBUF_IS_PKTHDR(m));
+    mpkt = OS_MBUF_PKTHDR(m);
+
+    /*
+     * Compute CRC-16 and append it to end.
+     */
+    off = 0;
+    tmp_buf[0] = CRC16_INITIAL_CRC;
+    for (n = m; n; n = SLIST_NEXT(n, om_next)) {
+        tmp_buf[0] = crc16_ccitt(tmp_buf[0], n->om_data, n->om_len);
+    }
+    tmp_buf[0] = htons(tmp_buf[0]);
+    dst = os_mbuf_extend(m, sizeof(uint16_t));
+    if (!dst) {
+        goto err;
+    }
+    memcpy(dst, tmp_buf, sizeof(uint16_t));
+
+    /*
+     * Create another mbuf chain with base64 encoded data.
+     */
+    n = os_msys_get(SHELL_NLIP_MAX_FRAME, 0);
+    if (!n || OS_MBUF_TRAILINGSPACE(n) < 32) {
+        goto err;
+    }
+
+    while (off < mpkt->omp_len) {
+        /*
+         * First fragment has a different header, and length of the full frame
+         * (need to base64 encode that).
+         */
+        if (off == 0) {
+            tmp_buf[0] = htons(SHELL_NLIP_PKT);
+        } else {
+            tmp_buf[0] = htons(SHELL_NLIP_DATA);
+        }
+        rc = os_mbuf_append(n, tmp_buf, sizeof(uint16_t));
+        if (rc) {
+            goto err;
+        }
+        tx_sz = 2;
+
+        if (off == 0) {
+            tmp_buf[0] = htons(mpkt->omp_len);
+            boff = sizeof(uint16_t);
+        } else {
+            boff = 0;
+        }
+
+        while (off < mpkt->omp_len) {
+            slen = mpkt->omp_len - off;
+            last = 1;
+            if (slen > sizeof(tmp_buf) + boff) {
+                slen = sizeof(tmp_buf) - boff;
+                last = 0;
+            }
+            if (tx_sz + BASE64_ENCODE_SIZE(slen + boff) >= 124) {
+                break;
+            }
+            rc = os_mbuf_copydata(m, off, slen, (uint8_t *)tmp_buf + boff);
+            assert(rc == 0);
+
+            off += slen;
+            slen += boff;
+
+            dst = os_mbuf_extend(n, BASE64_ENCODE_SIZE(slen));
+            if (!dst) {
+                goto err;
+            }
+            tx_sz += base64_encode(tmp_buf, slen, dst, last);
+            boff = 0;
+        }
+
+        if (os_mbuf_append(n, "\n", 1)) {
+            goto err;
+        }
+    }
+
+    os_mbuf_free_chain(m);
+    OS_ENTER_CRITICAL(sr);
+    if (!nus->nus_tx) {
+        nus->nus_tx = n;
+        uart_start_tx(nus->nus_dev);
+    } else {
+        os_mbuf_concat(nus->nus_tx, n);
+    }
+    OS_EXIT_CRITICAL(sr);
+
+    return 0;
+err:
+    os_mbuf_free_chain(m);
+    os_mbuf_free_chain(n);
+    return -1;
+}
+
+/*
+ * Called by UART driver to send out next character.
+ *
+ * Interrupts disabled when nmgr_uart_tx_char/nmgr_uart_rx_char are called.
+ */
+static int
+nmgr_uart_tx_char(void *arg)
+{
+    struct nmgr_uart_state *nus = (struct nmgr_uart_state *)arg;
+    struct os_mbuf *m;
+    uint8_t ch;
+
+    if (!nus->nus_tx) {
+        /*
+         * Out of data. Return -1 makes UART stop asking for more.
+         */
+        return -1;
+    }
+    while (nus->nus_tx->om_len == nus->nus_tx_off) {
+        /*
+         * If no active mbuf, move to next one.
+         */
+        m = SLIST_NEXT(nus->nus_tx, om_next);
+        os_mbuf_free(nus->nus_tx);
+        nus->nus_tx = m;
+
+        nus->nus_tx_off = 0;
+        if (!nus->nus_tx) {
+            return -1;
+        }
+    }
+
+    os_mbuf_copydata(nus->nus_tx, nus->nus_tx_off++, 1, &ch);
+
+    return ch;
+}
+
+/*
+ * Check for full packet. If frame is not right, free the mbuf.
+ */
+static void
+nmgr_uart_rx_pkt(struct nmgr_uart_state *nus, struct os_mbuf_pkthdr *rxm)
+{
+    struct os_mbuf *m;
+    struct nmgr_ser_hdr *nsh;
+    uint16_t crc;
+    int rc;
+
+    m = OS_MBUF_PKTHDR_TO_MBUF(rxm);
+
+    if (rxm->omp_len <= sizeof(uint16_t) + sizeof(crc)) {
+        goto err;
+    }
+
+    nsh = (struct nmgr_ser_hdr *)m->om_data;
+    switch (nsh->nsh_seq) {
+    case htons(SHELL_NLIP_PKT):
+        if (nus->nus_rx_pkt) {
+            os_mbuf_free_chain(OS_MBUF_PKTHDR_TO_MBUF(nus->nus_rx_pkt));
+            nus->nus_rx_pkt = NULL;
+        }
+        break;
+    case htons(SHELL_NLIP_DATA):
+        if (!nus->nus_rx_pkt) {
+            goto err;
+        }
+        break;
+    default:
+        goto err;
+    }
+
+    if (os_mbuf_append(m, "\0", 1)) {
+        /*
+         * Null-terminate the line for base64_decode's sake.
+         */
+        goto err;
+    }
+    m = os_mbuf_pullup(m, rxm->omp_len);
+    if (!m) {
+        /*
+         * Make data contiguous for base64_decode's sake.
+         */
+        goto err;
+    }
+    rxm = OS_MBUF_PKTHDR(m);
+    rc = base64_decode((char *)m->om_data + 2, (char *)m->om_data + 2);
+    if (rc < 0) {
+        goto err;
+    }
+    rxm->omp_len = m->om_len = rc + 2;
+    if (nus->nus_rx_pkt) {
+        os_mbuf_adj(m, 2);
+        os_mbuf_concat(OS_MBUF_PKTHDR_TO_MBUF(nus->nus_rx_pkt), m);
+    } else {
+        nus->nus_rx_pkt = rxm;
+    }
+
+    m = OS_MBUF_PKTHDR_TO_MBUF(nus->nus_rx_pkt);
+    nsh = (struct nmgr_ser_hdr *)m->om_data;
+    if (nus->nus_rx_pkt->omp_len - sizeof(*nsh) == ntohs(nsh->nsh_len)) {
+        os_mbuf_adj(m, 4);
+        os_mbuf_adj(m, -2);
+        nmgr_rx_req(&nus->nus_transport, m);
+        nus->nus_rx_pkt = NULL;
+    }
+    return;
+err:
+    os_mbuf_free_chain(m);
+}
+
+/*
+ * Callback from mgmt task context.
+ */
+static void
+nmgr_uart_rx_frame(struct os_event *ev)
+{
+    struct nmgr_uart_state *nus = NUS_EV_TO_STATE(ev);
+    struct os_mbuf_pkthdr *m;
+    int sr;
+
+    OS_ENTER_CRITICAL(sr);
+    m = nus->nus_rx_q;
+    nus->nus_rx_q = NULL;
+    OS_EXIT_CRITICAL(sr);
+    if (m) {
+        nmgr_uart_rx_pkt(nus, m);
+    }
+}
+
+/*
+ * Receive a character from UART.
+ */
+static int
+nmgr_uart_rx_char(void *arg, uint8_t data)
+{
+    struct nmgr_uart_state *nus = (struct nmgr_uart_state *)arg;
+    struct os_mbuf *m;
+    int rc;
+
+    if (!nus->nus_rx) {
+        m = os_msys_get_pkthdr(SHELL_NLIP_MAX_FRAME, 0);
+        if (!m) {
+            return 0;
+        }
+        nus->nus_rx = OS_MBUF_PKTHDR(m);
+        if (OS_MBUF_TRAILINGSPACE(m) < SHELL_NLIP_MAX_FRAME) {
+            /*
+             * mbuf is too small.
+             */
+            os_mbuf_free_chain(m);
+            nus->nus_rx = NULL;
+            return 0;
+        }
+    }
+
+    m = OS_MBUF_PKTHDR_TO_MBUF(nus->nus_rx);
+    if (data == '\n') {
+        /*
+         * Full line of input. Process it outside interrupt context.
+         */
+        assert(!nus->nus_rx_q);
+        nus->nus_rx_q = nus->nus_rx;
+        nus->nus_rx = NULL;
+        os_eventq_put(mgmt_evq_get(), &nus->nus_cb_ev);
+        return 0;
+    } else {
+        rc = os_mbuf_append(m, &data, 1);
+        if (rc == 0) {
+            return 0;
+        }
+    }
+    /* failed */
+    nus->nus_rx->omp_len = 0;
+    m->om_len = 0;
+    os_mbuf_free_chain(SLIST_NEXT(m, om_next));
+    SLIST_NEXT(m, om_next) = NULL;
+    return 0;
+}
+
+void
+nmgr_uart_pkg_init(void)
+{
+    struct nmgr_uart_state *nus = &nmgr_uart_state;
+    int rc;
+    struct uart_conf uc = {
+        .uc_speed = MYNEWT_VAL(NMGR_UART_SPEED),
+        .uc_databits = 8,
+        .uc_stopbits = 1,
+        .uc_parity = UART_PARITY_NONE,
+        .uc_flow_ctl = UART_FLOW_CTL_NONE,
+        .uc_tx_char = nmgr_uart_tx_char,
+        .uc_rx_char = nmgr_uart_rx_char,
+        .uc_cb_arg = nus
+    };
+
+    /* Ensure this function only gets called by sysinit. */
+    SYSINIT_ASSERT_ACTIVE();
+
+    rc = nmgr_transport_init(&nus->nus_transport, nmgr_uart_out, nmgr_uart_mtu);
+    assert(rc == 0);
+
+    nus->nus_dev =
+      (struct uart_dev *)os_dev_open(MYNEWT_VAL(NMGR_UART), 0, &uc);
+    assert(nus->nus_dev);
+
+    nus->nus_cb_ev.ev_cb = nmgr_uart_rx_frame;
+}
diff --git a/mgmt/newtmgr/transport/nmgr_uart/syscfg.yml b/mgmt/newtmgr/transport/nmgr_uart/syscfg.yml
new file mode 100644
index 0000000..2d9d15e
--- /dev/null
+++ b/mgmt/newtmgr/transport/nmgr_uart/syscfg.yml
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+syscfg.defs:
+  NMGR_UART:
+    description: 'UART port number to use for newtmgr'
+    value: '"uart0"'
+
+  NMGR_UART_SPEED:
+    description: 'Baudrate for newtmgr UART'
+    value: 115200
+

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