KTD LSM: update nanopb to 0.4.5

BUG=b/181723467
TEST=CRST Vanadium tests: sponge2/d8497d43-e9be-45a4-9d7a-80df73e8ec64
SOURCE=ktd

Signed-off-by: Ken Hofsass <hofsass@google.com>
Change-Id: If971c1df366109ca36cb4ef885cc99b5e432ebc4
Reviewed-on: https://cos-review.googlesource.com/c/third_party/kernel/+/21650
Main-Branch-Verified: Cusky Presubmit Bot <presubmit@cos-infra-prod.iam.gserviceaccount.com>
Reviewed-by: Oleksandr Tymoshenko <ovt@google.com>
Tested-by: Oleksandr Tymoshenko <ovt@google.com>
diff --git a/security/container/monitor.c b/security/container/monitor.c
index e01cad3..29f47dc 100644
--- a/security/container/monitor.c
+++ b/security/container/monitor.c
@@ -555,6 +555,7 @@
 		goto out;
 
 	/* Correct the container-id and feed the event to pipe */
+	report.has_container = true;
 	report.container.container_id = cid;
 	report.container.init_uuid.funcs.encode = pb_encode_uuid_field;
 	report.container.init_uuid.arg = uuid;
@@ -565,6 +566,7 @@
 	set_container_encode_callbacks(container);
 
 	event.which_event = schema_Event_container_tag;
+	event.event.container.has_container = true;
 
 	err = csm_sendeventproto(schema_Event_fields, &event);
 	if (!err)
diff --git a/security/container/monitor.h b/security/container/monitor.h
index 7fbe7e3a3..221d7f5 100644
--- a/security/container/monitor.h
+++ b/security/container/monitor.h
@@ -71,7 +71,7 @@
 int csm_update_config_from_buffer(void *data, size_t size);
 
 /* send event to userland */
-int csm_sendeventproto(const pb_field_t fields[], schema_Event *event);
+int csm_sendeventproto(const pb_msgdesc_t *fields, schema_Event *event);
 
 /* process events functions */
 int csm_bprm_check_security(struct linux_binprm *bprm);
diff --git a/security/container/pipe.c b/security/container/pipe.c
index ecc1c5e..49f5fe8 100644
--- a/security/container/pipe.c
+++ b/security/container/pipe.c
@@ -93,7 +93,7 @@
 	return perr;
 }
 
-static bool csm_get_expected_size(size_t *size, const pb_field_t fields[],
+static bool csm_get_expected_size(size_t *size, const pb_msgdesc_t *fields,
 				    const void *src_struct)
 {
 	schema_Event *event;
@@ -124,7 +124,7 @@
 }
 
 static struct msg_work_data *csm_encodeproto(size_t size,
-					     const pb_field_t fields[],
+					     const pb_msgdesc_t *fields,
 					     const void *src_struct)
 {
 	pb_ostream_t pos;
@@ -150,7 +150,7 @@
 	return wd;
 }
 
-static int csm_sendproto(int type, const pb_field_t fields[],
+static int csm_sendproto(int type, const pb_msgdesc_t *fields,
 			 const void *src_struct)
 {
 	int err = 0;
@@ -206,7 +206,7 @@
 	kfree(wd);
 }
 
-int csm_sendeventproto(const pb_field_t fields[], schema_Event *event)
+int csm_sendeventproto(const pb_msgdesc_t *fields, schema_Event *event)
 {
 	/* Last check before generating and sending an event. */
 	if (!csm_enabled)
diff --git a/security/container/process.c b/security/container/process.c
index 426e37a..d89faa0 100644
--- a/security/container/process.c
+++ b/security/container/process.c
@@ -562,6 +562,7 @@
 		/* Local socket */
 		err = kernel_getsockname(socket, (struct sockaddr *)&saddr);
 		if (err >= 0) {
+			socketfs->has_local = true;
 			fill_socket_description(&saddr, &fdata->local,
 					       &socketfs->local);
 		}
@@ -569,6 +570,7 @@
 		/* Remote socket, might not be connected. */
 		err = kernel_getpeername(socket, (struct sockaddr *)&saddr);
 		if (err >= 0) {
+			socketfs->has_remote = true;
 			fill_socket_description(&saddr, &fdata->remote,
 					       &socketfs->remote);
 		}
@@ -621,6 +623,7 @@
 	}
 
 	desc->mode = file_inode(file)->i_mode;
+	desc->has_file = true;
 	err = fill_file_description(file, &desc->file, fdata);
 
 end:
@@ -745,21 +748,27 @@
 	proc->creation_timestamp = ktime_get_real_ns();
 
 	/* Provide information about the launched binary. */
+	proc->has_binary = true;
 	err = fill_file_description(bprm->file, &proc->binary, &path_data);
 	if (err)
 		goto out_free_buf;
 
 	/* Information about streams */
+	proc->has_streams = true;
+
+	proc->streams.has_stdin = true;
 	err = fill_stream_description(&proc->streams.stdin, STDIN_FILENO,
 				      &stdin_data);
 	if (err)
 		goto out_free_buf;
 
+	proc->streams.has_stdout = true;
 	err = fill_stream_description(&proc->streams.stdout, STDOUT_FILENO,
 				      &stdout_data);
 	if (err)
 		goto out_free_buf;
 
+	proc->streams.has_stderr = true;
 	err = fill_stream_description(&proc->streams.stderr, STDERR_FILENO,
 				      &stderr_data);
 	if (err)
@@ -782,6 +791,8 @@
 	proc->args.envp.arg = &argv_ctx;
 
 	event.which_event = schema_Event_execute_tag;
+	event.event.execute.has_proc = true;
+	proc->has_args = true;
 
 	/*
 	 * Configurations options are checked when computing the serialized
@@ -833,6 +844,7 @@
 					sizeof(parent_uuid), task);
 
 	event.which_event = schema_Event_clone_tag;
+	event.event.clone.has_proc = true;
 	err = csm_sendeventproto(schema_Event_fields, &event);
 	if (err)
 		pr_err("csm_sendeventproto returned %d on exit\n", err);
@@ -913,6 +925,8 @@
 	memexec->end_addr = vma->vm_end;
 
 	event.which_event = schema_Event_memexec_tag;
+	event.event.memexec.has_proc = true;
+	event.event.memexec.has_mapped_file = true;
 
 	err = csm_sendeventproto(schema_Event_fields, &event);
 	if (err)
@@ -972,6 +986,8 @@
 	memexec->mmap_flags = flags;
 	memexec->action = schema_MemoryExecEvent_Action_MMAP_FILE;
 	event.which_event = schema_Event_memexec_tag;
+	event.event.memexec.has_proc = true;
+	event.event.memexec.has_mapped_file = true;
 
 	err = csm_sendeventproto(schema_Event_fields, &event);
 	if (err)
@@ -1098,6 +1114,7 @@
 			goto next;
 		}
 
+		proc->has_binary = true;
 		err = fill_file_description(exe_file, &proc->binary,
 					    &path_data);
 		if (err) {
@@ -1119,6 +1136,7 @@
 			goto next;
 
 		event.which_event = schema_Event_enumproc_tag;
+		event.event.execute.has_proc = true;
 		err = csm_sendeventproto(schema_Event_fields,
 					 &event);
 		if (err) {
diff --git a/security/container/protos/config.pb.c b/security/container/protos/config.pb.c
index 211bab0..08436ee 100644
--- a/security/container/protos/config.pb.c
+++ b/security/container/protos/config.pb.c
@@ -1,72 +1,25 @@
 /* Automatically generated nanopb constant definitions */
-/* Generated by nanopb-0.3.9.3 at Wed Jun  5 11:00:24 2019. */
+/* Generated by nanopb-0.4.5 */
 
 #include "config.pb.h"
-
-/* @@protoc_insertion_point(includes) */
-#if PB_PROTO_HEADER_VERSION != 30
+#if PB_PROTO_HEADER_VERSION != 40
 #error Regenerate this file with the current version of nanopb generator.
 #endif
 
+PB_BIND(schema_ContainerCollectorConfig, schema_ContainerCollectorConfig, AUTO)
 
 
-const pb_field_t schema_ContainerCollectorConfig_fields[2] = {
-    PB_FIELD(  1, BOOL    , SINGULAR, STATIC  , FIRST, schema_ContainerCollectorConfig, enabled, enabled, 0),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_ExecuteCollectorConfig, schema_ExecuteCollectorConfig, AUTO)
 
-const pb_field_t schema_ExecuteCollectorConfig_fields[5] = {
-    PB_FIELD(  1, BOOL    , SINGULAR, STATIC  , FIRST, schema_ExecuteCollectorConfig, enabled, enabled, 0),
-    PB_FIELD(  2, UINT32  , SINGULAR, STATIC  , OTHER, schema_ExecuteCollectorConfig, argv_limit, enabled, 0),
-    PB_FIELD(  3, UINT32  , SINGULAR, STATIC  , OTHER, schema_ExecuteCollectorConfig, envp_limit, argv_limit, 0),
-    PB_FIELD(  4, STRING  , REPEATED, CALLBACK, OTHER, schema_ExecuteCollectorConfig, envp_allowlist, envp_limit, 0),
-    PB_LAST_FIELD
-};
 
-const pb_field_t schema_MemExecCollectorConfig_fields[2] = {
-    PB_FIELD(  1, BOOL    , SINGULAR, STATIC  , FIRST, schema_MemExecCollectorConfig, enabled, enabled, 0),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_MemExecCollectorConfig, schema_MemExecCollectorConfig, AUTO)
 
-const pb_field_t schema_ConfigurationRequest_fields[4] = {
-    PB_FIELD(  1, MESSAGE , SINGULAR, STATIC  , FIRST, schema_ConfigurationRequest, container_config, container_config, &schema_ContainerCollectorConfig_fields),
-    PB_FIELD(  2, MESSAGE , SINGULAR, STATIC  , OTHER, schema_ConfigurationRequest, execute_config, container_config, &schema_ExecuteCollectorConfig_fields),
-    PB_FIELD(  3, MESSAGE , SINGULAR, STATIC  , OTHER, schema_ConfigurationRequest, memexec_config, execute_config, &schema_MemExecCollectorConfig_fields),
-    PB_LAST_FIELD
-};
 
-const pb_field_t schema_ConfigurationResponse_fields[5] = {
-    PB_FIELD(  1, UENUM   , SINGULAR, STATIC  , FIRST, schema_ConfigurationResponse, error, error, 0),
-    PB_FIELD(  2, STRING  , SINGULAR, CALLBACK, OTHER, schema_ConfigurationResponse, msg, error, 0),
-    PB_FIELD(  3, UINT64  , SINGULAR, STATIC  , OTHER, schema_ConfigurationResponse, version, msg, 0),
-    PB_FIELD(  4, UINT32  , SINGULAR, STATIC  , OTHER, schema_ConfigurationResponse, kernel_version, version, 0),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_ConfigurationRequest, schema_ConfigurationRequest, AUTO)
+
+
+PB_BIND(schema_ConfigurationResponse, schema_ConfigurationResponse, AUTO)
 
 
 
-/* Check that field information fits in pb_field_t */
-#if !defined(PB_FIELD_32BIT)
-/* If you get an error here, it means that you need to define PB_FIELD_32BIT
- * compile-time option. You can do that in pb.h or on compiler command line.
- * 
- * The reason you need to do this is that some of your messages contain tag
- * numbers or field sizes that are larger than what can fit in 8 or 16 bit
- * field descriptors.
- */
-PB_STATIC_ASSERT((pb_membersize(schema_ConfigurationRequest, container_config) < 65536 && pb_membersize(schema_ConfigurationRequest, execute_config) < 65536 && pb_membersize(schema_ConfigurationRequest, memexec_config) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_schema_ContainerCollectorConfig_schema_ExecuteCollectorConfig_schema_MemExecCollectorConfig_schema_ConfigurationRequest_schema_ConfigurationResponse)
-#endif
 
-#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
-/* If you get an error here, it means that you need to define PB_FIELD_16BIT
- * compile-time option. You can do that in pb.h or on compiler command line.
- * 
- * The reason you need to do this is that some of your messages contain tag
- * numbers or field sizes that are larger than what can fit in the default
- * 8 bit descriptors.
- */
-PB_STATIC_ASSERT((pb_membersize(schema_ConfigurationRequest, container_config) < 256 && pb_membersize(schema_ConfigurationRequest, execute_config) < 256 && pb_membersize(schema_ConfigurationRequest, memexec_config) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_schema_ContainerCollectorConfig_schema_ExecuteCollectorConfig_schema_MemExecCollectorConfig_schema_ConfigurationRequest_schema_ConfigurationResponse)
-#endif
-
-
-/* @@protoc_insertion_point(eof) */
diff --git a/security/container/protos/config.pb.h b/security/container/protos/config.pb.h
index 2685d2b..893961e 100644
--- a/security/container/protos/config.pb.h
+++ b/security/container/protos/config.pb.h
@@ -1,74 +1,81 @@
 /* Automatically generated nanopb header */
-/* Generated by nanopb-0.3.9.3 at Wed Jun  5 11:00:24 2019. */
+/* Generated by nanopb-0.4.5 */
 
 #ifndef PB_SCHEMA_CONFIG_PB_H_INCLUDED
 #define PB_SCHEMA_CONFIG_PB_H_INCLUDED
 #include <pb.h>
 
-/* @@protoc_insertion_point(includes) */
-#if PB_PROTO_HEADER_VERSION != 30
+#if PB_PROTO_HEADER_VERSION != 40
 #error Regenerate this file with the current version of nanopb generator.
 #endif
 
+/* Enum definitions */
+typedef enum _schema_ConfigurationResponse_ErrorCode { 
+    schema_ConfigurationResponse_ErrorCode_NO_ERROR = 0, 
+    schema_ConfigurationResponse_ErrorCode_UNKNOWN = 2 
+} schema_ConfigurationResponse_ErrorCode;
+
+/* Struct definitions */
+/* Report success or failure of previous ConfigurationRequest */
+typedef struct _schema_ConfigurationResponse { 
+    schema_ConfigurationResponse_ErrorCode error; 
+    pb_callback_t msg; 
+    uint64_t version; /* Version of the LSM */
+    uint32_t kernel_version; /* LINUX_VERSION_CODE */
+} schema_ConfigurationResponse;
+
+/* Collect information about running containers */
+typedef struct _schema_ContainerCollectorConfig { 
+    bool enabled; 
+} schema_ContainerCollectorConfig;
+
+typedef struct _schema_ExecuteCollectorConfig { 
+    bool enabled; 
+    /* truncate argv/envp if cumulative length exceeds limit */
+    uint32_t argv_limit; 
+    uint32_t envp_limit; 
+    /* If specified, only report the named environment variables.  An
+ empty envp_allowlist indicates that all environment variables
+ should be reported up to a cumulative total of envp_limit bytes. */
+    pb_callback_t envp_allowlist; 
+} schema_ExecuteCollectorConfig;
+
+/* Collect information about executable memory mappings. */
+typedef struct _schema_MemExecCollectorConfig { 
+    bool enabled; 
+} schema_MemExecCollectorConfig;
+
+/* Convey configuration information to Guest LSM */
+typedef struct _schema_ConfigurationRequest { 
+    bool has_container_config;
+    schema_ContainerCollectorConfig container_config; 
+    bool has_execute_config;
+    schema_ExecuteCollectorConfig execute_config; 
+    bool has_memexec_config;
+    schema_MemExecCollectorConfig memexec_config; 
+} schema_ConfigurationRequest;
+
+
+/* Helper constants for enums */
+#define _schema_ConfigurationResponse_ErrorCode_MIN schema_ConfigurationResponse_ErrorCode_NO_ERROR
+#define _schema_ConfigurationResponse_ErrorCode_MAX schema_ConfigurationResponse_ErrorCode_UNKNOWN
+#define _schema_ConfigurationResponse_ErrorCode_ARRAYSIZE ((schema_ConfigurationResponse_ErrorCode)(schema_ConfigurationResponse_ErrorCode_UNKNOWN+1))
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* Enum definitions */
-typedef enum _schema_ConfigurationResponse_ErrorCode {
-    schema_ConfigurationResponse_ErrorCode_NO_ERROR = 0,
-    schema_ConfigurationResponse_ErrorCode_UNKNOWN = 2
-} schema_ConfigurationResponse_ErrorCode;
-#define _schema_ConfigurationResponse_ErrorCode_MIN schema_ConfigurationResponse_ErrorCode_NO_ERROR
-#define _schema_ConfigurationResponse_ErrorCode_MAX schema_ConfigurationResponse_ErrorCode_UNKNOWN
-#define _schema_ConfigurationResponse_ErrorCode_ARRAYSIZE ((schema_ConfigurationResponse_ErrorCode)(schema_ConfigurationResponse_ErrorCode_UNKNOWN+1))
-
-/* Struct definitions */
-typedef struct _schema_ConfigurationResponse {
-    schema_ConfigurationResponse_ErrorCode error;
-    pb_callback_t msg;
-    uint64_t version;
-    uint32_t kernel_version;
-/* @@protoc_insertion_point(struct:schema_ConfigurationResponse) */
-} schema_ConfigurationResponse;
-
-typedef struct _schema_ContainerCollectorConfig {
-    bool enabled;
-/* @@protoc_insertion_point(struct:schema_ContainerCollectorConfig) */
-} schema_ContainerCollectorConfig;
-
-typedef struct _schema_ExecuteCollectorConfig {
-    bool enabled;
-    uint32_t argv_limit;
-    uint32_t envp_limit;
-    pb_callback_t envp_allowlist;
-/* @@protoc_insertion_point(struct:schema_ExecuteCollectorConfig) */
-} schema_ExecuteCollectorConfig;
-
-typedef struct _schema_MemExecCollectorConfig {
-    bool enabled;
-/* @@protoc_insertion_point(struct:schema_MemExecCollectorConfig) */
-} schema_MemExecCollectorConfig;
-
-typedef struct _schema_ConfigurationRequest {
-    schema_ContainerCollectorConfig container_config;
-    schema_ExecuteCollectorConfig execute_config;
-    schema_MemExecCollectorConfig memexec_config;
-/* @@protoc_insertion_point(struct:schema_ConfigurationRequest) */
-} schema_ConfigurationRequest;
-
-/* Default values for struct fields */
-
 /* Initializer values for message structs */
 #define schema_ContainerCollectorConfig_init_default {0}
 #define schema_ExecuteCollectorConfig_init_default {0, 0, 0, {{NULL}, NULL}}
 #define schema_MemExecCollectorConfig_init_default {0}
-#define schema_ConfigurationRequest_init_default {schema_ContainerCollectorConfig_init_default, schema_ExecuteCollectorConfig_init_default, schema_MemExecCollectorConfig_init_default}
+#define schema_ConfigurationRequest_init_default {false, schema_ContainerCollectorConfig_init_default, false, schema_ExecuteCollectorConfig_init_default, false, schema_MemExecCollectorConfig_init_default}
 #define schema_ConfigurationResponse_init_default {_schema_ConfigurationResponse_ErrorCode_MIN, {{NULL}, NULL}, 0, 0}
 #define schema_ContainerCollectorConfig_init_zero {0}
 #define schema_ExecuteCollectorConfig_init_zero  {0, 0, 0, {{NULL}, NULL}}
 #define schema_MemExecCollectorConfig_init_zero  {0}
-#define schema_ConfigurationRequest_init_zero    {schema_ContainerCollectorConfig_init_zero, schema_ExecuteCollectorConfig_init_zero, schema_MemExecCollectorConfig_init_zero}
+#define schema_ConfigurationRequest_init_zero    {false, schema_ContainerCollectorConfig_init_zero, false, schema_ExecuteCollectorConfig_init_zero, false, schema_MemExecCollectorConfig_init_zero}
 #define schema_ConfigurationResponse_init_zero   {_schema_ConfigurationResponse_ErrorCode_MIN, {{NULL}, NULL}, 0, 0}
 
 /* Field tags (for use in manual encoding/decoding) */
@@ -87,30 +94,64 @@
 #define schema_ConfigurationRequest_memexec_config_tag 3
 
 /* Struct field encoding specification for nanopb */
-extern const pb_field_t schema_ContainerCollectorConfig_fields[2];
-extern const pb_field_t schema_ExecuteCollectorConfig_fields[5];
-extern const pb_field_t schema_MemExecCollectorConfig_fields[2];
-extern const pb_field_t schema_ConfigurationRequest_fields[4];
-extern const pb_field_t schema_ConfigurationResponse_fields[5];
+#define schema_ContainerCollectorConfig_FIELDLIST(X, a) \
+X(a, STATIC,   SINGULAR, BOOL,     enabled,           1)
+#define schema_ContainerCollectorConfig_CALLBACK NULL
+#define schema_ContainerCollectorConfig_DEFAULT NULL
+
+#define schema_ExecuteCollectorConfig_FIELDLIST(X, a) \
+X(a, STATIC,   SINGULAR, BOOL,     enabled,           1) \
+X(a, STATIC,   SINGULAR, UINT32,   argv_limit,        2) \
+X(a, STATIC,   SINGULAR, UINT32,   envp_limit,        3) \
+X(a, CALLBACK, REPEATED, STRING,   envp_allowlist,    4)
+#define schema_ExecuteCollectorConfig_CALLBACK pb_default_field_callback
+#define schema_ExecuteCollectorConfig_DEFAULT NULL
+
+#define schema_MemExecCollectorConfig_FIELDLIST(X, a) \
+X(a, STATIC,   SINGULAR, BOOL,     enabled,           1)
+#define schema_MemExecCollectorConfig_CALLBACK NULL
+#define schema_MemExecCollectorConfig_DEFAULT NULL
+
+#define schema_ConfigurationRequest_FIELDLIST(X, a) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  container_config,   1) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  execute_config,    2) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  memexec_config,    3)
+#define schema_ConfigurationRequest_CALLBACK NULL
+#define schema_ConfigurationRequest_DEFAULT NULL
+#define schema_ConfigurationRequest_container_config_MSGTYPE schema_ContainerCollectorConfig
+#define schema_ConfigurationRequest_execute_config_MSGTYPE schema_ExecuteCollectorConfig
+#define schema_ConfigurationRequest_memexec_config_MSGTYPE schema_MemExecCollectorConfig
+
+#define schema_ConfigurationResponse_FIELDLIST(X, a) \
+X(a, STATIC,   SINGULAR, UENUM,    error,             1) \
+X(a, CALLBACK, SINGULAR, STRING,   msg,               2) \
+X(a, STATIC,   SINGULAR, UINT64,   version,           3) \
+X(a, STATIC,   SINGULAR, UINT32,   kernel_version,    4)
+#define schema_ConfigurationResponse_CALLBACK pb_default_field_callback
+#define schema_ConfigurationResponse_DEFAULT NULL
+
+extern const pb_msgdesc_t schema_ContainerCollectorConfig_msg;
+extern const pb_msgdesc_t schema_ExecuteCollectorConfig_msg;
+extern const pb_msgdesc_t schema_MemExecCollectorConfig_msg;
+extern const pb_msgdesc_t schema_ConfigurationRequest_msg;
+extern const pb_msgdesc_t schema_ConfigurationResponse_msg;
+
+/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
+#define schema_ContainerCollectorConfig_fields &schema_ContainerCollectorConfig_msg
+#define schema_ExecuteCollectorConfig_fields &schema_ExecuteCollectorConfig_msg
+#define schema_MemExecCollectorConfig_fields &schema_MemExecCollectorConfig_msg
+#define schema_ConfigurationRequest_fields &schema_ConfigurationRequest_msg
+#define schema_ConfigurationResponse_fields &schema_ConfigurationResponse_msg
 
 /* Maximum encoded size of messages (where known) */
-#define schema_ContainerCollectorConfig_size     2
 /* schema_ExecuteCollectorConfig_size depends on runtime parameters */
-#define schema_MemExecCollectorConfig_size       2
 /* schema_ConfigurationRequest_size depends on runtime parameters */
 /* schema_ConfigurationResponse_size depends on runtime parameters */
-
-/* Message IDs (where set with "msgid" option) */
-#ifdef PB_MSGID
-
-#define CONFIG_MESSAGES \
-
-
-#endif
+#define schema_ContainerCollectorConfig_size     2
+#define schema_MemExecCollectorConfig_size       2
 
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
-/* @@protoc_insertion_point(eof) */
 
 #endif
diff --git a/security/container/protos/event.pb.c b/security/container/protos/event.pb.c
index 1018ce2..2293566 100644
--- a/security/container/protos/event.pb.c
+++ b/security/container/protos/event.pb.c
@@ -1,174 +1,61 @@
 /* Automatically generated nanopb constant definitions */
-/* Generated by nanopb-0.3.9.1 at Mon Nov 11 16:11:19 2019. */
+/* Generated by nanopb-0.4.5 */
 
 #include "event.pb.h"
-
-/* @@protoc_insertion_point(includes) */
-#if PB_PROTO_HEADER_VERSION != 30
+#if PB_PROTO_HEADER_VERSION != 40
 #error Regenerate this file with the current version of nanopb generator.
 #endif
 
+PB_BIND(schema_SocketIp, schema_SocketIp, AUTO)
 
 
-const pb_field_t schema_SocketIp_fields[4] = {
-    PB_FIELD(  1, UINT32  , SINGULAR, STATIC  , FIRST, schema_SocketIp, family, family, 0),
-    PB_FIELD(  2, BYTES   , SINGULAR, CALLBACK, OTHER, schema_SocketIp, ip, family, 0),
-    PB_FIELD(  3, UINT32  , SINGULAR, STATIC  , OTHER, schema_SocketIp, port, ip, 0),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_Socket, schema_Socket, AUTO)
 
-const pb_field_t schema_Socket_fields[3] = {
-    PB_FIELD(  1, MESSAGE , SINGULAR, STATIC  , FIRST, schema_Socket, local, local, &schema_SocketIp_fields),
-    PB_FIELD(  2, MESSAGE , SINGULAR, STATIC  , OTHER, schema_Socket, remote, local, &schema_SocketIp_fields),
-    PB_LAST_FIELD
-};
 
-const pb_field_t schema_Overlay_fields[4] = {
-    PB_FIELD(  1, BOOL    , SINGULAR, STATIC  , FIRST, schema_Overlay, lower_layer, lower_layer, 0),
-    PB_FIELD(  2, BOOL    , SINGULAR, STATIC  , OTHER, schema_Overlay, upper_layer, lower_layer, 0),
-    PB_FIELD(  3, BYTES   , SINGULAR, CALLBACK, OTHER, schema_Overlay, modified_uuid, upper_layer, 0),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_Overlay, schema_Overlay, AUTO)
 
-const pb_field_t schema_File_fields[5] = {
-    PB_FIELD(  1, BYTES   , SINGULAR, CALLBACK, FIRST, schema_File, fullpath, fullpath, 0),
-    PB_ONEOF_FIELD(filesystem,   2, MESSAGE , ONEOF, STATIC  , OTHER, schema_File, overlayfs, fullpath, &schema_Overlay_fields),
-    PB_ONEOF_FIELD(filesystem,   4, MESSAGE , ONEOF, STATIC  , UNION, schema_File, socket, fullpath, &schema_Socket_fields),
-    PB_FIELD(  3, UINT32  , SINGULAR, STATIC  , OTHER, schema_File, ino, filesystem.socket, 0),
-    PB_LAST_FIELD
-};
 
-const pb_field_t schema_ProcessArguments_fields[5] = {
-    PB_FIELD(  1, BYTES   , REPEATED, CALLBACK, FIRST, schema_ProcessArguments, argv, argv, 0),
-    PB_FIELD(  2, UINT32  , SINGULAR, STATIC  , OTHER, schema_ProcessArguments, argv_truncated, argv, 0),
-    PB_FIELD(  3, BYTES   , REPEATED, CALLBACK, OTHER, schema_ProcessArguments, envp, argv_truncated, 0),
-    PB_FIELD(  4, UINT32  , SINGULAR, STATIC  , OTHER, schema_ProcessArguments, envp_truncated, envp, 0),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_File, schema_File, AUTO)
 
-const pb_field_t schema_Descriptor_fields[3] = {
-    PB_FIELD(  1, UINT32  , SINGULAR, STATIC  , FIRST, schema_Descriptor, mode, mode, 0),
-    PB_FIELD(  2, MESSAGE , SINGULAR, STATIC  , OTHER, schema_Descriptor, file, mode, &schema_File_fields),
-    PB_LAST_FIELD
-};
 
-const pb_field_t schema_Streams_fields[4] = {
-    PB_FIELD(  1, MESSAGE , SINGULAR, STATIC  , FIRST, schema_Streams, stdin, stdin, &schema_Descriptor_fields),
-    PB_FIELD(  2, MESSAGE , SINGULAR, STATIC  , OTHER, schema_Streams, stdout, stdin, &schema_Descriptor_fields),
-    PB_FIELD(  3, MESSAGE , SINGULAR, STATIC  , OTHER, schema_Streams, stderr, stdout, &schema_Descriptor_fields),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_ProcessArguments, schema_ProcessArguments, AUTO)
 
-const pb_field_t schema_Process_fields[13] = {
-    PB_FIELD(  1, UINT64  , SINGULAR, STATIC  , FIRST, schema_Process, creation_timestamp, creation_timestamp, 0),
-    PB_FIELD(  2, BYTES   , SINGULAR, CALLBACK, OTHER, schema_Process, uuid, creation_timestamp, 0),
-    PB_FIELD(  3, UINT32  , SINGULAR, STATIC  , OTHER, schema_Process, pid, uuid, 0),
-    PB_FIELD(  4, MESSAGE , SINGULAR, STATIC  , OTHER, schema_Process, binary, pid, &schema_File_fields),
-    PB_FIELD(  5, UINT32  , SINGULAR, STATIC  , OTHER, schema_Process, parent_pid, binary, 0),
-    PB_FIELD(  6, BYTES   , SINGULAR, CALLBACK, OTHER, schema_Process, parent_uuid, parent_pid, 0),
-    PB_FIELD(  7, UINT64  , SINGULAR, STATIC  , OTHER, schema_Process, container_id, parent_uuid, 0),
-    PB_FIELD(  8, UINT32  , SINGULAR, STATIC  , OTHER, schema_Process, container_pid, container_id, 0),
-    PB_FIELD(  9, UINT32  , SINGULAR, STATIC  , OTHER, schema_Process, container_parent_pid, container_pid, 0),
-    PB_FIELD( 10, MESSAGE , SINGULAR, STATIC  , OTHER, schema_Process, args, container_parent_pid, &schema_ProcessArguments_fields),
-    PB_FIELD( 11, MESSAGE , SINGULAR, STATIC  , OTHER, schema_Process, streams, args, &schema_Streams_fields),
-    PB_FIELD( 12, UINT64  , SINGULAR, STATIC  , OTHER, schema_Process, exec_session_id, streams, 0),
-    PB_LAST_FIELD
-};
 
-const pb_field_t schema_Container_fields[10] = {
-    PB_FIELD(  1, UINT64  , SINGULAR, STATIC  , FIRST, schema_Container, creation_timestamp, creation_timestamp, 0),
-    PB_FIELD(  2, BYTES   , SINGULAR, CALLBACK, OTHER, schema_Container, pod_namespace, creation_timestamp, 0),
-    PB_FIELD(  3, BYTES   , SINGULAR, CALLBACK, OTHER, schema_Container, pod_name, pod_namespace, 0),
-    PB_FIELD(  4, UINT64  , SINGULAR, STATIC  , OTHER, schema_Container, container_id, pod_name, 0),
-    PB_FIELD(  5, BYTES   , SINGULAR, CALLBACK, OTHER, schema_Container, container_name, container_id, 0),
-    PB_FIELD(  6, BYTES   , SINGULAR, CALLBACK, OTHER, schema_Container, container_image_uri, container_name, 0),
-    PB_FIELD(  7, BYTES   , REPEATED, CALLBACK, OTHER, schema_Container, labels, container_image_uri, 0),
-    PB_FIELD(  8, BYTES   , SINGULAR, CALLBACK, OTHER, schema_Container, init_uuid, labels, 0),
-    PB_FIELD(  9, BYTES   , SINGULAR, CALLBACK, OTHER, schema_Container, container_image_id, init_uuid, 0),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_Descriptor, schema_Descriptor, AUTO)
 
-const pb_field_t schema_ExecuteEvent_fields[2] = {
-    PB_FIELD(  1, MESSAGE , SINGULAR, STATIC  , FIRST, schema_ExecuteEvent, proc, proc, &schema_Process_fields),
-    PB_LAST_FIELD
-};
 
-const pb_field_t schema_CloneEvent_fields[2] = {
-    PB_FIELD(  1, MESSAGE , SINGULAR, STATIC  , FIRST, schema_CloneEvent, proc, proc, &schema_Process_fields),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_Streams, schema_Streams, 2)
 
-const pb_field_t schema_EnumerateProcessEvent_fields[2] = {
-    PB_FIELD(  1, MESSAGE , SINGULAR, STATIC  , FIRST, schema_EnumerateProcessEvent, proc, proc, &schema_Process_fields),
-    PB_LAST_FIELD
-};
 
-const pb_field_t schema_MemoryExecEvent_fields[12] = {
-    PB_FIELD(  1, MESSAGE , SINGULAR, STATIC  , FIRST, schema_MemoryExecEvent, proc, proc, &schema_Process_fields),
-    PB_FIELD(  2, UINT64  , SINGULAR, STATIC  , OTHER, schema_MemoryExecEvent, prot_exec_timestamp, proc, 0),
-    PB_FIELD(  3, UINT64  , SINGULAR, STATIC  , OTHER, schema_MemoryExecEvent, new_flags, prot_exec_timestamp, 0),
-    PB_FIELD(  4, UINT64  , SINGULAR, STATIC  , OTHER, schema_MemoryExecEvent, req_flags, new_flags, 0),
-    PB_FIELD(  5, UINT64  , SINGULAR, STATIC  , OTHER, schema_MemoryExecEvent, old_vm_flags, req_flags, 0),
-    PB_FIELD(  6, UINT64  , SINGULAR, STATIC  , OTHER, schema_MemoryExecEvent, mmap_flags, old_vm_flags, 0),
-    PB_FIELD(  7, MESSAGE , SINGULAR, STATIC  , OTHER, schema_MemoryExecEvent, mapped_file, mmap_flags, &schema_File_fields),
-    PB_FIELD(  8, UENUM   , SINGULAR, STATIC  , OTHER, schema_MemoryExecEvent, action, mapped_file, 0),
-    PB_FIELD(  9, UINT64  , SINGULAR, STATIC  , OTHER, schema_MemoryExecEvent, start_addr, action, 0),
-    PB_FIELD( 10, UINT64  , SINGULAR, STATIC  , OTHER, schema_MemoryExecEvent, end_addr, start_addr, 0),
-    PB_FIELD( 11, BOOL    , SINGULAR, STATIC  , OTHER, schema_MemoryExecEvent, is_initial_mmap, end_addr, 0),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_Process, schema_Process, 2)
 
-const pb_field_t schema_ContainerInfoEvent_fields[2] = {
-    PB_FIELD(  1, MESSAGE , SINGULAR, STATIC  , FIRST, schema_ContainerInfoEvent, container, container, &schema_Container_fields),
-    PB_LAST_FIELD
-};
 
-const pb_field_t schema_ExitEvent_fields[2] = {
-    PB_FIELD(  1, BYTES   , SINGULAR, CALLBACK, FIRST, schema_ExitEvent, process_uuid, process_uuid, 0),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_Container, schema_Container, AUTO)
 
-const pb_field_t schema_Event_fields[8] = {
-    PB_ONEOF_FIELD(event,   1, MESSAGE , ONEOF, STATIC  , FIRST, schema_Event, execute, execute, &schema_ExecuteEvent_fields),
-    PB_ONEOF_FIELD(event,   2, MESSAGE , ONEOF, STATIC  , UNION, schema_Event, container, container, &schema_ContainerInfoEvent_fields),
-    PB_ONEOF_FIELD(event,   3, MESSAGE , ONEOF, STATIC  , UNION, schema_Event, exit, exit, &schema_ExitEvent_fields),
-    PB_ONEOF_FIELD(event,   4, MESSAGE , ONEOF, STATIC  , UNION, schema_Event, memexec, memexec, &schema_MemoryExecEvent_fields),
-    PB_ONEOF_FIELD(event,   5, MESSAGE , ONEOF, STATIC  , UNION, schema_Event, clone, clone, &schema_CloneEvent_fields),
-    PB_ONEOF_FIELD(event,   7, MESSAGE , ONEOF, STATIC  , UNION, schema_Event, enumproc, enumproc, &schema_EnumerateProcessEvent_fields),
-    PB_FIELD(  6, UINT64  , SINGULAR, STATIC  , OTHER, schema_Event, timestamp, event.enumproc, 0),
-    PB_LAST_FIELD
-};
 
-const pb_field_t schema_ContainerReport_fields[3] = {
-    PB_FIELD(  1, UINT32  , SINGULAR, STATIC  , FIRST, schema_ContainerReport, pid, pid, 0),
-    PB_FIELD(  2, MESSAGE , SINGULAR, STATIC  , OTHER, schema_ContainerReport, container, pid, &schema_Container_fields),
-    PB_LAST_FIELD
-};
+PB_BIND(schema_ExecuteEvent, schema_ExecuteEvent, 2)
+
+
+PB_BIND(schema_CloneEvent, schema_CloneEvent, 2)
+
+
+PB_BIND(schema_EnumerateProcessEvent, schema_EnumerateProcessEvent, 2)
+
+
+PB_BIND(schema_MemoryExecEvent, schema_MemoryExecEvent, 2)
+
+
+PB_BIND(schema_ContainerInfoEvent, schema_ContainerInfoEvent, AUTO)
+
+
+PB_BIND(schema_ExitEvent, schema_ExitEvent, AUTO)
+
+
+PB_BIND(schema_Event, schema_Event, 2)
+
+
+PB_BIND(schema_ContainerReport, schema_ContainerReport, AUTO)
 
 
 
-/* Check that field information fits in pb_field_t */
-#if !defined(PB_FIELD_32BIT)
-/* If you get an error here, it means that you need to define PB_FIELD_32BIT
- * compile-time option. You can do that in pb.h or on compiler command line.
- * 
- * The reason you need to do this is that some of your messages contain tag
- * numbers or field sizes that are larger than what can fit in 8 or 16 bit
- * field descriptors.
- */
-PB_STATIC_ASSERT((pb_membersize(schema_Socket, local) < 65536 && pb_membersize(schema_Socket, remote) < 65536 && pb_membersize(schema_File, filesystem.overlayfs) < 65536 && pb_membersize(schema_File, filesystem.socket) < 65536 && pb_membersize(schema_Descriptor, file) < 65536 && pb_membersize(schema_Streams, stdin) < 65536 && pb_membersize(schema_Streams, stdout) < 65536 && pb_membersize(schema_Streams, stderr) < 65536 && pb_membersize(schema_Process, binary) < 65536 && pb_membersize(schema_Process, args) < 65536 && pb_membersize(schema_Process, streams) < 65536 && pb_membersize(schema_ExecuteEvent, proc) < 65536 && pb_membersize(schema_CloneEvent, proc) < 65536 && pb_membersize(schema_EnumerateProcessEvent, proc) < 65536 && pb_membersize(schema_MemoryExecEvent, proc) < 65536 && pb_membersize(schema_MemoryExecEvent, mapped_file) < 65536 && pb_membersize(schema_ContainerInfoEvent, container) < 65536 && pb_membersize(schema_Event, event.execute) < 65536 && pb_membersize(schema_Event, event.container) < 65536 && pb_membersize(schema_Event, event.exit) < 65536 && pb_membersize(schema_Event, event.memexec) < 65536 && pb_membersize(schema_Event, event.clone) < 65536 && pb_membersize(schema_Event, event.enumproc) < 65536 && pb_membersize(schema_ContainerReport, container) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_schema_SocketIp_schema_Socket_schema_Overlay_schema_File_schema_ProcessArguments_schema_Descriptor_schema_Streams_schema_Process_schema_Container_schema_ExecuteEvent_schema_CloneEvent_schema_EnumerateProcessEvent_schema_MemoryExecEvent_schema_ContainerInfoEvent_schema_ExitEvent_schema_Event_schema_ContainerReport)
-#endif
 
-#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
-/* If you get an error here, it means that you need to define PB_FIELD_16BIT
- * compile-time option. You can do that in pb.h or on compiler command line.
- * 
- * The reason you need to do this is that some of your messages contain tag
- * numbers or field sizes that are larger than what can fit in the default
- * 8 bit descriptors.
- */
-PB_STATIC_ASSERT((pb_membersize(schema_Socket, local) < 256 && pb_membersize(schema_Socket, remote) < 256 && pb_membersize(schema_File, filesystem.overlayfs) < 256 && pb_membersize(schema_File, filesystem.socket) < 256 && pb_membersize(schema_Descriptor, file) < 256 && pb_membersize(schema_Streams, stdin) < 256 && pb_membersize(schema_Streams, stdout) < 256 && pb_membersize(schema_Streams, stderr) < 256 && pb_membersize(schema_Process, binary) < 256 && pb_membersize(schema_Process, args) < 256 && pb_membersize(schema_Process, streams) < 256 && pb_membersize(schema_ExecuteEvent, proc) < 256 && pb_membersize(schema_CloneEvent, proc) < 256 && pb_membersize(schema_EnumerateProcessEvent, proc) < 256 && pb_membersize(schema_MemoryExecEvent, proc) < 256 && pb_membersize(schema_MemoryExecEvent, mapped_file) < 256 && pb_membersize(schema_ContainerInfoEvent, container) < 256 && pb_membersize(schema_Event, event.execute) < 256 && pb_membersize(schema_Event, event.container) < 256 && pb_membersize(schema_Event, event.exit) < 256 && pb_membersize(schema_Event, event.memexec) < 256 && pb_membersize(schema_Event, event.clone) < 256 && pb_membersize(schema_Event, event.enumproc) < 256 && pb_membersize(schema_ContainerReport, container) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_schema_SocketIp_schema_Socket_schema_Overlay_schema_File_schema_ProcessArguments_schema_Descriptor_schema_Streams_schema_Process_schema_Container_schema_ExecuteEvent_schema_CloneEvent_schema_EnumerateProcessEvent_schema_MemoryExecEvent_schema_ContainerInfoEvent_schema_ExitEvent_schema_Event_schema_ContainerReport)
-#endif
-
-
-/* @@protoc_insertion_point(eof) */
diff --git a/security/container/protos/event.pb.h b/security/container/protos/event.pb.h
index 0634e8e..9535068 100644
--- a/security/container/protos/event.pb.h
+++ b/security/container/protos/event.pb.h
@@ -1,158 +1,170 @@
 /* Automatically generated nanopb header */
-/* Generated by nanopb-0.3.9.1 at Mon Nov 11 16:11:19 2019. */
+/* Generated by nanopb-0.4.5 */
 
 #ifndef PB_SCHEMA_EVENT_PB_H_INCLUDED
 #define PB_SCHEMA_EVENT_PB_H_INCLUDED
 #include <pb.h>
 
-/* @@protoc_insertion_point(includes) */
-#if PB_PROTO_HEADER_VERSION != 30
+#if PB_PROTO_HEADER_VERSION != 40
 #error Regenerate this file with the current version of nanopb generator.
 #endif
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Enum definitions */
-typedef enum _schema_MemoryExecEvent_Action {
-    schema_MemoryExecEvent_Action_UNDEFINED = 0,
-    schema_MemoryExecEvent_Action_MPROTECT = 1,
-    schema_MemoryExecEvent_Action_MMAP_FILE = 2
+typedef enum _schema_MemoryExecEvent_Action { 
+    schema_MemoryExecEvent_Action_UNDEFINED = 0, 
+    schema_MemoryExecEvent_Action_MPROTECT = 1, 
+    schema_MemoryExecEvent_Action_MMAP_FILE = 2 
 } schema_MemoryExecEvent_Action;
-#define _schema_MemoryExecEvent_Action_MIN schema_MemoryExecEvent_Action_UNDEFINED
-#define _schema_MemoryExecEvent_Action_MAX schema_MemoryExecEvent_Action_MMAP_FILE
-#define _schema_MemoryExecEvent_Action_ARRAYSIZE ((schema_MemoryExecEvent_Action)(schema_MemoryExecEvent_Action_MMAP_FILE+1))
 
 /* Struct definitions */
-typedef struct _schema_ExitEvent {
-    pb_callback_t process_uuid;
-/* @@protoc_insertion_point(struct:schema_ExitEvent) */
+/* The process with the indicated pid has exited. */
+typedef struct _schema_ExitEvent { 
+    pb_callback_t process_uuid; 
 } schema_ExitEvent;
 
-typedef struct _schema_Container {
-    uint64_t creation_timestamp;
-    pb_callback_t pod_namespace;
-    pb_callback_t pod_name;
-    uint64_t container_id;
-    pb_callback_t container_name;
-    pb_callback_t container_image_uri;
-    pb_callback_t labels;
-    pb_callback_t init_uuid;
-    pb_callback_t container_image_id;
-/* @@protoc_insertion_point(struct:schema_Container) */
+typedef struct _schema_Container { 
+    uint64_t creation_timestamp; /* container create time in ns */
+    pb_callback_t pod_namespace; 
+    pb_callback_t pod_name; 
+    uint64_t container_id; /* unique across lifetime of Node */
+    pb_callback_t container_name; 
+    pb_callback_t container_image_uri; 
+    pb_callback_t labels; 
+    pb_callback_t init_uuid; 
+    pb_callback_t container_image_id; 
 } schema_Container;
 
-typedef struct _schema_Overlay {
-    bool lower_layer;
-    bool upper_layer;
-    pb_callback_t modified_uuid;
-/* @@protoc_insertion_point(struct:schema_Overlay) */
+typedef struct _schema_Overlay { 
+    bool lower_layer; 
+    bool upper_layer; 
+    pb_callback_t modified_uuid; /* The process who first modified the file. */
 } schema_Overlay;
 
-typedef struct _schema_ProcessArguments {
-    pb_callback_t argv;
-    uint32_t argv_truncated;
-    pb_callback_t envp;
-    uint32_t envp_truncated;
-/* @@protoc_insertion_point(struct:schema_ProcessArguments) */
+typedef struct _schema_ProcessArguments { 
+    pb_callback_t argv; /* process arguments */
+    uint32_t argv_truncated; /* number of characters truncated from argv */
+    pb_callback_t envp; /* process environment variables */
+    uint32_t envp_truncated; /* number of characters truncated from envp */
 } schema_ProcessArguments;
 
-typedef struct _schema_SocketIp {
-    uint32_t family;
-    pb_callback_t ip;
-    uint32_t port;
-/* @@protoc_insertion_point(struct:schema_SocketIp) */
+typedef struct _schema_SocketIp { 
+    uint32_t family; /* AF_* for socket type. */
+    pb_callback_t ip; /* ip4 or ip6 address. */
+    uint32_t port; /* port bind or connected. */
 } schema_SocketIp;
 
-typedef struct _schema_ContainerInfoEvent {
-    schema_Container container;
-/* @@protoc_insertion_point(struct:schema_ContainerInfoEvent) */
+/* Associate the following container information with all processes
+ that have the indicated container_id. */
+typedef struct _schema_ContainerInfoEvent { 
+    bool has_container;
+    schema_Container container; 
 } schema_ContainerInfoEvent;
 
-typedef struct _schema_ContainerReport {
-    uint32_t pid;
-    schema_Container container;
-/* @@protoc_insertion_point(struct:schema_ContainerReport) */
+/* Message sent by the daemonset to the LSM for container enlightenment. */
+typedef struct _schema_ContainerReport { 
+    uint32_t pid; /* Top pid of the running container. */
+    bool has_container;
+    schema_Container container; /* Information collected about the container. */
 } schema_ContainerReport;
 
-typedef struct _schema_Socket {
-    schema_SocketIp local;
-    schema_SocketIp remote;
-/* @@protoc_insertion_point(struct:schema_Socket) */
+typedef struct _schema_Socket { 
+    bool has_local;
+    schema_SocketIp local; 
+    bool has_remote;
+    schema_SocketIp remote; /* unset if not connected. */
 } schema_Socket;
 
-typedef struct _schema_File {
-    pb_callback_t fullpath;
+typedef struct _schema_File { 
+    pb_callback_t fullpath; 
     pb_size_t which_filesystem;
     union {
         schema_Overlay overlayfs;
         schema_Socket socket;
-    } filesystem;
-    uint32_t ino;
-/* @@protoc_insertion_point(struct:schema_File) */
+    } filesystem; /* inode number. */
+    uint32_t ino; 
+    uint64_t ctime; 
 } schema_File;
 
-typedef struct _schema_Descriptor {
-    uint32_t mode;
-    schema_File file;
-/* @@protoc_insertion_point(struct:schema_Descriptor) */
+typedef struct _schema_Descriptor { 
+    uint32_t mode; /* file mode (stat st_mode) */
+    bool has_file;
+    schema_File file; 
 } schema_Descriptor;
 
-typedef struct _schema_Streams {
-    schema_Descriptor stdin;
-    schema_Descriptor stdout;
-    schema_Descriptor stderr;
-/* @@protoc_insertion_point(struct:schema_Streams) */
+typedef struct _schema_Streams { 
+    bool has_stdin;
+    schema_Descriptor stdin; 
+    bool has_stdout;
+    schema_Descriptor stdout; 
+    bool has_stderr;
+    schema_Descriptor stderr; 
 } schema_Streams;
 
-typedef struct _schema_Process {
-    uint64_t creation_timestamp;
-    pb_callback_t uuid;
-    uint32_t pid;
-    schema_File binary;
-    uint32_t parent_pid;
-    pb_callback_t parent_uuid;
-    uint64_t container_id;
-    uint32_t container_pid;
-    uint32_t container_parent_pid;
-    schema_ProcessArguments args;
-    schema_Streams streams;
-    uint64_t exec_session_id;
-/* @@protoc_insertion_point(struct:schema_Process) */
+typedef struct _schema_Process { 
+    uint64_t creation_timestamp; /* Only populated in ExecuteEvent, in ns. */
+    pb_callback_t uuid; 
+    uint32_t pid; 
+    bool has_binary;
+    schema_File binary; /* Only populated in ExecuteEvent. */
+    uint32_t parent_pid; 
+    pb_callback_t parent_uuid; 
+    uint64_t container_id; /* unique id of process's container */
+    uint32_t container_pid; /* pid inside the container namespace pid */
+    uint32_t container_parent_pid; /* optional */
+    bool has_args;
+    schema_ProcessArguments args; /* Only populated in ExecuteEvent. */
+    bool has_streams;
+    schema_Streams streams; /* Only populated in ExecuteEvent. */
+    uint64_t exec_session_id; /* identifier set for kubectl exec sessions. */
 } schema_Process;
 
-typedef struct _schema_CloneEvent {
-    schema_Process proc;
-/* @@protoc_insertion_point(struct:schema_CloneEvent) */
+/* A process clone is being created. This message means that a cloning operation
+ is being attempted. It may be sent even if fork fails. */
+typedef struct _schema_CloneEvent { 
+    bool has_proc;
+    schema_Process proc; 
 } schema_CloneEvent;
 
-typedef struct _schema_EnumerateProcessEvent {
-    schema_Process proc;
-/* @@protoc_insertion_point(struct:schema_EnumerateProcessEvent) */
+/* Processes that are enumerated at startup will be sent with this event. There
+ is no distinction from events we would have seen from fork or exec. */
+typedef struct _schema_EnumerateProcessEvent { 
+    bool has_proc;
+    schema_Process proc; 
 } schema_EnumerateProcessEvent;
 
-typedef struct _schema_ExecuteEvent {
-    schema_Process proc;
-/* @@protoc_insertion_point(struct:schema_ExecuteEvent) */
+/* A binary being executed.
+ e.g., execve() */
+typedef struct _schema_ExecuteEvent { 
+    bool has_proc;
+    schema_Process proc; 
 } schema_ExecuteEvent;
 
-typedef struct _schema_MemoryExecEvent {
-    schema_Process proc;
-    uint64_t prot_exec_timestamp;
-    uint64_t new_flags;
-    uint64_t req_flags;
-    uint64_t old_vm_flags;
-    uint64_t mmap_flags;
-    schema_File mapped_file;
-    schema_MemoryExecEvent_Action action;
-    uint64_t start_addr;
-    uint64_t end_addr;
-    bool is_initial_mmap;
-/* @@protoc_insertion_point(struct:schema_MemoryExecEvent) */
+/* Collect information about mmap/mprotect calls with the PROT_EXEC flag set. */
+typedef struct _schema_MemoryExecEvent { 
+    bool has_proc;
+    schema_Process proc; /* The origin process */
+    /* The timestamp in ns when the memory was set executable */
+    uint64_t prot_exec_timestamp; 
+    /* The prot flags granted by the kernel for the operation */
+    uint64_t new_flags; 
+    /* The prot flags requested for the mprotect/mmap operation */
+    uint64_t req_flags; 
+    /* The vm_flags prior to the mprotect operation, if relevant */
+    uint64_t old_vm_flags; 
+    /* The operational flags for the mmap operation, if relevant */
+    uint64_t mmap_flags; 
+    /* Derived from the file struct describing the fd being mapped */
+    bool has_mapped_file;
+    schema_File mapped_file; 
+    schema_MemoryExecEvent_Action action; 
+    uint64_t start_addr; /* The executable memory region start addr */
+    uint64_t end_addr; /* The executable memory region end addr */
+    /* True if this event is a mmap of the process' binary */
+    bool is_initial_mmap; 
 } schema_MemoryExecEvent;
 
-typedef struct _schema_Event {
+/* Next ID: 8 */
+typedef struct _schema_Event { 
     pb_size_t which_event;
     union {
         schema_ExecuteEvent execute;
@@ -161,48 +173,56 @@
         schema_MemoryExecEvent memexec;
         schema_CloneEvent clone;
         schema_EnumerateProcessEvent enumproc;
-    } event;
-    uint64_t timestamp;
-/* @@protoc_insertion_point(struct:schema_Event) */
+    } event; 
+    uint64_t timestamp; 
 } schema_Event;
 
-/* Default values for struct fields */
+
+/* Helper constants for enums */
+#define _schema_MemoryExecEvent_Action_MIN schema_MemoryExecEvent_Action_UNDEFINED
+#define _schema_MemoryExecEvent_Action_MAX schema_MemoryExecEvent_Action_MMAP_FILE
+#define _schema_MemoryExecEvent_Action_ARRAYSIZE ((schema_MemoryExecEvent_Action)(schema_MemoryExecEvent_Action_MMAP_FILE+1))
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /* Initializer values for message structs */
 #define schema_SocketIp_init_default             {0, {{NULL}, NULL}, 0}
-#define schema_Socket_init_default               {schema_SocketIp_init_default, schema_SocketIp_init_default}
+#define schema_Socket_init_default               {false, schema_SocketIp_init_default, false, schema_SocketIp_init_default}
 #define schema_Overlay_init_default              {0, 0, {{NULL}, NULL}}
-#define schema_File_init_default                 {{{NULL}, NULL}, 0, {schema_Overlay_init_default}, 0}
+#define schema_File_init_default                 {{{NULL}, NULL}, 0, {schema_Overlay_init_default}, 0, 0}
 #define schema_ProcessArguments_init_default     {{{NULL}, NULL}, 0, {{NULL}, NULL}, 0}
-#define schema_Descriptor_init_default           {0, schema_File_init_default}
-#define schema_Streams_init_default              {schema_Descriptor_init_default, schema_Descriptor_init_default, schema_Descriptor_init_default}
-#define schema_Process_init_default              {0, {{NULL}, NULL}, 0, schema_File_init_default, 0, {{NULL}, NULL}, 0, 0, 0, schema_ProcessArguments_init_default, schema_Streams_init_default, 0}
+#define schema_Descriptor_init_default           {0, false, schema_File_init_default}
+#define schema_Streams_init_default              {false, schema_Descriptor_init_default, false, schema_Descriptor_init_default, false, schema_Descriptor_init_default}
+#define schema_Process_init_default              {0, {{NULL}, NULL}, 0, false, schema_File_init_default, 0, {{NULL}, NULL}, 0, 0, 0, false, schema_ProcessArguments_init_default, false, schema_Streams_init_default, 0}
 #define schema_Container_init_default            {0, {{NULL}, NULL}, {{NULL}, NULL}, 0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}}
-#define schema_ExecuteEvent_init_default         {schema_Process_init_default}
-#define schema_CloneEvent_init_default           {schema_Process_init_default}
-#define schema_EnumerateProcessEvent_init_default {schema_Process_init_default}
-#define schema_MemoryExecEvent_init_default      {schema_Process_init_default, 0, 0, 0, 0, 0, schema_File_init_default, _schema_MemoryExecEvent_Action_MIN, 0, 0, 0}
-#define schema_ContainerInfoEvent_init_default   {schema_Container_init_default}
+#define schema_ExecuteEvent_init_default         {false, schema_Process_init_default}
+#define schema_CloneEvent_init_default           {false, schema_Process_init_default}
+#define schema_EnumerateProcessEvent_init_default {false, schema_Process_init_default}
+#define schema_MemoryExecEvent_init_default      {false, schema_Process_init_default, 0, 0, 0, 0, 0, false, schema_File_init_default, _schema_MemoryExecEvent_Action_MIN, 0, 0, 0}
+#define schema_ContainerInfoEvent_init_default   {false, schema_Container_init_default}
 #define schema_ExitEvent_init_default            {{{NULL}, NULL}}
 #define schema_Event_init_default                {0, {schema_ExecuteEvent_init_default}, 0}
-#define schema_ContainerReport_init_default      {0, schema_Container_init_default}
+#define schema_ContainerReport_init_default      {0, false, schema_Container_init_default}
 #define schema_SocketIp_init_zero                {0, {{NULL}, NULL}, 0}
-#define schema_Socket_init_zero                  {schema_SocketIp_init_zero, schema_SocketIp_init_zero}
+#define schema_Socket_init_zero                  {false, schema_SocketIp_init_zero, false, schema_SocketIp_init_zero}
 #define schema_Overlay_init_zero                 {0, 0, {{NULL}, NULL}}
-#define schema_File_init_zero                    {{{NULL}, NULL}, 0, {schema_Overlay_init_zero}, 0}
+#define schema_File_init_zero                    {{{NULL}, NULL}, 0, {schema_Overlay_init_zero}, 0, 0}
 #define schema_ProcessArguments_init_zero        {{{NULL}, NULL}, 0, {{NULL}, NULL}, 0}
-#define schema_Descriptor_init_zero              {0, schema_File_init_zero}
-#define schema_Streams_init_zero                 {schema_Descriptor_init_zero, schema_Descriptor_init_zero, schema_Descriptor_init_zero}
-#define schema_Process_init_zero                 {0, {{NULL}, NULL}, 0, schema_File_init_zero, 0, {{NULL}, NULL}, 0, 0, 0, schema_ProcessArguments_init_zero, schema_Streams_init_zero, 0}
+#define schema_Descriptor_init_zero              {0, false, schema_File_init_zero}
+#define schema_Streams_init_zero                 {false, schema_Descriptor_init_zero, false, schema_Descriptor_init_zero, false, schema_Descriptor_init_zero}
+#define schema_Process_init_zero                 {0, {{NULL}, NULL}, 0, false, schema_File_init_zero, 0, {{NULL}, NULL}, 0, 0, 0, false, schema_ProcessArguments_init_zero, false, schema_Streams_init_zero, 0}
 #define schema_Container_init_zero               {0, {{NULL}, NULL}, {{NULL}, NULL}, 0, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}}
-#define schema_ExecuteEvent_init_zero            {schema_Process_init_zero}
-#define schema_CloneEvent_init_zero              {schema_Process_init_zero}
-#define schema_EnumerateProcessEvent_init_zero   {schema_Process_init_zero}
-#define schema_MemoryExecEvent_init_zero         {schema_Process_init_zero, 0, 0, 0, 0, 0, schema_File_init_zero, _schema_MemoryExecEvent_Action_MIN, 0, 0, 0}
-#define schema_ContainerInfoEvent_init_zero      {schema_Container_init_zero}
+#define schema_ExecuteEvent_init_zero            {false, schema_Process_init_zero}
+#define schema_CloneEvent_init_zero              {false, schema_Process_init_zero}
+#define schema_EnumerateProcessEvent_init_zero   {false, schema_Process_init_zero}
+#define schema_MemoryExecEvent_init_zero         {false, schema_Process_init_zero, 0, 0, 0, 0, 0, false, schema_File_init_zero, _schema_MemoryExecEvent_Action_MIN, 0, 0, 0}
+#define schema_ContainerInfoEvent_init_zero      {false, schema_Container_init_zero}
 #define schema_ExitEvent_init_zero               {{{NULL}, NULL}}
 #define schema_Event_init_zero                   {0, {schema_ExecuteEvent_init_zero}, 0}
-#define schema_ContainerReport_init_zero         {0, schema_Container_init_zero}
+#define schema_ContainerReport_init_zero         {0, false, schema_Container_init_zero}
 
 /* Field tags (for use in manual encoding/decoding) */
 #define schema_ExitEvent_process_uuid_tag        1
@@ -230,10 +250,11 @@
 #define schema_ContainerReport_container_tag     2
 #define schema_Socket_local_tag                  1
 #define schema_Socket_remote_tag                 2
+#define schema_File_fullpath_tag                 1
 #define schema_File_overlayfs_tag                2
 #define schema_File_socket_tag                   4
-#define schema_File_fullpath_tag                 1
 #define schema_File_ino_tag                      3
+#define schema_File_ctime_tag                    5
 #define schema_Descriptor_mode_tag               1
 #define schema_Descriptor_file_tag               2
 #define schema_Streams_stdin_tag                 1
@@ -274,54 +295,224 @@
 #define schema_Event_timestamp_tag               6
 
 /* Struct field encoding specification for nanopb */
-extern const pb_field_t schema_SocketIp_fields[4];
-extern const pb_field_t schema_Socket_fields[3];
-extern const pb_field_t schema_Overlay_fields[4];
-extern const pb_field_t schema_File_fields[5];
-extern const pb_field_t schema_ProcessArguments_fields[5];
-extern const pb_field_t schema_Descriptor_fields[3];
-extern const pb_field_t schema_Streams_fields[4];
-extern const pb_field_t schema_Process_fields[13];
-extern const pb_field_t schema_Container_fields[10];
-extern const pb_field_t schema_ExecuteEvent_fields[2];
-extern const pb_field_t schema_CloneEvent_fields[2];
-extern const pb_field_t schema_EnumerateProcessEvent_fields[2];
-extern const pb_field_t schema_MemoryExecEvent_fields[12];
-extern const pb_field_t schema_ContainerInfoEvent_fields[2];
-extern const pb_field_t schema_ExitEvent_fields[2];
-extern const pb_field_t schema_Event_fields[8];
-extern const pb_field_t schema_ContainerReport_fields[3];
+#define schema_SocketIp_FIELDLIST(X, a) \
+X(a, STATIC,   SINGULAR, UINT32,   family,            1) \
+X(a, CALLBACK, SINGULAR, BYTES,    ip,                2) \
+X(a, STATIC,   SINGULAR, UINT32,   port,              3)
+#define schema_SocketIp_CALLBACK pb_default_field_callback
+#define schema_SocketIp_DEFAULT NULL
+
+#define schema_Socket_FIELDLIST(X, a) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  local,             1) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  remote,            2)
+#define schema_Socket_CALLBACK NULL
+#define schema_Socket_DEFAULT NULL
+#define schema_Socket_local_MSGTYPE schema_SocketIp
+#define schema_Socket_remote_MSGTYPE schema_SocketIp
+
+#define schema_Overlay_FIELDLIST(X, a) \
+X(a, STATIC,   SINGULAR, BOOL,     lower_layer,       1) \
+X(a, STATIC,   SINGULAR, BOOL,     upper_layer,       2) \
+X(a, CALLBACK, SINGULAR, BYTES,    modified_uuid,     3)
+#define schema_Overlay_CALLBACK pb_default_field_callback
+#define schema_Overlay_DEFAULT NULL
+
+#define schema_File_FIELDLIST(X, a) \
+X(a, CALLBACK, SINGULAR, BYTES,    fullpath,          1) \
+X(a, STATIC,   ONEOF,    MESSAGE,  (filesystem,overlayfs,filesystem.overlayfs),   2) \
+X(a, STATIC,   SINGULAR, UINT32,   ino,               3) \
+X(a, STATIC,   ONEOF,    MESSAGE,  (filesystem,socket,filesystem.socket),   4) \
+X(a, STATIC,   SINGULAR, UINT64,   ctime,             5)
+#define schema_File_CALLBACK pb_default_field_callback
+#define schema_File_DEFAULT NULL
+#define schema_File_filesystem_overlayfs_MSGTYPE schema_Overlay
+#define schema_File_filesystem_socket_MSGTYPE schema_Socket
+
+#define schema_ProcessArguments_FIELDLIST(X, a) \
+X(a, CALLBACK, REPEATED, BYTES,    argv,              1) \
+X(a, STATIC,   SINGULAR, UINT32,   argv_truncated,    2) \
+X(a, CALLBACK, REPEATED, BYTES,    envp,              3) \
+X(a, STATIC,   SINGULAR, UINT32,   envp_truncated,    4)
+#define schema_ProcessArguments_CALLBACK pb_default_field_callback
+#define schema_ProcessArguments_DEFAULT NULL
+
+#define schema_Descriptor_FIELDLIST(X, a) \
+X(a, STATIC,   SINGULAR, UINT32,   mode,              1) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  file,              2)
+#define schema_Descriptor_CALLBACK NULL
+#define schema_Descriptor_DEFAULT NULL
+#define schema_Descriptor_file_MSGTYPE schema_File
+
+#define schema_Streams_FIELDLIST(X, a) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  stdin,             1) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  stdout,            2) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  stderr,            3)
+#define schema_Streams_CALLBACK NULL
+#define schema_Streams_DEFAULT NULL
+#define schema_Streams_stdin_MSGTYPE schema_Descriptor
+#define schema_Streams_stdout_MSGTYPE schema_Descriptor
+#define schema_Streams_stderr_MSGTYPE schema_Descriptor
+
+#define schema_Process_FIELDLIST(X, a) \
+X(a, STATIC,   SINGULAR, UINT64,   creation_timestamp,   1) \
+X(a, CALLBACK, SINGULAR, BYTES,    uuid,              2) \
+X(a, STATIC,   SINGULAR, UINT32,   pid,               3) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  binary,            4) \
+X(a, STATIC,   SINGULAR, UINT32,   parent_pid,        5) \
+X(a, CALLBACK, SINGULAR, BYTES,    parent_uuid,       6) \
+X(a, STATIC,   SINGULAR, UINT64,   container_id,      7) \
+X(a, STATIC,   SINGULAR, UINT32,   container_pid,     8) \
+X(a, STATIC,   SINGULAR, UINT32,   container_parent_pid,   9) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  args,             10) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  streams,          11) \
+X(a, STATIC,   SINGULAR, UINT64,   exec_session_id,  12)
+#define schema_Process_CALLBACK pb_default_field_callback
+#define schema_Process_DEFAULT NULL
+#define schema_Process_binary_MSGTYPE schema_File
+#define schema_Process_args_MSGTYPE schema_ProcessArguments
+#define schema_Process_streams_MSGTYPE schema_Streams
+
+#define schema_Container_FIELDLIST(X, a) \
+X(a, STATIC,   SINGULAR, UINT64,   creation_timestamp,   1) \
+X(a, CALLBACK, SINGULAR, BYTES,    pod_namespace,     2) \
+X(a, CALLBACK, SINGULAR, BYTES,    pod_name,          3) \
+X(a, STATIC,   SINGULAR, UINT64,   container_id,      4) \
+X(a, CALLBACK, SINGULAR, BYTES,    container_name,    5) \
+X(a, CALLBACK, SINGULAR, BYTES,    container_image_uri,   6) \
+X(a, CALLBACK, REPEATED, BYTES,    labels,            7) \
+X(a, CALLBACK, SINGULAR, BYTES,    init_uuid,         8) \
+X(a, CALLBACK, SINGULAR, BYTES,    container_image_id,   9)
+#define schema_Container_CALLBACK pb_default_field_callback
+#define schema_Container_DEFAULT NULL
+
+#define schema_ExecuteEvent_FIELDLIST(X, a) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  proc,              1)
+#define schema_ExecuteEvent_CALLBACK NULL
+#define schema_ExecuteEvent_DEFAULT NULL
+#define schema_ExecuteEvent_proc_MSGTYPE schema_Process
+
+#define schema_CloneEvent_FIELDLIST(X, a) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  proc,              1)
+#define schema_CloneEvent_CALLBACK NULL
+#define schema_CloneEvent_DEFAULT NULL
+#define schema_CloneEvent_proc_MSGTYPE schema_Process
+
+#define schema_EnumerateProcessEvent_FIELDLIST(X, a) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  proc,              1)
+#define schema_EnumerateProcessEvent_CALLBACK NULL
+#define schema_EnumerateProcessEvent_DEFAULT NULL
+#define schema_EnumerateProcessEvent_proc_MSGTYPE schema_Process
+
+#define schema_MemoryExecEvent_FIELDLIST(X, a) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  proc,              1) \
+X(a, STATIC,   SINGULAR, UINT64,   prot_exec_timestamp,   2) \
+X(a, STATIC,   SINGULAR, UINT64,   new_flags,         3) \
+X(a, STATIC,   SINGULAR, UINT64,   req_flags,         4) \
+X(a, STATIC,   SINGULAR, UINT64,   old_vm_flags,      5) \
+X(a, STATIC,   SINGULAR, UINT64,   mmap_flags,        6) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  mapped_file,       7) \
+X(a, STATIC,   SINGULAR, UENUM,    action,            8) \
+X(a, STATIC,   SINGULAR, UINT64,   start_addr,        9) \
+X(a, STATIC,   SINGULAR, UINT64,   end_addr,         10) \
+X(a, STATIC,   SINGULAR, BOOL,     is_initial_mmap,  11)
+#define schema_MemoryExecEvent_CALLBACK NULL
+#define schema_MemoryExecEvent_DEFAULT NULL
+#define schema_MemoryExecEvent_proc_MSGTYPE schema_Process
+#define schema_MemoryExecEvent_mapped_file_MSGTYPE schema_File
+
+#define schema_ContainerInfoEvent_FIELDLIST(X, a) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  container,         1)
+#define schema_ContainerInfoEvent_CALLBACK NULL
+#define schema_ContainerInfoEvent_DEFAULT NULL
+#define schema_ContainerInfoEvent_container_MSGTYPE schema_Container
+
+#define schema_ExitEvent_FIELDLIST(X, a) \
+X(a, CALLBACK, SINGULAR, BYTES,    process_uuid,      1)
+#define schema_ExitEvent_CALLBACK pb_default_field_callback
+#define schema_ExitEvent_DEFAULT NULL
+
+#define schema_Event_FIELDLIST(X, a) \
+X(a, STATIC,   ONEOF,    MESSAGE,  (event,execute,event.execute),   1) \
+X(a, STATIC,   ONEOF,    MESSAGE,  (event,container,event.container),   2) \
+X(a, STATIC,   ONEOF,    MESSAGE,  (event,exit,event.exit),   3) \
+X(a, STATIC,   ONEOF,    MESSAGE,  (event,memexec,event.memexec),   4) \
+X(a, STATIC,   ONEOF,    MESSAGE,  (event,clone,event.clone),   5) \
+X(a, STATIC,   SINGULAR, UINT64,   timestamp,         6) \
+X(a, STATIC,   ONEOF,    MESSAGE,  (event,enumproc,event.enumproc),   7)
+#define schema_Event_CALLBACK NULL
+#define schema_Event_DEFAULT NULL
+#define schema_Event_event_execute_MSGTYPE schema_ExecuteEvent
+#define schema_Event_event_container_MSGTYPE schema_ContainerInfoEvent
+#define schema_Event_event_exit_MSGTYPE schema_ExitEvent
+#define schema_Event_event_memexec_MSGTYPE schema_MemoryExecEvent
+#define schema_Event_event_clone_MSGTYPE schema_CloneEvent
+#define schema_Event_event_enumproc_MSGTYPE schema_EnumerateProcessEvent
+
+#define schema_ContainerReport_FIELDLIST(X, a) \
+X(a, STATIC,   SINGULAR, UINT32,   pid,               1) \
+X(a, STATIC,   OPTIONAL, MESSAGE,  container,         2)
+#define schema_ContainerReport_CALLBACK NULL
+#define schema_ContainerReport_DEFAULT NULL
+#define schema_ContainerReport_container_MSGTYPE schema_Container
+
+extern const pb_msgdesc_t schema_SocketIp_msg;
+extern const pb_msgdesc_t schema_Socket_msg;
+extern const pb_msgdesc_t schema_Overlay_msg;
+extern const pb_msgdesc_t schema_File_msg;
+extern const pb_msgdesc_t schema_ProcessArguments_msg;
+extern const pb_msgdesc_t schema_Descriptor_msg;
+extern const pb_msgdesc_t schema_Streams_msg;
+extern const pb_msgdesc_t schema_Process_msg;
+extern const pb_msgdesc_t schema_Container_msg;
+extern const pb_msgdesc_t schema_ExecuteEvent_msg;
+extern const pb_msgdesc_t schema_CloneEvent_msg;
+extern const pb_msgdesc_t schema_EnumerateProcessEvent_msg;
+extern const pb_msgdesc_t schema_MemoryExecEvent_msg;
+extern const pb_msgdesc_t schema_ContainerInfoEvent_msg;
+extern const pb_msgdesc_t schema_ExitEvent_msg;
+extern const pb_msgdesc_t schema_Event_msg;
+extern const pb_msgdesc_t schema_ContainerReport_msg;
+
+/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
+#define schema_SocketIp_fields &schema_SocketIp_msg
+#define schema_Socket_fields &schema_Socket_msg
+#define schema_Overlay_fields &schema_Overlay_msg
+#define schema_File_fields &schema_File_msg
+#define schema_ProcessArguments_fields &schema_ProcessArguments_msg
+#define schema_Descriptor_fields &schema_Descriptor_msg
+#define schema_Streams_fields &schema_Streams_msg
+#define schema_Process_fields &schema_Process_msg
+#define schema_Container_fields &schema_Container_msg
+#define schema_ExecuteEvent_fields &schema_ExecuteEvent_msg
+#define schema_CloneEvent_fields &schema_CloneEvent_msg
+#define schema_EnumerateProcessEvent_fields &schema_EnumerateProcessEvent_msg
+#define schema_MemoryExecEvent_fields &schema_MemoryExecEvent_msg
+#define schema_ContainerInfoEvent_fields &schema_ContainerInfoEvent_msg
+#define schema_ExitEvent_fields &schema_ExitEvent_msg
+#define schema_Event_fields &schema_Event_msg
+#define schema_ContainerReport_fields &schema_ContainerReport_msg
 
 /* Maximum encoded size of messages (where known) */
 /* schema_SocketIp_size depends on runtime parameters */
-#define schema_Socket_size                       (12 + schema_SocketIp_size + schema_SocketIp_size)
+/* schema_Socket_size depends on runtime parameters */
 /* schema_Overlay_size depends on runtime parameters */
 /* schema_File_size depends on runtime parameters */
 /* schema_ProcessArguments_size depends on runtime parameters */
-#define schema_Descriptor_size                   (12 + schema_File_size)
-#define schema_Streams_size                      (54 + schema_File_size + schema_File_size + schema_File_size)
+/* schema_Descriptor_size depends on runtime parameters */
+/* schema_Streams_size depends on runtime parameters */
 /* schema_Process_size depends on runtime parameters */
 /* schema_Container_size depends on runtime parameters */
-#define schema_ExecuteEvent_size                 (6 + schema_Process_size)
-#define schema_CloneEvent_size                   (6 + schema_Process_size)
-#define schema_EnumerateProcessEvent_size        (6 + schema_Process_size)
-#define schema_MemoryExecEvent_size              (93 + schema_Process_size + schema_File_size)
-#define schema_ContainerInfoEvent_size           (6 + schema_Container_size)
+/* schema_ExecuteEvent_size depends on runtime parameters */
+/* schema_CloneEvent_size depends on runtime parameters */
+/* schema_EnumerateProcessEvent_size depends on runtime parameters */
+/* schema_MemoryExecEvent_size depends on runtime parameters */
+/* schema_ContainerInfoEvent_size depends on runtime parameters */
 /* schema_ExitEvent_size depends on runtime parameters */
-#define schema_Event_size                        (11 + ((((((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) > schema_ExitEvent_size ? ((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) : schema_ExitEvent_size) > schema_ContainerInfoEvent_size ? (((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) > schema_ExitEvent_size ? ((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) : schema_ExitEvent_size) : schema_ContainerInfoEvent_size) > schema_MemoryExecEvent_size ? ((((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) > schema_ExitEvent_size ? ((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) : schema_ExitEvent_size) > schema_ContainerInfoEvent_size ? (((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) > schema_ExitEvent_size ? ((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) : schema_ExitEvent_size) : schema_ContainerInfoEvent_size) : schema_MemoryExecEvent_size) > 0 ? (((((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) > schema_ExitEvent_size ? ((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) : schema_ExitEvent_size) > schema_ContainerInfoEvent_size ? (((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) > schema_ExitEvent_size ? ((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) : schema_ExitEvent_size) : schema_ContainerInfoEvent_size) > schema_MemoryExecEvent_size ? ((((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) > schema_ExitEvent_size ? ((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) : schema_ExitEvent_size) > schema_ContainerInfoEvent_size ? (((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) > schema_ExitEvent_size ? ((schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) > schema_ExecuteEvent_size ? (schema_CloneEvent_size > schema_EnumerateProcessEvent_size ? schema_CloneEvent_size : schema_EnumerateProcessEvent_size) : schema_ExecuteEvent_size) : schema_ExitEvent_size) : schema_ContainerInfoEvent_size) : schema_MemoryExecEvent_size) : 0))
-#define schema_ContainerReport_size              (12 + schema_Container_size)
-
-/* Message IDs (where set with "msgid" option) */
-#ifdef PB_MSGID
-
-#define EVENT_MESSAGES \
-
-
-#endif
+/* schema_Event_size depends on runtime parameters */
+/* schema_ContainerReport_size depends on runtime parameters */
 
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
-/* @@protoc_insertion_point(eof) */
 
 #endif
diff --git a/security/container/protos/nanopb/METADATA b/security/container/protos/nanopb/METADATA
index 0ff5272..6b85630 100644
--- a/security/container/protos/nanopb/METADATA
+++ b/security/container/protos/nanopb/METADATA
@@ -6,11 +6,11 @@
     type: GIT
     value: "https://github.com/nanopb/nanopb/"
   }
-  version: "0.3.9.1"
+  version: "0.4.5"
   last_upgrade_date: {
-    year: 2018
-    month: 10
-    day: 9
+    year: 2021
+    month: 8
+    day: 12
   }
   license_type: NOTICE
   security {
diff --git a/security/container/protos/nanopb/pb.h b/security/container/protos/nanopb/pb.h
index 174a84b..be7c067 100644
--- a/security/container/protos/nanopb/pb.h
+++ b/security/container/protos/nanopb/pb.h
@@ -21,9 +21,6 @@
  * A compiler warning will tell if you need this. */
 /* #define PB_MAX_REQUIRED_FIELDS 256 */
 
-/* Add support for tag numbers > 255 and fields larger than 255 bytes. */
-/* #define PB_FIELD_16BIT 1 */
-
 /* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */
 /* #define PB_FIELD_32BIT 1 */
 
@@ -33,10 +30,22 @@
 /* Disable support for custom streams (support only memory buffers). */
 /* #define PB_BUFFER_ONLY 1 */
 
-/* Switch back to the old-style callback function signature.
- * This was the default until nanopb-0.2.1. */
-/* #define PB_OLD_CALLBACK_STYLE */
+/* Disable support for 64-bit datatypes, for compilers without int64_t
+   or to save some code space. */
+/* #define PB_WITHOUT_64BIT 1 */
 
+/* Don't encode scalar arrays as packed. This is only to be used when
+ * the decoder on the receiving side cannot process packed scalar arrays.
+ * Such example is older protobuf.js. */
+/* #define PB_ENCODE_ARRAYS_UNPACKED 1 */
+
+/* Enable conversion of doubles to floats for platforms that do not
+ * support 64-bit doubles. Most commonly AVR. */
+/* #define PB_CONVERT_DOUBLE_FLOAT 1 */
+
+/* Check whether incoming strings are valid UTF-8 sequences. Slows down
+ * the string processing slightly and slightly increases code size. */
+/* #define PB_VALIDATE_UTF8 1 */
 
 /******************************************************************
  * You usually don't need to change anything below this line.     *
@@ -46,7 +55,7 @@
 
 /* Version of the nanopb library. Just in case you want to check it in
  * your own program. */
-#define NANOPB_VERSION nanopb-0.3.9.1
+#define NANOPB_VERSION nanopb-0.4.5
 
 /* Include all the system headers needed by nanopb. You will need the
  * definitions of the following:
@@ -66,12 +75,17 @@
 #include <stddef.h>
 #include <stdbool.h>
 #include <string.h>
+#include <limits.h>
 
 #ifdef PB_ENABLE_MALLOC
 #include <stdlib.h>
 #endif
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Macro for defining packed structures (compiler dependent).
  * This just reduces memory requirements, but is not required.
  */
@@ -107,6 +121,19 @@
 #define PB_UNUSED(x) (void)(x)
 #endif
 
+/* Harvard-architecture processors may need special attributes for storing
+ * field information in program memory. */
+#ifndef PB_PROGMEM
+#ifdef __AVR__
+#include <avr/pgmspace.h>
+#define PB_PROGMEM             PROGMEM
+#define PB_PROGMEM_READU32(x)  pgm_read_dword(&x)
+#else
+#define PB_PROGMEM
+#define PB_PROGMEM_READU32(x)  (x)
+#endif
+#endif
+
 /* Compile-time assertion, used for checking compatible compilation options.
  * If this does not work properly on your compiler, use
  * #define PB_NO_STATIC_ASSERT to disable it.
@@ -117,13 +144,20 @@
  * in the place where the PB_STATIC_ASSERT macro was called.
  */
 #ifndef PB_NO_STATIC_ASSERT
-#ifndef PB_STATIC_ASSERT
-#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
-#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
-#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER
-#endif
+#  ifndef PB_STATIC_ASSERT
+#    if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+       /* C11 standard _Static_assert mechanism */
+#      define PB_STATIC_ASSERT(COND,MSG) _Static_assert(COND,#MSG);
+#    else
+       /* Classic negative-size-array static assert mechanism */
+#      define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
+#      define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
+#      define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##_##LINE##_##COUNTER
+#    endif
+#  endif
 #else
-#define PB_STATIC_ASSERT(COND,MSG)
+   /* Static asserts disabled by PB_NO_STATIC_ASSERT */
+#  define PB_STATIC_ASSERT(COND,MSG)
 #endif
 
 /* Number of required fields to keep track of. */
@@ -135,6 +169,13 @@
 #error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64).
 #endif
 
+#ifdef PB_WITHOUT_64BIT
+#ifdef PB_CONVERT_DOUBLE_FLOAT
+/* Cannot use doubles without 64-bit types */
+#undef PB_CONVERT_DOUBLE_FLOAT
+#endif
+#endif
+
 /* List of possible field types. These are used in the autogenerated code.
  * Least-significant 4 bits tell the scalar type
  * Most-significant 4 bits specify repeated/required/packed etc.
@@ -145,59 +186,69 @@
 /**** Field data types ****/
 
 /* Numeric types */
-#define PB_LTYPE_VARINT  0x00 /* int32, int64, enum, bool */
-#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */
-#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */
-#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */
-#define PB_LTYPE_FIXED64 0x04 /* fixed64, sfixed64, double */
+#define PB_LTYPE_BOOL    0x00U /* bool */
+#define PB_LTYPE_VARINT  0x01U /* int32, int64, enum, bool */
+#define PB_LTYPE_UVARINT 0x02U /* uint32, uint64 */
+#define PB_LTYPE_SVARINT 0x03U /* sint32, sint64 */
+#define PB_LTYPE_FIXED32 0x04U /* fixed32, sfixed32, float */
+#define PB_LTYPE_FIXED64 0x05U /* fixed64, sfixed64, double */
 
 /* Marker for last packable field type. */
-#define PB_LTYPE_LAST_PACKABLE 0x04
+#define PB_LTYPE_LAST_PACKABLE 0x05U
 
 /* Byte array with pre-allocated buffer.
  * data_size is the length of the allocated PB_BYTES_ARRAY structure. */
-#define PB_LTYPE_BYTES 0x05
+#define PB_LTYPE_BYTES 0x06U
 
 /* String with pre-allocated buffer.
  * data_size is the maximum length. */
-#define PB_LTYPE_STRING 0x06
+#define PB_LTYPE_STRING 0x07U
 
 /* Submessage
  * submsg_fields is pointer to field descriptions */
-#define PB_LTYPE_SUBMESSAGE 0x07
+#define PB_LTYPE_SUBMESSAGE 0x08U
+
+/* Submessage with pre-decoding callback
+ * The pre-decoding callback is stored as pb_callback_t right before pSize.
+ * submsg_fields is pointer to field descriptions */
+#define PB_LTYPE_SUBMSG_W_CB 0x09U
 
 /* Extension pseudo-field
  * The field contains a pointer to pb_extension_t */
-#define PB_LTYPE_EXTENSION 0x08
+#define PB_LTYPE_EXTENSION 0x0AU
 
 /* Byte array with inline, pre-allocated byffer.
  * data_size is the length of the inline, allocated buffer.
  * This differs from PB_LTYPE_BYTES by defining the element as
  * pb_byte_t[data_size] rather than pb_bytes_array_t. */
-#define PB_LTYPE_FIXED_LENGTH_BYTES 0x09
+#define PB_LTYPE_FIXED_LENGTH_BYTES 0x0BU
 
 /* Number of declared LTYPES */
-#define PB_LTYPES_COUNT 0x0A
-#define PB_LTYPE_MASK 0x0F
+#define PB_LTYPES_COUNT 0x0CU
+#define PB_LTYPE_MASK 0x0FU
 
 /**** Field repetition rules ****/
 
-#define PB_HTYPE_REQUIRED 0x00
-#define PB_HTYPE_OPTIONAL 0x10
-#define PB_HTYPE_REPEATED 0x20
-#define PB_HTYPE_ONEOF    0x30
-#define PB_HTYPE_MASK     0x30
+#define PB_HTYPE_REQUIRED 0x00U
+#define PB_HTYPE_OPTIONAL 0x10U
+#define PB_HTYPE_SINGULAR 0x10U
+#define PB_HTYPE_REPEATED 0x20U
+#define PB_HTYPE_FIXARRAY 0x20U
+#define PB_HTYPE_ONEOF    0x30U
+#define PB_HTYPE_MASK     0x30U
 
 /**** Field allocation types ****/
  
-#define PB_ATYPE_STATIC   0x00
-#define PB_ATYPE_POINTER  0x80
-#define PB_ATYPE_CALLBACK 0x40
-#define PB_ATYPE_MASK     0xC0
+#define PB_ATYPE_STATIC   0x00U
+#define PB_ATYPE_POINTER  0x80U
+#define PB_ATYPE_CALLBACK 0x40U
+#define PB_ATYPE_MASK     0xC0U
 
 #define PB_ATYPE(x) ((x) & PB_ATYPE_MASK)
 #define PB_HTYPE(x) ((x) & PB_HTYPE_MASK)
 #define PB_LTYPE(x) ((x) & PB_LTYPE_MASK)
+#define PB_LTYPE_IS_SUBMSG(x) (PB_LTYPE(x) == PB_LTYPE_SUBMESSAGE || \
+                               PB_LTYPE(x) == PB_LTYPE_SUBMSG_W_CB)
 
 /* Data type used for storing sizes of struct fields
  * and array counts.
@@ -205,12 +256,9 @@
 #if defined(PB_FIELD_32BIT)
     typedef uint32_t pb_size_t;
     typedef int32_t pb_ssize_t;
-#elif defined(PB_FIELD_16BIT)
+#else
     typedef uint_least16_t pb_size_t;
     typedef int_least16_t pb_ssize_t;
-#else
-    typedef uint_least8_t pb_size_t;
-    typedef int_least8_t pb_ssize_t;
 #endif
 #define PB_SIZE_MAX ((pb_size_t)-1)
 
@@ -220,30 +268,51 @@
  */
 typedef uint_least8_t pb_byte_t;
 
+/* Forward declaration of struct types */
+typedef struct pb_istream_s pb_istream_t;
+typedef struct pb_ostream_s pb_ostream_t;
+typedef struct pb_field_iter_s pb_field_iter_t;
+
 /* This structure is used in auto-generated constants
  * to specify struct fields.
- * You can change field sizes if you need structures
- * larger than 256 bytes or field tags larger than 256.
- * The compiler should complain if your .proto has such
- * structures. Fix that by defining PB_FIELD_16BIT or
- * PB_FIELD_32BIT.
  */
-PB_PACKED_STRUCT_START
-typedef struct pb_field_s pb_field_t;
-struct pb_field_s {
-    pb_size_t tag;
-    pb_type_t type;
-    pb_size_t data_offset; /* Offset of field data, relative to previous field. */
-    pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */
-    pb_size_t data_size; /* Data size in bytes for a single item */
-    pb_size_t array_size; /* Maximum number of entries in array */
-    
-    /* Field definitions for submessage
-     * OR default value for all other non-array, non-callback types
-     * If null, then field will zeroed. */
-    const void *ptr;
-} pb_packed;
-PB_PACKED_STRUCT_END
+typedef struct pb_msgdesc_s pb_msgdesc_t;
+struct pb_msgdesc_s {
+    const uint32_t *field_info;
+    const pb_msgdesc_t * const * submsg_info;
+    const pb_byte_t *default_value;
+
+    bool (*field_callback)(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field);
+
+    pb_size_t field_count;
+    pb_size_t required_field_count;
+    pb_size_t largest_tag;
+};
+
+/* Iterator for message descriptor */
+struct pb_field_iter_s {
+    const pb_msgdesc_t *descriptor;  /* Pointer to message descriptor constant */
+    void *message;                   /* Pointer to start of the structure */
+
+    pb_size_t index;                 /* Index of the field */
+    pb_size_t field_info_index;      /* Index to descriptor->field_info array */
+    pb_size_t required_field_index;  /* Index that counts only the required fields */
+    pb_size_t submessage_index;      /* Index that counts only submessages */
+
+    pb_size_t tag;                   /* Tag of current field */
+    pb_size_t data_size;             /* sizeof() of a single item */
+    pb_size_t array_size;            /* Number of array entries */
+    pb_type_t type;                  /* Type of current field */
+
+    void *pField;                    /* Pointer to current field in struct */
+    void *pData;                     /* Pointer to current data contents. Different than pField for arrays and pointers. */
+    void *pSize;                     /* Pointer to count/has field */
+
+    const pb_msgdesc_t *submsg_desc; /* For submessage fields, pointer to field descriptor for the submessage. */
+};
+
+/* For compatibility with legacy code */
+typedef pb_field_iter_t pb_field_t;
 
 /* Make sure that the standard integer types are of the expected sizes.
  * Otherwise fixed32/fixed64 fields can break.
@@ -287,28 +356,22 @@
  *
  * The callback can be null if you want to skip a field.
  */
-typedef struct pb_istream_s pb_istream_t;
-typedef struct pb_ostream_s pb_ostream_t;
 typedef struct pb_callback_s pb_callback_t;
 struct pb_callback_s {
-#ifdef PB_OLD_CALLBACK_STYLE
-    /* Deprecated since nanopb-0.2.1 */
-    union {
-        bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg);
-        bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg);
-    } funcs;
-#else
-    /* New function signature, which allows modifying arg contents in callback. */
+    /* Callback functions receive a pointer to the arg field.
+     * You can access the value of the field as *arg, and modify it if needed.
+     */
     union {
         bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg);
         bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg);
     } funcs;
-#endif    
     
     /* Free arg for use by callback */
     void *arg;
 };
 
+extern bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field);
+
 /* Wire types. Library user needs these only in encoder callbacks. */
 typedef enum {
     PB_WT_VARINT = 0,
@@ -366,6 +429,8 @@
     bool found;
 };
 
+#define pb_extension_init_zero {NULL,NULL,NULL,false}
+
 /* Memory allocation functions to use. You can define pb_realloc and
  * pb_free to custom functions if you want. */
 #ifdef PB_ENABLE_MALLOC
@@ -378,7 +443,7 @@
 #endif
 
 /* This is used to inform about need to regenerate .pb.h/.pb.c files. */
-#define PB_PROTO_HEADER_VERSION 30
+#define PB_PROTO_HEADER_VERSION 40
 
 /* These macros are used to declare pb_field_t's in the constant array. */
 /* Size of a structure member, in bytes. */
@@ -387,106 +452,359 @@
 #define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0]))
 /* Delta from start of one member to the start of another member. */
 #define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2))
-/* Marks the end of the field list */
-#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0}
 
-/* Macros for filling in the data_offset field */
-/* data_offset for first field in a message */
-#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1))
-/* data_offset for subsequent fields */
-#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2))
-/* data offset for subsequent fields inside an union (oneof) */
-#define PB_DATAOFFSET_UNION(st, m1, m2) (PB_SIZE_MAX)
-/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */
-#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \
-                                  ? PB_DATAOFFSET_FIRST(st, m1, m2) \
-                                  : PB_DATAOFFSET_OTHER(st, m1, m2))
+/* Force expansion of macro value */
+#define PB_EXPAND(x) x
 
-/* Required fields are the simplest. They just have delta (padding) from
- * previous field end, and the size of the field. Pointer is used for
- * submessages and default values.
+/* Binding of a message field set into a specific structure */
+#define PB_BIND(msgname, structname, width) \
+    const uint32_t structname ## _field_info[] PB_PROGMEM = \
+    { \
+        msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ ## width, structname) \
+        0 \
+    }; \
+    const pb_msgdesc_t* const structname ## _submsg_info[] = \
+    { \
+        msgname ## _FIELDLIST(PB_GEN_SUBMSG_INFO, structname) \
+        NULL \
+    }; \
+    const pb_msgdesc_t structname ## _msg = \
+    { \
+       structname ## _field_info, \
+       structname ## _submsg_info, \
+       msgname ## _DEFAULT, \
+       msgname ## _CALLBACK, \
+       0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \
+       0 msgname ## _FIELDLIST(PB_GEN_REQ_FIELD_COUNT, structname), \
+       0 msgname ## _FIELDLIST(PB_GEN_LARGEST_TAG, structname), \
+    }; \
+    msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname)
+
+#define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1
+#define PB_GEN_REQ_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) \
+    + (PB_HTYPE_ ## htype == PB_HTYPE_REQUIRED)
+#define PB_GEN_LARGEST_TAG(structname, atype, htype, ltype, fieldname, tag) \
+    * 0 + tag
+
+/* X-macro for generating the entries in struct_field_info[] array. */
+#define PB_GEN_FIELD_INFO_1(structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
+
+#define PB_GEN_FIELD_INFO_2(structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
+
+#define PB_GEN_FIELD_INFO_4(structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
+
+#define PB_GEN_FIELD_INFO_8(structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
+
+#define PB_GEN_FIELD_INFO_AUTO(structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
+                   tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
+
+#define PB_FIELDINFO_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
+
+#define PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_FIELDINFO_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
+
+/* X-macro for generating asserts that entries fit in struct_field_info[] array.
+ * The structure of macros here must match the structure above in PB_GEN_FIELD_INFO_x(),
+ * but it is not easily reused because of how macro substitutions work. */
+#define PB_GEN_FIELD_INFO_ASSERT_1(structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_ASSERT_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
+
+#define PB_GEN_FIELD_INFO_ASSERT_2(structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_ASSERT_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
+
+#define PB_GEN_FIELD_INFO_ASSERT_4(structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_ASSERT_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
+
+#define PB_GEN_FIELD_INFO_ASSERT_8(structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_ASSERT_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
+
+#define PB_GEN_FIELD_INFO_ASSERT_AUTO(structname, atype, htype, ltype, fieldname, tag) \
+    PB_FIELDINFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
+                   tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
+                   PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
+                   PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
+
+#define PB_FIELDINFO_ASSERT_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
+
+#define PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_FIELDINFO_ASSERT_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
+
+#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
+#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
+#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
+#define PB_DO_PB_HTYPE_REQUIRED(structname, fieldname) offsetof(structname, fieldname)
+#define PB_DO_PB_HTYPE_SINGULAR(structname, fieldname) offsetof(structname, fieldname)
+#define PB_DO_PB_HTYPE_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname))
+#define PB_DO_PB_HTYPE_OPTIONAL(structname, fieldname) offsetof(structname, fieldname)
+#define PB_DO_PB_HTYPE_REPEATED(structname, fieldname) offsetof(structname, fieldname)
+#define PB_DO_PB_HTYPE_FIXARRAY(structname, fieldname) offsetof(structname, fieldname)
+
+#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SO ## htype(structname, fieldname)
+#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SO_PTR ## htype(structname, fieldname)
+#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SO_CB ## htype(structname, fieldname)
+#define PB_SO_PB_HTYPE_REQUIRED(structname, fieldname) 0
+#define PB_SO_PB_HTYPE_SINGULAR(structname, fieldname) 0
+#define PB_SO_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname))
+#define PB_SO_PB_HTYPE_ONEOF2(structname, fullname, unionname) PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname)
+#define PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname)
+#define PB_SO_PB_HTYPE_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname)
+#define PB_SO_PB_HTYPE_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count)
+#define PB_SO_PB_HTYPE_FIXARRAY(structname, fieldname) 0
+#define PB_SO_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 0
+#define PB_SO_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 0
+#define PB_SO_PTR_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
+#define PB_SO_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 0
+#define PB_SO_PTR_PB_HTYPE_REPEATED(structname, fieldname) PB_SO_PB_HTYPE_REPEATED(structname, fieldname)
+#define PB_SO_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) 0
+#define PB_SO_CB_PB_HTYPE_REQUIRED(structname, fieldname) 0
+#define PB_SO_CB_PB_HTYPE_SINGULAR(structname, fieldname) 0
+#define PB_SO_CB_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
+#define PB_SO_CB_PB_HTYPE_OPTIONAL(structname, fieldname) 0
+#define PB_SO_CB_PB_HTYPE_REPEATED(structname, fieldname) 0
+#define PB_SO_CB_PB_HTYPE_FIXARRAY(structname, fieldname) 0
+
+#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_AS ## htype(structname, fieldname)
+#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_AS_PTR ## htype(structname, fieldname)
+#define PB_ARRAY_SIZE_CALLBACK(htype, structname, fieldname) 1
+#define PB_AS_PB_HTYPE_REQUIRED(structname, fieldname) 1
+#define PB_AS_PB_HTYPE_SINGULAR(structname, fieldname) 1
+#define PB_AS_PB_HTYPE_OPTIONAL(structname, fieldname) 1
+#define PB_AS_PB_HTYPE_ONEOF(structname, fieldname) 1
+#define PB_AS_PB_HTYPE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname)
+#define PB_AS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname)
+#define PB_AS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 1
+#define PB_AS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 1
+#define PB_AS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 1
+#define PB_AS_PTR_PB_HTYPE_ONEOF(structname, fieldname) 1
+#define PB_AS_PTR_PB_HTYPE_REPEATED(structname, fieldname) 1
+#define PB_AS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0])
+
+#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DS ## htype(structname, fieldname)
+#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DS_PTR ## htype(structname, fieldname)
+#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DS_CB ## htype(structname, fieldname)
+#define PB_DS_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DS_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DS_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DS_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
+#define PB_DS_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DS_PTR_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0])
+#define PB_DS_PTR_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
+#define PB_DS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0])
+#define PB_DS_CB_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DS_CB_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DS_CB_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DS_CB_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
+#define PB_DS_CB_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname)
+#define PB_DS_CB_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname)
+
+#define PB_ONEOF_NAME(type, tuple) PB_EXPAND(PB_ONEOF_NAME_ ## type tuple)
+#define PB_ONEOF_NAME_UNION(unionname,membername,fullname) unionname
+#define PB_ONEOF_NAME_MEMBER(unionname,membername,fullname) membername
+#define PB_ONEOF_NAME_FULL(unionname,membername,fullname) fullname
+
+#define PB_GEN_SUBMSG_INFO(structname, atype, htype, ltype, fieldname, tag) \
+    PB_SUBMSG_INFO_ ## htype(_PB_LTYPE_ ## ltype, structname, fieldname)
+
+#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
+#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
+#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
+#define PB_SUBMSG_INFO_ONEOF(ltype, structname, fieldname) PB_SUBMSG_INFO_ONEOF2(ltype, structname, PB_ONEOF_NAME(UNION, fieldname), PB_ONEOF_NAME(MEMBER, fieldname))
+#define PB_SUBMSG_INFO_ONEOF2(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername)
+#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SI ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE)
+#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
+#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
+#define PB_SI_PB_LTYPE_BOOL(t)
+#define PB_SI_PB_LTYPE_BYTES(t)
+#define PB_SI_PB_LTYPE_DOUBLE(t)
+#define PB_SI_PB_LTYPE_ENUM(t)
+#define PB_SI_PB_LTYPE_UENUM(t)
+#define PB_SI_PB_LTYPE_FIXED32(t)
+#define PB_SI_PB_LTYPE_FIXED64(t)
+#define PB_SI_PB_LTYPE_FLOAT(t)
+#define PB_SI_PB_LTYPE_INT32(t)
+#define PB_SI_PB_LTYPE_INT64(t)
+#define PB_SI_PB_LTYPE_MESSAGE(t)  PB_SUBMSG_DESCRIPTOR(t)
+#define PB_SI_PB_LTYPE_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t)
+#define PB_SI_PB_LTYPE_SFIXED32(t)
+#define PB_SI_PB_LTYPE_SFIXED64(t)
+#define PB_SI_PB_LTYPE_SINT32(t)
+#define PB_SI_PB_LTYPE_SINT64(t)
+#define PB_SI_PB_LTYPE_STRING(t)
+#define PB_SI_PB_LTYPE_UINT32(t)
+#define PB_SI_PB_LTYPE_UINT64(t)
+#define PB_SI_PB_LTYPE_EXTENSION(t)
+#define PB_SI_PB_LTYPE_FIXED_LENGTH_BYTES(t)
+#define PB_SUBMSG_DESCRIPTOR(t)    &(t ## _msg),
+
+/* The field descriptors use a variable width format, with width of either
+ * 1, 2, 4 or 8 of 32-bit words. The two lowest bytes of the first byte always
+ * encode the descriptor size, 6 lowest bits of field tag number, and 8 bits
+ * of the field type.
+ *
+ * Descriptor size is encoded as 0 = 1 word, 1 = 2 words, 2 = 4 words, 3 = 8 words.
+ *
+ * Formats, listed starting with the least significant bit of the first word.
+ * 1 word:  [2-bit len] [6-bit tag] [8-bit type] [8-bit data_offset] [4-bit size_offset] [4-bit data_size]
+ *
+ * 2 words: [2-bit len] [6-bit tag] [8-bit type] [12-bit array_size] [4-bit size_offset]
+ *          [16-bit data_offset] [12-bit data_size] [4-bit tag>>6]
+ *
+ * 4 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit array_size]
+ *          [8-bit size_offset] [24-bit tag>>6]
+ *          [32-bit data_offset]
+ *          [32-bit data_size]
+ *
+ * 8 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit reserved]
+ *          [8-bit size_offset] [24-bit tag>>6]
+ *          [32-bit data_offset]
+ *          [32-bit data_size]
+ *          [32-bit array_size]
+ *          [32-bit reserved]
+ *          [32-bit reserved]
+ *          [32-bit reserved]
  */
-#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \
-    fd, 0, pb_membersize(st, m), 0, ptr}
 
-/* Optional fields add the delta to the has_ variable. */
-#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
-    fd, \
-    pb_delta(st, has_ ## m, m), \
-    pb_membersize(st, m), 0, ptr}
+#define PB_FIELDINFO_1(tag, type, data_offset, data_size, size_offset, array_size) \
+    (0 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(data_offset) & 0xFF) << 16) | \
+     (((uint32_t)(size_offset) & 0x0F) << 24) | (((uint32_t)(data_size) & 0x0F) << 28)),
 
-#define PB_SINGULAR_STATIC(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
-    fd, 0, pb_membersize(st, m), 0, ptr}
+#define PB_FIELDINFO_2(tag, type, data_offset, data_size, size_offset, array_size) \
+    (1 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFF) << 16) | (((uint32_t)(size_offset) & 0x0F) << 28)), \
+    (((uint32_t)(data_offset) & 0xFFFF) | (((uint32_t)(data_size) & 0xFFF) << 16) | (((uint32_t)(tag) & 0x3c0) << 22)),
 
-/* Repeated fields have a _count field and also the maximum number of entries. */
-#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \
-    fd, \
-    pb_delta(st, m ## _count, m), \
-    pb_membersize(st, m[0]), \
-    pb_arraysize(st, m), ptr}
+#define PB_FIELDINFO_4(tag, type, data_offset, data_size, size_offset, array_size) \
+    (2 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFFF) << 16)), \
+    ((uint32_t)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
+    (data_offset), (data_size),
 
-/* Allocated fields carry the size of the actual data, not the pointer */
-#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \
-    fd, 0, pb_membersize(st, m[0]), 0, ptr}
+#define PB_FIELDINFO_8(tag, type, data_offset, data_size, size_offset, array_size) \
+    (3 | (((tag) << 2) & 0xFF) | ((type) << 8)), \
+    ((uint32_t)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
+    (data_offset), (data_size), (array_size), 0, 0, 0,
 
-/* Optional fields don't need a has_ variable, as information would be redundant */
-#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \
-    fd, 0, pb_membersize(st, m[0]), 0, ptr}
-
-/* Same as optional fields*/
-#define PB_SINGULAR_POINTER(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \
-    fd, 0, pb_membersize(st, m[0]), 0, ptr}
-
-/* Repeated fields have a _count field and a pointer to array of pointers */
-#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \
-    fd, pb_delta(st, m ## _count, m), \
-    pb_membersize(st, m[0]), 0, ptr}
-
-/* Callbacks are much like required fields except with special datatype. */
-#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \
-    fd, 0, pb_membersize(st, m), 0, ptr}
-
-#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
-    fd, 0, pb_membersize(st, m), 0, ptr}
-
-#define PB_SINGULAR_CALLBACK(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
-    fd, 0, pb_membersize(st, m), 0, ptr}
-    
-#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \
-    fd, 0, pb_membersize(st, m), 0, ptr}
-
-/* Optional extensions don't have the has_ field, as that would be redundant.
- * Furthermore, the combination of OPTIONAL without has_ field is used
- * for indicating proto3 style fields. Extensions exist in proto2 mode only,
- * so they should be encoded according to proto2 rules. To avoid the conflict,
- * extensions are marked as REQUIRED instead.
+/* These assertions verify that the field information fits in the allocated space.
+ * The generator tries to automatically determine the correct width that can fit all
+ * data associated with a message. These asserts will fail only if there has been a
+ * problem in the automatic logic - this may be worth reporting as a bug. As a workaround,
+ * you can increase the descriptor width by defining PB_FIELDINFO_WIDTH or by setting
+ * descriptorsize option in .options file.
  */
-#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \
-    0, \
-    0, \
-    pb_membersize(st, m), 0, ptr}
+#define PB_FITS(value,bits) ((uint32_t)(value) < ((uint32_t)1<<bits))
+#define PB_FIELDINFO_ASSERT_1(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,6) && PB_FITS(data_offset,8) && PB_FITS(size_offset,4) && PB_FITS(data_size,4) && PB_FITS(array_size,1), FIELDINFO_DOES_NOT_FIT_width1_field ## tag)
 
-#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \
-    PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr)
+#define PB_FIELDINFO_ASSERT_2(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,10) && PB_FITS(data_offset,16) && PB_FITS(size_offset,4) && PB_FITS(data_size,12) && PB_FITS(array_size,12), FIELDINFO_DOES_NOT_FIT_width2_field ## tag)
 
-#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \
-    PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr)
+#ifndef PB_FIELD_32BIT
+/* Maximum field sizes are still 16-bit if pb_size_t is 16-bit */
+#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,16) && PB_FITS(data_offset,16) && PB_FITS((int_least8_t)size_offset,8) && PB_FITS(data_size,16) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag)
+
+#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,16) && PB_FITS(data_offset,16) && PB_FITS((int_least8_t)size_offset,8) && PB_FITS(data_size,16) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width8_field ## tag)
+#else
+/* Up to 32-bit fields supported.
+ * Note that the checks are against 31 bits to avoid compiler warnings about shift wider than type in the test.
+ * I expect that there is no reasonable use for >2GB messages with nanopb anyway.
+ */
+#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS(size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag)
+
+#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \
+    PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS(size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,31), FIELDINFO_DOES_NOT_FIT_width8_field ## tag)
+#endif
+
+
+/* Automatic picking of FIELDINFO width:
+ * Uses width 1 when possible, otherwise resorts to width 2.
+ * This is used when PB_BIND() is called with "AUTO" as the argument.
+ * The generator will give explicit size argument when it knows that a message
+ * structure grows beyond 1-word format limits.
+ */
+#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FI_WIDTH ## atype(htype, ltype)
+#define PB_FI_WIDTH_PB_ATYPE_STATIC(htype, ltype) PB_FI_WIDTH ## htype(ltype)
+#define PB_FI_WIDTH_PB_ATYPE_POINTER(htype, ltype) PB_FI_WIDTH ## htype(ltype)
+#define PB_FI_WIDTH_PB_ATYPE_CALLBACK(htype, ltype) 2
+#define PB_FI_WIDTH_PB_HTYPE_REQUIRED(ltype) PB_FI_WIDTH ## ltype
+#define PB_FI_WIDTH_PB_HTYPE_SINGULAR(ltype) PB_FI_WIDTH ## ltype
+#define PB_FI_WIDTH_PB_HTYPE_OPTIONAL(ltype) PB_FI_WIDTH ## ltype
+#define PB_FI_WIDTH_PB_HTYPE_ONEOF(ltype) PB_FI_WIDTH ## ltype
+#define PB_FI_WIDTH_PB_HTYPE_REPEATED(ltype) 2
+#define PB_FI_WIDTH_PB_HTYPE_FIXARRAY(ltype) 2
+#define PB_FI_WIDTH_PB_LTYPE_BOOL      1
+#define PB_FI_WIDTH_PB_LTYPE_BYTES     2
+#define PB_FI_WIDTH_PB_LTYPE_DOUBLE    1
+#define PB_FI_WIDTH_PB_LTYPE_ENUM      1
+#define PB_FI_WIDTH_PB_LTYPE_UENUM     1
+#define PB_FI_WIDTH_PB_LTYPE_FIXED32   1
+#define PB_FI_WIDTH_PB_LTYPE_FIXED64   1
+#define PB_FI_WIDTH_PB_LTYPE_FLOAT     1
+#define PB_FI_WIDTH_PB_LTYPE_INT32     1
+#define PB_FI_WIDTH_PB_LTYPE_INT64     1
+#define PB_FI_WIDTH_PB_LTYPE_MESSAGE   2
+#define PB_FI_WIDTH_PB_LTYPE_MSG_W_CB  2
+#define PB_FI_WIDTH_PB_LTYPE_SFIXED32  1
+#define PB_FI_WIDTH_PB_LTYPE_SFIXED64  1
+#define PB_FI_WIDTH_PB_LTYPE_SINT32    1
+#define PB_FI_WIDTH_PB_LTYPE_SINT64    1
+#define PB_FI_WIDTH_PB_LTYPE_STRING    2
+#define PB_FI_WIDTH_PB_LTYPE_UINT32    1
+#define PB_FI_WIDTH_PB_LTYPE_UINT64    1
+#define PB_FI_WIDTH_PB_LTYPE_EXTENSION 1
+#define PB_FI_WIDTH_PB_LTYPE_FIXED_LENGTH_BYTES 2
 
 /* The mapping from protobuf types to LTYPEs is done using these macros. */
-#define PB_LTYPE_MAP_BOOL               PB_LTYPE_VARINT
+#define PB_LTYPE_MAP_BOOL               PB_LTYPE_BOOL
 #define PB_LTYPE_MAP_BYTES              PB_LTYPE_BYTES
 #define PB_LTYPE_MAP_DOUBLE             PB_LTYPE_FIXED64
 #define PB_LTYPE_MAP_ENUM               PB_LTYPE_VARINT
@@ -497,6 +815,7 @@
 #define PB_LTYPE_MAP_INT32              PB_LTYPE_VARINT
 #define PB_LTYPE_MAP_INT64              PB_LTYPE_VARINT
 #define PB_LTYPE_MAP_MESSAGE            PB_LTYPE_SUBMESSAGE
+#define PB_LTYPE_MAP_MSG_W_CB           PB_LTYPE_SUBMSG_W_CB
 #define PB_LTYPE_MAP_SFIXED32           PB_LTYPE_FIXED32
 #define PB_LTYPE_MAP_SFIXED64           PB_LTYPE_FIXED64
 #define PB_LTYPE_MAP_SINT32             PB_LTYPE_SVARINT
@@ -507,67 +826,6 @@
 #define PB_LTYPE_MAP_EXTENSION          PB_LTYPE_EXTENSION
 #define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES
 
-/* This is the actual macro used in field descriptions.
- * It takes these arguments:
- * - Field tag number
- * - Field type:   BOOL, BYTES, DOUBLE, ENUM, UENUM, FIXED32, FIXED64,
- *                 FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64
- *                 SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION
- * - Field rules:  REQUIRED, OPTIONAL or REPEATED
- * - Allocation:   STATIC, CALLBACK or POINTER
- * - Placement: FIRST or OTHER, depending on if this is the first field in structure.
- * - Message name
- * - Field name
- * - Previous field name (or field name again for first field)
- * - Pointer to default value or submsg fields.
- */
-
-#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
-        PB_ ## rules ## _ ## allocation(tag, message, field, \
-        PB_DATAOFFSET_ ## placement(message, field, prevfield), \
-        PB_LTYPE_MAP_ ## type, ptr)
-
-/* Field description for repeated static fixed count fields.*/
-#define PB_REPEATED_FIXED_COUNT(tag, type, placement, message, field, prevfield, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | PB_LTYPE_MAP_ ## type, \
-    PB_DATAOFFSET_ ## placement(message, field, prevfield), \
-    0, \
-    pb_membersize(message, field[0]), \
-    pb_arraysize(message, field), ptr}
-
-/* Field description for oneof fields. This requires taking into account the
- * union name also, that's why a separate set of macros is needed.
- */
-#define PB_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \
-    fd, pb_delta(st, which_ ## u, u.m), \
-    pb_membersize(st, u.m), 0, ptr}
-
-#define PB_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \
-    fd, pb_delta(st, which_ ## u, u.m), \
-    pb_membersize(st, u.m[0]), 0, ptr}
-
-#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
-        PB_ONEOF_ ## allocation(union_name, tag, message, field, \
-        PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \
-        PB_LTYPE_MAP_ ## type, ptr)
-
-#define PB_ANONYMOUS_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \
-    fd, pb_delta(st, which_ ## u, m), \
-    pb_membersize(st, m), 0, ptr}
-
-#define PB_ANONYMOUS_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \
-    {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \
-    fd, pb_delta(st, which_ ## u, m), \
-    pb_membersize(st, m[0]), 0, ptr}
-
-#define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
-        PB_ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \
-        PB_DATAOFFSET_ ## placement(message, field, prevfield), \
-        PB_LTYPE_MAP_ ## type, ptr)
-
 /* These macros are used for giving out error messages.
  * They are mostly a debugging aid; the main error information
  * is the true/false return value from functions.
@@ -590,4 +848,28 @@
 
 #define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false
 
+#ifdef __cplusplus
+} /* extern "C" */
 #endif
+
+#ifdef __cplusplus
+#if __cplusplus >= 201103L
+#define PB_CONSTEXPR constexpr
+#else  // __cplusplus >= 201103L
+#define PB_CONSTEXPR
+#endif  // __cplusplus >= 201103L
+
+#if __cplusplus >= 201703L
+#define PB_INLINE_CONSTEXPR inline constexpr
+#else  // __cplusplus >= 201703L
+#define PB_INLINE_CONSTEXPR PB_CONSTEXPR
+#endif  // __cplusplus >= 201703L
+
+namespace nanopb {
+// Each type will be partially specialized by the generator.
+template <typename GenMessageT> struct MessageDescriptor;
+}  // namespace nanopb
+#endif  /* __cplusplus */
+
+#endif
+
diff --git a/security/container/protos/nanopb/pb_common.c b/security/container/protos/nanopb/pb_common.c
index 4fb7186..6aee76b 100644
--- a/security/container/protos/nanopb/pb_common.c
+++ b/security/container/protos/nanopb/pb_common.c
@@ -5,93 +5,384 @@
 
 #include "pb_common.h"
 
-bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct)
+static bool load_descriptor_values(pb_field_iter_t *iter)
 {
-    iter->start = fields;
-    iter->pos = fields;
-    iter->required_field_index = 0;
-    iter->dest_struct = dest_struct;
-    iter->pData = (char*)dest_struct + iter->pos->data_offset;
-    iter->pSize = (char*)iter->pData + iter->pos->size_offset;
-    
-    return (iter->pos->tag != 0);
+    uint32_t word0;
+    uint32_t data_offset;
+    int_least8_t size_offset;
+
+    if (iter->index >= iter->descriptor->field_count)
+        return false;
+
+    word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
+    iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
+
+    switch(word0 & 3)
+    {
+        case 0: {
+            /* 1-word format */
+            iter->array_size = 1;
+            iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
+            size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
+            data_offset = (word0 >> 16) & 0xFF;
+            iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
+            break;
+        }
+
+        case 1: {
+            /* 2-word format */
+            uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
+
+            iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
+            iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6));
+            size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
+            data_offset = word1 & 0xFFFF;
+            iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
+            break;
+        }
+
+        case 2: {
+            /* 4-word format */
+            uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
+            uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
+            uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
+
+            iter->array_size = (pb_size_t)(word0 >> 16);
+            iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
+            size_offset = (int_least8_t)(word1 & 0xFF);
+            data_offset = word2;
+            iter->data_size = (pb_size_t)word3;
+            break;
+        }
+
+        default: {
+            /* 8-word format */
+            uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
+            uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
+            uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
+            uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
+
+            iter->array_size = (pb_size_t)word4;
+            iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
+            size_offset = (int_least8_t)(word1 & 0xFF);
+            data_offset = word2;
+            iter->data_size = (pb_size_t)word3;
+            break;
+        }
+    }
+
+    if (!iter->message)
+    {
+        /* Avoid doing arithmetic on null pointers, it is undefined */
+        iter->pField = NULL;
+        iter->pSize = NULL;
+    }
+    else
+    {
+        iter->pField = (char*)iter->message + data_offset;
+
+        if (size_offset)
+        {
+            iter->pSize = (char*)iter->pField - size_offset;
+        }
+        else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
+                 (PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
+                  PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
+        {
+            /* Fixed count array */
+            iter->pSize = &iter->array_size;
+        }
+        else
+        {
+            iter->pSize = NULL;
+        }
+
+        if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
+        {
+            iter->pData = *(void**)iter->pField;
+        }
+        else
+        {
+            iter->pData = iter->pField;
+        }
+    }
+
+    if (PB_LTYPE_IS_SUBMSG(iter->type))
+    {
+        iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index];
+    }
+    else
+    {
+        iter->submsg_desc = NULL;
+    }
+
+    return true;
+}
+
+static void advance_iterator(pb_field_iter_t *iter)
+{
+    iter->index++;
+
+    if (iter->index >= iter->descriptor->field_count)
+    {
+        /* Restart */
+        iter->index = 0;
+        iter->field_info_index = 0;
+        iter->submessage_index = 0;
+        iter->required_field_index = 0;
+    }
+    else
+    {
+        /* Increment indexes based on previous field type.
+         * All field info formats have the following fields:
+         * - lowest 2 bits tell the amount of words in the descriptor (2^n words)
+         * - bits 2..7 give the lowest bits of tag number.
+         * - bits 8..15 give the field type.
+         */
+        uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
+        pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
+        pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
+
+        /* Add to fields.
+         * The cast to pb_size_t is needed to avoid -Wconversion warning.
+         * Because the data is is constants from generator, there is no danger of overflow.
+         */
+        iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
+        iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED));
+        iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type));
+    }
+}
+
+bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
+{
+    memset(iter, 0, sizeof(*iter));
+
+    iter->descriptor = desc;
+    iter->message = message;
+
+    return load_descriptor_values(iter);
+}
+
+bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
+{
+    const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
+    bool status;
+
+    uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
+    if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER)
+    {
+        /* For pointer extensions, the pointer is stored directly
+         * in the extension structure. This avoids having an extra
+         * indirection. */
+        status = pb_field_iter_begin(iter, msg, &extension->dest);
+    }
+    else
+    {
+        status = pb_field_iter_begin(iter, msg, extension->dest);
+    }
+
+    iter->pSize = &extension->found;
+    return status;
 }
 
 bool pb_field_iter_next(pb_field_iter_t *iter)
 {
-    const pb_field_t *prev_field = iter->pos;
-
-    if (prev_field->tag == 0)
-    {
-        /* Handle empty message types, where the first field is already the terminator.
-         * In other cases, the iter->pos never points to the terminator. */
-        return false;
-    }
-    
-    iter->pos++;
-    
-    if (iter->pos->tag == 0)
-    {
-        /* Wrapped back to beginning, reinitialize */
-        (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct);
-        return false;
-    }
-    else
-    {
-        /* Increment the pointers based on previous field size */
-        size_t prev_size = prev_field->data_size;
-    
-        if (PB_HTYPE(prev_field->type) == PB_HTYPE_ONEOF &&
-            PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF &&
-            iter->pos->data_offset == PB_SIZE_MAX)
-        {
-            /* Don't advance pointers inside unions */
-            return true;
-        }
-        else if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC &&
-                 PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED)
-        {
-            /* In static arrays, the data_size tells the size of a single entry and
-             * array_size is the number of entries */
-            prev_size *= prev_field->array_size;
-        }
-        else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER)
-        {
-            /* Pointer fields always have a constant size in the main structure.
-             * The data_size only applies to the dynamically allocated area. */
-            prev_size = sizeof(void*);
-        }
-
-        if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED)
-        {
-            /* Count the required fields, in order to check their presence in the
-             * decoder. */
-            iter->required_field_index++;
-        }
-    
-        iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset;
-        iter->pSize = (char*)iter->pData + iter->pos->size_offset;
-        return true;
-    }
+    advance_iterator(iter);
+    (void)load_descriptor_values(iter);
+    return iter->index != 0;
 }
 
 bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
 {
-    const pb_field_t *start = iter->pos;
-    
-    do {
-        if (iter->pos->tag == tag &&
-            PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION)
+    if (iter->tag == tag)
+    {
+        return true; /* Nothing to do, correct field already. */
+    }
+    else if (tag > iter->descriptor->largest_tag)
+    {
+        return false;
+    }
+    else
+    {
+        pb_size_t start = iter->index;
+        uint32_t fieldinfo;
+
+        if (tag < iter->tag)
         {
-            /* Found the wanted field */
-            return true;
+            /* Fields are in tag number order, so we know that tag is between
+             * 0 and our start position. Setting index to end forces
+             * advance_iterator() call below to restart from beginning. */
+            iter->index = iter->descriptor->field_count;
         }
-        
-        (void)pb_field_iter_next(iter);
-    } while (iter->pos != start);
-    
-    /* Searched all the way back to start, and found nothing. */
-    return false;
+
+        do
+        {
+            /* Advance iterator but don't load values yet */
+            advance_iterator(iter);
+
+            /* Do fast check for tag number match */
+            fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
+
+            if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
+            {
+                /* Good candidate, check further */
+                (void)load_descriptor_values(iter);
+
+                if (iter->tag == tag &&
+                    PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION)
+                {
+                    /* Found it */
+                    return true;
+                }
+            }
+        } while (iter->index != start);
+
+        /* Searched all the way back to start, and found nothing. */
+        (void)load_descriptor_values(iter);
+        return false;
+    }
 }
 
+bool pb_field_iter_find_extension(pb_field_iter_t *iter)
+{
+    if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
+    {
+        return true;
+    }
+    else
+    {
+        pb_size_t start = iter->index;
+        uint32_t fieldinfo;
+
+        do
+        {
+            /* Advance iterator but don't load values yet */
+            advance_iterator(iter);
+
+            /* Do fast check for field type */
+            fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
+
+            if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION)
+            {
+                return load_descriptor_values(iter);
+            }
+        } while (iter->index != start);
+
+        /* Searched all the way back to start, and found nothing. */
+        (void)load_descriptor_values(iter);
+        return false;
+    }
+}
+
+static void *pb_const_cast(const void *p)
+{
+    /* Note: this casts away const, in order to use the common field iterator
+     * logic for both encoding and decoding. The cast is done using union
+     * to avoid spurious compiler warnings. */
+    union {
+        void *p1;
+        const void *p2;
+    } t;
+    t.p2 = p;
+    return t.p1;
+}
+
+bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
+{
+    return pb_field_iter_begin(iter, desc, pb_const_cast(message));
+}
+
+bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
+{
+    return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension));
+}
+
+bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
+{
+    if (field->data_size == sizeof(pb_callback_t))
+    {
+        pb_callback_t *pCallback = (pb_callback_t*)field->pData;
+
+        if (pCallback != NULL)
+        {
+            if (istream != NULL && pCallback->funcs.decode != NULL)
+            {
+                return pCallback->funcs.decode(istream, field, &pCallback->arg);
+            }
+
+            if (ostream != NULL && pCallback->funcs.encode != NULL)
+            {
+                return pCallback->funcs.encode(ostream, field, &pCallback->arg);
+            }
+        }
+    }
+
+    return true; /* Success, but didn't do anything */
+
+}
+
+#ifdef PB_VALIDATE_UTF8
+
+/* This function checks whether a string is valid UTF-8 text.
+ *
+ * Algorithm is adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
+ * Original copyright: Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> 2005-03-30
+ * Licensed under "Short code license", which allows use under MIT license or
+ * any compatible with it.
+ */
+
+bool pb_validate_utf8(const char *str)
+{
+    const pb_byte_t *s = (const pb_byte_t*)str;
+    while (*s)
+    {
+        if (*s < 0x80)
+        {
+            /* 0xxxxxxx */
+            s++;
+        }
+        else if ((s[0] & 0xe0) == 0xc0)
+        {
+            /* 110XXXXx 10xxxxxx */
+            if ((s[1] & 0xc0) != 0x80 ||
+                (s[0] & 0xfe) == 0xc0)                        /* overlong? */
+                return false;
+            else
+                s += 2;
+        }
+        else if ((s[0] & 0xf0) == 0xe0)
+        {
+            /* 1110XXXX 10Xxxxxx 10xxxxxx */
+            if ((s[1] & 0xc0) != 0x80 ||
+                (s[2] & 0xc0) != 0x80 ||
+                (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) ||    /* overlong? */
+                (s[0] == 0xed && (s[1] & 0xe0) == 0xa0) ||    /* surrogate? */
+                (s[0] == 0xef && s[1] == 0xbf &&
+                (s[2] & 0xfe) == 0xbe))                 /* U+FFFE or U+FFFF? */
+                return false;
+            else
+                s += 3;
+        }
+        else if ((s[0] & 0xf8) == 0xf0)
+        {
+            /* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
+            if ((s[1] & 0xc0) != 0x80 ||
+                (s[2] & 0xc0) != 0x80 ||
+                (s[3] & 0xc0) != 0x80 ||
+                (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) ||    /* overlong? */
+                (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */
+                return false;
+            else
+                s += 4;
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+#endif
 
diff --git a/security/container/protos/nanopb/pb_common.h b/security/container/protos/nanopb/pb_common.h
index 60b3d37..58aa90f 100644
--- a/security/container/protos/nanopb/pb_common.h
+++ b/security/container/protos/nanopb/pb_common.h
@@ -11,20 +11,18 @@
 extern "C" {
 #endif
 
-/* Iterator for pb_field_t list */
-struct pb_field_iter_s {
-    const pb_field_t *start;       /* Start of the pb_field_t array */
-    const pb_field_t *pos;         /* Current position of the iterator */
-    unsigned required_field_index; /* Zero-based index that counts only the required fields */
-    void *dest_struct;             /* Pointer to start of the structure */
-    void *pData;                   /* Pointer to current field value */
-    void *pSize;                   /* Pointer to count/has field */
-};
-typedef struct pb_field_iter_s pb_field_iter_t;
-
 /* Initialize the field iterator structure to beginning.
  * Returns false if the message type is empty. */
-bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct);
+bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message);
+
+/* Get a field iterator for extension field. */
+bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension);
+
+/* Same as pb_field_iter_begin(), but for const message pointer.
+ * Note that the pointers in pb_field_iter_t will be non-const but shouldn't
+ * be written to when using these functions. */
+bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message);
+bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension);
 
 /* Advance the iterator to the next field.
  * Returns false when the iterator wraps back to the first field. */
@@ -34,6 +32,15 @@
  * Returns false if no such field exists. */
 bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag);
 
+/* Find a field with type PB_LTYPE_EXTENSION, or return false if not found.
+ * There can be only one extension range field per message. */
+bool pb_field_iter_find_extension(pb_field_iter_t *iter);
+
+#ifdef PB_VALIDATE_UTF8
+/* Validate UTF-8 text string */
+bool pb_validate_utf8(const char *s);
+#endif
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/security/container/protos/nanopb/pb_decode.c b/security/container/protos/nanopb/pb_decode.c
index 4b80e81..b194825 100644
--- a/security/container/protos/nanopb/pb_decode.c
+++ b/security/container/protos/nanopb/pb_decode.c
@@ -21,36 +21,32 @@
  * Declarations internal to this file *
  **************************************/
 
-typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn;
-
 static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
-static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);
-static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);
-static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);
-static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter);
-static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension);
-static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);
-static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter);
-static bool checkreturn find_extension_field(pb_field_iter_t *iter);
-static void pb_field_set_to_default(pb_field_iter_t *iter);
-static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct);
-static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest);
 static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof);
-static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest);
-static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest);
+static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size);
+static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
+static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
+static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
+static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
+static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field);
+static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type);
+static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension);
+static bool pb_field_set_to_default(pb_field_iter_t *field);
+static bool pb_message_set_to_defaults(pb_field_iter_t *iter);
+static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_iter_t *field);
 static bool checkreturn pb_skip_varint(pb_istream_t *stream);
 static bool checkreturn pb_skip_string(pb_istream_t *stream);
 
 #ifdef PB_ENABLE_MALLOC
 static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size);
-static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter);
-static void pb_release_single_field(const pb_field_iter_t *iter);
+static void initialize_pointer_field(void *pItem, pb_field_iter_t *field);
+static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *field);
+static void pb_release_single_field(pb_field_iter_t *field);
 #endif
 
 #ifdef PB_WITHOUT_64BIT
@@ -61,22 +57,11 @@
 #define pb_uint64_t uint64_t
 #endif
 
-/* --- Function pointers to field decoders ---
- * Order in the array must match pb_action_t LTYPE numbering.
- */
-static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = {
-    &pb_dec_varint,
-    &pb_dec_uvarint,
-    &pb_dec_svarint,
-    &pb_dec_fixed32,
-    &pb_dec_fixed64,
-    
-    &pb_dec_bytes,
-    &pb_dec_string,
-    &pb_dec_submessage,
-    NULL, /* extensions */
-    &pb_dec_fixed_length_bytes
-};
+#define PB_WT_PACKED ((pb_wire_type_t)0xFF)
+
+typedef struct {
+    uint32_t bitfield[(PB_MAX_REQUIRED_FIELDS + 31) / 32];
+} pb_fields_seen_t;
 
 /*******************************
  * pb_istream_t implementation *
@@ -99,6 +84,9 @@
 
 bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count)
 {
+    if (count == 0)
+        return true;
+
 #ifndef PB_BUFFER_ONLY
 	if (buf == NULL && stream->callback != buf_read)
 	{
@@ -151,7 +139,7 @@
     return true;    
 }
 
-pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize)
+pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen)
 {
     pb_istream_t stream;
     /* Cast away the const from buf without a compiler error.  We are
@@ -168,7 +156,7 @@
 #endif
     state.c_state = buf;
     stream.state = state.state;
-    stream.bytes_left = bufsize;
+    stream.bytes_left = msglen;
 #ifndef PB_NO_ERRMSG
     stream.errmsg = NULL;
 #endif
@@ -216,9 +204,11 @@
             if (bitpos >= 32)
             {
                 /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */
-                uint8_t sign_extension = (bitpos < 63) ? 0xFF : 0x01;
-                
-                if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension))
+                pb_byte_t sign_extension = (bitpos < 63) ? 0xFF : 0x01;
+                bool valid_extension = ((byte & 0x7F) == 0x00 ||
+                         ((result >> 31) != 0 && byte == sign_extension));
+
+                if (bitpos >= 64 || !valid_extension)
                 {
                     PB_RETURN_ERROR(stream, "varint overflow");
                 }
@@ -287,7 +277,12 @@
     if (!pb_decode_varint32(stream, &length))
         return false;
     
-    return pb_read(stream, NULL, length);
+    if ((size_t)length != length)
+    {
+        PB_RETURN_ERROR(stream, "size too large");
+    }
+
+    return pb_read(stream, NULL, (size_t)length);
 }
 
 bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof)
@@ -302,12 +297,6 @@
         return false;
     }
     
-    if (temp == 0)
-    {
-        *eof = true; /* Special feature: allow 0-terminated messages. */
-        return false;
-    }
-    
     *tag = temp >> 3;
     *wire_type = (pb_wire_type_t)(temp & 7);
     return true;
@@ -338,8 +327,11 @@
             do
             {
                 (*size)++;
-                if (*size > max_size) return false;
-                if (!pb_read(stream, buf, 1)) return false;
+                if (*size > max_size)
+                    PB_RETURN_ERROR(stream, "varint overflow");
+
+                if (!pb_read(stream, buf, 1))
+                    return false;
             } while (*buf++ & 0x80);
             return true;
             
@@ -374,8 +366,8 @@
     if (substream->bytes_left < size)
         PB_RETURN_ERROR(stream, "parent stream too short");
     
-    substream->bytes_left = size;
-    stream->bytes_left -= size;
+    substream->bytes_left = (size_t)size;
+    stream->bytes_left -= (size_t)size;
     return true;
 }
 
@@ -398,45 +390,111 @@
  * Decode a single field *
  *************************/
 
-static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
+static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
 {
-    pb_type_t type;
-    pb_decoder_t func;
-    
-    type = iter->pos->type;
-    func = PB_DECODERS[PB_LTYPE(type)];
+    switch (PB_LTYPE(field->type))
+    {
+        case PB_LTYPE_BOOL:
+            if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED)
+                PB_RETURN_ERROR(stream, "wrong wire type");
 
-    switch (PB_HTYPE(type))
+            return pb_dec_bool(stream, field);
+
+        case PB_LTYPE_VARINT:
+        case PB_LTYPE_UVARINT:
+        case PB_LTYPE_SVARINT:
+            if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED)
+                PB_RETURN_ERROR(stream, "wrong wire type");
+
+            return pb_dec_varint(stream, field);
+
+        case PB_LTYPE_FIXED32:
+            if (wire_type != PB_WT_32BIT && wire_type != PB_WT_PACKED)
+                PB_RETURN_ERROR(stream, "wrong wire type");
+
+            return pb_decode_fixed32(stream, field->pData);
+
+        case PB_LTYPE_FIXED64:
+            if (wire_type != PB_WT_64BIT && wire_type != PB_WT_PACKED)
+                PB_RETURN_ERROR(stream, "wrong wire type");
+
+#ifdef PB_CONVERT_DOUBLE_FLOAT
+            if (field->data_size == sizeof(float))
+            {
+                return pb_decode_double_as_float(stream, (float*)field->pData);
+            }
+#endif
+
+#ifdef PB_WITHOUT_64BIT
+            PB_RETURN_ERROR(stream, "invalid data_size");
+#else
+            return pb_decode_fixed64(stream, field->pData);
+#endif
+
+        case PB_LTYPE_BYTES:
+            if (wire_type != PB_WT_STRING)
+                PB_RETURN_ERROR(stream, "wrong wire type");
+
+            return pb_dec_bytes(stream, field);
+
+        case PB_LTYPE_STRING:
+            if (wire_type != PB_WT_STRING)
+                PB_RETURN_ERROR(stream, "wrong wire type");
+
+            return pb_dec_string(stream, field);
+
+        case PB_LTYPE_SUBMESSAGE:
+        case PB_LTYPE_SUBMSG_W_CB:
+            if (wire_type != PB_WT_STRING)
+                PB_RETURN_ERROR(stream, "wrong wire type");
+
+            return pb_dec_submessage(stream, field);
+
+        case PB_LTYPE_FIXED_LENGTH_BYTES:
+            if (wire_type != PB_WT_STRING)
+                PB_RETURN_ERROR(stream, "wrong wire type");
+
+            return pb_dec_fixed_length_bytes(stream, field);
+
+        default:
+            PB_RETURN_ERROR(stream, "invalid field type");
+    }
+}
+
+static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
+{
+    switch (PB_HTYPE(field->type))
     {
         case PB_HTYPE_REQUIRED:
-            return func(stream, iter->pos, iter->pData);
+            return decode_basic_field(stream, wire_type, field);
             
         case PB_HTYPE_OPTIONAL:
-            if (iter->pSize != iter->pData)
-                *(bool*)iter->pSize = true;
-            return func(stream, iter->pos, iter->pData);
+            if (field->pSize != NULL)
+                *(bool*)field->pSize = true;
+            return decode_basic_field(stream, wire_type, field);
     
         case PB_HTYPE_REPEATED:
             if (wire_type == PB_WT_STRING
-                && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
+                && PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
             {
                 /* Packed array */
                 bool status = true;
-                pb_size_t *size = (pb_size_t*)iter->pSize;
-
                 pb_istream_t substream;
+                pb_size_t *size = (pb_size_t*)field->pSize;
+                field->pData = (char*)field->pField + field->data_size * (*size);
+
                 if (!pb_make_string_substream(stream, &substream))
                     return false;
 
-                while (substream.bytes_left > 0 && *size < iter->pos->array_size)
+                while (substream.bytes_left > 0 && *size < field->array_size)
                 {
-                    void *pItem = (char*)iter->pData + iter->pos->data_size * (*size);
-                    if (!func(&substream, iter->pos, pItem))
+                    if (!decode_basic_field(&substream, PB_WT_PACKED, field))
                     {
                         status = false;
                         break;
                     }
                     (*size)++;
+                    field->pData = (char*)field->pData + field->data_size;
                 }
 
                 if (substream.bytes_left != 0)
@@ -449,25 +507,44 @@
             else
             {
                 /* Repeated field */
-                pb_size_t *size = (pb_size_t*)iter->pSize;
-                char *pItem = (char*)iter->pData + iter->pos->data_size * (*size);
+                pb_size_t *size = (pb_size_t*)field->pSize;
+                field->pData = (char*)field->pField + field->data_size * (*size);
 
-                if ((*size)++ >= iter->pos->array_size)
+                if ((*size)++ >= field->array_size)
                     PB_RETURN_ERROR(stream, "array overflow");
 
-                return func(stream, iter->pos, pItem);
+                return decode_basic_field(stream, wire_type, field);
             }
 
         case PB_HTYPE_ONEOF:
-            *(pb_size_t*)iter->pSize = iter->pos->tag;
-            if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
+            if (PB_LTYPE_IS_SUBMSG(field->type) &&
+                *(pb_size_t*)field->pSize != field->tag)
             {
                 /* We memset to zero so that any callbacks are set to NULL.
-                 * Then set any default values. */
-                memset(iter->pData, 0, iter->pos->data_size);
-                pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData);
+                 * This is because the callbacks might otherwise have values
+                 * from some other union field.
+                 * If callbacks are needed inside oneof field, use .proto
+                 * option submsg_callback to have a separate callback function
+                 * that can set the fields before submessage is decoded.
+                 * pb_dec_submessage() will set any default values. */
+                memset(field->pData, 0, (size_t)field->data_size);
+
+                /* Set default values for the submessage fields. */
+                if (field->submsg_desc->default_value != NULL ||
+                    field->submsg_desc->field_callback != NULL ||
+                    field->submsg_desc->submsg_info[0] != NULL)
+                {
+                    pb_field_iter_t submsg_iter;
+                    if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData))
+                    {
+                        if (!pb_message_set_to_defaults(&submsg_iter))
+                            PB_RETURN_ERROR(stream, "failed to set defaults");
+                    }
+                }
             }
-            return func(stream, iter->pos, iter->pData);
+            *(pb_size_t*)field->pSize = field->tag;
+
+            return decode_basic_field(stream, wire_type, field);
 
         default:
             PB_RETURN_ERROR(stream, "invalid field type");
@@ -486,6 +563,16 @@
     if (data_size == 0 || array_size == 0)
         PB_RETURN_ERROR(stream, "invalid size");
     
+#ifdef __AVR__
+    /* Workaround for AVR libc bug 53284: http://savannah.nongnu.org/bugs/?53284
+     * Realloc to size of 1 byte can cause corruption of the malloc structures.
+     */
+    if (data_size == 1 && array_size == 1)
+    {
+        data_size = 2;
+    }
+#endif
+
     /* Check for multiplication overflows.
      * This code avoids the costly division if the sizes are small enough.
      * Multiplication is safe as long as only half of bits are set
@@ -515,76 +602,71 @@
 }
 
 /* Clear a newly allocated item in case it contains a pointer, or is a submessage. */
-static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter)
+static void initialize_pointer_field(void *pItem, pb_field_iter_t *field)
 {
-    if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING ||
-        PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES)
+    if (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
+        PB_LTYPE(field->type) == PB_LTYPE_BYTES)
     {
         *(void**)pItem = NULL;
     }
-    else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE)
+    else if (PB_LTYPE_IS_SUBMSG(field->type))
     {
         /* We memset to zero so that any callbacks are set to NULL.
-         * Then set any default values. */
-        memset(pItem, 0, iter->pos->data_size);
-        pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem);
+         * Default values will be set by pb_dec_submessage(). */
+        memset(pItem, 0, field->data_size);
     }
 }
 #endif
 
-static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
+static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
 {
 #ifndef PB_ENABLE_MALLOC
     PB_UNUSED(wire_type);
-    PB_UNUSED(iter);
+    PB_UNUSED(field);
     PB_RETURN_ERROR(stream, "no malloc support");
 #else
-    pb_type_t type;
-    pb_decoder_t func;
-    
-    type = iter->pos->type;
-    func = PB_DECODERS[PB_LTYPE(type)];
-    
-    switch (PB_HTYPE(type))
+    switch (PB_HTYPE(field->type))
     {
         case PB_HTYPE_REQUIRED:
         case PB_HTYPE_OPTIONAL:
         case PB_HTYPE_ONEOF:
-            if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE &&
-                *(void**)iter->pData != NULL)
+            if (PB_LTYPE_IS_SUBMSG(field->type) && *(void**)field->pField != NULL)
             {
                 /* Duplicate field, have to release the old allocation first. */
-                pb_release_single_field(iter);
+                /* FIXME: Does this work correctly for oneofs? */
+                pb_release_single_field(field);
             }
         
-            if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
+            if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
             {
-                *(pb_size_t*)iter->pSize = iter->pos->tag;
+                *(pb_size_t*)field->pSize = field->tag;
             }
 
-            if (PB_LTYPE(type) == PB_LTYPE_STRING ||
-                PB_LTYPE(type) == PB_LTYPE_BYTES)
+            if (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
+                PB_LTYPE(field->type) == PB_LTYPE_BYTES)
             {
-                return func(stream, iter->pos, iter->pData);
+                /* pb_dec_string and pb_dec_bytes handle allocation themselves */
+                field->pData = field->pField;
+                return decode_basic_field(stream, wire_type, field);
             }
             else
             {
-                if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1))
+                if (!allocate_field(stream, field->pField, field->data_size, 1))
                     return false;
                 
-                initialize_pointer_field(*(void**)iter->pData, iter);
-                return func(stream, iter->pos, *(void**)iter->pData);
+                field->pData = *(void**)field->pField;
+                initialize_pointer_field(field->pData, field);
+                return decode_basic_field(stream, wire_type, field);
             }
     
         case PB_HTYPE_REPEATED:
             if (wire_type == PB_WT_STRING
-                && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
+                && PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
             {
                 /* Packed array, multiple items come in at once. */
                 bool status = true;
-                pb_size_t *size = (pb_size_t*)iter->pSize;
+                pb_size_t *size = (pb_size_t*)field->pSize;
                 size_t allocated_size = *size;
-                void *pItem;
                 pb_istream_t substream;
                 
                 if (!pb_make_string_substream(stream, &substream))
@@ -592,14 +674,27 @@
                 
                 while (substream.bytes_left)
                 {
+                    if (*size == PB_SIZE_MAX)
+                    {
+#ifndef PB_NO_ERRMSG
+                        stream->errmsg = "too many array entries";
+#endif
+                        status = false;
+                        break;
+                    }
+
                     if ((size_t)*size + 1 > allocated_size)
                     {
                         /* Allocate more storage. This tries to guess the
                          * number of remaining entries. Round the division
                          * upwards. */
-                        allocated_size += (substream.bytes_left - 1) / iter->pos->data_size + 1;
+                        size_t remain = (substream.bytes_left - 1) / field->data_size + 1;
+                        if (remain < PB_SIZE_MAX - allocated_size)
+                            allocated_size += remain;
+                        else
+                            allocated_size += 1;
                         
-                        if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size))
+                        if (!allocate_field(&substream, field->pField, field->data_size, allocated_size))
                         {
                             status = false;
                             break;
@@ -607,23 +702,14 @@
                     }
 
                     /* Decode the array entry */
-                    pItem = *(char**)iter->pData + iter->pos->data_size * (*size);
-                    initialize_pointer_field(pItem, iter);
-                    if (!func(&substream, iter->pos, pItem))
+                    field->pData = *(char**)field->pField + field->data_size * (*size);
+                    initialize_pointer_field(field->pData, field);
+                    if (!decode_basic_field(&substream, PB_WT_PACKED, field))
                     {
                         status = false;
                         break;
                     }
                     
-                    if (*size == PB_SIZE_MAX)
-                    {
-#ifndef PB_NO_ERRMSG
-                        stream->errmsg = "too many array entries";
-#endif
-                        status = false;
-                        break;
-                    }
-                    
                     (*size)++;
                 }
                 if (!pb_close_string_substream(stream, &substream))
@@ -634,19 +720,18 @@
             else
             {
                 /* Normal repeated field, i.e. only one item at a time. */
-                pb_size_t *size = (pb_size_t*)iter->pSize;
-                void *pItem;
-                
+                pb_size_t *size = (pb_size_t*)field->pSize;
+
                 if (*size == PB_SIZE_MAX)
                     PB_RETURN_ERROR(stream, "too many array entries");
                 
-                (*size)++;
-                if (!allocate_field(stream, iter->pData, iter->pos->data_size, *size))
+                if (!allocate_field(stream, field->pField, field->data_size, (size_t)(*size + 1)))
                     return false;
             
-                pItem = *(char**)iter->pData + iter->pos->data_size * (*size - 1);
-                initialize_pointer_field(pItem, iter);
-                return func(stream, iter->pos, pItem);
+                field->pData = *(char**)field->pField + field->data_size * (*size);
+                (*size)++;
+                initialize_pointer_field(field->pData, field);
+                return decode_basic_field(stream, wire_type, field);
             }
 
         default:
@@ -655,31 +740,25 @@
 #endif
 }
 
-static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
+static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
 {
-    pb_callback_t *pCallback = (pb_callback_t*)iter->pData;
-    
-#ifdef PB_OLD_CALLBACK_STYLE
-    void *arg = pCallback->arg;
-#else
-    void **arg = &(pCallback->arg);
-#endif
-    
-    if (pCallback == NULL || pCallback->funcs.decode == NULL)
+    if (!field->descriptor->field_callback)
         return pb_skip_field(stream, wire_type);
-    
+
     if (wire_type == PB_WT_STRING)
     {
         pb_istream_t substream;
+        size_t prev_bytes_left;
         
         if (!pb_make_string_substream(stream, &substream))
             return false;
         
         do
         {
-            if (!pCallback->funcs.decode(&substream, iter->pos, arg))
+            prev_bytes_left = substream.bytes_left;
+            if (!field->descriptor->field_callback(&substream, NULL, field))
                 PB_RETURN_ERROR(stream, "callback failed");
-        } while (substream.bytes_left);
+        } while (substream.bytes_left > 0 && substream.bytes_left < prev_bytes_left);
         
         if (!pb_close_string_substream(stream, &substream))
             return false;
@@ -700,69 +779,52 @@
             return false;
         substream = pb_istream_from_buffer(buffer, size);
         
-        return pCallback->funcs.decode(&substream, iter->pos, arg);
+        return field->descriptor->field_callback(&substream, NULL, field);
     }
 }
 
-static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter)
+static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field)
 {
 #ifdef PB_ENABLE_MALLOC
     /* When decoding an oneof field, check if there is old data that must be
      * released first. */
-    if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF)
+    if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
     {
-        if (!pb_release_union_field(stream, iter))
+        if (!pb_release_union_field(stream, field))
             return false;
     }
 #endif
 
-    switch (PB_ATYPE(iter->pos->type))
+    switch (PB_ATYPE(field->type))
     {
         case PB_ATYPE_STATIC:
-            return decode_static_field(stream, wire_type, iter);
+            return decode_static_field(stream, wire_type, field);
         
         case PB_ATYPE_POINTER:
-            return decode_pointer_field(stream, wire_type, iter);
+            return decode_pointer_field(stream, wire_type, field);
         
         case PB_ATYPE_CALLBACK:
-            return decode_callback_field(stream, wire_type, iter);
+            return decode_callback_field(stream, wire_type, field);
         
         default:
             PB_RETURN_ERROR(stream, "invalid field type");
     }
 }
 
-static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension)
-{
-    /* Fake a field iterator for the extension field.
-     * It is not actually safe to advance this iterator, but decode_field
-     * will not even try to. */
-    const pb_field_t *field = (const pb_field_t*)extension->type->arg;
-    (void)pb_field_iter_begin(iter, field, extension->dest);
-    iter->pData = extension->dest;
-    iter->pSize = &extension->found;
-    
-    if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
-    {
-        /* For pointer extensions, the pointer is stored directly
-         * in the extension structure. This avoids having an extra
-         * indirection. */
-        iter->pData = &extension->dest;
-    }
-}
-
-/* Default handler for extension fields. Expects a pb_field_t structure
- * in extension->type->arg. */
+/* Default handler for extension fields. Expects to have a pb_msgdesc_t
+ * pointer in the extension->type->arg field, pointing to a message with
+ * only one field in it.  */
 static bool checkreturn default_extension_decoder(pb_istream_t *stream,
     pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type)
 {
-    const pb_field_t *field = (const pb_field_t*)extension->type->arg;
     pb_field_iter_t iter;
-    
-    if (field->tag != tag)
+
+    if (!pb_field_iter_begin_extension(&iter, extension))
+        PB_RETURN_ERROR(stream, "invalid extension");
+
+    if (iter.tag != tag || !iter.message)
         return true;
-    
-    iter_from_extension(&iter, extension);
+
     extension->found = true;
     return decode_field(stream, wire_type, &iter);
 }
@@ -770,9 +832,8 @@
 /* Try to decode an unknown field as an extension field. Tries each extension
  * decoder in turn, until one of them handles the field or loop ends. */
 static bool checkreturn decode_extension(pb_istream_t *stream,
-    uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter)
+    uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension)
 {
-    pb_extension_t *extension = *(pb_extension_t* const *)iter->pData;
     size_t pos = stream->bytes_left;
     
     while (extension != NULL && pos == stream->bytes_left)
@@ -792,129 +853,153 @@
     return true;
 }
 
-/* Step through the iterator until an extension field is found or until all
- * entries have been checked. There can be only one extension field per
- * message. Returns false if no extension field is found. */
-static bool checkreturn find_extension_field(pb_field_iter_t *iter)
-{
-    const pb_field_t *start = iter->pos;
-    
-    do {
-        if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION)
-            return true;
-        (void)pb_field_iter_next(iter);
-    } while (iter->pos != start);
-    
-    return false;
-}
-
 /* Initialize message fields to default values, recursively */
-static void pb_field_set_to_default(pb_field_iter_t *iter)
+static bool pb_field_set_to_default(pb_field_iter_t *field)
 {
     pb_type_t type;
-    type = iter->pos->type;
-    
+    type = field->type;
+
     if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
     {
-        pb_extension_t *ext = *(pb_extension_t* const *)iter->pData;
+        pb_extension_t *ext = *(pb_extension_t* const *)field->pData;
         while (ext != NULL)
         {
             pb_field_iter_t ext_iter;
-            ext->found = false;
-            iter_from_extension(&ext_iter, ext);
-            pb_field_set_to_default(&ext_iter);
+            if (pb_field_iter_begin_extension(&ext_iter, ext))
+            {
+                ext->found = false;
+                if (!pb_message_set_to_defaults(&ext_iter))
+                    return false;
+            }
             ext = ext->next;
         }
     }
     else if (PB_ATYPE(type) == PB_ATYPE_STATIC)
     {
         bool init_data = true;
-        if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && iter->pSize != iter->pData)
+        if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->pSize != NULL)
         {
             /* Set has_field to false. Still initialize the optional field
              * itself also. */
-            *(bool*)iter->pSize = false;
+            *(bool*)field->pSize = false;
         }
         else if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
                  PB_HTYPE(type) == PB_HTYPE_ONEOF)
         {
             /* REPEATED: Set array count to 0, no need to initialize contents.
                ONEOF: Set which_field to 0. */
-            *(pb_size_t*)iter->pSize = 0;
+            *(pb_size_t*)field->pSize = 0;
             init_data = false;
         }
 
         if (init_data)
         {
-            if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE)
+            if (PB_LTYPE_IS_SUBMSG(field->type) &&
+                (field->submsg_desc->default_value != NULL ||
+                 field->submsg_desc->field_callback != NULL ||
+                 field->submsg_desc->submsg_info[0] != NULL))
             {
-                /* Initialize submessage to defaults */
-                pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData);
-            }
-            else if (iter->pos->ptr != NULL)
-            {
-                /* Initialize to default value */
-                memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size);
+                /* Initialize submessage to defaults.
+                 * Only needed if it has default values
+                 * or callback/submessage fields. */
+                pb_field_iter_t submsg_iter;
+                if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData))
+                {
+                    if (!pb_message_set_to_defaults(&submsg_iter))
+                        return false;
+                }
             }
             else
             {
                 /* Initialize to zeros */
-                memset(iter->pData, 0, iter->pos->data_size);
+                memset(field->pData, 0, (size_t)field->data_size);
             }
         }
     }
     else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
     {
         /* Initialize the pointer to NULL. */
-        *(void**)iter->pData = NULL;
-        
+        *(void**)field->pField = NULL;
+
         /* Initialize array count to 0. */
         if (PB_HTYPE(type) == PB_HTYPE_REPEATED ||
             PB_HTYPE(type) == PB_HTYPE_ONEOF)
         {
-            *(pb_size_t*)iter->pSize = 0;
+            *(pb_size_t*)field->pSize = 0;
         }
     }
     else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
     {
         /* Don't overwrite callback */
     }
+
+    return true;
 }
 
-static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct)
+static bool pb_message_set_to_defaults(pb_field_iter_t *iter)
 {
-    pb_field_iter_t iter;
+    pb_istream_t defstream = PB_ISTREAM_EMPTY;
+    uint32_t tag = 0;
+    pb_wire_type_t wire_type = PB_WT_VARINT;
+    bool eof;
 
-    if (!pb_field_iter_begin(&iter, fields, dest_struct))
-        return; /* Empty message type */
-    
+    if (iter->descriptor->default_value)
+    {
+        defstream = pb_istream_from_buffer(iter->descriptor->default_value, (size_t)-1);
+        if (!pb_decode_tag(&defstream, &wire_type, &tag, &eof))
+            return false;
+    }
+
     do
     {
-        pb_field_set_to_default(&iter);
-    } while (pb_field_iter_next(&iter));
+        if (!pb_field_set_to_default(iter))
+            return false;
+
+        if (tag != 0 && iter->tag == tag)
+        {
+            /* We have a default value for this field in the defstream */
+            if (!decode_field(&defstream, wire_type, iter))
+                return false;
+            if (!pb_decode_tag(&defstream, &wire_type, &tag, &eof))
+                return false;
+
+            if (iter->pSize)
+                *(bool*)iter->pSize = false;
+        }
+    } while (pb_field_iter_next(iter));
+
+    return true;
 }
 
 /*********************
  * Decode all fields *
  *********************/
 
-bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
+static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags)
 {
-    uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0};
-    const uint32_t allbits = ~(uint32_t)0;
     uint32_t extension_range_start = 0;
-    pb_field_iter_t iter;
+    pb_extension_t *extensions = NULL;
 
     /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed
      * count field. This can only handle _one_ repeated fixed count field that
      * is unpacked and unordered among other (non repeated fixed count) fields.
      */
-    const pb_field_t *fixed_count_field = NULL;
+    pb_size_t fixed_count_field = PB_SIZE_MAX;
     pb_size_t fixed_count_size = 0;
+    pb_size_t fixed_count_total_size = 0;
 
-    /* Return value ignored, as empty message types will be correctly handled by
-     * pb_field_iter_find() anyway. */
-    (void)pb_field_iter_begin(&iter, fields, dest_struct);
+    pb_fields_seen_t fields_seen = {{0, 0}};
+    const uint32_t allbits = ~(uint32_t)0;
+    pb_field_iter_t iter;
+
+    if (pb_field_iter_begin(&iter, fields, dest_struct))
+    {
+        if ((flags & PB_DECODE_NOINIT) == 0)
+        {
+            if (!pb_message_set_to_defaults(&iter))
+                PB_RETURN_ERROR(stream, "failed to set defaults");
+        }
+    }
 
     while (stream->bytes_left)
     {
@@ -930,28 +1015,46 @@
                 return false;
         }
 
-        if (!pb_field_iter_find(&iter, tag))
+        if (tag == 0)
+        {
+          if (flags & PB_DECODE_NULLTERMINATED)
+          {
+            break;
+          }
+          else
+          {
+            PB_RETURN_ERROR(stream, "zero tag");
+          }
+        }
+
+        if (!pb_field_iter_find(&iter, tag) || PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION)
         {
             /* No match found, check if it matches an extension. */
+            if (extension_range_start == 0)
+            {
+                if (pb_field_iter_find_extension(&iter))
+                {
+                    extensions = *(pb_extension_t* const *)iter.pData;
+                    extension_range_start = iter.tag;
+                }
+
+                if (!extensions)
+                {
+                    extension_range_start = (uint32_t)-1;
+                }
+            }
+
             if (tag >= extension_range_start)
             {
-                if (!find_extension_field(&iter))
-                    extension_range_start = (uint32_t)-1;
-                else
-                    extension_range_start = iter.pos->tag;
+                size_t pos = stream->bytes_left;
 
-                if (tag >= extension_range_start)
+                if (!decode_extension(stream, tag, wire_type, extensions))
+                    return false;
+
+                if (pos != stream->bytes_left)
                 {
-                    size_t pos = stream->bytes_left;
-
-                    if (!decode_extension(stream, tag, wire_type, &iter))
-                        return false;
-
-                    if (pos != stream->bytes_left)
-                    {
-                        /* The field was handled */
-                        continue;
-                    }
+                    /* The field was handled */
+                    continue;
                 }
             }
 
@@ -964,32 +1067,32 @@
         /* If a repeated fixed count field was found, get size from
          * 'fixed_count_field' as there is no counter contained in the struct.
          */
-        if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REPEATED
-            && iter.pSize == iter.pData)
+        if (PB_HTYPE(iter.type) == PB_HTYPE_REPEATED && iter.pSize == &iter.array_size)
         {
-            if (fixed_count_field != iter.pos) {
+            if (fixed_count_field != iter.index) {
                 /* If the new fixed count field does not match the previous one,
                  * check that the previous one is NULL or that it finished
                  * receiving all the expected data.
                  */
-                if (fixed_count_field != NULL &&
-                    fixed_count_size != fixed_count_field->array_size)
+                if (fixed_count_field != PB_SIZE_MAX &&
+                    fixed_count_size != fixed_count_total_size)
                 {
                     PB_RETURN_ERROR(stream, "wrong size for fixed count field");
                 }
 
-                fixed_count_field = iter.pos;
+                fixed_count_field = iter.index;
                 fixed_count_size = 0;
+                fixed_count_total_size = iter.array_size;
             }
 
             iter.pSize = &fixed_count_size;
         }
 
-        if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED
+        if (PB_HTYPE(iter.type) == PB_HTYPE_REQUIRED
             && iter.required_field_index < PB_MAX_REQUIRED_FIELDS)
         {
             uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31));
-            fields_seen[iter.required_field_index >> 5] |= tmp;
+            fields_seen.bitfield[iter.required_field_index >> 5] |= tmp;
         }
 
         if (!decode_field(stream, wire_type, &iter))
@@ -997,62 +1100,64 @@
     }
 
     /* Check that all elements of the last decoded fixed count field were present. */
-    if (fixed_count_field != NULL &&
-        fixed_count_size != fixed_count_field->array_size)
+    if (fixed_count_field != PB_SIZE_MAX &&
+        fixed_count_size != fixed_count_total_size)
     {
         PB_RETURN_ERROR(stream, "wrong size for fixed count field");
     }
 
     /* Check that all required fields were present. */
     {
-        /* First figure out the number of required fields by
-         * seeking to the end of the field array. Usually we
-         * are already close to end after decoding.
-         */
-        unsigned req_field_count;
-        pb_type_t last_type;
-        unsigned i;
-        do {
-            req_field_count = iter.required_field_index;
-            last_type = iter.pos->type;
-        } while (pb_field_iter_next(&iter));
-        
-        /* Fixup if last field was also required. */
-        if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0)
-            req_field_count++;
-        
-        if (req_field_count > PB_MAX_REQUIRED_FIELDS)
-            req_field_count = PB_MAX_REQUIRED_FIELDS;
+        pb_size_t req_field_count = iter.descriptor->required_field_count;
 
         if (req_field_count > 0)
         {
+            pb_size_t i;
+
+            if (req_field_count > PB_MAX_REQUIRED_FIELDS)
+                req_field_count = PB_MAX_REQUIRED_FIELDS;
+
             /* Check the whole words */
             for (i = 0; i < (req_field_count >> 5); i++)
             {
-                if (fields_seen[i] != allbits)
+                if (fields_seen.bitfield[i] != allbits)
                     PB_RETURN_ERROR(stream, "missing required field");
             }
-            
+
             /* Check the remaining bits (if any) */
             if ((req_field_count & 31) != 0)
             {
-                if (fields_seen[req_field_count >> 5] !=
-                    (allbits >> (32 - (req_field_count & 31))))
+                if (fields_seen.bitfield[req_field_count >> 5] !=
+                    (allbits >> (uint_least8_t)(32 - (req_field_count & 31))))
                 {
                     PB_RETURN_ERROR(stream, "missing required field");
                 }
             }
         }
     }
-    
+
     return true;
 }
 
-bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
+bool checkreturn pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags)
 {
     bool status;
-    pb_message_set_to_defaults(fields, dest_struct);
-    status = pb_decode_noinit(stream, fields, dest_struct);
+
+    if ((flags & PB_DECODE_DELIMITED) == 0)
+    {
+      status = pb_decode_inner(stream, fields, dest_struct, flags);
+    }
+    else
+    {
+      pb_istream_t substream;
+      if (!pb_make_string_substream(stream, &substream))
+        return false;
+
+      status = pb_decode_inner(&substream, fields, dest_struct, flags);
+
+      if (!pb_close_string_substream(stream, &substream))
+        return false;
+    }
     
 #ifdef PB_ENABLE_MALLOC
     if (!status)
@@ -1062,49 +1167,28 @@
     return status;
 }
 
-bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
+bool checkreturn pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct)
 {
-    pb_istream_t substream;
     bool status;
 
-    if (!pb_make_string_substream(stream, &substream))
-        return false;
+    status = pb_decode_inner(stream, fields, dest_struct, 0);
 
-    status = pb_decode_noinit(&substream, fields, dest_struct);
+#ifdef PB_ENABLE_MALLOC
+    if (!status)
+        pb_release(fields, dest_struct);
+#endif
 
-    if (!pb_close_string_substream(stream, &substream))
-        return false;
     return status;
 }
 
-bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
-{
-    pb_istream_t substream;
-    bool status;
-    
-    if (!pb_make_string_substream(stream, &substream))
-        return false;
-    
-    status = pb_decode(&substream, fields, dest_struct);
-
-    if (!pb_close_string_substream(stream, &substream))
-        return false;
-    return status;
-}
-
-bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct)
-{
-    /* This behaviour will be separated in nanopb-0.4.0, see issue #278. */
-    return pb_decode(stream, fields, dest_struct);
-}
-
 #ifdef PB_ENABLE_MALLOC
 /* Given an oneof field, if there has already been a field inside this oneof,
  * release it before overwriting with a different one. */
-static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter)
+static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *field)
 {
-    pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */
-    pb_size_t new_tag = iter->pos->tag; /* New which_ value */
+    pb_field_iter_t old_field = *field;
+    pb_size_t old_tag = *(pb_size_t*)field->pSize; /* Previous which_ value */
+    pb_size_t new_tag = field->tag; /* New which_ value */
 
     if (old_tag == 0)
         return true; /* Ok, no old data in union */
@@ -1114,27 +1198,30 @@
 
     /* Release old data. The find can fail if the message struct contains
      * invalid data. */
-    if (!pb_field_iter_find(iter, old_tag))
+    if (!pb_field_iter_find(&old_field, old_tag))
         PB_RETURN_ERROR(stream, "invalid union tag");
 
-    pb_release_single_field(iter);
+    pb_release_single_field(&old_field);
 
-    /* Restore iterator to where it should be.
-     * This shouldn't fail unless the pb_field_t structure is corrupted. */
-    if (!pb_field_iter_find(iter, new_tag))
-        PB_RETURN_ERROR(stream, "iterator error");
-    
+    if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
+    {
+        /* Initialize the pointer to NULL to make sure it is valid
+         * even in case of error return. */
+        *(void**)field->pField = NULL;
+        field->pData = NULL;
+    }
+
     return true;
 }
 
-static void pb_release_single_field(const pb_field_iter_t *iter)
+static void pb_release_single_field(pb_field_iter_t *field)
 {
     pb_type_t type;
-    type = iter->pos->type;
+    type = field->type;
 
     if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
     {
-        if (*(pb_size_t*)iter->pSize != iter->pos->tag)
+        if (*(pb_size_t*)field->pSize != field->tag)
             return; /* This is not the current field in the union */
     }
 
@@ -1144,48 +1231,48 @@
     if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
     {
         /* Release fields from all extensions in the linked list */
-        pb_extension_t *ext = *(pb_extension_t**)iter->pData;
+        pb_extension_t *ext = *(pb_extension_t**)field->pData;
         while (ext != NULL)
         {
             pb_field_iter_t ext_iter;
-            iter_from_extension(&ext_iter, ext);
-            pb_release_single_field(&ext_iter);
+            if (pb_field_iter_begin_extension(&ext_iter, ext))
+            {
+                pb_release_single_field(&ext_iter);
+            }
             ext = ext->next;
         }
     }
-    else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
+    else if (PB_LTYPE_IS_SUBMSG(type) && PB_ATYPE(type) != PB_ATYPE_CALLBACK)
     {
         /* Release fields in submessage or submsg array */
-        void *pItem = iter->pData;
         pb_size_t count = 1;
         
         if (PB_ATYPE(type) == PB_ATYPE_POINTER)
         {
-            pItem = *(void**)iter->pData;
+            field->pData = *(void**)field->pField;
+        }
+        else
+        {
+            field->pData = field->pField;
         }
         
         if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
         {
-            if (PB_ATYPE(type) == PB_ATYPE_STATIC && iter->pSize == iter->pData) {
-                /* No _count field so use size of the array */
-                count = iter->pos->array_size;
-            } else {
-                count = *(pb_size_t*)iter->pSize;
-            }
+            count = *(pb_size_t*)field->pSize;
 
-            if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size)
+            if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > field->array_size)
             {
                 /* Protect against corrupted _count fields */
-                count = iter->pos->array_size;
+                count = field->array_size;
             }
         }
         
-        if (pItem)
+        if (field->pData)
         {
-            while (count--)
+            for (; count > 0; count--)
             {
-                pb_release((const pb_field_t*)iter->pos->ptr, pItem);
-                pItem = (char*)pItem + iter->pos->data_size;
+                pb_release(field->submsg_desc, field->pData);
+                field->pData = (char*)field->pData + field->data_size;
             }
         }
     }
@@ -1197,9 +1284,9 @@
              PB_LTYPE(type) == PB_LTYPE_BYTES))
         {
             /* Release entries in repeated string or bytes array */
-            void **pItem = *(void***)iter->pData;
-            pb_size_t count = *(pb_size_t*)iter->pSize;
-            while (count--)
+            void **pItem = *(void***)field->pField;
+            pb_size_t count = *(pb_size_t*)field->pSize;
+            for (; count > 0; count--)
             {
                 pb_free(*pItem);
                 *pItem++ = NULL;
@@ -1209,16 +1296,16 @@
         if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
         {
             /* We are going to release the array, so set the size to 0 */
-            *(pb_size_t*)iter->pSize = 0;
+            *(pb_size_t*)field->pSize = 0;
         }
         
-        /* Release main item */
-        pb_free(*(void**)iter->pData);
-        *(void**)iter->pData = NULL;
+        /* Release main pointer */
+        pb_free(*(void**)field->pField);
+        *(void**)field->pField = NULL;
     }
 }
 
-void pb_release(const pb_field_t fields[], void *dest_struct)
+void pb_release(const pb_msgdesc_t *fields, void *dest_struct)
 {
     pb_field_iter_t iter;
     
@@ -1237,6 +1324,16 @@
 
 /* Field decoders */
 
+bool pb_decode_bool(pb_istream_t *stream, bool *dest)
+{
+    uint32_t value;
+    if (!pb_decode_varint32(stream, &value))
+        return false;
+
+    *(bool*)dest = (value != 0);
+    return true;
+}
+
 bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest)
 {
     pb_uint64_t value;
@@ -1253,146 +1350,136 @@
 
 bool pb_decode_fixed32(pb_istream_t *stream, void *dest)
 {
-    pb_byte_t bytes[4];
+    union {
+        uint32_t fixed32;
+        pb_byte_t bytes[4];
+    } u;
 
-    if (!pb_read(stream, bytes, 4))
+    if (!pb_read(stream, u.bytes, 4))
         return false;
-    
-    *(uint32_t*)dest = ((uint32_t)bytes[0] << 0) |
-                       ((uint32_t)bytes[1] << 8) |
-                       ((uint32_t)bytes[2] << 16) |
-                       ((uint32_t)bytes[3] << 24);
+
+#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && CHAR_BIT == 8
+    /* fast path - if we know that we're on little endian, assign directly */
+    *(uint32_t*)dest = u.fixed32;
+#else
+    *(uint32_t*)dest = ((uint32_t)u.bytes[0] << 0) |
+                       ((uint32_t)u.bytes[1] << 8) |
+                       ((uint32_t)u.bytes[2] << 16) |
+                       ((uint32_t)u.bytes[3] << 24);
+#endif
     return true;
 }
 
 #ifndef PB_WITHOUT_64BIT
 bool pb_decode_fixed64(pb_istream_t *stream, void *dest)
 {
-    pb_byte_t bytes[8];
+    union {
+        uint64_t fixed64;
+        pb_byte_t bytes[8];
+    } u;
 
-    if (!pb_read(stream, bytes, 8))
+    if (!pb_read(stream, u.bytes, 8))
         return false;
-    
-    *(uint64_t*)dest = ((uint64_t)bytes[0] << 0) |
-                       ((uint64_t)bytes[1] << 8) |
-                       ((uint64_t)bytes[2] << 16) |
-                       ((uint64_t)bytes[3] << 24) |
-                       ((uint64_t)bytes[4] << 32) |
-                       ((uint64_t)bytes[5] << 40) |
-                       ((uint64_t)bytes[6] << 48) |
-                       ((uint64_t)bytes[7] << 56);
-    
-    return true;
-}
-#endif
 
-static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
-    pb_uint64_t value;
-    pb_int64_t svalue;
-    pb_int64_t clamped;
-    if (!pb_decode_varint(stream, &value))
-        return false;
-    
-    /* See issue 97: Google's C++ protobuf allows negative varint values to
-     * be cast as int32_t, instead of the int64_t that should be used when
-     * encoding. Previous nanopb versions had a bug in encoding. In order to
-     * not break decoding of such messages, we cast <=32 bit fields to
-     * int32_t first to get the sign correct.
-     */
-    if (field->data_size == sizeof(pb_int64_t))
-        svalue = (pb_int64_t)value;
-    else
-        svalue = (int32_t)value;
-
-    /* Cast to the proper field size, while checking for overflows */
-    if (field->data_size == sizeof(pb_int64_t))
-        clamped = *(pb_int64_t*)dest = svalue;
-    else if (field->data_size == sizeof(int32_t))
-        clamped = *(int32_t*)dest = (int32_t)svalue;
-    else if (field->data_size == sizeof(int_least16_t))
-        clamped = *(int_least16_t*)dest = (int_least16_t)svalue;
-    else if (field->data_size == sizeof(int_least8_t))
-        clamped = *(int_least8_t*)dest = (int_least8_t)svalue;
-    else
-        PB_RETURN_ERROR(stream, "invalid data_size");
-
-    if (clamped != svalue)
-        PB_RETURN_ERROR(stream, "integer too large");
-    
-    return true;
-}
-
-static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
-    pb_uint64_t value, clamped;
-    if (!pb_decode_varint(stream, &value))
-        return false;
-    
-    /* Cast to the proper field size, while checking for overflows */
-    if (field->data_size == sizeof(pb_uint64_t))
-        clamped = *(pb_uint64_t*)dest = value;
-    else if (field->data_size == sizeof(uint32_t))
-        clamped = *(uint32_t*)dest = (uint32_t)value;
-    else if (field->data_size == sizeof(uint_least16_t))
-        clamped = *(uint_least16_t*)dest = (uint_least16_t)value;
-    else if (field->data_size == sizeof(uint_least8_t))
-        clamped = *(uint_least8_t*)dest = (uint_least8_t)value;
-    else
-        PB_RETURN_ERROR(stream, "invalid data_size");
-    
-    if (clamped != value)
-        PB_RETURN_ERROR(stream, "integer too large");
-
-    return true;
-}
-
-static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
-    pb_int64_t value, clamped;
-    if (!pb_decode_svarint(stream, &value))
-        return false;
-    
-    /* Cast to the proper field size, while checking for overflows */
-    if (field->data_size == sizeof(pb_int64_t))
-        clamped = *(pb_int64_t*)dest = value;
-    else if (field->data_size == sizeof(int32_t))
-        clamped = *(int32_t*)dest = (int32_t)value;
-    else if (field->data_size == sizeof(int_least16_t))
-        clamped = *(int_least16_t*)dest = (int_least16_t)value;
-    else if (field->data_size == sizeof(int_least8_t))
-        clamped = *(int_least8_t*)dest = (int_least8_t)value;
-    else
-        PB_RETURN_ERROR(stream, "invalid data_size");
-
-    if (clamped != value)
-        PB_RETURN_ERROR(stream, "integer too large");
-    
-    return true;
-}
-
-static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
-    PB_UNUSED(field);
-    return pb_decode_fixed32(stream, dest);
-}
-
-static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest)
-{
-    PB_UNUSED(field);
-#ifndef PB_WITHOUT_64BIT
-    return pb_decode_fixed64(stream, dest);
+#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN && CHAR_BIT == 8
+    /* fast path - if we know that we're on little endian, assign directly */
+    *(uint64_t*)dest = u.fixed64;
 #else
-    PB_UNUSED(dest);
-    PB_RETURN_ERROR(stream, "no 64bit support");
+    *(uint64_t*)dest = ((uint64_t)u.bytes[0] << 0) |
+                       ((uint64_t)u.bytes[1] << 8) |
+                       ((uint64_t)u.bytes[2] << 16) |
+                       ((uint64_t)u.bytes[3] << 24) |
+                       ((uint64_t)u.bytes[4] << 32) |
+                       ((uint64_t)u.bytes[5] << 40) |
+                       ((uint64_t)u.bytes[6] << 48) |
+                       ((uint64_t)u.bytes[7] << 56);
 #endif
+    return true;
+}
+#endif
+
+static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field)
+{
+    return pb_decode_bool(stream, (bool*)field->pData);
 }
 
-static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest)
+static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field)
+{
+    if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT)
+    {
+        pb_uint64_t value, clamped;
+        if (!pb_decode_varint(stream, &value))
+            return false;
+
+        /* Cast to the proper field size, while checking for overflows */
+        if (field->data_size == sizeof(pb_uint64_t))
+            clamped = *(pb_uint64_t*)field->pData = value;
+        else if (field->data_size == sizeof(uint32_t))
+            clamped = *(uint32_t*)field->pData = (uint32_t)value;
+        else if (field->data_size == sizeof(uint_least16_t))
+            clamped = *(uint_least16_t*)field->pData = (uint_least16_t)value;
+        else if (field->data_size == sizeof(uint_least8_t))
+            clamped = *(uint_least8_t*)field->pData = (uint_least8_t)value;
+        else
+            PB_RETURN_ERROR(stream, "invalid data_size");
+
+        if (clamped != value)
+            PB_RETURN_ERROR(stream, "integer too large");
+
+        return true;
+    }
+    else
+    {
+        pb_uint64_t value;
+        pb_int64_t svalue;
+        pb_int64_t clamped;
+
+        if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT)
+        {
+            if (!pb_decode_svarint(stream, &svalue))
+                return false;
+        }
+        else
+        {
+            if (!pb_decode_varint(stream, &value))
+                return false;
+
+            /* See issue 97: Google's C++ protobuf allows negative varint values to
+            * be cast as int32_t, instead of the int64_t that should be used when
+            * encoding. Nanopb versions before 0.2.5 had a bug in encoding. In order to
+            * not break decoding of such messages, we cast <=32 bit fields to
+            * int32_t first to get the sign correct.
+            */
+            if (field->data_size == sizeof(pb_int64_t))
+                svalue = (pb_int64_t)value;
+            else
+                svalue = (int32_t)value;
+        }
+
+        /* Cast to the proper field size, while checking for overflows */
+        if (field->data_size == sizeof(pb_int64_t))
+            clamped = *(pb_int64_t*)field->pData = svalue;
+        else if (field->data_size == sizeof(int32_t))
+            clamped = *(int32_t*)field->pData = (int32_t)svalue;
+        else if (field->data_size == sizeof(int_least16_t))
+            clamped = *(int_least16_t*)field->pData = (int_least16_t)svalue;
+        else if (field->data_size == sizeof(int_least8_t))
+            clamped = *(int_least8_t*)field->pData = (int_least8_t)svalue;
+        else
+            PB_RETURN_ERROR(stream, "invalid data_size");
+
+        if (clamped != svalue)
+            PB_RETURN_ERROR(stream, "integer too large");
+
+        return true;
+    }
+}
+
+static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field)
 {
     uint32_t size;
     size_t alloc_size;
-    pb_bytes_array_t *bdest;
+    pb_bytes_array_t *dest;
     
     if (!pb_decode_varint32(stream, &size))
         return false;
@@ -1409,44 +1496,54 @@
 #ifndef PB_ENABLE_MALLOC
         PB_RETURN_ERROR(stream, "no malloc support");
 #else
-        if (!allocate_field(stream, dest, alloc_size, 1))
+        if (stream->bytes_left < size)
+            PB_RETURN_ERROR(stream, "end-of-stream");
+
+        if (!allocate_field(stream, field->pData, alloc_size, 1))
             return false;
-        bdest = *(pb_bytes_array_t**)dest;
+        dest = *(pb_bytes_array_t**)field->pData;
 #endif
     }
     else
     {
         if (alloc_size > field->data_size)
             PB_RETURN_ERROR(stream, "bytes overflow");
-        bdest = (pb_bytes_array_t*)dest;
+        dest = (pb_bytes_array_t*)field->pData;
     }
 
-    bdest->size = (pb_size_t)size;
-    return pb_read(stream, bdest->bytes, size);
+    dest->size = (pb_size_t)size;
+    return pb_read(stream, dest->bytes, (size_t)size);
 }
 
-static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest)
+static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field)
 {
     uint32_t size;
     size_t alloc_size;
-    bool status;
+    pb_byte_t *dest = (pb_byte_t*)field->pData;
+
     if (!pb_decode_varint32(stream, &size))
         return false;
-    
+
+    if (size == (uint32_t)-1)
+        PB_RETURN_ERROR(stream, "size too large");
+
     /* Space for null terminator */
-    alloc_size = size + 1;
-    
+    alloc_size = (size_t)(size + 1);
+
     if (alloc_size < size)
         PB_RETURN_ERROR(stream, "size too large");
-    
+
     if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
     {
 #ifndef PB_ENABLE_MALLOC
         PB_RETURN_ERROR(stream, "no malloc support");
 #else
-        if (!allocate_field(stream, dest, alloc_size, 1))
+        if (stream->bytes_left < size)
+            PB_RETURN_ERROR(stream, "end-of-stream");
+
+        if (!allocate_field(stream, field->pData, alloc_size, 1))
             return false;
-        dest = *(void**)dest;
+        dest = *(pb_byte_t**)field->pData;
 #endif
     }
     else
@@ -1455,36 +1552,72 @@
             PB_RETURN_ERROR(stream, "string overflow");
     }
     
-    status = pb_read(stream, (pb_byte_t*)dest, size);
-    *((pb_byte_t*)dest + size) = 0;
-    return status;
+    dest[size] = 0;
+
+    if (!pb_read(stream, dest, (size_t)size))
+        return false;
+
+#ifdef PB_VALIDATE_UTF8
+    if (!pb_validate_utf8((const char*)dest))
+        PB_RETURN_ERROR(stream, "invalid utf8");
+#endif
+
+    return true;
 }
 
-static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest)
+static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field)
 {
-    bool status;
+    bool status = true;
+    bool submsg_consumed = false;
     pb_istream_t substream;
-    const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr;
-    
+
     if (!pb_make_string_substream(stream, &substream))
         return false;
     
-    if (field->ptr == NULL)
+    if (field->submsg_desc == NULL)
         PB_RETURN_ERROR(stream, "invalid field descriptor");
     
-    /* New array entries need to be initialized, while required and optional
-     * submessages have already been initialized in the top-level pb_decode. */
-    if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
-        status = pb_decode(&substream, submsg_fields, dest);
-    else
-        status = pb_decode_noinit(&substream, submsg_fields, dest);
+    /* Submessages can have a separate message-level callback that is called
+     * before decoding the message. Typically it is used to set callback fields
+     * inside oneofs. */
+    if (PB_LTYPE(field->type) == PB_LTYPE_SUBMSG_W_CB && field->pSize != NULL)
+    {
+        /* Message callback is stored right before pSize. */
+        pb_callback_t *callback = (pb_callback_t*)field->pSize - 1;
+        if (callback->funcs.decode)
+        {
+            status = callback->funcs.decode(&substream, field, &callback->arg);
+
+            if (substream.bytes_left == 0)
+            {
+                submsg_consumed = true;
+            }
+        }
+    }
+
+    /* Now decode the submessage contents */
+    if (status && !submsg_consumed)
+    {
+        unsigned int flags = 0;
+
+        /* Static required/optional fields are already initialized by top-level
+         * pb_decode(), no need to initialize them again. */
+        if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
+            PB_HTYPE(field->type) != PB_HTYPE_REPEATED)
+        {
+            flags = PB_DECODE_NOINIT;
+        }
+
+        status = pb_decode_inner(&substream, field->submsg_desc, field->pData, flags);
+    }
     
     if (!pb_close_string_substream(stream, &substream))
         return false;
+
     return status;
 }
 
-static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest)
+static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_iter_t *field)
 {
     uint32_t size;
 
@@ -1497,12 +1630,80 @@
     if (size == 0)
     {
         /* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */
-        memset(dest, 0, field->data_size);
+        memset(field->pData, 0, (size_t)field->data_size);
         return true;
     }
 
     if (size != field->data_size)
         PB_RETURN_ERROR(stream, "incorrect fixed length bytes size");
 
-    return pb_read(stream, (pb_byte_t*)dest, field->data_size);
+    return pb_read(stream, (pb_byte_t*)field->pData, (size_t)field->data_size);
 }
+
+#ifdef PB_CONVERT_DOUBLE_FLOAT
+bool pb_decode_double_as_float(pb_istream_t *stream, float *dest)
+{
+    uint_least8_t sign;
+    int exponent;
+    uint32_t mantissa;
+    uint64_t value;
+    union { float f; uint32_t i; } out;
+
+    if (!pb_decode_fixed64(stream, &value))
+        return false;
+
+    /* Decompose input value */
+    sign = (uint_least8_t)((value >> 63) & 1);
+    exponent = (int)((value >> 52) & 0x7FF) - 1023;
+    mantissa = (value >> 28) & 0xFFFFFF; /* Highest 24 bits */
+
+    /* Figure if value is in range representable by floats. */
+    if (exponent == 1024)
+    {
+        /* Special value */
+        exponent = 128;
+        mantissa >>= 1;
+    }
+    else
+    {
+        if (exponent > 127)
+        {
+            /* Too large, convert to infinity */
+            exponent = 128;
+            mantissa = 0;
+        }
+        else if (exponent < -150)
+        {
+            /* Too small, convert to zero */
+            exponent = -127;
+            mantissa = 0;
+        }
+        else if (exponent < -126)
+        {
+            /* Denormalized */
+            mantissa |= 0x1000000;
+            mantissa >>= (-126 - exponent);
+            exponent = -127;
+        }
+
+        /* Round off mantissa */
+        mantissa = (mantissa + 1) >> 1;
+
+        /* Check if mantissa went over 2.0 */
+        if (mantissa & 0x800000)
+        {
+            exponent += 1;
+            mantissa &= 0x7FFFFF;
+            mantissa >>= 1;
+        }
+    }
+
+    /* Combine fields */
+    out.i = mantissa;
+    out.i |= (uint32_t)(exponent + 127) << 23;
+    out.i |= (uint32_t)sign << 31;
+
+    *dest = out.f;
+    return true;
+}
+#endif
diff --git a/security/container/protos/nanopb/pb_decode.h b/security/container/protos/nanopb/pb_decode.h
index 398b24a..824acd4 100644
--- a/security/container/protos/nanopb/pb_decode.h
+++ b/security/container/protos/nanopb/pb_decode.h
@@ -45,6 +45,12 @@
 #endif
 };
 
+#ifndef PB_NO_ERRMSG
+#define PB_ISTREAM_EMPTY {0,0,0,0}
+#else
+#define PB_ISTREAM_EMPTY {0,0,0}
+#endif
+
 /***************************
  * Main decoding functions *
  ***************************/
@@ -65,44 +71,51 @@
  *    stream = pb_istream_from_buffer(buffer, count);
  *    pb_decode(&stream, MyMessage_fields, &msg);
  */
-bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
+bool pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct);
 
-/* Same as pb_decode, except does not initialize the destination structure
- * to default values. This is slightly faster if you need no default values
- * and just do memset(struct, 0, sizeof(struct)) yourself.
+/* Extended version of pb_decode, with several options to control
+ * the decoding process:
  *
- * This can also be used for 'merging' two messages, i.e. update only the
- * fields that exist in the new message.
+ * PB_DECODE_NOINIT:         Do not initialize the fields to default values.
+ *                           This is slightly faster if you do not need the default
+ *                           values and instead initialize the structure to 0 using
+ *                           e.g. memset(). This can also be used for merging two
+ *                           messages, i.e. combine already existing data with new
+ *                           values.
  *
- * Note: If this function returns with an error, it will not release any
- * dynamically allocated fields. You will need to call pb_release() yourself.
+ * PB_DECODE_DELIMITED:      Input message starts with the message size as varint.
+ *                           Corresponds to parseDelimitedFrom() in Google's
+ *                           protobuf API.
+ *
+ * PB_DECODE_NULLTERMINATED: Stop reading when field tag is read as 0. This allows
+ *                           reading null terminated messages.
+ *                           NOTE: Until nanopb-0.4.0, pb_decode() also allows
+ *                           null-termination. This behaviour is not supported in
+ *                           most other protobuf implementations, so PB_DECODE_DELIMITED
+ *                           is a better option for compatibility.
+ *
+ * Multiple flags can be combined with bitwise or (| operator)
  */
-bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
+#define PB_DECODE_NOINIT          0x01U
+#define PB_DECODE_DELIMITED       0x02U
+#define PB_DECODE_NULLTERMINATED  0x04U
+bool pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags);
 
-/* Same as pb_decode, except expects the stream to start with the message size
- * encoded as varint. Corresponds to parseDelimitedFrom() in Google's
- * protobuf API.
- */
-bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
-
-/* Same as pb_decode_delimited, except that it does not initialize the destination structure.
- * See pb_decode_noinit
- */
-bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
-
-/* Same as pb_decode, except allows the message to be terminated with a null byte.
- * NOTE: Until nanopb-0.4.0, pb_decode() also allows null-termination. This behaviour
- * is not supported in most other protobuf implementations, so pb_decode_delimited()
- * is a better option for compatibility.
- */
-bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
+/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
+#define pb_decode_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NOINIT)
+#define pb_decode_delimited(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED)
+#define pb_decode_delimited_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED | PB_DECODE_NOINIT)
+#define pb_decode_nullterminated(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NULLTERMINATED)
 
 #ifdef PB_ENABLE_MALLOC
 /* Release any allocated pointer fields. If you use dynamic allocation, you should
  * call this for any successfully decoded message when you are done with it. If
  * pb_decode() returns with an error, the message is already released.
  */
-void pb_release(const pb_field_t fields[], void *dest_struct);
+void pb_release(const pb_msgdesc_t *fields, void *dest_struct);
+#else
+/* Allocation is not supported, so release is no-op */
+#define pb_release(fields, dest_struct) PB_UNUSED(fields); PB_UNUSED(dest_struct);
 #endif
 
 
@@ -112,10 +125,13 @@
 
 /* Create an input stream for reading from a memory buffer.
  *
+ * msglen should be the actual length of the message, not the full size of
+ * allocated buffer.
+ *
  * Alternatively, you can use a custom stream that reads directly from e.g.
  * a file or a network socket.
  */
-pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize);
+pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen);
 
 /* Function to read from a pb_istream_t. You can use this if you need to
  * read some custom header data, or to read data in field callbacks.
@@ -134,7 +150,7 @@
 /* Skip the field payload data, given the wire type. */
 bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type);
 
-/* Decode an integer in the varint format. This works for bool, enum, int32,
+/* Decode an integer in the varint format. This works for enum, int32,
  * int64, uint32 and uint64 field types. */
 #ifndef PB_WITHOUT_64BIT
 bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest);
@@ -142,10 +158,13 @@
 #define pb_decode_varint pb_decode_varint32
 #endif
 
-/* Decode an integer in the varint format. This works for bool, enum, int32,
+/* Decode an integer in the varint format. This works for enum, int32,
  * and uint32 field types. */
 bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest);
 
+/* Decode a bool value in varint format. */
+bool pb_decode_bool(pb_istream_t *stream, bool *dest);
+
 /* Decode an integer in the zig-zagged svarint format. This works for sint32
  * and sint64. */
 #ifndef PB_WITHOUT_64BIT
@@ -164,6 +183,11 @@
 bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
 #endif
 
+#ifdef PB_CONVERT_DOUBLE_FLOAT
+/* Decode a double value into float variable. */
+bool pb_decode_double_as_float(pb_istream_t *stream, float *dest);
+#endif
+
 /* Make a limited-length substream for reading a PB_WT_STRING field. */
 bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream);
 bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream);
diff --git a/security/container/protos/nanopb/pb_encode.c b/security/container/protos/nanopb/pb_encode.c
index 089172c..de716f7 100644
--- a/security/container/protos/nanopb/pb_encode.c
+++ b/security/container/protos/nanopb/pb_encode.c
@@ -20,51 +20,31 @@
 /**************************************
  * Declarations internal to this file *
  **************************************/
-typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn;
-
 static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
-static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func);
-static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
+static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field);
+static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field);
+static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field);
+static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field);
 static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
-static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData);
-static void *pb_const_cast(const void *p);
-static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src);
-static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src);
+static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high);
+static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field);
+static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field);
 
 #ifdef PB_WITHOUT_64BIT
 #define pb_int64_t int32_t
 #define pb_uint64_t uint32_t
-
-static bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value);
 #else
 #define pb_int64_t int64_t
 #define pb_uint64_t uint64_t
 #endif
 
-/* --- Function pointers to field encoders ---
- * Order in the array must match pb_action_t LTYPE numbering.
- */
-static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = {
-    &pb_enc_varint,
-    &pb_enc_uvarint,
-    &pb_enc_svarint,
-    &pb_enc_fixed32,
-    &pb_enc_fixed64,
-    
-    &pb_enc_bytes,
-    &pb_enc_string,
-    &pb_enc_submessage,
-    NULL, /* extensions */
-    &pb_enc_fixed_length_bytes
-};
-
 /*******************************
  * pb_ostream_t implementation *
  *******************************/
@@ -100,10 +80,13 @@
 
 bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
 {
-    if (stream->callback != NULL)
+    if (count > 0 && stream->callback != NULL)
     {
-        if (stream->bytes_written + count > stream->max_size)
+        if (stream->bytes_written + count < stream->bytes_written ||
+            stream->bytes_written + count > stream->max_size)
+        {
             PB_RETURN_ERROR(stream, "stream full");
+        }
 
 #ifdef PB_BUFFER_ONLY
         if (!buf_write(stream, buf, count))
@@ -122,20 +105,40 @@
  * Encode a single field *
  *************************/
 
-/* Encode a static array. Handles the size calculations and possible packing. */
-static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field,
-                         const void *pData, size_t count, pb_encoder_t func)
+/* Read a bool value without causing undefined behavior even if the value
+ * is invalid. See issue #434 and
+ * https://stackoverflow.com/questions/27661768/weird-results-for-conditional
+ */
+static bool safe_read_bool(const void *pSize)
 {
+    const char *p = (const char *)pSize;
     size_t i;
-    const void *p;
+    for (i = 0; i < sizeof(bool); i++)
+    {
+        if (p[i] != 0)
+            return true;
+    }
+    return false;
+}
+
+/* Encode a static array. Handles the size calculations and possible packing. */
+static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field)
+{
+    pb_size_t i;
+    pb_size_t count;
+#ifndef PB_ENCODE_ARRAYS_UNPACKED
     size_t size;
-    
+#endif
+
+    count = *(pb_size_t*)field->pSize;
+
     if (count == 0)
         return true;
 
     if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size)
         PB_RETURN_ERROR(stream, "array max size exceeded");
     
+#ifndef PB_ENCODE_ARRAYS_UNPACKED
     /* We always pack arrays if the datatype allows it. */
     if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
     {
@@ -145,22 +148,23 @@
         /* Determine the total size of packed array. */
         if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
         {
-            size = 4 * count;
+            size = 4 * (size_t)count;
         }
         else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
         {
-            size = 8 * count;
+            size = 8 * (size_t)count;
         }
         else
         { 
             pb_ostream_t sizestream = PB_OSTREAM_SIZING;
-            p = pData;
+            void *pData_orig = field->pData;
             for (i = 0; i < count; i++)
             {
-                if (!func(&sizestream, field, p))
-                    return false;
-                p = (const char*)p + field->data_size;
+                if (!pb_enc_varint(&sizestream, field))
+                    PB_RETURN_ERROR(stream, PB_GET_ERROR(&sizestream));
+                field->pData = (char*)field->pData + field->data_size;
             }
+            field->pData = pData_orig;
             size = sizestream.bytes_written;
         }
         
@@ -171,22 +175,27 @@
             return pb_write(stream, NULL, size); /* Just sizing.. */
         
         /* Write the data */
-        p = pData;
         for (i = 0; i < count; i++)
         {
-            if (!func(stream, field, p))
-                return false;
-            p = (const char*)p + field->data_size;
+            if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32 || PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
+            {
+                if (!pb_enc_fixed(stream, field))
+                    return false;
+            }
+            else
+            {
+                if (!pb_enc_varint(stream, field))
+                    return false;
+            }
+
+            field->pData = (char*)field->pData + field->data_size;
         }
     }
-    else
+    else /* Unpacked fields */
+#endif
     {
-        p = pData;
         for (i = 0; i < count; i++)
         {
-            if (!pb_encode_tag_for_field(stream, field))
-                return false;
-
             /* Normally the data is stored directly in the array entries, but
              * for pointer-type string and bytes fields, the array entries are
              * actually pointers themselves also. So we have to dereference once
@@ -195,15 +204,32 @@
                 (PB_LTYPE(field->type) == PB_LTYPE_STRING ||
                  PB_LTYPE(field->type) == PB_LTYPE_BYTES))
             {
-                if (!func(stream, field, *(const void* const*)p))
+                bool status;
+                void *pData_orig = field->pData;
+                field->pData = *(void* const*)field->pData;
+
+                if (!field->pData)
+                {
+                    /* Null pointer in array is treated as empty string / bytes */
+                    status = pb_encode_tag_for_field(stream, field) &&
+                             pb_encode_varint(stream, 0);
+                }
+                else
+                {
+                    status = encode_basic_field(stream, field);
+                }
+
+                field->pData = pData_orig;
+
+                if (!status)
                     return false;
             }
             else
             {
-                if (!func(stream, field, p))
+                if (!encode_basic_field(stream, field))
                     return false;
             }
-            p = (const char*)p + field->data_size;
+            field->pData = (char*)field->pData + field->data_size;
         }
     }
     
@@ -212,44 +238,67 @@
 
 /* In proto3, all fields are optional and are only encoded if their value is "non-zero".
  * This function implements the check for the zero value. */
-static bool pb_check_proto3_default_value(const pb_field_t *field, const void *pData)
+static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field)
 {
     pb_type_t type = field->type;
-    const void *pSize = (const char*)pData + field->size_offset;
-
-    if (PB_HTYPE(type) == PB_HTYPE_REQUIRED)
-    {
-        /* Required proto2 fields inside proto3 submessage, pretty rare case */
-        return false;
-    }
-    else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
-    {
-        /* Repeated fields inside proto3 submessage: present if count != 0 */
-        return *(const pb_size_t*)pSize == 0;
-    }
-    else if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
-    {
-        /* Oneof fields */
-        return *(const pb_size_t*)pSize == 0;
-    }
-    else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset)
-    {
-        /* Proto2 optional fields inside proto3 submessage */
-        return *(const bool*)pSize == false;
-    }
-
-    /* Rest is proto3 singular fields */
 
     if (PB_ATYPE(type) == PB_ATYPE_STATIC)
     {
-        if (PB_LTYPE(type) == PB_LTYPE_BYTES)
+        if (PB_HTYPE(type) == PB_HTYPE_REQUIRED)
         {
-            const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData;
+            /* Required proto2 fields inside proto3 submessage, pretty rare case */
+            return false;
+        }
+        else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
+        {
+            /* Repeated fields inside proto3 submessage: present if count != 0 */
+            return *(const pb_size_t*)field->pSize == 0;
+        }
+        else if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
+        {
+            /* Oneof fields */
+            return *(const pb_size_t*)field->pSize == 0;
+        }
+        else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->pSize != NULL)
+        {
+            /* Proto2 optional fields inside proto3 message, or proto3
+             * submessage fields. */
+            return safe_read_bool(field->pSize) == false;
+        }
+        else if (field->descriptor->default_value)
+        {
+            /* Proto3 messages do not have default values, but proto2 messages
+             * can contain optional fields without has_fields (generator option 'proto3').
+             * In this case they must always be encoded, to make sure that the
+             * non-zero default value is overwritten.
+             */
+            return false;
+        }
+
+        /* Rest is proto3 singular fields */
+        if (PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
+        {
+            /* Simple integer / float fields */
+            pb_size_t i;
+            const char *p = (const char*)field->pData;
+            for (i = 0; i < field->data_size; i++)
+            {
+                if (p[i] != 0)
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+        else if (PB_LTYPE(type) == PB_LTYPE_BYTES)
+        {
+            const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)field->pData;
             return bytes->size == 0;
         }
         else if (PB_LTYPE(type) == PB_LTYPE_STRING)
         {
-            return *(const char*)pData == '\0';
+            return *(const char*)field->pData == '\0';
         }
         else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES)
         {
@@ -258,19 +307,20 @@
              * it anyway. */
             return field->data_size == 0;
         }
-        else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE)
+        else if (PB_LTYPE_IS_SUBMSG(type))
         {
             /* Check all fields in the submessage to find if any of them
              * are non-zero. The comparison cannot be done byte-per-byte
              * because the C struct may contain padding bytes that must
-             * be skipped.
+             * be skipped. Note that usually proto3 submessages have
+             * a separate has_field that is checked earlier in this if.
              */
             pb_field_iter_t iter;
-            if (pb_field_iter_begin(&iter, (const pb_field_t*)field->ptr, pb_const_cast(pData)))
+            if (pb_field_iter_begin(&iter, field->submsg_desc, field->pData))
             {
                 do
                 {
-                    if (!pb_check_proto3_default_value(iter.pos, iter.pData))
+                    if (!pb_check_proto3_default_value(&iter))
                     {
                         return false;
                     }
@@ -279,185 +329,162 @@
             return true;
         }
     }
-    
-	{
-	    /* Catch-all branch that does byte-per-byte comparison for zero value.
-	     *
-	     * This is for all pointer fields, and for static PB_LTYPE_VARINT,
-	     * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also
-	     * callback fields. These all have integer or pointer value which
-	     * can be compared with 0.
-	     */
-	    pb_size_t i;
-	    const char *p = (const char*)pData;
-	    for (i = 0; i < field->data_size; i++)
-	    {
-	        if (p[i] != 0)
-	        {
-	            return false;
-	        }
-	    }
+    else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
+    {
+        return field->pData == NULL;
+    }
+    else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
+    {
+        if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
+        {
+            const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData;
+            return extension == NULL;
+        }
+        else if (field->descriptor->field_callback == pb_default_field_callback)
+        {
+            pb_callback_t *pCallback = (pb_callback_t*)field->pData;
+            return pCallback->funcs.encode == NULL;
+        }
+        else
+        {
+            return field->descriptor->field_callback == NULL;
+        }
+    }
 
-	    return true;
-	}
+    return false; /* Not typically reached, safe default for weird special cases. */
 }
 
 /* Encode a field with static or pointer allocation, i.e. one whose data
  * is available to the encoder directly. */
-static bool checkreturn encode_basic_field(pb_ostream_t *stream,
-    const pb_field_t *field, const void *pData)
+static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
-    pb_encoder_t func;
-    bool implicit_has;
-    const void *pSize = &implicit_has;
-    
-    func = PB_ENCODERS[PB_LTYPE(field->type)];
-    
-    if (field->size_offset)
+    if (!field->pData)
     {
-        /* Static optional, repeated or oneof field */
-        pSize = (const char*)pData + field->size_offset;
-    }
-    else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL)
-    {
-        /* Proto3 style field, optional but without explicit has_ field. */
-        implicit_has = !pb_check_proto3_default_value(field, pData);
-    }
-    else
-    {
-        /* Required field, always present */
-        implicit_has = true;
+        /* Missing pointer field */
+        return true;
     }
 
-    if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
-    {
-        /* pData is a pointer to the field, which contains pointer to
-         * the data. If the 2nd pointer is NULL, it is interpreted as if
-         * the has_field was false.
-         */
-        pData = *(const void* const*)pData;
-        implicit_has = (pData != NULL);
-    }
+    if (!pb_encode_tag_for_field(stream, field))
+        return false;
 
-    switch (PB_HTYPE(field->type))
+    switch (PB_LTYPE(field->type))
     {
-        case PB_HTYPE_REQUIRED:
-            if (!pData)
-                PB_RETURN_ERROR(stream, "missing required field");
-            if (!pb_encode_tag_for_field(stream, field))
-                return false;
-            if (!func(stream, field, pData))
-                return false;
-            break;
-        
-        case PB_HTYPE_OPTIONAL:
-            if (*(const bool*)pSize)
-            {
-                if (!pb_encode_tag_for_field(stream, field))
-                    return false;
-            
-                if (!func(stream, field, pData))
-                    return false;
-            }
-            break;
-        
-        case PB_HTYPE_REPEATED: {
-            pb_size_t count;
-            if (field->size_offset != 0) {
-                count = *(const pb_size_t*)pSize;
-            } else {
-                count = field->array_size;
-            }
-            if (!encode_array(stream, field, pData, count, func))
-                return false;
-            break;
-        }
-        
-        case PB_HTYPE_ONEOF:
-            if (*(const pb_size_t*)pSize == field->tag)
-            {
-                if (!pb_encode_tag_for_field(stream, field))
-                    return false;
+        case PB_LTYPE_BOOL:
+            return pb_enc_bool(stream, field);
 
-                if (!func(stream, field, pData))
-                    return false;
-            }
-            break;
-            
+        case PB_LTYPE_VARINT:
+        case PB_LTYPE_UVARINT:
+        case PB_LTYPE_SVARINT:
+            return pb_enc_varint(stream, field);
+
+        case PB_LTYPE_FIXED32:
+        case PB_LTYPE_FIXED64:
+            return pb_enc_fixed(stream, field);
+
+        case PB_LTYPE_BYTES:
+            return pb_enc_bytes(stream, field);
+
+        case PB_LTYPE_STRING:
+            return pb_enc_string(stream, field);
+
+        case PB_LTYPE_SUBMESSAGE:
+        case PB_LTYPE_SUBMSG_W_CB:
+            return pb_enc_submessage(stream, field);
+
+        case PB_LTYPE_FIXED_LENGTH_BYTES:
+            return pb_enc_fixed_length_bytes(stream, field);
+
         default:
             PB_RETURN_ERROR(stream, "invalid field type");
     }
-    
-    return true;
 }
 
 /* Encode a field with callback semantics. This means that a user function is
  * called to provide and encode the actual data. */
-static bool checkreturn encode_callback_field(pb_ostream_t *stream,
-    const pb_field_t *field, const void *pData)
+static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
-    const pb_callback_t *callback = (const pb_callback_t*)pData;
-    
-#ifdef PB_OLD_CALLBACK_STYLE
-    const void *arg = callback->arg;
-#else
-    void * const *arg = &(callback->arg);
-#endif    
-    
-    if (callback->funcs.encode != NULL)
+    if (field->descriptor->field_callback != NULL)
     {
-        if (!callback->funcs.encode(stream, field, arg))
+        if (!field->descriptor->field_callback(NULL, stream, field))
             PB_RETURN_ERROR(stream, "callback error");
     }
     return true;
 }
 
-/* Encode a single field of any callback or static type. */
-static bool checkreturn encode_field(pb_ostream_t *stream,
-    const pb_field_t *field, const void *pData)
+/* Encode a single field of any callback, pointer or static type. */
+static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field)
 {
-    switch (PB_ATYPE(field->type))
+    /* Check field presence */
+    if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
     {
-        case PB_ATYPE_STATIC:
-        case PB_ATYPE_POINTER:
-            return encode_basic_field(stream, field, pData);
-        
-        case PB_ATYPE_CALLBACK:
-            return encode_callback_field(stream, field, pData);
-        
-        default:
-            PB_RETURN_ERROR(stream, "invalid field type");
+        if (*(const pb_size_t*)field->pSize != field->tag)
+        {
+            /* Different type oneof field */
+            return true;
+        }
     }
-}
-
-/* Default handler for extension fields. Expects to have a pb_field_t
- * pointer in the extension->type->arg field. */
-static bool checkreturn default_extension_encoder(pb_ostream_t *stream,
-    const pb_extension_t *extension)
-{
-    const pb_field_t *field = (const pb_field_t*)extension->type->arg;
-    
-    if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
+    else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL)
     {
-        /* For pointer extensions, the pointer is stored directly
-         * in the extension structure. This avoids having an extra
-         * indirection. */
-        return encode_field(stream, field, &extension->dest);
+        if (field->pSize)
+        {
+            if (safe_read_bool(field->pSize) == false)
+            {
+                /* Missing optional field */
+                return true;
+            }
+        }
+        else if (PB_ATYPE(field->type) == PB_ATYPE_STATIC)
+        {
+            /* Proto3 singular field */
+            if (pb_check_proto3_default_value(field))
+                return true;
+        }
+    }
+
+    if (!field->pData)
+    {
+        if (PB_HTYPE(field->type) == PB_HTYPE_REQUIRED)
+            PB_RETURN_ERROR(stream, "missing required field");
+
+        /* Pointer field set to NULL */
+        return true;
+    }
+
+    /* Then encode field contents */
+    if (PB_ATYPE(field->type) == PB_ATYPE_CALLBACK)
+    {
+        return encode_callback_field(stream, field);
+    }
+    else if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
+    {
+        return encode_array(stream, field);
     }
     else
     {
-        return encode_field(stream, field, extension->dest);
+        return encode_basic_field(stream, field);
     }
 }
 
+/* Default handler for extension fields. Expects to have a pb_msgdesc_t
+ * pointer in the extension->type->arg field, pointing to a message with
+ * only one field in it.  */
+static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension)
+{
+    pb_field_iter_t iter;
+
+    if (!pb_field_iter_begin_extension_const(&iter, extension))
+        PB_RETURN_ERROR(stream, "invalid extension");
+
+    return encode_field(stream, &iter);
+}
+
+
 /* Walk through all the registered extensions and give them a chance
  * to encode themselves. */
-static bool checkreturn encode_extension_field(pb_ostream_t *stream,
-    const pb_field_t *field, const void *pData)
+static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
-    const pb_extension_t *extension = *(const pb_extension_t* const *)pData;
-    PB_UNUSED(field);
-    
+    const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData;
+
     while (extension)
     {
         bool status;
@@ -479,35 +506,23 @@
  * Encode all fields *
  *********************/
 
-static void *pb_const_cast(const void *p)
-{
-    /* Note: this casts away const, in order to use the common field iterator
-     * logic for both encoding and decoding. */
-    union {
-        void *p1;
-        const void *p2;
-    } t;
-    t.p2 = p;
-    return t.p1;
-}
-
-bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
+bool checkreturn pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct)
 {
     pb_field_iter_t iter;
-    if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct)))
+    if (!pb_field_iter_begin_const(&iter, fields, src_struct))
         return true; /* Empty message type */
     
     do {
-        if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION)
+        if (PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION)
         {
             /* Special case for the extension field placeholder */
-            if (!encode_extension_field(stream, iter.pos, iter.pData))
+            if (!encode_extension_field(stream, &iter))
                 return false;
         }
         else
         {
             /* Regular field */
-            if (!encode_field(stream, iter.pos, iter.pData))
+            if (!encode_field(stream, &iter))
                 return false;
         }
     } while (pb_field_iter_next(&iter));
@@ -515,22 +530,28 @@
     return true;
 }
 
-bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
+bool checkreturn pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags)
 {
+  if ((flags & PB_ENCODE_DELIMITED) != 0)
+  {
     return pb_encode_submessage(stream, fields, src_struct);
-}
-
-bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
-{
+  }
+  else if ((flags & PB_ENCODE_NULLTERMINATED) != 0)
+  {
     const pb_byte_t zero = 0;
 
     if (!pb_encode(stream, fields, src_struct))
         return false;
 
     return pb_write(stream, &zero, 1);
+  }
+  else
+  {
+    return pb_encode(stream, fields, src_struct);
+  }
 }
 
-bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct)
+bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct)
 {
     pb_ostream_t stream = PB_OSTREAM_SIZING;
     
@@ -545,52 +566,57 @@
  * Helper functions *
  ********************/
 
-#ifdef PB_WITHOUT_64BIT
-bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value)
+/* This function avoids 64-bit shifts as they are quite slow on many platforms. */
+static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high)
 {
-  pb_byte_t buffer[10];
-  size_t i = 0;
-  size_t compensation = 32;/* we need to compensate 32 bits all set to 1 */
+    size_t i = 0;
+    pb_byte_t buffer[10];
+    pb_byte_t byte = (pb_byte_t)(low & 0x7F);
+    low >>= 7;
 
-  while (value)
-  {
-    buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80);
-    value >>= 7;
-    if (compensation)
+    while (i < 4 && (low != 0 || high != 0))
     {
-      /* re-set all the compensation bits we can or need */
-      size_t bits = compensation > 7 ? 7 : compensation;
-      value ^= (pb_uint64_t)((0xFFu >> (8 - bits)) << 25); /* set the number of bits needed on the lowest of the most significant 7 bits */
-      compensation -= bits;
+        byte |= 0x80;
+        buffer[i++] = byte;
+        byte = (pb_byte_t)(low & 0x7F);
+        low >>= 7;
     }
-    i++;
-  }
-  buffer[i - 1] &= 0x7F; /* Unset top bit on last byte */
 
-  return pb_write(stream, buffer, i);
+    if (high)
+    {
+        byte = (pb_byte_t)(byte | ((high & 0x07) << 4));
+        high >>= 3;
+
+        while (high)
+        {
+            byte |= 0x80;
+            buffer[i++] = byte;
+            byte = (pb_byte_t)(high & 0x7F);
+            high >>= 7;
+        }
+    }
+
+    buffer[i++] = byte;
+
+    return pb_write(stream, buffer, i);
 }
-#endif
 
 bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value)
 {
-    pb_byte_t buffer[10];
-    size_t i = 0;
-    
     if (value <= 0x7F)
     {
-        pb_byte_t v = (pb_byte_t)value;
-        return pb_write(stream, &v, 1);
+        /* Fast path: single byte */
+        pb_byte_t byte = (pb_byte_t)value;
+        return pb_write(stream, &byte, 1);
     }
-    
-    while (value)
+    else
     {
-        buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80);
-        value >>= 7;
-        i++;
+#ifdef PB_WITHOUT_64BIT
+        return pb_encode_varint_32(stream, value, 0);
+#else
+        return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)(value >> 32));
+#endif
     }
-    buffer[i-1] &= 0x7F; /* Unset top bit on last byte */
-    
-    return pb_write(stream, buffer, i);
 }
 
 bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value)
@@ -638,11 +664,12 @@
     return pb_encode_varint(stream, tag);
 }
 
-bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field)
+bool pb_encode_tag_for_field ( pb_ostream_t* stream, const pb_field_iter_t* field )
 {
     pb_wire_type_t wiretype;
     switch (PB_LTYPE(field->type))
     {
+        case PB_LTYPE_BOOL:
         case PB_LTYPE_VARINT:
         case PB_LTYPE_UVARINT:
         case PB_LTYPE_SVARINT:
@@ -660,6 +687,7 @@
         case PB_LTYPE_BYTES:
         case PB_LTYPE_STRING:
         case PB_LTYPE_SUBMESSAGE:
+        case PB_LTYPE_SUBMSG_W_CB:
         case PB_LTYPE_FIXED_LENGTH_BYTES:
             wiretype = PB_WT_STRING;
             break;
@@ -679,7 +707,7 @@
     return pb_write(stream, buffer, size);
 }
 
-bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct)
+bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct)
 {
     /* First calculate the message size using a non-writing substream. */
     pb_ostream_t substream = PB_OSTREAM_SIZING;
@@ -731,139 +759,229 @@
 
 /* Field encoders */
 
-static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
-    pb_int64_t value = 0;
-    
-    if (field->data_size == sizeof(int_least8_t))
-        value = *(const int_least8_t*)src;
-    else if (field->data_size == sizeof(int_least16_t))
-        value = *(const int_least16_t*)src;
-    else if (field->data_size == sizeof(int32_t))
-        value = *(const int32_t*)src;
-    else if (field->data_size == sizeof(pb_int64_t))
-        value = *(const pb_int64_t*)src;
-    else
-        PB_RETURN_ERROR(stream, "invalid data_size");
-    
-#ifdef PB_WITHOUT_64BIT
-    if (value < 0)
-      return pb_encode_negative_varint(stream, (pb_uint64_t)value);
-    else
-#endif
-      return pb_encode_varint(stream, (pb_uint64_t)value);
-}
-
-static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
-    pb_uint64_t value = 0;
-    
-    if (field->data_size == sizeof(uint_least8_t))
-        value = *(const uint_least8_t*)src;
-    else if (field->data_size == sizeof(uint_least16_t))
-        value = *(const uint_least16_t*)src;
-    else if (field->data_size == sizeof(uint32_t))
-        value = *(const uint32_t*)src;
-    else if (field->data_size == sizeof(pb_uint64_t))
-        value = *(const pb_uint64_t*)src;
-    else
-        PB_RETURN_ERROR(stream, "invalid data_size");
-    
+    uint32_t value = safe_read_bool(field->pData) ? 1 : 0;
+    PB_UNUSED(field);
     return pb_encode_varint(stream, value);
 }
 
-static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
-    pb_int64_t value = 0;
-    
-    if (field->data_size == sizeof(int_least8_t))
-        value = *(const int_least8_t*)src;
-    else if (field->data_size == sizeof(int_least16_t))
-        value = *(const int_least16_t*)src;
-    else if (field->data_size == sizeof(int32_t))
-        value = *(const int32_t*)src;
-    else if (field->data_size == sizeof(pb_int64_t))
-        value = *(const pb_int64_t*)src;
+    if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT)
+    {
+        /* Perform unsigned integer extension */
+        pb_uint64_t value = 0;
+
+        if (field->data_size == sizeof(uint_least8_t))
+            value = *(const uint_least8_t*)field->pData;
+        else if (field->data_size == sizeof(uint_least16_t))
+            value = *(const uint_least16_t*)field->pData;
+        else if (field->data_size == sizeof(uint32_t))
+            value = *(const uint32_t*)field->pData;
+        else if (field->data_size == sizeof(pb_uint64_t))
+            value = *(const pb_uint64_t*)field->pData;
+        else
+            PB_RETURN_ERROR(stream, "invalid data_size");
+
+        return pb_encode_varint(stream, value);
+    }
     else
-        PB_RETURN_ERROR(stream, "invalid data_size");
-    
-    return pb_encode_svarint(stream, value);
-}
+    {
+        /* Perform signed integer extension */
+        pb_int64_t value = 0;
 
-static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src)
-{
-    PB_UNUSED(field);
-#ifndef PB_WITHOUT_64BIT
-    return pb_encode_fixed64(stream, src);
-#else
-    PB_UNUSED(src);
-    PB_RETURN_ERROR(stream, "no 64bit support");
+        if (field->data_size == sizeof(int_least8_t))
+            value = *(const int_least8_t*)field->pData;
+        else if (field->data_size == sizeof(int_least16_t))
+            value = *(const int_least16_t*)field->pData;
+        else if (field->data_size == sizeof(int32_t))
+            value = *(const int32_t*)field->pData;
+        else if (field->data_size == sizeof(pb_int64_t))
+            value = *(const pb_int64_t*)field->pData;
+        else
+            PB_RETURN_ERROR(stream, "invalid data_size");
+
+        if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT)
+            return pb_encode_svarint(stream, value);
+#ifdef PB_WITHOUT_64BIT
+        else if (value < 0)
+            return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)-1);
 #endif
+        else
+            return pb_encode_varint(stream, (pb_uint64_t)value);
+
+    }
 }
 
-static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
-    PB_UNUSED(field);
-    return pb_encode_fixed32(stream, src);
+#ifdef PB_CONVERT_DOUBLE_FLOAT
+    if (field->data_size == sizeof(float) && PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
+    {
+        return pb_encode_float_as_double(stream, *(float*)field->pData);
+    }
+#endif
+
+    if (field->data_size == sizeof(uint32_t))
+    {
+        return pb_encode_fixed32(stream, field->pData);
+    }
+#ifndef PB_WITHOUT_64BIT
+    else if (field->data_size == sizeof(uint64_t))
+    {
+        return pb_encode_fixed64(stream, field->pData);
+    }
+#endif
+    else
+    {
+        PB_RETURN_ERROR(stream, "invalid data_size");
+    }
 }
 
-static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
     const pb_bytes_array_t *bytes = NULL;
 
-    bytes = (const pb_bytes_array_t*)src;
+    bytes = (const pb_bytes_array_t*)field->pData;
     
-    if (src == NULL)
+    if (bytes == NULL)
     {
         /* Treat null pointer as an empty bytes field */
         return pb_encode_string(stream, NULL, 0);
     }
     
     if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
-        PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) > field->data_size)
+        bytes->size > field->data_size - offsetof(pb_bytes_array_t, bytes))
     {
         PB_RETURN_ERROR(stream, "bytes size exceeded");
     }
     
-    return pb_encode_string(stream, bytes->bytes, bytes->size);
+    return pb_encode_string(stream, bytes->bytes, (size_t)bytes->size);
 }
 
-static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
     size_t size = 0;
-    size_t max_size = field->data_size;
-    const char *p = (const char*)src;
+    size_t max_size = (size_t)field->data_size;
+    const char *str = (const char*)field->pData;
     
     if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
+    {
         max_size = (size_t)-1;
+    }
+    else
+    {
+        /* pb_dec_string() assumes string fields end with a null
+         * terminator when the type isn't PB_ATYPE_POINTER, so we
+         * shouldn't allow more than max-1 bytes to be written to
+         * allow space for the null terminator.
+         */
+        if (max_size == 0)
+            PB_RETURN_ERROR(stream, "zero-length string");
 
-    if (src == NULL)
+        max_size -= 1;
+    }
+
+
+    if (str == NULL)
     {
         size = 0; /* Treat null pointer as an empty string */
     }
     else
     {
+        const char *p = str;
+
         /* strnlen() is not always available, so just use a loop */
         while (size < max_size && *p != '\0')
         {
             size++;
             p++;
         }
+
+        if (*p != '\0')
+        {
+            PB_RETURN_ERROR(stream, "unterminated string");
+        }
     }
 
-    return pb_encode_string(stream, (const pb_byte_t*)src, size);
+#ifdef PB_VALIDATE_UTF8
+    if (!pb_validate_utf8(str))
+        PB_RETURN_ERROR(stream, "invalid utf8");
+#endif
+
+    return pb_encode_string(stream, (const pb_byte_t*)str, size);
 }
 
-static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
-    if (field->ptr == NULL)
+    if (field->submsg_desc == NULL)
         PB_RETURN_ERROR(stream, "invalid field descriptor");
+
+    if (PB_LTYPE(field->type) == PB_LTYPE_SUBMSG_W_CB && field->pSize != NULL)
+    {
+        /* Message callback is stored right before pSize. */
+        pb_callback_t *callback = (pb_callback_t*)field->pSize - 1;
+        if (callback->funcs.encode)
+        {
+            if (!callback->funcs.encode(stream, field, &callback->arg))
+                return false;
+        }
+    }
     
-    return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src);
+    return pb_encode_submessage(stream, field->submsg_desc, field->pData);
 }
 
-static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src)
+static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field)
 {
-    return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size);
+    return pb_encode_string(stream, (const pb_byte_t*)field->pData, (size_t)field->data_size);
 }
 
+#ifdef PB_CONVERT_DOUBLE_FLOAT
+bool pb_encode_float_as_double(pb_ostream_t *stream, float value)
+{
+    union { float f; uint32_t i; } in;
+    uint_least8_t sign;
+    int exponent;
+    uint64_t mantissa;
+
+    in.f = value;
+
+    /* Decompose input value */
+    sign = (uint_least8_t)((in.i >> 31) & 1);
+    exponent = (int)((in.i >> 23) & 0xFF) - 127;
+    mantissa = in.i & 0x7FFFFF;
+
+    if (exponent == 128)
+    {
+        /* Special value (NaN etc.) */
+        exponent = 1024;
+    }
+    else if (exponent == -127)
+    {
+        if (!mantissa)
+        {
+            /* Zero */
+            exponent = -1023;
+        }
+        else
+        {
+            /* Denormalized */
+            mantissa <<= 1;
+            while (!(mantissa & 0x800000))
+            {
+                mantissa <<= 1;
+                exponent--;
+            }
+            mantissa &= 0x7FFFFF;
+        }
+    }
+
+    /* Combine fields */
+    mantissa <<= 29;
+    mantissa |= (uint64_t)(exponent + 1023) << 52;
+    mantissa |= (uint64_t)sign << 63;
+
+    return pb_encode_fixed64(stream, &mantissa);
+}
+#endif
diff --git a/security/container/protos/nanopb/pb_encode.h b/security/container/protos/nanopb/pb_encode.h
index 8bf78dd..9cff22a 100644
--- a/security/container/protos/nanopb/pb_encode.h
+++ b/security/container/protos/nanopb/pb_encode.h
@@ -64,22 +64,31 @@
  *    stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
  *    pb_encode(&stream, MyMessage_fields, &msg);
  */
-bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
+bool pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
 
-/* Same as pb_encode, but prepends the length of the message as a varint.
- * Corresponds to writeDelimitedTo() in Google's protobuf API.
+/* Extended version of pb_encode, with several options to control the
+ * encoding process:
+ *
+ * PB_ENCODE_DELIMITED:      Prepend the length of message as a varint.
+ *                           Corresponds to writeDelimitedTo() in Google's
+ *                           protobuf API.
+ *
+ * PB_ENCODE_NULLTERMINATED: Append a null byte to the message for termination.
+ *                           NOTE: This behaviour is not supported in most other
+ *                           protobuf implementations, so PB_ENCODE_DELIMITED
+ *                           is a better option for compatibility.
  */
-bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
+#define PB_ENCODE_DELIMITED       0x02U
+#define PB_ENCODE_NULLTERMINATED  0x04U
+bool pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags);
 
-/* Same as pb_encode, but appends a null byte to the message for termination.
- * NOTE: This behaviour is not supported in most other protobuf implementations, so pb_encode_delimited()
- * is a better option for compatibility.
- */
-bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
+/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
+#define pb_encode_delimited(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_DELIMITED)
+#define pb_encode_nullterminated(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_NULLTERMINATED)
 
 /* Encode the message to get the size of the encoded data, but do not store
  * the data. */
-bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct);
+bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct);
 
 /**************************************
  * Functions for manipulating streams *
@@ -121,9 +130,9 @@
 
 /* Encode field header based on type and field number defined in the field
  * structure. Call this from the callback before writing out field contents. */
-bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field);
+bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_iter_t *field);
 
-/* Encode field header by manually specifing wire type. You need to use this
+/* Encode field header by manually specifying wire type. You need to use this
  * if you want to write out packed arrays from a callback field. */
 bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number);
 
@@ -156,12 +165,18 @@
 bool pb_encode_fixed64(pb_ostream_t *stream, const void *value);
 #endif
 
+#ifdef PB_CONVERT_DOUBLE_FLOAT
+/* Encode a float value so that it appears like a double in the encoded
+ * message. */
+bool pb_encode_float_as_double(pb_ostream_t *stream, float value);
+#endif
+
 /* Encode a submessage field.
  * You need to pass the pb_field_t array and pointer to struct, just like
  * with pb_encode(). This internally encodes the submessage twice, first to
  * calculate message size and then to actually write it out.
  */
-bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
+bool pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
 
 #ifdef __cplusplus
 } /* extern "C" */