msgbuf: Define a separate msgbuf structure for encode/decode function

Define separate msgbuf structures to avoid casting away const-qualifiers
in the msgbuf constructor function:

* pldm_msgbuf_rw: for encode functions with non const-qualified buffer
* pldm_msgbuf_ro: for decode functions with const-qualified buffer

Further, use _Generic() to keep the API ergonomic while still yielding a
compile error when wrong msgbuf type is passed.

Change-Id: I71dbcb7996e9fb402b49870fce539a939c1497e5
Signed-off-by: John Chung <john.chung@arm.com>
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/dsp/base.c b/src/dsp/base.c
index 05fcb9a..816a871 100644
--- a/src/dsp/base.c
+++ b/src/dsp/base.c
@@ -506,7 +506,7 @@
 int decode_set_tid_req(const struct pldm_msg *msg, size_t payload_length,
 		       uint8_t *tid)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !tid) {
@@ -533,7 +533,7 @@
 				 uint32_t *section_offset,
 				 uint32_t *section_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || pldm_type == NULL || transfer_opflag == NULL ||
@@ -587,7 +587,7 @@
 	uint8_t instance_id, const struct pldm_base_multipart_receive_req *req,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (req == NULL || msg == NULL || payload_length == NULL) {
@@ -627,7 +627,7 @@
 	struct pldm_base_multipart_receive_resp *resp,
 	uint32_t *data_integrity_checksum)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || resp == NULL || data_integrity_checksum == NULL) {
@@ -663,7 +663,7 @@
 	if (resp->data.length > 0) {
 		resp->data.ptr = NULL;
 		pldm_msgbuf_span_required(buf, resp->data.length,
-					  (void **)&resp->data.ptr);
+					  (const void **)&resp->data.ptr);
 	}
 
 	if (resp->transfer_flag !=
@@ -680,7 +680,7 @@
 	const struct pldm_base_multipart_receive_resp *resp, uint32_t checksum,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !resp || !payload_length || !resp->data.ptr) {
@@ -795,7 +795,7 @@
 	const struct pldm_base_negotiate_transfer_params_req *req,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (req == NULL || msg == NULL || payload_length == NULL) {
@@ -837,7 +837,7 @@
 	const struct pldm_msg *msg, size_t payload_length,
 	struct pldm_base_negotiate_transfer_params_resp *resp)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || resp == NULL) {
diff --git a/src/dsp/file.c b/src/dsp/file.c
index 07a283c..f22e977 100644
--- a/src/dsp/file.c
+++ b/src/dsp/file.c
@@ -18,7 +18,7 @@
 				 const struct pldm_file_df_open_req *req,
 				 struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (req == NULL || msg == NULL) {
@@ -53,7 +53,7 @@
 				 size_t payload_length,
 				 struct pldm_file_df_open_req *req)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !req) {
@@ -77,7 +77,7 @@
 				  const struct pldm_file_df_open_resp *resp,
 				  struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !resp) {
@@ -114,7 +114,7 @@
 				  size_t payload_length,
 				  struct pldm_file_df_open_resp *resp)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !resp) {
@@ -149,7 +149,7 @@
 				  const struct pldm_file_df_close_req *req,
 				  struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (!req || !msg) {
@@ -184,7 +184,7 @@
 				  size_t payload_length,
 				  struct pldm_file_df_close_req *req)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !req) {
@@ -208,7 +208,7 @@
 				   const struct pldm_file_df_close_resp *resp,
 				   struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !resp) {
@@ -256,7 +256,7 @@
 	uint8_t instance_id, const struct pldm_file_df_heartbeat_req *req,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (!req || !msg) {
@@ -291,7 +291,7 @@
 				       size_t payload_length,
 				       struct pldm_file_df_heartbeat_resp *resp)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !resp) {
diff --git a/src/dsp/firmware_update.c b/src/dsp/firmware_update.c
index 7381546..e7befe8 100644
--- a/src/dsp/firmware_update.c
+++ b/src/dsp/firmware_update.c
@@ -393,11 +393,11 @@
 	uint32_t package_header_checksum = 0;
 	size_t package_header_variable_size;
 	size_t package_header_payload_size;
+	const void *package_payload_offset;
 	size_t package_header_areas_size;
 	uint16_t package_header_size;
-	void *package_payload_offset;
 	size_t package_payload_size;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int checksums = 1;
 	int rc;
 
@@ -511,8 +511,9 @@
 		return pldm_msgbuf_discard(buf, rc);
 	}
 
-	pldm_msgbuf_span_required(buf, hdr->package_version_string.length,
-				  (void **)&hdr->package_version_string.ptr);
+	pldm_msgbuf_span_required(
+		buf, hdr->package_version_string.length,
+		(const void **)&hdr->package_version_string.ptr);
 
 	if (package_header_size < (PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE + 3 +
 				   checksums * sizeof(uint32_t))) {
@@ -530,7 +531,7 @@
 	package_header_areas_size = package_header_variable_size -
 				    hdr->package_version_string.length;
 	rc = pldm_msgbuf_span_required(buf, package_header_areas_size,
-				       (void **)&pkg->areas.ptr);
+				       (const void **)&pkg->areas.ptr);
 	if (rc) {
 		return pldm_msgbuf_discard(buf, rc);
 	}
@@ -638,12 +639,12 @@
 }
 
 /* Currently only used for decode_firmware_device_id_record_errno() */
-static int pldm_msgbuf_init_dynamic_uint16(struct pldm_msgbuf *buf, size_t req,
-					   void *data, size_t len,
+static int pldm_msgbuf_init_dynamic_uint16(struct pldm_msgbuf_ro *buf,
+					   size_t req, void *data, size_t len,
 					   void **tail_data, size_t *tail_len)
 {
+	const void *dyn_start;
 	size_t dyn_length;
-	void *dyn_start;
 	int rc;
 
 	rc = pldm_msgbuf_init_errno(buf, req, data, len);
@@ -676,7 +677,8 @@
 		return pldm_msgbuf_discard(buf, rc);
 	}
 
-	rc = pldm_msgbuf_span_remaining(buf, tail_data, tail_len);
+	rc = pldm_msgbuf_span_remaining(buf, (const void **)tail_data,
+					tail_len);
 	if (rc) {
 		return pldm_msgbuf_discard(buf, rc);
 	}
@@ -696,7 +698,7 @@
 	struct pldm_package_firmware_device_id_record *rec)
 {
 	size_t firmware_device_package_data_offset;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	uint16_t record_len = 0;
 	int rc;
 
@@ -756,7 +758,7 @@
 	assert((hdr->component_bitmap_bit_length & 7) == 0);
 	rc = pldm_msgbuf_span_required(
 		buf, hdr->component_bitmap_bit_length / 8,
-		(void **)&rec->applicable_components.bitmap.ptr);
+		(const void **)&rec->applicable_components.bitmap.ptr);
 	if (rc) {
 		return pldm_msgbuf_discard(buf, rc);
 	}
@@ -765,7 +767,7 @@
 
 	pldm_msgbuf_span_required(
 		buf, rec->component_image_set_version_string.length,
-		(void **)&rec->component_image_set_version_string.ptr);
+		(const void **)&rec->component_image_set_version_string.ptr);
 
 	/* The total length reserved for `package_data` and `reference_manifest_data` */
 	firmware_device_package_data_offset =
@@ -773,12 +775,12 @@
 		rec->reference_manifest_data.length;
 
 	pldm_msgbuf_span_until(buf, firmware_device_package_data_offset,
-			       (void **)&rec->record_descriptors.ptr,
+			       (const void **)&rec->record_descriptors.ptr,
 			       &rec->record_descriptors.length);
 
 	pldm_msgbuf_span_required(
 		buf, rec->firmware_device_package_data.length,
-		(void **)&rec->firmware_device_package_data.ptr);
+		(const void **)&rec->firmware_device_package_data.ptr);
 	if (!rec->firmware_device_package_data.length) {
 		rec->firmware_device_package_data.ptr = NULL;
 	}
@@ -787,7 +789,7 @@
 	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
 		pldm_msgbuf_span_required(
 			buf, rec->reference_manifest_data.length,
-			(void **)&rec->reference_manifest_data.ptr);
+			(const void **)&rec->reference_manifest_data.ptr);
 
 	} else {
 		assert(rec->reference_manifest_data.length == 0);
@@ -851,7 +853,7 @@
 int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
 				     struct pldm_descriptor *desc)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!iter || !iter->field || !desc) {
@@ -872,9 +874,9 @@
 
 	desc->descriptor_data = NULL;
 	pldm_msgbuf_span_required(buf, desc->descriptor_length,
-				  (void **)&desc->descriptor_data);
+				  (const void **)&desc->descriptor_data);
 	iter->field->ptr = NULL;
-	pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
+	pldm_msgbuf_span_remaining(buf, (const void **)&iter->field->ptr,
 				   &iter->field->length);
 
 	return pldm_msgbuf_complete(buf);
@@ -1149,7 +1151,7 @@
 	const struct pldm_descriptor *descriptors, struct pldm_msg *msg,
 	size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (descriptors == NULL || msg == NULL || payload_length == NULL) {
@@ -1324,7 +1326,7 @@
 	const struct pldm_get_firmware_parameters_resp_full *resp_data,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (resp_data == NULL || msg == NULL || payload_length == NULL) {
@@ -1380,7 +1382,7 @@
 	const struct pldm_component_parameter_entry_full *comp,
 	uint8_t *payload, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (comp == NULL || payload == NULL || payload_length == NULL) {
@@ -1530,7 +1532,7 @@
 	const struct pldm_msg *msg, size_t payload_length,
 	struct pldm_query_downstream_devices_resp *resp_data)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || resp_data == NULL || !payload_length) {
@@ -1580,7 +1582,7 @@
 	const struct pldm_query_downstream_identifiers_req *params_req,
 	struct pldm_msg *msg, size_t payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !params_req) {
@@ -1623,8 +1625,8 @@
 	struct pldm_query_downstream_identifiers_resp *resp_data,
 	struct pldm_downstream_device_iter *iter)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
-	void *remaining = NULL;
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
+	const void *remaining = NULL;
 	int rc = 0;
 
 	if (msg == NULL || resp_data == NULL || iter == NULL ||
@@ -1679,7 +1681,7 @@
 	struct pldm_downstream_device_iter *iter,
 	struct pldm_downstream_device *dev)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!iter || !iter->field.ptr || !dev) {
@@ -1694,7 +1696,7 @@
 
 	pldm_msgbuf_extract(buf, dev->downstream_device_index);
 	pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
-	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
+	pldm_msgbuf_span_remaining(buf, (const void **)&iter->field.ptr,
 				   &iter->field.length);
 
 	return pldm_msgbuf_complete(buf);
@@ -1706,7 +1708,7 @@
 	const struct pldm_get_downstream_firmware_parameters_req *params_req,
 	struct pldm_msg *msg, size_t payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !params_req) {
@@ -1749,8 +1751,8 @@
 	struct pldm_get_downstream_firmware_parameters_resp *resp_data,
 	struct pldm_downstream_device_parameters_iter *iter)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
-	void *remaining = NULL;
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
+	const void *remaining = NULL;
 	size_t length;
 	int rc;
 
@@ -1805,10 +1807,10 @@
 	struct pldm_downstream_device_parameters_iter *iter,
 	struct pldm_downstream_device_parameters_entry *entry)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
-	void *comp_ver_str;
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
+	const void *comp_ver_str;
+	const void *cursor;
 	size_t remaining;
-	void *cursor;
 	int rc;
 
 	if (iter == NULL || iter->field.ptr == NULL || entry == NULL) {
@@ -1894,7 +1896,7 @@
 	const struct pldm_request_downstream_device_update_req *req_data,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (!req_data || !msg || !payload_length ||
@@ -1935,7 +1937,7 @@
 	struct pldm_request_downstream_device_update_req *req)
 {
 	int rc;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 
 	if (!msg || !req) {
 		return -EINVAL;
@@ -1961,7 +1963,7 @@
 	const struct pldm_request_downstream_device_update_resp *resp_data,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (!resp_data || !msg || !payload_length) {
@@ -1997,7 +1999,7 @@
 	const struct pldm_msg *msg, size_t payload_length,
 	struct pldm_request_downstream_device_update_resp *resp_data)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!msg || !resp_data) {
@@ -2094,7 +2096,7 @@
 {
 	int rc;
 	uint8_t t;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 
 	if (msg == NULL || req == NULL) {
 		return -EINVAL;
@@ -2167,7 +2169,7 @@
 			       const struct pldm_request_update_resp *resp_data,
 			       struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || payload_length == NULL) {
@@ -2266,7 +2268,7 @@
 {
 	int rc;
 	uint8_t t;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 
 	if (msg == NULL || pcomp == NULL) {
 		return -EINVAL;
@@ -2348,7 +2350,7 @@
 	const struct pldm_pass_component_table_resp *resp_data,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || payload_length == NULL) {
@@ -2439,7 +2441,7 @@
 {
 	int rc;
 	uint8_t t;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 
 	if (msg == NULL || up == NULL) {
 		return -EINVAL;
@@ -2531,7 +2533,7 @@
 	uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || payload_length == NULL) {
@@ -2587,7 +2589,7 @@
 	const struct pldm_request_firmware_data_req *req_params,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || payload_length == NULL) {
@@ -2657,7 +2659,7 @@
 int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
 				 struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || payload_length == NULL) {
@@ -2727,7 +2729,7 @@
 int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
 			       struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || payload_length == NULL) {
@@ -2811,7 +2813,7 @@
 			      const struct pldm_apply_complete_req *req_data,
 			      struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || payload_length == NULL) {
@@ -2868,7 +2870,7 @@
 				 size_t payload_length, bool *self_contained)
 {
 	uint8_t self_contained_u8 = 0;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || self_contained == NULL) {
@@ -2962,7 +2964,7 @@
 	const struct pldm_activate_firmware_resp *resp_data,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || payload_length == NULL) {
@@ -3083,7 +3085,7 @@
 			   const struct pldm_get_status_resp *status,
 			   struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (status == NULL || msg == NULL || payload_length == NULL) {
@@ -3229,7 +3231,7 @@
 			      const struct pldm_cancel_update_resp *resp_data,
 			      struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || payload_length == NULL) {
@@ -3278,7 +3280,7 @@
 int pldm_package_firmware_device_id_record_iter_init(struct pldm_package *pkg)
 {
 	struct pldm_package_iter *iter;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!pkg || !pkg->pin || !pkg->hdr) {
@@ -3315,7 +3317,7 @@
 	}
 
 	pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
-	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
+	pldm_msgbuf_span_remaining(buf, (const void **)&iter->field.ptr,
 				   &iter->field.length);
 
 	return pldm_msgbuf_complete(buf);
@@ -3342,7 +3344,7 @@
 int pldm_package_downstream_device_id_record_iter_init(struct pldm_package *pkg)
 {
 	struct pldm_package_iter *iter;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!pkg || !pkg->pin || !pkg->hdr) {
@@ -3396,7 +3398,7 @@
 	}
 
 	pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
-	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
+	pldm_msgbuf_span_remaining(buf, (const void **)&iter->field.ptr,
 				   &iter->field.length);
 
 	return pldm_msgbuf_complete(buf);
@@ -3410,7 +3412,7 @@
 {
 	struct pldm_package_iter *iter;
 	size_t package_data_offset;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	uint16_t record_len = 0;
 	int rc;
 
@@ -3478,7 +3480,7 @@
 	assert((pkg->hdr->component_bitmap_bit_length & 7) == 0);
 	rc = pldm_msgbuf_span_required(
 		buf, pkg->hdr->component_bitmap_bit_length / 8,
-		(void **)&rec->applicable_components.bitmap.ptr);
+		(const void **)&rec->applicable_components.bitmap.ptr);
 	if (rc) {
 		return pldm_msgbuf_discard(buf, rc);
 	}
@@ -3487,7 +3489,8 @@
 
 	pldm_msgbuf_span_required(
 		buf, rec->self_contained_activation_min_version_string.length,
-		(void **)&rec->self_contained_activation_min_version_string.ptr);
+		(const void **)&rec
+			->self_contained_activation_min_version_string.ptr);
 	if (rec->update_option_flags.bits.bit0) {
 		pldm_msgbuf_extract(
 			buf,
@@ -3501,18 +3504,18 @@
 		rec->package_data.length + rec->reference_manifest_data.length;
 
 	pldm_msgbuf_span_until(buf, package_data_offset,
-			       (void **)&rec->record_descriptors.ptr,
+			       (const void **)&rec->record_descriptors.ptr,
 			       &rec->record_descriptors.length);
 
 	pldm_msgbuf_span_required(buf, rec->package_data.length,
-				  (void **)&rec->package_data.ptr);
+				  (const void **)&rec->package_data.ptr);
 
 	/* Supported in package header revision 1.3 (FR04H) and above. */
 	if (pkg->hdr->package_header_format_revision >=
 	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
 		pldm_msgbuf_span_required(
 			buf, rec->reference_manifest_data.length,
-			(void **)&rec->reference_manifest_data.ptr);
+			(const void **)&rec->reference_manifest_data.ptr);
 	} else {
 		assert(rec->reference_manifest_data.length == 0);
 		rec->reference_manifest_data.ptr = NULL;
@@ -3526,7 +3529,7 @@
 {
 	struct pldm_package_iter *iter;
 	uint16_t component_image_count;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!pkg || !pkg->pin || !pkg->hdr) {
@@ -3576,7 +3579,7 @@
 	}
 	iter->entries = component_image_count;
 
-	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
+	pldm_msgbuf_span_remaining(buf, (const void **)&iter->field.ptr,
 				   &iter->field.length);
 
 	return pldm_msgbuf_complete(buf);
@@ -3591,7 +3594,7 @@
 	uint32_t component_location_offset = 0;
 	struct pldm_package_iter *iter;
 	uint32_t component_size = 0;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!pkg || !info) {
@@ -3637,8 +3640,9 @@
 		return pldm_msgbuf_discard(buf, rc);
 	}
 
-	pldm_msgbuf_span_required(buf, info->component_version_string.length,
-				  (void **)&info->component_version_string.ptr);
+	pldm_msgbuf_span_required(
+		buf, info->component_version_string.length,
+		(const void **)&info->component_version_string.ptr);
 
 	/* Supported in package header revision 1.2 (FR03H) and above. */
 	if (pkg->hdr->package_header_format_revision >=
@@ -3650,7 +3654,7 @@
 		}
 		pldm_msgbuf_span_required(
 			buf, info->component_opaque_data.length,
-			(void **)&info->component_opaque_data.ptr);
+			(const void **)&info->component_opaque_data.ptr);
 	} else {
 		info->component_opaque_data.length = 0;
 	}
@@ -3659,7 +3663,7 @@
 		info->component_opaque_data.ptr = NULL;
 	}
 
-	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
+	pldm_msgbuf_span_remaining(buf, (const void **)&iter->field.ptr,
 				   &iter->field.length);
 
 	rc = pldm_msgbuf_complete_consumed(buf);
@@ -3681,7 +3685,7 @@
 
 	pldm_msgbuf_span_required(buf, component_location_offset, NULL);
 	pldm_msgbuf_span_required(buf, component_size,
-				  (void **)&info->component_image.ptr);
+				  (const void **)&info->component_image.ptr);
 
 	rc = pldm_msgbuf_complete(buf);
 	if (rc) {
diff --git a/src/dsp/pdr.c b/src/dsp/pdr.c
index f8873b1..fd36b56 100644
--- a/src/dsp/pdr.c
+++ b/src/dsp/pdr.c
@@ -6,10 +6,11 @@
 
 #include <assert.h>
 #include <endian.h>
+#include <errno.h>
+#include <limits.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
 
 #define PDR_ENTITY_ASSOCIATION_MIN_SIZE                                        \
 	(sizeof(struct pldm_pdr_hdr) +                                         \
@@ -407,7 +408,7 @@
 static int decode_pldm_state_sensor_pdr(uint8_t *data, uint32_t size,
 					struct pldm_state_sensor_pdr *pdr)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc = 0;
 	rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_state_sensor_pdr),
 				    (uint8_t *)data, size);
@@ -534,7 +535,7 @@
 static int decode_pldm_state_effecter_pdr(uint8_t *data, uint32_t size,
 					  struct pldm_state_effecter_pdr *pdr)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc = 0;
 	rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_state_effecter_pdr),
 				    (uint8_t *)data, size);
@@ -619,8 +620,8 @@
 	record = repo->first;
 
 	while (record != NULL) {
-		struct pldm_msgbuf _buf;
-		struct pldm_msgbuf *buf = &_buf;
+		struct pldm_msgbuf_ro _buf;
+		struct pldm_msgbuf_ro *buf = &_buf;
 		rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_pdr_hdr),
 					    record->data, record->size);
 
@@ -1701,8 +1702,8 @@
 	int rc = 0;
 	uint16_t header_length = 0;
 	uint8_t num_children = 0;
-	PLDM_MSGBUF_DEFINE_P(src);
-	PLDM_MSGBUF_DEFINE_P(dst);
+	PLDM_MSGBUF_RO_DEFINE_P(src);
+	PLDM_MSGBUF_RW_DEFINE_P(dst);
 
 	pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
 
@@ -1851,9 +1852,9 @@
 	uint16_t new_pdr_size;
 	uint16_t container_id = 0;
 	void *container_id_addr;
-	PLDM_MSGBUF_DEFINE_P(dst);
-	PLDM_MSGBUF_DEFINE_P(src_p);
-	PLDM_MSGBUF_DEFINE_P(src_c);
+	PLDM_MSGBUF_RW_DEFINE_P(dst);
+	PLDM_MSGBUF_RO_DEFINE_P(src_p);
+	PLDM_MSGBUF_RO_DEFINE_P(src_c);
 	int rc = 0;
 
 	pldm_pdr_record *prev = repo->first;
@@ -1998,7 +1999,7 @@
 	pldm_pdr_record *record = repo->first;
 
 	while (record != NULL) {
-		PLDM_MSGBUF_DEFINE_P(dst);
+		PLDM_MSGBUF_RO_DEFINE_P(dst);
 
 		rc = pldm_msgbuf_init_errno(dst,
 					    PDR_ENTITY_ASSOCIATION_MIN_SIZE,
@@ -2057,8 +2058,8 @@
 {
 	uint16_t header_length = 0;
 	uint8_t num_children = 0;
-	PLDM_MSGBUF_DEFINE_P(src);
-	PLDM_MSGBUF_DEFINE_P(dst);
+	PLDM_MSGBUF_RO_DEFINE_P(src);
+	PLDM_MSGBUF_RW_DEFINE_P(dst);
 	int rc;
 	pldm_pdr_record *record;
 	pldm_pdr_record *prev;
@@ -2241,7 +2242,7 @@
 	uint16_t record_fru_rsi = 0;
 	uint8_t *skip_data = NULL;
 	uint8_t skip_data_size = 0;
-	PLDM_MSGBUF_DEFINE_P(dst);
+	PLDM_MSGBUF_RO_DEFINE_P(dst);
 	int rc = 0;
 
 	rc = pldm_msgbuf_init_errno(dst, PDR_FRU_RECORD_SET_MIN_SIZE,
@@ -2250,7 +2251,8 @@
 		return rc;
 	}
 	skip_data_size = sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t);
-	pldm_msgbuf_span_required(dst, skip_data_size, (void **)&skip_data);
+	pldm_msgbuf_span_required(dst, skip_data_size,
+				  (const void **)&skip_data);
 	pldm_msgbuf_extract(dst, record_fru_rsi);
 
 	rc = pldm_msgbuf_complete(dst);
@@ -2315,7 +2317,7 @@
 	record = repo->first;
 
 	while (record != NULL) {
-		PLDM_MSGBUF_DEFINE_P(buf);
+		PLDM_MSGBUF_RO_DEFINE_P(buf);
 
 		rc = pldm_msgbuf_init_errno(buf, PDR_FRU_RECORD_SET_MIN_SIZE,
 					    record->data, record->size);
diff --git a/src/dsp/platform.c b/src/dsp/platform.c
index 33861e1..d1fdce6 100644
--- a/src/dsp/platform.c
+++ b/src/dsp/platform.c
@@ -265,7 +265,7 @@
 					 uint8_t *comp_effecter_count,
 					 set_effecter_state_field *field)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 	int i;
 
@@ -314,7 +314,7 @@
 		       uint8_t *transfer_op_flag, uint16_t *request_cnt,
 		       uint16_t *record_chg_num)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || record_hndl == NULL || data_transfer_hndl == NULL ||
@@ -466,7 +466,7 @@
 	uint32_t *repository_size, uint32_t *largest_record_size,
 	uint8_t *data_transfer_handle_timeout)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || completion_code == NULL ||
@@ -533,7 +533,7 @@
 	const struct pldm_msg *msg, size_t payload_length,
 	struct pldm_pdr_repository_info_resp *resp)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || resp == NULL) {
@@ -626,7 +626,7 @@
 			uint8_t *record_data, size_t record_data_length,
 			uint8_t *transfer_crc)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || completion_code == NULL ||
@@ -688,7 +688,7 @@
 			     struct pldm_get_pdr_resp *resp, size_t resp_len,
 			     uint8_t *transfer_crc)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || resp == NULL || transfer_crc == NULL) {
@@ -742,7 +742,7 @@
 					  uint8_t *effecter_data_size,
 					  uint8_t effecter_value[4])
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || effecter_id == NULL || effecter_data_size == NULL ||
@@ -966,7 +966,7 @@
 					  uint8_t *comp_sensor_count,
 					  get_sensor_state_field *field)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	uint8_t i;
 	int rc;
 
@@ -1022,7 +1022,7 @@
 					 bitfield8_t *sensor_rearm,
 					 uint8_t *reserved)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || sensor_id == NULL || sensor_rearm == NULL) {
@@ -1091,7 +1091,7 @@
 				      uint8_t *event_class,
 				      size_t *event_data_offset)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || format_version == NULL || tid == NULL ||
@@ -1145,7 +1145,7 @@
 	uint8_t *format_version, uint8_t *transfer_operation_flag,
 	uint32_t *data_transfer_handle, uint16_t *event_id_to_acknowledge)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || format_version == NULL ||
@@ -1231,7 +1231,7 @@
 	uint8_t *event_data, uint32_t checksum, struct pldm_msg *msg,
 	size_t payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (!msg) {
@@ -1371,7 +1371,7 @@
 				       uint8_t *completion_code,
 				       uint8_t *platform_event_status)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || completion_code == NULL ||
@@ -1441,7 +1441,7 @@
 					  uint8_t *completion_code,
 					  uint16_t *terminus_max_buffer_size)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || completion_code == NULL ||
@@ -1516,7 +1516,7 @@
 					uint8_t *event_class,
 					uint8_t event_class_count)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int i;
 	int rc;
 
@@ -1589,7 +1589,7 @@
 			     uint8_t *sensor_event_class_type,
 			     size_t *event_class_data_offset)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (event_data == NULL || sensor_id == NULL ||
@@ -1656,7 +1656,7 @@
 int decode_sensor_op_data(const uint8_t *sensor_data, size_t sensor_data_length,
 			  uint8_t *present_op_state, uint8_t *previous_op_state)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (sensor_data == NULL || present_op_state == NULL ||
@@ -1688,7 +1688,7 @@
 			     uint8_t *event_state,
 			     uint8_t *previous_event_state)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (sensor_data == NULL || sensor_offset == NULL ||
@@ -1722,7 +1722,7 @@
 			       uint8_t *sensor_data_size,
 			       uint32_t *present_reading)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (sensor_data == NULL || sensor_data_size == NULL ||
@@ -1815,7 +1815,7 @@
 	const void *pdr_data, size_t pdr_data_length,
 	struct pldm_numeric_sensor_value_pdr *pdr_value)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!pdr_data || !pdr_value) {
@@ -2027,7 +2027,7 @@
 					  size_t payload_length,
 					  uint16_t *effecter_id)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || effecter_id == NULL) {
@@ -2060,7 +2060,7 @@
 					   uint8_t *pending_value,
 					   uint8_t *present_value)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || effecter_data_size == NULL ||
@@ -2187,7 +2187,7 @@
 					      uint8_t *number_of_change_records,
 					      size_t *change_record_data_offset)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (event_data == NULL || event_data_format == NULL ||
@@ -2222,7 +2222,7 @@
 	const void *event_data, size_t event_data_length,
 	struct pldm_message_poll_event *poll_event)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!event_data || !poll_event) {
@@ -2255,7 +2255,7 @@
 	const struct pldm_message_poll_event *poll_event, void *event_data,
 	size_t event_data_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (poll_event == NULL || event_data == NULL) {
@@ -2284,7 +2284,7 @@
 	uint8_t *event_data_operation, uint8_t *number_of_change_entries,
 	size_t *change_entry_data_offset)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (change_record_data == NULL || event_data_operation == NULL ||
@@ -2351,7 +2351,7 @@
 	uint8_t *present_state, uint8_t *previous_state, uint8_t *event_state,
 	uint8_t *present_reading)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || completion_code == NULL ||
@@ -2479,7 +2479,7 @@
 				  size_t payload_length, uint16_t *sensor_id,
 				  uint8_t *rearm_event_state)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || sensor_id == NULL || rearm_event_state == NULL) {
@@ -2508,7 +2508,7 @@
 	const struct pldm_msg *msg, size_t payload_length,
 	struct pldm_set_numeric_sensor_enable_req *req)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	uint8_t event_enable = 0;
 	uint8_t op_state = 0;
 	int rc;
@@ -2550,7 +2550,7 @@
 	const struct pldm_msg *msg, size_t payload_length,
 	struct pldm_set_state_sensor_enables_req *req)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || req == NULL) {
@@ -2621,7 +2621,7 @@
 	struct pldm_get_event_receiver_resp *event_receiver_info,
 	struct pldm_msg *msg, size_t *payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 	if (!msg || !event_receiver_info) {
 		return -EINVAL;
@@ -2661,7 +2661,7 @@
 				   size_t payload_length,
 				   struct pldm_get_event_receiver_resp *resp)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 	if (!msg) {
 		return -EINVAL;
@@ -2742,7 +2742,7 @@
 				   size_t payload_length,
 				   uint8_t *completion_code)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || completion_code == NULL) {
@@ -2774,7 +2774,7 @@
 				  uint16_t *heartbeat_timer)
 
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || event_message_global_enable == NULL ||
@@ -2849,7 +2849,7 @@
 					       struct pldm_msg *msg,
 					       size_t payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL) {
@@ -2901,7 +2901,7 @@
 	uint8_t *event_class, uint32_t *event_data_size, void **event_data,
 	uint32_t *event_data_integrity_checksum)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || completion_code == NULL || tid == NULL ||
@@ -2952,7 +2952,8 @@
 	}
 
 	if (*event_data_size > 0) {
-		pldm_msgbuf_span_required(buf, *event_data_size, event_data);
+		pldm_msgbuf_span_required(buf, *event_data_size,
+					  (const void **)event_data);
 	}
 
 	if (*transfer_flag == PLDM_END ||
@@ -2973,7 +2974,7 @@
 	const void *pdr_data, size_t pdr_data_length,
 	struct pldm_numeric_effecter_value_pdr *pdr_value)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	struct pldm_value_pdr_hdr hdr;
 	int rc;
 
@@ -3069,7 +3070,7 @@
 					 struct pldm_msg *msg,
 					 size_t payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL) {
@@ -3104,7 +3105,7 @@
 					 size_t payload_length,
 					 uint16_t *effecter_id)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || effecter_id == NULL) {
@@ -3128,7 +3129,7 @@
 	const struct pldm_msg *msg, size_t payload_length,
 	struct pldm_get_state_effecter_states_resp *resp)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	get_effecter_state_field *field;
 	int rc;
 	int i;
@@ -3180,7 +3181,7 @@
 	uint8_t instance_id, struct pldm_get_state_effecter_states_resp *resp,
 	struct pldm_msg *msg, size_t payload_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	get_effecter_state_field *field;
 	int rc;
 	int i;
@@ -3232,11 +3233,11 @@
 	const void *data, size_t data_length,
 	struct pldm_entity_auxiliary_names_pdr *pdr, size_t pdr_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
-	PLDM_MSGBUF_DEFINE_P(src);
-	PLDM_MSGBUF_DEFINE_P(dst);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(src);
+	PLDM_MSGBUF_RW_DEFINE_P(dst);
+	const void *names = NULL;
 	size_t names_len = 0;
-	void *names = NULL;
 	int rc;
 	int i;
 
@@ -3355,7 +3356,7 @@
 int decode_pldm_entity_auxiliary_names_pdr_index(
 	struct pldm_entity_auxiliary_names_pdr *pdr)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 	int i;
 
@@ -3398,13 +3399,13 @@
 
 	for (i = 0; i < pdr->name_string_count; i++) {
 		void *loc = NULL;
-		pldm_msgbuf_span_string_utf16(buf, &loc, NULL);
+		pldm_msgbuf_span_string_utf16(buf, (const void **)&loc, NULL);
 		pdr->names[i].name = loc;
 	}
 
 	for (i = 0; i < pdr->name_string_count; i++) {
 		void *loc = NULL;
-		pldm_msgbuf_span_string_ascii(buf, &loc, NULL);
+		pldm_msgbuf_span_string_ascii(buf, (const void **)&loc, NULL);
 		pdr->names[i].tag = loc;
 	}
 
@@ -3417,7 +3418,7 @@
 				    struct pldm_platform_cper_event *cper_event,
 				    size_t cper_event_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!cper_event || !event_data) {
@@ -3477,7 +3478,7 @@
 	const void *data, size_t data_length,
 	struct pldm_platform_file_descriptor_pdr *pdr)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (!data || !pdr) {
@@ -3519,7 +3520,7 @@
 	}
 
 	pldm_msgbuf_span_required(buf, pdr->file_name.length,
-				  (void **)&pdr->file_name.ptr);
+				  (const void **)&pdr->file_name.ptr);
 
 	pdr->oem_file_classification_name.length = 0;
 
@@ -3532,7 +3533,7 @@
 
 		pldm_msgbuf_span_required(
 			buf, pdr->oem_file_classification_name.length,
-			(void **)&pdr->oem_file_classification_name.ptr);
+			(const void **)&pdr->oem_file_classification_name.ptr);
 	}
 
 	return pldm_msgbuf_complete_consumed(buf);
diff --git a/src/firmware_device/fd.c b/src/firmware_device/fd.c
index 0967033..0437dd1 100644
--- a/src/firmware_device/fd.c
+++ b/src/firmware_device/fd.c
@@ -1,17 +1,17 @@
 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdlib.h>
+#include "compiler.h"
+#include "fd-internal.h"
+#include "msgbuf.h"
 
 #include <libpldm/pldm.h>
 #include <libpldm/firmware_update.h>
 #include <libpldm/firmware_fd.h>
 #include <libpldm/utils.h>
-#include <compiler.h>
-#include <msgbuf.h>
 
-#include "fd-internal.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
 
 /* FD_T1 Update mode idle timeout, 120 seconds (range [60s, 120s])*/
 static const pldm_fd_time_t DEFAULT_FD_T1_TIMEOUT = 120000;
@@ -276,7 +276,7 @@
 {
 	uint16_t entry_count;
 	const struct pldm_firmware_component_standalone **entries;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	int rc;
 
 	/* No request data */
diff --git a/src/msgbuf.h b/src/msgbuf.h
index 78ec89a..274ca4e 100644
--- a/src/msgbuf.h
+++ b/src/msgbuf.h
@@ -2,579 +2,127 @@
 #ifndef PLDM_MSGBUF_H
 #define PLDM_MSGBUF_H
 
-#include "compiler.h"
+#include "msgbuf/core.h"
+
+#define PLDM__MSGBUF_DEFINE_P(name, mode)                                      \
+	struct pldm_msgbuf_##mode _##name LIBPLDM_CC_CLEANUP(                  \
+		pldm__msgbuf_##mode##_cleanup) = { NULL, INTMAX_MIN };         \
+	struct pldm_msgbuf_##mode *(name) = &(_##name)
+
+#define PLDM_MSGBUF_RO_DEFINE_P(name) PLDM__MSGBUF_DEFINE_P(name, ro)
+#define PLDM_MSGBUF_RW_DEFINE_P(name) PLDM__MSGBUF_DEFINE_P(name, rw)
 
 /*
- * Historically, many of the structs exposed in libpldm's public headers are
- * defined with __attribute__((packed)). This is unfortunate: it gives the
- * impression that a wire-format buffer can be cast to the message type to make
- * the message's fields easily accessible. As it turns out, that's not
- * that's valid for several reasons:
+ * Use the C11 `_Generic` keyword to keep pldm_msgbuf related function consistent
+ * and to produce compile-time errors when the wrong pldm_msgbuf type is passed.
  *
- * 1. Casting the wire-format buffer to a struct of the message type doesn't
- *    abstract the endianness of message field values
+ * Previously we cast away `const` in `pldm_msgbuf_init_error()`, which was a hack.
+ * Instead, introduce:
+ *   - pldm_msgbuf_ro: read-only buffer with a `const` cursor
+ *   - pldm_msgbuf_rw: read-write buffer with a non-const cursor
  *
- * 2. Some messages contain packed tagged union fields which cannot be properly
- *    described in a C struct.
- *
- * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
- * that is type-safe, spatially memory-safe, endian-safe, performant, and
- * free of undefined-behaviour. Message structs that are added to the public
- * library API should no-longer be marked __attribute__((packed)), and the
- * implementation of their encode and decode functions must exploit the msgbuf
- * API.
- *
- * However, we would like to allow implementation of codec functions in terms of
- * msgbuf APIs even if they're decoding a message into a (historically) packed
- * struct. Some of the complexity that follows is a consequence of the packed/
- * unpacked conflict.
+ * `pldm_msgbuf_ro` is used by decode APIs to extract payloads into PLDM
+ * structures. `pldm_msgbuf_rw` is used by encode APIs to insert payloads from
+ * PLDM structures.
  */
 
-#ifdef __cplusplus
-/*
- * Fix up C11's _Static_assert() vs C++'s static_assert().
- *
- * Can we please have nice things for once.
- */
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-#define _Static_assert(...) static_assert(__VA_ARGS__)
-extern "C" {
-#endif
+#define pldm_msgbuf_init_errno(ctx, minsize, buf, len)                         \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_init_errno,            \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_init_errno)(           \
+		ctx, minsize, buf, len)
 
-#include <libpldm/base.h>
-#include <libpldm/pldm_types.h>
+#define pldm_msgbuf_discard(ctx, error)                                        \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_discard,               \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_discard)(ctx, error)
 
-#include "compiler.h"
+#define pldm_msgbuf_complete(ctx)                                              \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_complete,              \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_complete)(ctx)
 
-#include <assert.h>
-#include <endian.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/types.h>
-#include <uchar.h>
+#define pldm_msgbuf_complete_consumed(ctx)                                     \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_complete_consumed,     \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_complete_consumed)(    \
+		ctx)
 
-/*
- * We can't use static_assert() outside of some other C construct. Deal
- * with high-level global assertions by burying them in an unused struct
- * declaration, that has a sole member for compliance with the requirement that
- * types must have a size.
-*/
-static struct {
-	static_assert(
-		INTMAX_MAX != SIZE_MAX,
-		"Extraction and insertion value comparisons may be broken");
-	static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
-		      "Extraction and insertion arithmetic may be broken");
-	int compliance;
-} build_assertions LIBPLDM_CC_UNUSED;
+#define pldm_msgbuf_validate(ctx)                                              \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_validate,              \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_validate)(ctx)
 
-struct pldm_msgbuf {
-	uint8_t *cursor;
-	intmax_t remaining;
-};
+#define pldm_msgbuf_consumed(ctx)                                              \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_consumed,              \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_consumed)(ctx)
 
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-void pldm__msgbuf_cleanup(struct pldm_msgbuf *ctx LIBPLDM_CC_UNUSED)
-{
-	assert(ctx->cursor == NULL && ctx->remaining == INTMAX_MIN);
-}
+#define pldm__msgbuf_invalidate(ctx)                                           \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm__msgbuf_rw_invalidate,           \
+		struct pldm_msgbuf_ro *: pldm__msgbuf_ro_invalidate)(ctx)
 
-#ifdef __cplusplus
-// NOLINTBEGIN(bugprone-macro-parentheses)
-#define PLDM_MSGBUF_DEFINE_P(name)                                             \
-	struct pldm_msgbuf _##name LIBPLDM_CC_CLEANUP(                         \
-		pldm__msgbuf_cleanup) = { NULL, INTMAX_MIN };                  \
-	auto *name = &(_##name)
-// NOLINTEND(bugprone-macro-parentheses)
-#else
-#define PLDM_MSGBUF_DEFINE_P(name)                                             \
-	struct pldm_msgbuf _##name LIBPLDM_CC_CLEANUP(                         \
-		pldm__msgbuf_cleanup) = { NULL, INTMAX_MIN };                  \
-	struct pldm_msgbuf *(name) = &(_##name)
-#endif
+#define pldm_msgbuf_span_required(ctx, required, cursor)                       \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_span_required,         \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_span_required)(        \
+		ctx, required, cursor)
 
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-int pldm__msgbuf_invalidate(struct pldm_msgbuf *ctx)
-{
-	ctx->remaining = INTMAX_MIN;
-	return -EOVERFLOW;
-}
+#define pldm_msgbuf_span_until(ctx, trailer, cursor, length)                   \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_span_until,            \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_span_until)(           \
+		ctx, trailer, cursor, length)
 
-/**
- * @brief Initialize pldm buf struct for buf extractor
- *
- * @param[out] ctx - pldm_msgbuf context for extractor
- * @param[in] minsize - The minimum required length of buffer `buf`
- * @param[in] buf - buffer to be extracted
- * @param[in] len - size of buffer
- *
- * @return 0 on success, otherwise an error code appropriate for the current
- *         personality.
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE
-LIBPLDM_CC_WARN_UNUSED_RESULT
-int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm_msgbuf_init_errno(struct pldm_msgbuf *ctx, size_t minsize, const void *buf,
-		       size_t len)
-{
-	ctx->cursor = NULL;
+#define pldm_msgbuf_span_string_utf16(ctx, cursor, len)                        \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_span_string_utf16,     \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_span_string_utf16)(    \
+		ctx, cursor, len)
 
-	if ((minsize > len)) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
+#define pldm_msgbuf_span_remaining(ctx, cursor, len)                           \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_span_remaining,        \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_span_remaining)(       \
+		ctx, cursor, len)
 
-#if INTMAX_MAX < SIZE_MAX
-	if (len > INTMAX_MAX) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-#endif
+#define pldm_msgbuf_span_string_ascii(ctx, cursor, len)                        \
+	_Generic((ctx),                                                        \
+		struct pldm_msgbuf_rw *: pldm_msgbuf_rw_span_string_ascii,     \
+		struct pldm_msgbuf_ro *: pldm_msgbuf_ro_span_string_ascii)(    \
+		ctx, cursor, len)
 
-	if (UINTPTR_MAX - (uintptr_t)buf < len) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-
-	ctx->cursor = (uint8_t *)buf;
-	ctx->remaining = (intmax_t)len;
-
-	return 0;
-}
-
-/**
- * @brief Validate buffer overflow state
- *
- * @param[in] ctx - pldm_msgbuf context for extractor
- *
- * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
- * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
- * prior accesses would have occurred beyond the bounds of the buffer, and
- * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
- * pointer.
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE
-LIBPLDM_CC_WARN_UNUSED_RESULT
-int pldm_msgbuf_validate(struct pldm_msgbuf *ctx)
-{
-	if (ctx->remaining < 0) {
-		return -EOVERFLOW;
-	}
-
-	return 0;
-}
-
-/**
- * @brief Test whether a message buffer has been exactly consumed
- *
- * @param[in] ctx - pldm_msgbuf context for extractor
- *
- * @return 0 iff there are zero bytes of data that remain unread from the buffer
- * and no overflow has occurred. Otherwise, -EBADMSG if the buffer has not been
- * completely consumed, or -EOVERFLOW if accesses were attempted beyond the
- * bounds of the buffer.
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE
-LIBPLDM_CC_WARN_UNUSED_RESULT
-int pldm_msgbuf_consumed(struct pldm_msgbuf *ctx)
-{
-	if (ctx->remaining > 0) {
-		return -EBADMSG;
-	}
-
-	if (ctx->remaining < 0) {
-		return -EOVERFLOW;
-	}
-
-	return 0;
-}
-
-/**
- * @brief End use of a msgbuf under error conditions
- *
- * @param[in] ctx - The msgbuf instance to discard
- * @param[in] error - The error value to propagate
- *
- * Under normal conditions use of a msgbuf instance must be ended using @ref
- * pldm_msgbuf_complete or one of its related APIs. Under error conditions, @ref
- * pldm_msgbuf_discard should be used instead, as it makes it straight-forward
- * to finalise the msgbuf while propagating the existing error code.
- *
- * @return The value provided in @param error
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE
-LIBPLDM_CC_WARN_UNUSED_RESULT
-int pldm_msgbuf_discard(struct pldm_msgbuf *ctx, int error)
-{
-	ctx->cursor = NULL;
-	pldm__msgbuf_invalidate(ctx);
-	return error;
-}
-
-/**
- * @brief Complete the pldm_msgbuf instance
- *
- * @param[in] ctx - pldm_msgbuf context for extractor
- *
- * @return 0 if all buffer accesses were in-bounds, -EOVERFLOW otherwise.
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE
-LIBPLDM_CC_WARN_UNUSED_RESULT
-int pldm_msgbuf_complete(struct pldm_msgbuf *ctx)
-{
-	return pldm_msgbuf_discard(ctx, pldm_msgbuf_validate(ctx));
-}
-
-/**
- * @brief Complete the pldm_msgbuf instance, and check that the underlying buffer
- * has been entirely consumed without overflow
- *
- * @param[in] ctx - pldm_msgbuf context
- *
- * @return 0 if all buffer access were in-bounds and completely consume the
- * underlying buffer. Otherwise, -EBADMSG if the buffer has not been completely
- * consumed, or -EOVERFLOW if accesses were attempted beyond the bounds of the
- * buffer.
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE
-LIBPLDM_CC_WARN_UNUSED_RESULT
-int pldm_msgbuf_complete_consumed(struct pldm_msgbuf *ctx)
-{
-	return pldm_msgbuf_discard(ctx, pldm_msgbuf_consumed(ctx));
-}
-
-/*
- * Exploit the pre-processor to perform type checking by macro substitution.
- *
- * A C type is defined by its alignment as well as its object
- * size, and compilers have a hammer to enforce it in the form of
- * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
- * the libpldm public API this presents a problem: Naively attempting to use the
- * msgbuf APIs on a member of a packed struct would yield an error.
- *
- * The msgbuf APIs are implemented such that data is moved through unaligned
- * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
- * make the object pointers take a trip through `void *` at its API boundary.
- * That presents a bit too much of an opportunity to non-surgically remove your
- * own foot, so here we set about doing something to mitigate that as well.
- *
- * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
- * only for the purpose of object sizes, disregarding alignment. We have a few
- * constraints that cause some headaches:
- *
- * 1. We have to perform the type-check before a call through a C function,
- *    as the function must take the object pointer argument as `void *`.
- *    Essentially, this constrains us to doing something with macros.
- *
- * 2. While libpldm is a C library, its test suite is written in C++ to take
- *    advantage of gtest.
- *
- * 3. Ideally we'd do something with C's `static_assert()`, however
- *    `static_assert()` is defined as void, and as we're constrained to macros,
- *    using `static_assert()` would require a statement-expression
- *
- * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
- *    are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
- *    the purpose of enabling statement-expressions in this one instance.
- *
- * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
- *    however it's implemented in terms of `_Generic()`, which is not available
- *    in C++.
- *
- * Combined this means we need separate solutions for C and C++.
- *
- * For C, as we don't have statement-expressions, we need to exploit some other
- * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
- * API function call. We also have to take care of the fact that the call-sites
- * may be in the context of a variable assignment for error-handling purposes.
- * The key observation is that we can use the comma operator as a sequence point
- * to order the type check before the API call, discarding the "result" value of
- * the type check and yielding the return value of the API call.
- *
- * C++ could be less of a headache than the C as we can leverage template
- * functions. An advantage of template functions is that while their definition
- * is driven by instantion, the definition does not appear at the source
- * location of the instantiation, which gives it a great leg-up over the problems
- * we have in the C path. However, the use of the msgbuf APIs in the test suite
- * still makes things somewhat tricky, as the call-sites in the test suite are
- * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
- * takes both the object type and the required type as template arguments, and
- * then define the object pointer parameter as `void *` for a call through to
- * the appropriate msgbuf API. However, because the msgbuf API call-sites are
- * encapsulated in gtest macros, use of commas in the template specification
- * causes pre-processor confusion. In this way we're constrained to only one
- * template argument per function.
- *
- * Implement the C++ path using template functions that take the destination
- * object type as a template argument, while the name of the function symbols
- * are derived from the required type. The manual implementations of these
- * appear at the end of the header. The type safety is actually enforced
- * by `static_assert()` this time, as we can use statements as we're not
- * constrained to an expression in the templated function body.
- *
- * The invocations of pldm_msgbuf_extract_typecheck() typically result in
- * double-evaluation of some arguments. We're not yet bothered by this for two
- * reasons:
- *
- * 1. The nature of the current call-sites are such that there are no
- *    argument expressions that result in undesirable side-effects
- *
- * 2. It's an API internal to the libpldm implementation, and we can fix things
- *    whenever something crops up the violates the observation in 1.
- */
-#ifdef __cplusplus
-#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...)                        \
-	pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
-#else
 #define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...)                        \
 	(pldm_require_obj_type(dst, ty), fn(__VA_ARGS__))
-#endif
 
-/**
- * @brief pldm_msgbuf extractor for a uint8_t
- *
- * @param[in,out] ctx - pldm_msgbuf context for extractor
- * @param[out] dst - destination of extracted value
- *
- * @return PLDM_SUCCESS if buffer accesses were in-bounds,
- * PLDM_ERROR_INVALID_LENGTH otherwise.
- * PLDM_ERROR_INVALID_DATA if input a invalid ctx
- */
 #define pldm_msgbuf_extract_uint8(ctx, dst)                                    \
 	pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8,     \
 				      dst, ctx, (void *)&(dst))
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_uint8(struct pldm_msgbuf *ctx, void *dst)
-{
-	if (ctx->remaining >= (intmax_t)sizeof(uint8_t)) {
-		assert(ctx->cursor);
-		memcpy(dst, ctx->cursor, sizeof(uint8_t));
-		ctx->cursor++;
-		ctx->remaining -= sizeof(uint8_t);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(uint8_t)) {
-		ctx->remaining -= sizeof(uint8_t);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
 
 #define pldm_msgbuf_extract_int8(ctx, dst)                                     \
 	pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst,  \
 				      ctx, (void *)&(dst))
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_int8(struct pldm_msgbuf *ctx, void *dst)
-{
-	if (ctx->remaining >= (intmax_t)sizeof(int8_t)) {
-		assert(ctx->cursor);
-		memcpy(dst, ctx->cursor, sizeof(int8_t));
-		ctx->cursor++;
-		ctx->remaining -= sizeof(int8_t);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(int8_t)) {
-		ctx->remaining -= sizeof(int8_t);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
 
 #define pldm_msgbuf_extract_uint16(ctx, dst)                                   \
 	pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16,   \
 				      dst, ctx, (void *)&(dst))
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_uint16(struct pldm_msgbuf *ctx, void *dst)
-{
-	uint16_t ldst;
-
-	// Check for underflow while tracking the magnitude of the buffer overflow
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(ldst) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
-		assert(ctx->cursor);
-
-		// Use memcpy() to have the compiler deal with any alignment
-		// issues on the target architecture
-		memcpy(&ldst, ctx->cursor, sizeof(ldst));
-
-		// Only assign the target value once it's correctly decoded
-		ldst = le16toh(ldst);
-
-		// Allow storing to unaligned
-		memcpy(dst, &ldst, sizeof(ldst));
-
-		ctx->cursor += sizeof(ldst);
-		ctx->remaining -= sizeof(ldst);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
-		ctx->remaining -= sizeof(ldst);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
 
 #define pldm_msgbuf_extract_int16(ctx, dst)                                    \
 	pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16,     \
 				      dst, ctx, (void *)&(dst))
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_int16(struct pldm_msgbuf *ctx, void *dst)
-{
-	int16_t ldst;
-
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(ldst) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
-		assert(ctx->cursor);
-		memcpy(&ldst, ctx->cursor, sizeof(ldst));
-		ldst = le16toh(ldst);
-		memcpy(dst, &ldst, sizeof(ldst));
-		ctx->cursor += sizeof(ldst);
-		ctx->remaining -= sizeof(ldst);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
-		ctx->remaining -= sizeof(ldst);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
 
 #define pldm_msgbuf_extract_uint32(ctx, dst)                                   \
 	pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32,   \
 				      dst, ctx, (void *)&(dst))
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_uint32(struct pldm_msgbuf *ctx, void *dst)
-{
-	uint32_t ldst;
-
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(ldst) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
-		assert(ctx->cursor);
-		memcpy(&ldst, ctx->cursor, sizeof(ldst));
-		ldst = le32toh(ldst);
-		memcpy(dst, &ldst, sizeof(ldst));
-		ctx->cursor += sizeof(ldst);
-		ctx->remaining -= sizeof(ldst);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
-		ctx->remaining -= sizeof(ldst);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
 
 #define pldm_msgbuf_extract_int32(ctx, dst)                                    \
 	pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32,     \
 				      dst, ctx, (void *)&(dst))
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_int32(struct pldm_msgbuf *ctx, void *dst)
-{
-	int32_t ldst;
-
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(ldst) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
-		assert(ctx->cursor);
-		memcpy(&ldst, ctx->cursor, sizeof(ldst));
-		ldst = le32toh(ldst);
-		memcpy(dst, &ldst, sizeof(ldst));
-		ctx->cursor += sizeof(ldst);
-		ctx->remaining -= sizeof(ldst);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
-		ctx->remaining -= sizeof(ldst);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
 
 #define pldm_msgbuf_extract_real32(ctx, dst)                                   \
 	pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32,   \
 				      dst, ctx, (void *)&(dst))
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_real32(struct pldm_msgbuf *ctx, void *dst)
-{
-	uint32_t ldst;
-
-	static_assert(sizeof(real32_t) == sizeof(ldst),
-		      "Mismatched type sizes for dst and ldst");
-
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(ldst) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
-		assert(ctx->cursor);
-		memcpy(&ldst, ctx->cursor, sizeof(ldst));
-		ldst = le32toh(ldst);
-		memcpy(dst, &ldst, sizeof(ldst));
-		ctx->cursor += sizeof(ldst);
-		ctx->remaining -= sizeof(ldst);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
-		ctx->remaining -= sizeof(ldst);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
 
 /**
  * Extract the field at the msgbuf cursor into the lvalue named by dst.
@@ -614,274 +162,6 @@
 		int32_t *: pldm__msgbuf_extract_int32,                         \
 		real32_t *: pldm__msgbuf_extract_real32)(ctx, dst)
 
-/**
- * @ref pldm_msgbuf_extract_array
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_WARN_UNUSED_RESULT
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_array_void(struct pldm_msgbuf *ctx, size_t count,
-				void *dst, size_t dst_count)
-{
-	if (count > dst_count) {
-		return -EINVAL;
-	}
-
-	if (!count) {
-		return 0;
-	}
-
-#if INTMAX_MAX < SIZE_MAX
-	if (count > INTMAX_MAX) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-#endif
-
-	if (ctx->remaining >= (intmax_t)count) {
-		assert(ctx->cursor);
-		memcpy(dst, ctx->cursor, count);
-		ctx->cursor += count;
-		ctx->remaining -= (intmax_t)count;
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
-		ctx->remaining -= (intmax_t)count;
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-/**
- * @ref pldm_msgbuf_extract_array
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_WARN_UNUSED_RESULT
-LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_extract_array_char(struct pldm_msgbuf *ctx, size_t count, char *dst,
-			       size_t dst_count)
-{
-	return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
-}
-
-/**
- * @ref pldm_msgbuf_extract_array
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_WARN_UNUSED_RESULT
-LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf *ctx, size_t count,
-				uint8_t *dst, size_t dst_count)
-{
-	return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
-}
-
-/**
- * Extract an array of data from the msgbuf instance
- *
- * @param ctx - The msgbuf instance from which to extract an array of data
- * @param count - The number of array elements to extract
- * @param dst - The array object into which elements from @p ctx should be
-                extracted
- * @param dst_count - The maximum number of elements to place into @p dst
- *
- * Note that both @p count and @p dst_count can only be counted by `sizeof` for
- * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
- * of array elements and _not_ the object size of the array.
- */
-#define pldm_msgbuf_extract_array(ctx, count, dst, dst_count)                  \
-	_Generic((*(dst)),                                                     \
-		uint8_t: pldm_msgbuf_extract_array_uint8,                      \
-		char: pldm_msgbuf_extract_array_char)(ctx, count, dst,         \
-						      dst_count)
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint64(struct pldm_msgbuf *ctx,
-						       const uint64_t src)
-{
-	uint64_t val = htole64(src);
-
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(src) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(src)) {
-		assert(ctx->cursor);
-		memcpy(ctx->cursor, &val, sizeof(val));
-		ctx->cursor += sizeof(src);
-		ctx->remaining -= sizeof(src);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
-		ctx->remaining -= sizeof(src);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint32(struct pldm_msgbuf *ctx,
-						       const uint32_t src)
-{
-	uint32_t val = htole32(src);
-
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(src) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(src)) {
-		assert(ctx->cursor);
-		memcpy(ctx->cursor, &val, sizeof(val));
-		ctx->cursor += sizeof(src);
-		ctx->remaining -= sizeof(src);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
-		ctx->remaining -= sizeof(src);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint16(struct pldm_msgbuf *ctx,
-						       const uint16_t src)
-{
-	uint16_t val = htole16(src);
-
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(src) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(src)) {
-		assert(ctx->cursor);
-		memcpy(ctx->cursor, &val, sizeof(val));
-		ctx->cursor += sizeof(src);
-		ctx->remaining -= sizeof(src);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
-		ctx->remaining -= sizeof(src);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_uint8(struct pldm_msgbuf *ctx,
-						      const uint8_t src)
-{
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(src) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(src)) {
-		assert(ctx->cursor);
-		memcpy(ctx->cursor, &src, sizeof(src));
-		ctx->cursor += sizeof(src);
-		ctx->remaining -= sizeof(src);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
-		ctx->remaining -= sizeof(src);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int32(struct pldm_msgbuf *ctx,
-						      const int32_t src)
-{
-	int32_t val = htole32(src);
-
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(src) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(src)) {
-		assert(ctx->cursor);
-		memcpy(ctx->cursor, &val, sizeof(val));
-		ctx->cursor += sizeof(src);
-		ctx->remaining -= sizeof(src);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
-		ctx->remaining -= sizeof(src);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int16(struct pldm_msgbuf *ctx,
-						      const int16_t src)
-{
-	int16_t val = htole16(src);
-
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(src) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(src)) {
-		assert(ctx->cursor);
-		memcpy(ctx->cursor, &val, sizeof(val));
-		ctx->cursor += sizeof(src);
-		ctx->remaining -= sizeof(src);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
-		ctx->remaining -= sizeof(src);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int8(struct pldm_msgbuf *ctx,
-						     const int8_t src)
-{
-	static_assert(
-		// NOLINTNEXTLINE(bugprone-sizeof-expression)
-		sizeof(src) < INTMAX_MAX,
-		"The following addition may not uphold the runtime assertion");
-
-	if (ctx->remaining >= (intmax_t)sizeof(src)) {
-		assert(ctx->cursor);
-		memcpy(ctx->cursor, &src, sizeof(src));
-		ctx->cursor += sizeof(src);
-		ctx->remaining -= sizeof(src);
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
-		ctx->remaining -= sizeof(src);
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
 #define pldm_msgbuf_insert(dst, src)                                           \
 	_Generic((src),                                                        \
 		uint8_t: pldm_msgbuf_insert_uint8,                             \
@@ -893,70 +173,6 @@
 		uint64_t: pldm_msgbuf_insert_uint64)(dst, src)
 
 /**
- * @ref pldm_msgbuf_insert_array
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_WARN_UNUSED_RESULT
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_insert_array_void(struct pldm_msgbuf *ctx, size_t count,
-			       const void *src, size_t src_count)
-{
-	if (count > src_count) {
-		return -EINVAL;
-	}
-
-	if (!count) {
-		return 0;
-	}
-
-#if INTMAX_MAX < SIZE_MAX
-	if (count > INTMAX_MAX) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-#endif
-
-	if (ctx->remaining >= (intmax_t)count) {
-		assert(ctx->cursor);
-		memcpy(ctx->cursor, src, count);
-		ctx->cursor += count;
-		ctx->remaining -= (intmax_t)count;
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
-		ctx->remaining -= (intmax_t)count;
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-/**
- * @ref pldm_msgbuf_insert_array
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_WARN_UNUSED_RESULT
-LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_insert_array_char(struct pldm_msgbuf *ctx, size_t count,
-			      const char *src, size_t src_count)
-{
-	return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
-}
-
-/**
- * @ref pldm_msgbuf_insert_array
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_WARN_UNUSED_RESULT
-LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf *ctx, size_t count,
-			       const uint8_t *src, size_t src_count)
-{
-	return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
-}
-
-/**
  * Insert an array of data into the msgbuf instance
  *
  * @param ctx - The msgbuf instance into which the array of data should be
@@ -976,530 +192,4 @@
 		char: pldm_msgbuf_insert_array_char)(dst, count, src,          \
 						     src_count)
 
-LIBPLDM_CC_NONNULL_ARGS(1)
-LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_required(struct pldm_msgbuf *ctx,
-						       size_t required,
-						       void **cursor)
-{
-#if INTMAX_MAX < SIZE_MAX
-	if (required > INTMAX_MAX) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-#endif
-
-	if (ctx->remaining >= (intmax_t)required) {
-		assert(ctx->cursor);
-		if (cursor) {
-			*cursor = ctx->cursor;
-		}
-		ctx->cursor += required;
-		ctx->remaining -= (intmax_t)required;
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)required) {
-		ctx->remaining -= (intmax_t)required;
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-LIBPLDM_CC_NONNULL_ARGS(1)
-LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_span_string_ascii(struct pldm_msgbuf *ctx, void **cursor,
-			      size_t *length)
-{
-	intmax_t measured;
-
-	if (ctx->remaining < 0) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-	assert(ctx->cursor);
-
-	measured = (intmax_t)strnlen((const char *)ctx->cursor, ctx->remaining);
-	if (measured == ctx->remaining) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-
-	/* Include the NUL terminator in the span length, as spans are opaque */
-	measured++;
-
-	if (ctx->remaining >= measured) {
-		assert(ctx->cursor);
-		if (cursor) {
-			*cursor = ctx->cursor;
-		}
-
-		ctx->cursor += measured;
-
-		if (length) {
-			*length = measured;
-		}
-
-		ctx->remaining -= measured;
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + measured) {
-		ctx->remaining -= measured;
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-LIBPLDM_CC_NONNULL_ARGS(1)
-LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_span_string_utf16(struct pldm_msgbuf *ctx, void **cursor,
-			      size_t *length)
-{
-	static const char16_t term = 0;
-	ptrdiff_t measured;
-	void *end;
-
-	if (ctx->remaining < 0) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-	assert(ctx->cursor);
-
-	/*
-	 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
-	 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
-	 * start of the string
-	 */
-	end = ctx->cursor;
-	do {
-		if (end != ctx->cursor) {
-			/*
-			 * If we've looped we've found a relatively-unaligned NUL code-point.
-			 * Scan again from a relatively-aligned start point.
-			 */
-			end = (char *)end + 1;
-		}
-		measured = (char *)end - (char *)ctx->cursor;
-		end = memmem(end, ctx->remaining - measured, &term,
-			     sizeof(term));
-	} while (end && ((uintptr_t)end & 1) != ((uintptr_t)ctx->cursor & 1));
-
-	if (!end) {
-		/*
-		 * Optimistically, the last required pattern byte was one beyond the end of
-		 * the buffer. Setting ctx->remaining negative ensures the
-		 * `pldm_msgbuf_complete*()` APIs also return an error.
-		 */
-		return pldm__msgbuf_invalidate(ctx);
-	}
-
-	end = (char *)end + sizeof(char16_t);
-	measured = (char *)end - (char *)ctx->cursor;
-
-#if INTMAX_MAX < PTRDIFF_MAX
-	if (measured >= INTMAX_MAX) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-#endif
-
-	if (ctx->remaining >= (intmax_t)measured) {
-		assert(ctx->cursor);
-		if (cursor) {
-			*cursor = ctx->cursor;
-		}
-
-		ctx->cursor += measured;
-
-		if (length) {
-			*length = (size_t)measured;
-		}
-
-		ctx->remaining -= (intmax_t)measured;
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)measured) {
-		ctx->remaining -= (intmax_t)measured;
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_span_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
-{
-	if (ctx->remaining < 0) {
-		return -EOVERFLOW;
-	}
-
-	assert(ctx->cursor);
-	*cursor = ctx->cursor;
-	ctx->cursor += ctx->remaining;
-	*len = ctx->remaining;
-	ctx->remaining = 0;
-
-	return 0;
-}
-
-LIBPLDM_CC_NONNULL_ARGS(1)
-LIBPLDM_CC_ALWAYS_INLINE
-int pldm_msgbuf_span_until(struct pldm_msgbuf *ctx, size_t trailer,
-			   void **cursor, size_t *length)
-{
-#if INTMAX_MAX < SIZE_MAX
-	if (trailer > INTMAX_MAX) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-#endif
-
-	if (ctx->remaining >= (intmax_t)trailer) {
-		ptrdiff_t delta;
-
-		assert(ctx->cursor);
-
-		delta = ctx->remaining - (intmax_t)trailer;
-		if (cursor) {
-			*cursor = ctx->cursor;
-		}
-		ctx->cursor += delta;
-		if (length) {
-			*length = delta;
-		}
-		ctx->remaining = (intmax_t)trailer;
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)trailer) {
-		ctx->remaining = INTMAX_MIN + (intmax_t)trailer;
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_peek_remaining(struct pldm_msgbuf *ctx, void **cursor, size_t *len)
-{
-	if (ctx->remaining < 0) {
-		return -EOVERFLOW;
-	}
-
-	assert(ctx->cursor);
-	*cursor = ctx->cursor;
-	*len = ctx->remaining;
-
-	return 0;
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_skip(struct pldm_msgbuf *ctx,
-					      size_t count)
-{
-#if INTMAX_MAX < SIZE_MAX
-	if (count > INTMAX_MAX) {
-		return pldm__msgbuf_invalidate(ctx);
-	}
-#endif
-
-	if (ctx->remaining >= (intmax_t)count) {
-		assert(ctx->cursor);
-		ctx->cursor += count;
-		ctx->remaining -= (intmax_t)count;
-		return 0;
-	}
-
-	if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
-		ctx->remaining -= (intmax_t)count;
-		return -EOVERFLOW;
-	}
-
-	return pldm__msgbuf_invalidate(ctx);
-}
-
-/**
- * @brief Complete the pldm_msgbuf instance and return the number of bytes
- * consumed.
- *
- * @param ctx - The msgbuf.
- * @param orig_len - The original size of the msgbuf, the `len` argument passed to
- * 		pldm_msgbuf_init_errno().
- * @param ret_used_len - The number of bytes that have been used from the msgbuf instance.
- *
- * This can be called after a number of pldm_msgbuf_insert...() calls to
- * determine the total size that was written.
- *
- * @return 0 on success, -EOVERFLOW if an implausible orig_len was provided or
- * an out-of-bounds access occurred.
- */
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE
-LIBPLDM_CC_WARN_UNUSED_RESULT
-int pldm_msgbuf_complete_used(struct pldm_msgbuf *ctx, size_t orig_len,
-			      size_t *ret_used_len)
-{
-	int rc;
-
-	ctx->cursor = NULL;
-	rc = pldm_msgbuf_validate(ctx);
-	if (rc) {
-		pldm__msgbuf_invalidate(ctx);
-		return rc;
-	}
-
-	if ((size_t)ctx->remaining > orig_len) {
-		/* Caller passed incorrect orig_len */
-		return pldm__msgbuf_invalidate(ctx);
-	}
-
-	*ret_used_len = orig_len - ctx->remaining;
-	pldm__msgbuf_invalidate(ctx);
-	return 0;
-}
-
-/**
- * @brief pldm_msgbuf copy data between two msg buffers
- *
- * @param[in,out] src - pldm_msgbuf for source from where value should be copied
- * @param[in,out] dst - destination of copy from source
- * @param[in] size - size of data to be copied
- * @param[in] description - description of data copied
- *
- * @return PLDM_SUCCESS if buffer accesses were in-bounds,
- * PLDM_ERROR_INVALID_LENGTH otherwise.
- * PLDM_ERROR_INVALID_DATA if input is invalid
- */
-#define pldm_msgbuf_copy(dst, src, type, name)                                 \
-	pldm__msgbuf_copy(dst, src, sizeof(type), #name)
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_copy(struct pldm_msgbuf *dst, struct pldm_msgbuf *src, size_t size,
-		  const char *description LIBPLDM_CC_UNUSED)
-{
-#if INTMAX_MAX < SIZE_MAX
-	if (size > INTMAX_MAX) {
-		pldm__msgbuf_invalidate(src);
-		pldm__msgbuf_invalidate(dst);
-		return -EOVERFLOW;
-	}
-#endif
-
-	if (src->remaining >= (intmax_t)size &&
-	    dst->remaining >= (intmax_t)size) {
-		assert(src->cursor && dst->cursor);
-		memcpy(dst->cursor, src->cursor, size);
-		src->cursor += size;
-		src->remaining -= (intmax_t)size;
-		dst->cursor += size;
-		dst->remaining -= (intmax_t)size;
-		return 0;
-	}
-
-	if (src->remaining > INTMAX_MIN + (intmax_t)size) {
-		src->remaining -= (intmax_t)size;
-	} else {
-		pldm__msgbuf_invalidate(src);
-	}
-
-	if (dst->remaining > INTMAX_MIN + (intmax_t)size) {
-		dst->remaining -= (intmax_t)size;
-	} else {
-		pldm__msgbuf_invalidate(dst);
-	}
-
-	return -EOVERFLOW;
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_WARN_UNUSED_RESULT
-LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
-{
-	void *ascii = NULL;
-	size_t len = 0;
-	int rc;
-
-	rc = pldm_msgbuf_span_string_ascii(src, &ascii, &len);
-	if (rc < 0) {
-		return rc;
-	}
-
-	return pldm__msgbuf_insert_array_void(dst, len, ascii, len);
-}
-
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_WARN_UNUSED_RESULT
-LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf *dst, struct pldm_msgbuf *src)
-{
-	void *utf16 = NULL;
-	size_t len = 0;
-	int rc;
-
-	rc = pldm_msgbuf_span_string_utf16(src, &utf16, &len);
-	if (rc < 0) {
-		return rc;
-	}
-
-	return pldm__msgbuf_insert_array_void(dst, len, utf16, len);
-}
-
-/**
- * @brief pldm_msgbuf uint8_t extractor for a size_t
- *
- * @param[in,out] ctx - pldm_msgbuf context for extractor
- * @param[out] dst - destination of extracted value
- *
- * @return 0 if buffer accesses were in-bounds,
- * -EINVAL if dst pointer is invalid,
- * -EOVERFLOW is the buffer was out of bound.
- */
-#define pldm_msgbuf_extract_uint8_to_size(ctx, dst)                            \
-	pldm__msgbuf_extract_uint8_to_size(ctx, &(dst))
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_uint8_to_size(struct pldm_msgbuf *ctx, size_t *dst)
-{
-	uint8_t value;
-	int rc;
-
-	rc = pldm__msgbuf_extract_uint8(ctx, &value);
-	if (rc) {
-		return rc;
-	}
-
-	static_assert(SIZE_MAX >= UINT8_MAX, "Invalid promotion");
-
-	*dst = value;
-	return 0;
-}
-
-/**
- * @brief pldm_msgbuf uint16_t extractor for a size_t
- *
- * @param[in,out] ctx - pldm_msgbuf context for extractor
- * @param[out] dst - destination of extracted value
- *
- * @return 0 if buffer accesses were in-bounds,
- * -EINVAL if dst pointer is invalid,
- * -EOVERFLOW is the buffer was out of bound.
- */
-#define pldm_msgbuf_extract_uint16_to_size(ctx, dst)                           \
-	pldm__msgbuf_extract_uint16_to_size(ctx, &(dst))
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_uint16_to_size(struct pldm_msgbuf *ctx, size_t *dst)
-{
-	uint16_t value;
-	int rc;
-
-	rc = pldm__msgbuf_extract_uint16(ctx, &value);
-	if (rc) {
-		return rc;
-	}
-
-	static_assert(SIZE_MAX >= UINT16_MAX, "Invalid promotion");
-
-	*dst = value;
-	return 0;
-}
-
-/**
- * @brief pldm_msgbuf uint32_t extractor for a size_t
- *
- * @param[in,out] ctx - pldm_msgbuf context for extractor
- * @param[out] dst - destination of extracted value
- *
- * @return 0 if buffer accesses were in-bounds,
- * -EINVAL if dst pointer is invalid,
- * -EOVERFLOW is the buffer was out of bound.
- */
-#define pldm_msgbuf_extract_uint32_to_size(ctx, dst)                           \
-	pldm__msgbuf_extract_uint32_to_size(ctx, &(dst))
-LIBPLDM_CC_NONNULL
-LIBPLDM_CC_ALWAYS_INLINE int
-// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
-pldm__msgbuf_extract_uint32_to_size(struct pldm_msgbuf *ctx, size_t *dst)
-{
-	uint32_t value;
-	int rc;
-
-	rc = pldm__msgbuf_extract_uint32(ctx, &value);
-	if (rc) {
-		return rc;
-	}
-
-	static_assert(SIZE_MAX >= UINT32_MAX, "Invalid promotion");
-
-	*dst = value;
-	return 0;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __cplusplus
-#include <type_traits>
-
-template <typename T>
-static inline int pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf *ctx,
-						void *buf)
-{
-	static_assert(std::is_same<uint8_t, T>::value);
-	return pldm__msgbuf_extract_uint8(ctx, buf);
-}
-
-template <typename T>
-static inline int pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf *ctx,
-					       void *buf)
-{
-	static_assert(std::is_same<int8_t, T>::value);
-	return pldm__msgbuf_extract_int8(ctx, buf);
-}
-
-template <typename T>
-static inline int pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf *ctx,
-						 void *buf)
-{
-	static_assert(std::is_same<uint16_t, T>::value);
-	return pldm__msgbuf_extract_uint16(ctx, buf);
-}
-
-template <typename T>
-static inline int pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf *ctx,
-						void *buf)
-{
-	static_assert(std::is_same<int16_t, T>::value);
-	return pldm__msgbuf_extract_int16(ctx, buf);
-}
-
-template <typename T>
-static inline int pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf *ctx,
-						 void *buf)
-{
-	static_assert(std::is_same<uint32_t, T>::value);
-	return pldm__msgbuf_extract_uint32(ctx, buf);
-}
-
-template <typename T>
-static inline int pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf *ctx,
-						void *buf)
-{
-	static_assert(std::is_same<int32_t, T>::value);
-	return pldm__msgbuf_extract_int32(ctx, buf);
-}
-
-template <typename T>
-static inline int pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf *ctx,
-						 void *buf)
-{
-	static_assert(std::is_same<real32_t, T>::value);
-	return pldm__msgbuf_extract_real32(ctx, buf);
-}
-#endif
-
 #endif /* BUF_H */
diff --git a/src/msgbuf/core.h b/src/msgbuf/core.h
new file mode 100644
index 0000000..bce7b59
--- /dev/null
+++ b/src/msgbuf/core.h
@@ -0,0 +1,1579 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+#ifndef PLDM_MSGBUF_CORE_H
+#define PLDM_MSGBUF_CORE_H
+
+/*
+ * Historically, many of the structs exposed in libpldm's public headers are
+ * defined with __attribute__((packed)). This is unfortunate: it gives the
+ * impression that a wire-format buffer can be cast to the message type to make
+ * the message's fields easily accessible. As it turns out, that's not
+ * that's valid for several reasons:
+ *
+ * 1. Casting the wire-format buffer to a struct of the message type doesn't
+ *    abstract the endianness of message field values
+ *
+ * 2. Some messages contain packed tagged union fields which cannot be properly
+ *    described in a C struct.
+ *
+ * The msgbuf APIs exist to assist with (un)packing the wire-format in a way
+ * that is type-safe, spatially memory-safe, endian-safe, performant, and
+ * free of undefined-behaviour. Message structs that are added to the public
+ * library API should no-longer be marked __attribute__((packed)), and the
+ * implementation of their encode and decode functions must exploit the msgbuf
+ * API.
+ *
+ * However, we would like to allow implementation of codec functions in terms of
+ * msgbuf APIs even if they're decoding a message into a (historically) packed
+ * struct. Some of the complexity that follows is a consequence of the packed/
+ * unpacked conflict.
+ */
+
+#ifdef __cplusplus
+/*
+ * Fix up C11's _Static_assert() vs C++'s static_assert().
+ *
+ * Can we please have nice things for once.
+ */
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+#define _Static_assert(...) static_assert(__VA_ARGS__)
+
+extern "C" {
+#endif
+
+#include "compiler.h"
+
+#include <libpldm/pldm_types.h>
+
+#include <endian.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <uchar.h>
+
+/*
+ * We can't use static_assert() outside of some other C construct. Deal
+ * with high-level global assertions by burying them in an unused struct
+ * declaration, that has a sole member for compliance with the requirement that
+ * types must have a size.
+*/
+static struct {
+	static_assert(
+		INTMAX_MAX != SIZE_MAX,
+		"Extraction and insertion value comparisons may be broken");
+	static_assert(INTMAX_MIN + INTMAX_MAX <= 0,
+		      "Extraction and insertion arithmetic may be broken");
+	int compliance;
+} build_assertions LIBPLDM_CC_UNUSED;
+
+struct pldm_msgbuf_rw {
+	uint8_t *cursor;
+	intmax_t remaining;
+};
+
+struct pldm_msgbuf_ro {
+	const uint8_t *cursor;
+	intmax_t remaining;
+};
+
+LIBPLDM_CC_ALWAYS_INLINE
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+void pldm__msgbuf_cleanup(const void *cursor LIBPLDM_CC_UNUSED,
+			  intmax_t remaining LIBPLDM_CC_UNUSED)
+{
+	assert(cursor == NULL && remaining == INTMAX_MIN);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+void pldm__msgbuf_rw_cleanup(struct pldm_msgbuf_rw *ctx LIBPLDM_CC_UNUSED)
+{
+	pldm__msgbuf_cleanup((const void *)ctx->cursor, ctx->remaining);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+void pldm__msgbuf_ro_cleanup(struct pldm_msgbuf_ro *ctx LIBPLDM_CC_UNUSED)
+{
+	pldm__msgbuf_cleanup((const void *)ctx->cursor, ctx->remaining);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+int pldm__msgbuf_set_invalid(intmax_t *remaining)
+{
+	*remaining = INTMAX_MIN;
+	return -EOVERFLOW;
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+int pldm__msgbuf_rw_invalidate(struct pldm_msgbuf_rw *ctx)
+{
+	return pldm__msgbuf_set_invalid(&ctx->remaining);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+int pldm__msgbuf_ro_invalidate(struct pldm_msgbuf_ro *ctx)
+{
+	return pldm__msgbuf_set_invalid(&ctx->remaining);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_init_errno(const uint8_t **cursor, intmax_t *remaining,
+			size_t minsize, const void *buf, size_t len)
+{
+	*cursor = NULL;
+
+	if ((minsize > len)) {
+		return pldm__msgbuf_set_invalid(remaining);
+	}
+
+#if INTMAX_MAX < SIZE_MAX
+	if (len > INTMAX_MAX) {
+		return pldm__msgbuf_set_invalid(remaining);
+	}
+#endif
+
+	if (UINTPTR_MAX - (uintptr_t)buf < len) {
+		return pldm__msgbuf_set_invalid(remaining);
+	}
+
+	*cursor = (const uint8_t *)buf;
+	*remaining = (intmax_t)len;
+
+	return 0;
+}
+
+/**
+ * @brief Initialize pldm buf struct for buf extractor
+ *
+ * @param[out] ctx - pldm_msgbuf_rw context for extractor
+ * @param[in] minsize - The minimum required length of buffer `buf`
+ * @param[in] buf - buffer to be extracted
+ * @param[in] len - size of buffer
+ *
+ * @return 0 on success, otherwise an error code appropriate for the current
+ *         personality.
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm_msgbuf_rw_init_errno(struct pldm_msgbuf_rw *ctx, size_t minsize,
+			  const void *buf, size_t len)
+{
+	return pldm__msgbuf_init_errno((const uint8_t **)&ctx->cursor,
+				       &ctx->remaining, minsize, buf, len);
+}
+
+/**
+ * @brief Initialize pldm buf struct for buf extractor
+ *
+ * @param[out] ctx - pldm_msgbuf_ro context for extractor
+ * @param[in] minsize - The minimum required length of buffer `buf`
+ * @param[in] buf - buffer to be extracted
+ * @param[in] len - size of buffer
+ *
+ * @return 0 on success, otherwise an error code appropriate for the current
+ *         personality.
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm_msgbuf_ro_init_errno(struct pldm_msgbuf_ro *ctx, size_t minsize,
+			  const void *buf, size_t len)
+{
+	return pldm__msgbuf_init_errno(&ctx->cursor, &ctx->remaining, minsize,
+				       buf, len);
+}
+
+/**
+ * @brief Validate buffer overflow state
+ *
+ * @param[in] ctx - msgbuf context for extractor
+ *
+ * @return PLDM_SUCCESS if there are zero or more bytes of data that remain
+ * unread from the buffer. Otherwise, PLDM_ERROR_INVALID_LENGTH indicates that a
+ * prior accesses would have occurred beyond the bounds of the buffer, and
+ * PLDM_ERROR_INVALID_DATA indicates that the provided context was not a valid
+ * pointer.
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+int pldm__msgbuf_validate(intmax_t remaining)
+{
+	if (remaining < 0) {
+		return -EOVERFLOW;
+	}
+
+	return 0;
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_ro_validate(struct pldm_msgbuf_ro *ctx)
+{
+	return pldm__msgbuf_validate(ctx->remaining);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_rw_validate(struct pldm_msgbuf_rw *ctx)
+{
+	return pldm__msgbuf_validate(ctx->remaining);
+}
+
+/**
+ * @brief Test whether a message buffer has been exactly consumed
+ *
+ * @param[in] ctx - pldm_msgbuf context for extractor
+ *
+ * @return 0 iff there are zero bytes of data that remain unread from the buffer
+ * and no overflow has occurred. Otherwise, -EBADMSG if the buffer has not been
+ * completely consumed, or -EOVERFLOW if accesses were attempted beyond the
+ * bounds of the buffer.
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+int pldm__msgbuf_consumed(intmax_t remaining)
+{
+	if (remaining > 0) {
+		return -EBADMSG;
+	}
+
+	if (remaining < 0) {
+		return -EOVERFLOW;
+	}
+
+	return 0;
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_ro_consumed(struct pldm_msgbuf_ro *ctx)
+{
+	return pldm__msgbuf_consumed(ctx->remaining);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_rw_consumed(struct pldm_msgbuf_rw *ctx)
+{
+	return pldm__msgbuf_consumed(ctx->remaining);
+}
+
+/**
+ * @brief End use of a msgbuf under error conditions
+ *
+ * @param[in] ctx - The msgbuf instance to discard
+ * @param[in] error - The error value to propagate
+ *
+ * Under normal conditions use of a msgbuf instance must be ended using @ref
+ * pldm_msgbuf_complete or one of its related APIs. Under error conditions, @ref
+ * pldm_msgbuf_discard should be used instead, as it makes it straight-forward
+ * to finalise the msgbuf while propagating the existing error code.
+ *
+ * @return The value provided in @param error
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+int pldm__msgbuf_discard(const uint8_t **cursor, intmax_t *remaining, int error)
+{
+	*cursor = NULL;
+	pldm__msgbuf_set_invalid(remaining);
+	return error;
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_rw_discard(struct pldm_msgbuf_rw *ctx, int error)
+{
+	return pldm__msgbuf_discard((const uint8_t **)&ctx->cursor,
+				    &ctx->remaining, error);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_ro_discard(struct pldm_msgbuf_ro *ctx, int error)
+{
+	return pldm__msgbuf_discard(&ctx->cursor, &ctx->remaining, error);
+}
+
+/**
+ * @brief Complete the pldm_msgbuf_rw instance
+ *
+ * @param[in] ctx - pldm_msgbuf_rw context for extractor
+ *
+ * @return 0 if all buffer accesses were in-bounds, -EOVERFLOW otherwise.
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_rw_complete(struct pldm_msgbuf_rw *ctx)
+{
+	return pldm_msgbuf_rw_discard(ctx, pldm_msgbuf_rw_validate(ctx));
+}
+
+/**
+ * @brief Complete the pldm_msgbuf_ro instance
+ *
+ * @param[in] ctx - pldm_msgbuf_ro context for extractor
+ *
+ * @return 0 if all buffer accesses were in-bounds, -EOVERFLOW otherwise.
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_ro_complete(struct pldm_msgbuf_ro *ctx)
+{
+	return pldm_msgbuf_ro_discard(ctx, pldm_msgbuf_ro_validate(ctx));
+}
+
+/**
+ * @brief Complete the pldm_msgbuf_rw instance, and check that the underlying buffer
+ * has been entirely consumed without overflow
+ *
+ * @param[in] ctx - pldm_msgbuf_rw context
+ *
+ * @return 0 if all buffer access were in-bounds and completely consume the
+ * underlying buffer. Otherwise, -EBADMSG if the buffer has not been completely
+ * consumed, or -EOVERFLOW if accesses were attempted beyond the bounds of the
+ * buffer.
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_rw_complete_consumed(struct pldm_msgbuf_rw *ctx)
+{
+	return pldm_msgbuf_rw_discard(ctx, pldm_msgbuf_rw_consumed(ctx));
+}
+
+/**
+ * @brief Complete the pldm_msgbuf_ro instance, and check that the underlying buffer
+ * has been entirely consumed without overflow
+ *
+ * @param[in] ctx - pldm_msgbuf_ro context
+ *
+ * @return 0 if all buffer access were in-bounds and completely consume the
+ * underlying buffer. Otherwise, -EBADMSG if the buffer has not been completely
+ * consumed, or -EOVERFLOW if accesses were attempted beyond the bounds of the
+ * buffer.
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_ro_complete_consumed(struct pldm_msgbuf_ro *ctx)
+{
+	return pldm_msgbuf_ro_discard(ctx, pldm_msgbuf_ro_consumed(ctx));
+}
+
+/*
+ * Exploit the pre-processor to perform type checking by macro substitution.
+ *
+ * A C type is defined by its alignment as well as its object
+ * size, and compilers have a hammer to enforce it in the form of
+ * `-Waddress-of-packed-member`. Due to the unpacked/packed struct conflict in
+ * the libpldm public API this presents a problem: Naively attempting to use the
+ * msgbuf APIs on a member of a packed struct would yield an error.
+ *
+ * The msgbuf APIs are implemented such that data is moved through unaligned
+ * pointers in a safe way, but to mitigate `-Waddress-of-packed-member` we must
+ * make the object pointers take a trip through `void *` at its API boundary.
+ * That presents a bit too much of an opportunity to non-surgically remove your
+ * own foot, so here we set about doing something to mitigate that as well.
+ *
+ * pldm_msgbuf_extract_typecheck() exists to enforce pointer type correctness
+ * only for the purpose of object sizes, disregarding alignment. We have a few
+ * constraints that cause some headaches:
+ *
+ * 1. We have to perform the type-check before a call through a C function,
+ *    as the function must take the object pointer argument as `void *`.
+ *    Essentially, this constrains us to doing something with macros.
+ *
+ * 2. While libpldm is a C library, its test suite is written in C++ to take
+ *    advantage of gtest.
+ *
+ * 3. Ideally we'd do something with C's `static_assert()`, however
+ *    `static_assert()` is defined as void, and as we're constrained to macros,
+ *    using `static_assert()` would require a statement-expression
+ *
+ * 4. Currently the project is built with `-std=c17`. CPP statement-expressions
+ *    are a GNU extension. We prefer to avoid switching to `-std=gnu17` just for
+ *    the purpose of enabling statement-expressions in this one instance.
+ *
+ * 5. We can achieve a conditional build error using `pldm_require_obj_type()`,
+ *    however it's implemented in terms of `_Generic()`, which is not available
+ *    in C++.
+ *
+ * Combined this means we need separate solutions for C and C++.
+ *
+ * For C, as we don't have statement-expressions, we need to exploit some other
+ * language feature to inject a `pldm_require_obj_type()` prior to the msgbuf
+ * API function call. We also have to take care of the fact that the call-sites
+ * may be in the context of a variable assignment for error-handling purposes.
+ * The key observation is that we can use the comma operator as a sequence point
+ * to order the type check before the API call, discarding the "result" value of
+ * the type check and yielding the return value of the API call.
+ *
+ * C++ could be less of a headache than the C as we can leverage template
+ * functions. An advantage of template functions is that while their definition
+ * is driven by instantion, the definition does not appear at the source
+ * location of the instantiation, which gives it a great leg-up over the problems
+ * we have in the C path. However, the use of the msgbuf APIs in the test suite
+ * still makes things somewhat tricky, as the call-sites in the test suite are
+ * wrapped up in EXPECT_*() gtest macros. Ideally we'd implement functions that
+ * takes both the object type and the required type as template arguments, and
+ * then define the object pointer parameter as `void *` for a call through to
+ * the appropriate msgbuf API. However, because the msgbuf API call-sites are
+ * encapsulated in gtest macros, use of commas in the template specification
+ * causes pre-processor confusion. In this way we're constrained to only one
+ * template argument per function.
+ *
+ * Implement the C++ path using template functions that take the destination
+ * object type as a template argument, while the name of the function symbols
+ * are derived from the required type. The manual implementations of these
+ * appear at the end of the header. The type safety is actually enforced
+ * by `static_assert()` this time, as we can use statements as we're not
+ * constrained to an expression in the templated function body.
+ *
+ * The invocations of pldm_msgbuf_extract_typecheck() typically result in
+ * double-evaluation of some arguments. We're not yet bothered by this for two
+ * reasons:
+ *
+ * 1. The nature of the current call-sites are such that there are no
+ *    argument expressions that result in undesirable side-effects
+ *
+ * 2. It's an API internal to the libpldm implementation, and we can fix things
+ *    whenever something crops up the violates the observation in 1.
+ */
+
+/**
+ * @brief pldm_msgbuf extractor for a uint8_t
+ *
+ * @param[in,out] ctx - pldm_msgbuf context for extractor
+ * @param[out] dst - destination of extracted value
+ *
+ * @return PLDM_SUCCESS if buffer accesses were in-bounds,
+ * PLDM_ERROR_INVALID_LENGTH otherwise.
+ * PLDM_ERROR_INVALID_DATA if input a invalid ctx
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_uint8(struct pldm_msgbuf_ro *ctx, void *dst)
+{
+	if (ctx->remaining >= (intmax_t)sizeof(uint8_t)) {
+		assert(ctx->cursor);
+		memcpy(dst, ctx->cursor, sizeof(uint8_t));
+		ctx->cursor++;
+		ctx->remaining -= sizeof(uint8_t);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(uint8_t)) {
+		ctx->remaining -= sizeof(uint8_t);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_ro_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_int8(struct pldm_msgbuf_ro *ctx, void *dst)
+{
+	if (ctx->remaining >= (intmax_t)sizeof(int8_t)) {
+		assert(ctx->cursor);
+		memcpy(dst, ctx->cursor, sizeof(int8_t));
+		ctx->cursor++;
+		ctx->remaining -= sizeof(int8_t);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(int8_t)) {
+		ctx->remaining -= sizeof(int8_t);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_ro_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_uint16(struct pldm_msgbuf_ro *ctx, void *dst)
+{
+	uint16_t ldst;
+
+	// Check for underflow while tracking the magnitude of the buffer overflow
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(ldst) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
+		assert(ctx->cursor);
+
+		// Use memcpy() to have the compiler deal with any alignment
+		// issues on the target architecture
+		memcpy(&ldst, ctx->cursor, sizeof(ldst));
+
+		// Only assign the target value once it's correctly decoded
+		ldst = le16toh(ldst);
+
+		// Allow storing to unaligned
+		memcpy(dst, &ldst, sizeof(ldst));
+
+		ctx->cursor += sizeof(ldst);
+		ctx->remaining -= sizeof(ldst);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+		ctx->remaining -= sizeof(ldst);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_ro_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_int16(struct pldm_msgbuf_ro *ctx, void *dst)
+{
+	int16_t ldst;
+
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(ldst) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
+		assert(ctx->cursor);
+		memcpy(&ldst, ctx->cursor, sizeof(ldst));
+		ldst = le16toh(ldst);
+		memcpy(dst, &ldst, sizeof(ldst));
+		ctx->cursor += sizeof(ldst);
+		ctx->remaining -= sizeof(ldst);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+		ctx->remaining -= sizeof(ldst);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_ro_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_uint32(struct pldm_msgbuf_ro *ctx, void *dst)
+{
+	uint32_t ldst;
+
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(ldst) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
+		assert(ctx->cursor);
+		memcpy(&ldst, ctx->cursor, sizeof(ldst));
+		ldst = le32toh(ldst);
+		memcpy(dst, &ldst, sizeof(ldst));
+		ctx->cursor += sizeof(ldst);
+		ctx->remaining -= sizeof(ldst);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+		ctx->remaining -= sizeof(ldst);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_ro_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_int32(struct pldm_msgbuf_ro *ctx, void *dst)
+{
+	int32_t ldst;
+
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(ldst) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
+		assert(ctx->cursor);
+		memcpy(&ldst, ctx->cursor, sizeof(ldst));
+		ldst = le32toh(ldst);
+		memcpy(dst, &ldst, sizeof(ldst));
+		ctx->cursor += sizeof(ldst);
+		ctx->remaining -= sizeof(ldst);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+		ctx->remaining -= sizeof(ldst);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_ro_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_real32(struct pldm_msgbuf_ro *ctx, void *dst)
+{
+	uint32_t ldst;
+
+	static_assert(sizeof(real32_t) == sizeof(ldst),
+		      "Mismatched type sizes for dst and ldst");
+
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(ldst) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(ldst)) {
+		assert(ctx->cursor);
+		memcpy(&ldst, ctx->cursor, sizeof(ldst));
+		ldst = le32toh(ldst);
+		memcpy(dst, &ldst, sizeof(ldst));
+		ctx->cursor += sizeof(ldst);
+		ctx->remaining -= sizeof(ldst);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(ldst)) {
+		ctx->remaining -= sizeof(ldst);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_ro_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_WARN_UNUSED_RESULT
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_array_void(struct pldm_msgbuf_ro *ctx, size_t count,
+				void *dst, size_t dst_count)
+{
+	if (count > dst_count) {
+		return -EINVAL;
+	}
+
+	if (!count) {
+		return 0;
+	}
+
+#if INTMAX_MAX < SIZE_MAX
+	if (count > INTMAX_MAX) {
+		return pldm__msgbuf_ro_invalidate(ctx);
+	}
+#endif
+
+	if (ctx->remaining >= (intmax_t)count) {
+		assert(ctx->cursor);
+		memcpy(dst, ctx->cursor, count);
+		ctx->cursor += count;
+		ctx->remaining -= (intmax_t)count;
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
+		ctx->remaining -= (intmax_t)count;
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_ro_invalidate(ctx);
+}
+
+/**
+ * @ref pldm_msgbuf_extract_array
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_WARN_UNUSED_RESULT
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_extract_array_char(struct pldm_msgbuf_ro *ctx, size_t count,
+			       char *dst, size_t dst_count)
+{
+	return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
+}
+
+/**
+ * @ref pldm_msgbuf_extract_array
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_WARN_UNUSED_RESULT
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_extract_array_uint8(struct pldm_msgbuf_ro *ctx, size_t count,
+				uint8_t *dst, size_t dst_count)
+{
+	return pldm__msgbuf_extract_array_void(ctx, count, dst, dst_count);
+}
+
+/**
+ * Extract an array of data from the msgbuf instance
+ *
+ * @param ctx - The msgbuf instance from which to extract an array of data
+ * @param count - The number of array elements to extract
+ * @param dst - The array object into which elements from @p ctx should be
+                extracted
+ * @param dst_count - The maximum number of elements to place into @p dst
+ *
+ * Note that both @p count and @p dst_count can only be counted by `sizeof` for
+ * arrays where `sizeof(*dst) == 1` holds. Specifically, they count the number
+ * of array elements and _not_ the object size of the array.
+ */
+#define pldm_msgbuf_extract_array(ctx, count, dst, dst_count)                  \
+	_Generic((*(dst)),                                                     \
+		uint8_t: pldm_msgbuf_extract_array_uint8,                      \
+		char: pldm_msgbuf_extract_array_char)(ctx, count, dst,         \
+						      dst_count)
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_insert_uint64(struct pldm_msgbuf_rw *ctx, const uint64_t src)
+{
+	uint64_t val = htole64(src);
+
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(src)) {
+		assert(ctx->cursor);
+		memcpy(ctx->cursor, &val, sizeof(val));
+		ctx->cursor += sizeof(src);
+		ctx->remaining -= sizeof(src);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
+		ctx->remaining -= sizeof(src);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_rw_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_insert_uint32(struct pldm_msgbuf_rw *ctx, const uint32_t src)
+{
+	uint32_t val = htole32(src);
+
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(src)) {
+		assert(ctx->cursor);
+		memcpy(ctx->cursor, &val, sizeof(val));
+		ctx->cursor += sizeof(src);
+		ctx->remaining -= sizeof(src);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
+		ctx->remaining -= sizeof(src);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_rw_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_insert_uint16(struct pldm_msgbuf_rw *ctx, const uint16_t src)
+{
+	uint16_t val = htole16(src);
+
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(src)) {
+		assert(ctx->cursor);
+		memcpy(ctx->cursor, &val, sizeof(val));
+		ctx->cursor += sizeof(src);
+		ctx->remaining -= sizeof(src);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
+		ctx->remaining -= sizeof(src);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_rw_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_insert_uint8(struct pldm_msgbuf_rw *ctx, const uint8_t src)
+{
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(src)) {
+		assert(ctx->cursor);
+		memcpy(ctx->cursor, &src, sizeof(src));
+		ctx->cursor += sizeof(src);
+		ctx->remaining -= sizeof(src);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
+		ctx->remaining -= sizeof(src);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_rw_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_insert_int32(struct pldm_msgbuf_rw *ctx, const int32_t src)
+{
+	int32_t val = htole32(src);
+
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(src)) {
+		assert(ctx->cursor);
+		memcpy(ctx->cursor, &val, sizeof(val));
+		ctx->cursor += sizeof(src);
+		ctx->remaining -= sizeof(src);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
+		ctx->remaining -= sizeof(src);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_rw_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_insert_int16(struct pldm_msgbuf_rw *ctx, const int16_t src)
+{
+	int16_t val = htole16(src);
+
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(src)) {
+		assert(ctx->cursor);
+		memcpy(ctx->cursor, &val, sizeof(val));
+		ctx->cursor += sizeof(src);
+		ctx->remaining -= sizeof(src);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
+		ctx->remaining -= sizeof(src);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_rw_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_insert_int8(struct pldm_msgbuf_rw *ctx,
+						     const int8_t src)
+{
+	static_assert(
+		// NOLINTNEXTLINE(bugprone-sizeof-expression)
+		sizeof(src) < INTMAX_MAX,
+		"The following addition may not uphold the runtime assertion");
+
+	if (ctx->remaining >= (intmax_t)sizeof(src)) {
+		assert(ctx->cursor);
+		memcpy(ctx->cursor, &src, sizeof(src));
+		ctx->cursor += sizeof(src);
+		ctx->remaining -= sizeof(src);
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)sizeof(src)) {
+		ctx->remaining -= sizeof(src);
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_rw_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_WARN_UNUSED_RESULT
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_insert_array_void(struct pldm_msgbuf_rw *ctx, size_t count,
+			       const void *src, size_t src_count)
+{
+	if (count > src_count) {
+		return -EINVAL;
+	}
+
+	if (!count) {
+		return 0;
+	}
+
+#if INTMAX_MAX < SIZE_MAX
+	if (count > INTMAX_MAX) {
+		return pldm__msgbuf_rw_invalidate(ctx);
+	}
+#endif
+
+	if (ctx->remaining >= (intmax_t)count) {
+		assert(ctx->cursor);
+		memcpy(ctx->cursor, src, count);
+		ctx->cursor += count;
+		ctx->remaining -= (intmax_t)count;
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
+		ctx->remaining -= (intmax_t)count;
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_rw_invalidate(ctx);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_WARN_UNUSED_RESULT
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_insert_array_char(struct pldm_msgbuf_rw *ctx, size_t count,
+			      const char *src, size_t src_count)
+{
+	return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_WARN_UNUSED_RESULT
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_insert_array_uint8(struct pldm_msgbuf_rw *ctx, size_t count,
+			       const uint8_t *src, size_t src_count)
+{
+	return pldm__msgbuf_insert_array_void(ctx, count, src, src_count);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_span_required(const uint8_t **buf, intmax_t *remaining,
+			   size_t required, const void **cursor)
+{
+#if INTMAX_MAX < SIZE_MAX
+	if (required > INTMAX_MAX) {
+		return pldm__msgbuf_set_invalid(remaining);
+	}
+#endif
+
+	if (*remaining >= (intmax_t)required) {
+		assert(*buf);
+		if (cursor) {
+			*cursor = *buf;
+		}
+		*buf += required;
+		*remaining -= (intmax_t)required;
+		return 0;
+	}
+
+	if (*remaining > INTMAX_MIN + (intmax_t)required) {
+		*remaining -= (intmax_t)required;
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_set_invalid(remaining);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_ro_span_required(struct pldm_msgbuf_ro *ctx, size_t required,
+			     const void **cursor)
+{
+	return pldm__msgbuf_span_required(&ctx->cursor, &ctx->remaining,
+					  required, cursor);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_rw_span_required(struct pldm_msgbuf_rw *ctx, size_t required,
+			     void **cursor)
+{
+	return pldm__msgbuf_span_required((const uint8_t **)&ctx->cursor,
+					  &ctx->remaining, required,
+					  (const void **)cursor);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_span_string_ascii(const uint8_t **buf, intmax_t *remaining,
+			       const void **cursor, size_t *length)
+{
+	intmax_t measured;
+
+	if (*remaining < 0) {
+		return pldm__msgbuf_set_invalid(remaining);
+	}
+	assert(*buf);
+
+	measured = (intmax_t)strnlen((const char *)*buf, *remaining);
+	if (measured == *remaining) {
+		return pldm__msgbuf_set_invalid(remaining);
+	}
+
+	/* Include the NUL terminator in the span length, as spans are opaque */
+	measured++;
+
+	if (*remaining >= measured) {
+		assert(*buf);
+		if (cursor) {
+			*cursor = *buf;
+		}
+
+		*buf += measured;
+
+		if (length) {
+			*length = measured;
+		}
+
+		*remaining -= measured;
+		return 0;
+	}
+
+	if (*remaining > INTMAX_MIN + measured) {
+		*remaining -= measured;
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_set_invalid(remaining);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_rw_span_string_ascii(struct pldm_msgbuf_rw *ctx, void **cursor,
+				 size_t *length)
+{
+	return pldm__msgbuf_span_string_ascii((const uint8_t **)&ctx->cursor,
+					      &ctx->remaining,
+					      (const void **)cursor, length);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_ro_span_string_ascii(struct pldm_msgbuf_ro *ctx,
+				 const void **cursor, size_t *length)
+{
+	return pldm__msgbuf_span_string_ascii(&ctx->cursor, &ctx->remaining,
+					      cursor, length);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+int pldm__msgbuf_span_string_utf16(const uint8_t **buf, intmax_t *remaining,
+				   const void **cursor, size_t *length)
+{
+	static const char16_t term = 0;
+	ptrdiff_t measured;
+	const void *end;
+
+	if (*remaining < 0) {
+		return pldm__msgbuf_set_invalid(remaining);
+	}
+	assert(*buf);
+
+	/*
+	 * Avoid tripping up on UTF16-LE: We may have consecutive NUL _bytes_ that do
+	 * not form a UTF16 NUL _code-point_ due to alignment with respect to the
+	 * start of the string
+	 */
+	end = *buf;
+	do {
+		if (end != *buf) {
+			/*
+			 * If we've looped we've found a relatively-unaligned NUL code-point.
+			 * Scan again from a relatively-aligned start point.
+			 */
+			end = (char *)end + 1;
+		}
+		measured = (char *)end - (char *)*buf;
+		end = memmem(end, *remaining - measured, &term, sizeof(term));
+	} while (end && ((uintptr_t)end & 1) != ((uintptr_t)*buf & 1));
+
+	if (!end) {
+		/*
+		 * Optimistically, the last required pattern byte was one beyond the end of
+		 * the buffer. Setting ctx->remaining negative ensures the
+		 * `pldm_msgbuf_complete*()` APIs also return an error.
+		 */
+		return pldm__msgbuf_set_invalid(remaining);
+	}
+
+	end = (char *)end + sizeof(char16_t);
+	measured = (char *)end - (char *)*buf;
+
+#if INTMAX_MAX < PTRDIFF_MAX
+	if (measured >= INTMAX_MAX) {
+		return pldm__msgbuf_set_invalid(remaining);
+	}
+#endif
+
+	if (*remaining >= (intmax_t)measured) {
+		assert(*buf);
+		if (cursor) {
+			*cursor = *buf;
+		}
+
+		*buf += measured;
+
+		if (length) {
+			*length = (size_t)measured;
+		}
+
+		*remaining -= (intmax_t)measured;
+		return 0;
+	}
+
+	if (*remaining > INTMAX_MIN + (intmax_t)measured) {
+		*remaining -= (intmax_t)measured;
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_set_invalid(remaining);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_ro_span_string_utf16(struct pldm_msgbuf_ro *ctx,
+				 const void **cursor, size_t *length)
+{
+	return pldm__msgbuf_span_string_utf16(&ctx->cursor, &ctx->remaining,
+					      cursor, length);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_rw_span_string_utf16(struct pldm_msgbuf_rw *ctx, void **cursor,
+				 size_t *length)
+{
+	return pldm__msgbuf_span_string_utf16((const uint8_t **)&ctx->cursor,
+					      &ctx->remaining,
+					      (const void **)cursor, length);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_span_remaining(const uint8_t **buf, intmax_t *remaining,
+			    const void **cursor, size_t *len)
+{
+	if (*remaining < 0) {
+		return -EOVERFLOW;
+	}
+
+	assert(*buf);
+	*cursor = *buf;
+	*buf += *remaining;
+	*len = *remaining;
+	*remaining = 0;
+
+	return 0;
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_rw_span_remaining(struct pldm_msgbuf_rw *ctx, void **cursor,
+			      size_t *len)
+{
+	return pldm__msgbuf_span_remaining((const uint8_t **)&ctx->cursor,
+					   &ctx->remaining,
+					   (const void **)cursor, len);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_ro_span_remaining(struct pldm_msgbuf_ro *ctx, const void **cursor,
+			      size_t *len)
+{
+	return pldm__msgbuf_span_remaining(&ctx->cursor, &ctx->remaining,
+					   cursor, len);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+int pldm__msgbuf_span_until(const uint8_t **buf, intmax_t *remaining,
+			    size_t trailer, const void **cursor, size_t *length)
+{
+#if INTMAX_MAX < SIZE_MAX
+	if (trailer > INTMAX_MAX) {
+		return pldm__msgbuf_set_invalid(remaining);
+	}
+#endif
+
+	if (*remaining >= (intmax_t)trailer) {
+		ptrdiff_t delta;
+
+		assert(*buf);
+
+		delta = *remaining - (intmax_t)trailer;
+		if (cursor) {
+			*cursor = *buf;
+		}
+		*buf += delta;
+		if (length) {
+			*length = delta;
+		}
+		*remaining = (intmax_t)trailer;
+		return 0;
+	}
+
+	if (*remaining > INTMAX_MIN + (intmax_t)trailer) {
+		*remaining = INTMAX_MIN + (intmax_t)trailer;
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_set_invalid(remaining);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE
+int pldm_msgbuf_ro_span_until(struct pldm_msgbuf_ro *ctx, size_t trailer,
+			      const void **cursor, size_t *length)
+{
+	return pldm__msgbuf_span_until(&ctx->cursor, &ctx->remaining, trailer,
+				       cursor, length);
+}
+
+LIBPLDM_CC_NONNULL_ARGS(1)
+LIBPLDM_CC_ALWAYS_INLINE
+int pldm_msgbuf_rw_span_until(struct pldm_msgbuf_rw *ctx, size_t trailer,
+			      void **cursor, size_t *length)
+{
+	return pldm__msgbuf_span_until((const uint8_t **)&ctx->cursor,
+				       &ctx->remaining, trailer,
+				       (const void **)cursor, length);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_peek_remaining(struct pldm_msgbuf_rw *ctx, void **cursor,
+			   size_t *len)
+{
+	if (ctx->remaining < 0) {
+		return -EOVERFLOW;
+	}
+
+	assert(ctx->cursor);
+	*cursor = ctx->cursor;
+	*len = ctx->remaining;
+
+	return 0;
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_skip(struct pldm_msgbuf_rw *ctx,
+					      size_t count)
+{
+#if INTMAX_MAX < SIZE_MAX
+	if (count > INTMAX_MAX) {
+		return pldm__msgbuf_rw_invalidate(ctx);
+	}
+#endif
+
+	if (ctx->remaining >= (intmax_t)count) {
+		assert(ctx->cursor);
+		ctx->cursor += count;
+		ctx->remaining -= (intmax_t)count;
+		return 0;
+	}
+
+	if (ctx->remaining > INTMAX_MIN + (intmax_t)count) {
+		ctx->remaining -= (intmax_t)count;
+		return -EOVERFLOW;
+	}
+
+	return pldm__msgbuf_rw_invalidate(ctx);
+}
+
+/**
+ * @brief Complete the pldm_msgbuf instance and return the number of bytes
+ * consumed.
+ *
+ * @param ctx - The msgbuf.
+ * @param orig_len - The original size of the msgbuf, the `len` argument passed to
+ * 		pldm_msgbuf_init_errno().
+ * @param ret_used_len - The number of bytes that have been used from the msgbuf instance.
+ *
+ * This can be called after a number of pldm_msgbuf_insert...() calls to
+ * determine the total size that was written.
+ *
+ * @return 0 on success, -EOVERFLOW if an implausible orig_len was provided or
+ * an out-of-bounds access occurred.
+ */
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE
+LIBPLDM_CC_WARN_UNUSED_RESULT
+int pldm_msgbuf_complete_used(struct pldm_msgbuf_rw *ctx, size_t orig_len,
+			      size_t *ret_used_len)
+{
+	int rc;
+
+	ctx->cursor = NULL;
+	rc = pldm_msgbuf_rw_validate(ctx);
+	if (rc) {
+		pldm__msgbuf_rw_invalidate(ctx);
+		return rc;
+	}
+
+	if ((size_t)ctx->remaining > orig_len) {
+		/* Caller passed incorrect orig_len */
+		return pldm__msgbuf_rw_invalidate(ctx);
+	}
+
+	*ret_used_len = orig_len - ctx->remaining;
+	pldm__msgbuf_rw_invalidate(ctx);
+	return 0;
+}
+
+/**
+ * @brief pldm_msgbuf copy data between two msg buffers
+ *
+ * @param[in,out] src - pldm_msgbuf for source from where value should be copied
+ * @param[in,out] dst - destination of copy from source
+ * @param[in] size - size of data to be copied
+ * @param[in] description - description of data copied
+ *
+ * @return PLDM_SUCCESS if buffer accesses were in-bounds,
+ * PLDM_ERROR_INVALID_LENGTH otherwise.
+ * PLDM_ERROR_INVALID_DATA if input is invalid
+ */
+#define pldm_msgbuf_copy(dst, src, type, name)                                 \
+	pldm__msgbuf_copy(dst, src, sizeof(type), #name)
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_copy(struct pldm_msgbuf_rw *dst, struct pldm_msgbuf_ro *src,
+		  size_t size, const char *description LIBPLDM_CC_UNUSED)
+{
+#if INTMAX_MAX < SIZE_MAX
+	if (size > INTMAX_MAX) {
+		pldm__msgbuf_ro_invalidate(src);
+		pldm__msgbuf_rw_invalidate(dst);
+		return -EOVERFLOW;
+	}
+#endif
+
+	if (src->remaining >= (intmax_t)size &&
+	    dst->remaining >= (intmax_t)size) {
+		assert(src->cursor && dst->cursor);
+		memcpy(dst->cursor, src->cursor, size);
+		src->cursor += size;
+		src->remaining -= (intmax_t)size;
+		dst->cursor += size;
+		dst->remaining -= (intmax_t)size;
+		return 0;
+	}
+
+	if (src->remaining > INTMAX_MIN + (intmax_t)size) {
+		src->remaining -= (intmax_t)size;
+	} else {
+		pldm__msgbuf_ro_invalidate(src);
+	}
+
+	if (dst->remaining > INTMAX_MIN + (intmax_t)size) {
+		dst->remaining -= (intmax_t)size;
+	} else {
+		pldm__msgbuf_rw_invalidate(dst);
+	}
+
+	return -EOVERFLOW;
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_WARN_UNUSED_RESULT
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_copy_string_ascii(struct pldm_msgbuf_rw *dst,
+			      struct pldm_msgbuf_ro *src)
+{
+	const void *ascii = NULL;
+	size_t len = 0;
+	int rc;
+
+	rc = pldm_msgbuf_ro_span_string_ascii(src, &ascii, &len);
+	if (rc < 0) {
+		return rc;
+	}
+
+	return pldm__msgbuf_insert_array_void(dst, len, ascii, len);
+}
+
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_WARN_UNUSED_RESULT
+LIBPLDM_CC_ALWAYS_INLINE int
+pldm_msgbuf_copy_string_utf16(struct pldm_msgbuf_rw *dst,
+			      struct pldm_msgbuf_ro *src)
+{
+	const void *utf16 = NULL;
+	size_t len = 0;
+	int rc;
+
+	rc = pldm_msgbuf_ro_span_string_utf16(src, &utf16, &len);
+	if (rc < 0) {
+		return rc;
+	}
+
+	return pldm__msgbuf_insert_array_void(dst, len, utf16, len);
+}
+
+/**
+ * @brief pldm_msgbuf uint8_t extractor for a size_t
+ *
+ * @param[in,out] ctx - pldm_msgbuf context for extractor
+ * @param[out] dst - destination of extracted value
+ *
+ * @return 0 if buffer accesses were in-bounds,
+ * -EINVAL if dst pointer is invalid,
+ * -EOVERFLOW is the buffer was out of bound.
+ */
+#define pldm_msgbuf_extract_uint8_to_size(ctx, dst)                            \
+	pldm__msgbuf_extract_uint8_to_size(ctx, &(dst))
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_uint8_to_size(struct pldm_msgbuf_ro *ctx, size_t *dst)
+{
+	uint8_t value = 0;
+	int rc;
+
+	rc = pldm__msgbuf_extract_uint8(ctx, &value);
+	if (rc) {
+		return rc;
+	}
+
+	static_assert(SIZE_MAX >= UINT8_MAX, "Invalid promotion");
+
+	*dst = value;
+	return 0;
+}
+
+/**
+ * @brief pldm_msgbuf uint16_t extractor for a size_t
+ *
+ * @param[in,out] ctx - pldm_msgbuf context for extractor
+ * @param[out] dst - destination of extracted value
+ *
+ * @return 0 if buffer accesses were in-bounds,
+ * -EINVAL if dst pointer is invalid,
+ * -EOVERFLOW is the buffer was out of bound.
+ */
+#define pldm_msgbuf_extract_uint16_to_size(ctx, dst)                           \
+	pldm__msgbuf_extract_uint16_to_size(ctx, &(dst))
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_uint16_to_size(struct pldm_msgbuf_ro *ctx, size_t *dst)
+{
+	uint16_t value = 0;
+	int rc;
+
+	rc = pldm__msgbuf_extract_uint16(ctx, &value);
+	if (rc) {
+		return rc;
+	}
+
+	static_assert(SIZE_MAX >= UINT16_MAX, "Invalid promotion");
+
+	*dst = value;
+	return 0;
+}
+
+/**
+ * @brief pldm_msgbuf uint32_t extractor for a size_t
+ *
+ * @param[in,out] ctx - pldm_msgbuf context for extractor
+ * @param[out] dst - destination of extracted value
+ *
+ * @return 0 if buffer accesses were in-bounds,
+ * -EINVAL if dst pointer is invalid,
+ * -EOVERFLOW is the buffer was out of bound.
+ */
+#define pldm_msgbuf_extract_uint32_to_size(ctx, dst)                           \
+	pldm__msgbuf_extract_uint32_to_size(ctx, &(dst))
+LIBPLDM_CC_NONNULL
+LIBPLDM_CC_ALWAYS_INLINE int
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+pldm__msgbuf_extract_uint32_to_size(struct pldm_msgbuf_ro *ctx, size_t *dst)
+{
+	uint32_t value = 0;
+	int rc;
+
+	rc = pldm__msgbuf_extract_uint32(ctx, &value);
+	if (rc) {
+		return rc;
+	}
+
+	static_assert(SIZE_MAX >= UINT32_MAX, "Invalid promotion");
+
+	*dst = value;
+	return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/msgbuf/platform.h b/src/msgbuf/platform.h
index 897c199..695ab1e 100644
--- a/src/msgbuf/platform.h
+++ b/src/msgbuf/platform.h
@@ -9,7 +9,7 @@
 
 LIBPLDM_CC_NONNULL
 LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_extract_value_pdr_hdr(struct pldm_msgbuf *ctx,
+pldm_msgbuf_extract_value_pdr_hdr(struct pldm_msgbuf_ro *ctx,
 				  struct pldm_value_pdr_hdr *hdr, size_t lower,
 				  size_t upper)
 {
@@ -36,7 +36,7 @@
 }
 
 LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_extract_sensor_data(struct pldm_msgbuf *ctx,
+pldm_msgbuf_extract_sensor_data(struct pldm_msgbuf_ro *ctx,
 				enum pldm_sensor_readings_data_type tag,
 				union_sensor_data_size *dst)
 {
@@ -64,7 +64,7 @@
  * above
  */
 LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_extract_sensor_value(struct pldm_msgbuf *ctx,
+pldm_msgbuf_extract_sensor_value(struct pldm_msgbuf_ro *ctx,
 				 enum pldm_sensor_readings_data_type tag,
 				 void *val)
 {
@@ -91,7 +91,7 @@
 				      pldm__msgbuf_extract_range_field_format, \
 				      dst, ctx, tag, (void *)&(dst))
 LIBPLDM_CC_ALWAYS_INLINE int pldm__msgbuf_extract_range_field_format(
-	struct pldm_msgbuf *ctx, enum pldm_range_field_format tag, void *rff)
+	struct pldm_msgbuf_ro *ctx, enum pldm_range_field_format tag, void *rff)
 {
 	switch (tag) {
 	case PLDM_RANGE_FIELD_FORMAT_UINT8:
@@ -129,7 +129,7 @@
 
 /* This API is bad, but it's because the caller's APIs are also bad */
 LIBPLDM_CC_ALWAYS_INLINE int
-pldm_msgbuf_extract_effecter_value(struct pldm_msgbuf *ctx,
+pldm_msgbuf_extract_effecter_value(struct pldm_msgbuf_ro *ctx,
 				   enum pldm_effecter_data_size tag, void *dst)
 {
 	switch (tag) {
@@ -155,7 +155,7 @@
 				      pldm__msgbuf_extract_range_field_format, \
 				      dst, ctx, tag, (void *)&(dst))
 LIBPLDM_CC_ALWAYS_INLINE int
-pldm__msgbuf_extract_effecter_data(struct pldm_msgbuf *ctx,
+pldm__msgbuf_extract_effecter_data(struct pldm_msgbuf_ro *ctx,
 				   enum pldm_effecter_data_size tag, void *ed)
 {
 	switch (tag) {
@@ -192,8 +192,10 @@
 #include <type_traits>
 
 template <typename T>
-static inline int pldm_msgbuf_typecheck_range_field_format(
-	struct pldm_msgbuf *ctx, enum pldm_range_field_format tag, void *_rff)
+static inline int
+pldm_msgbuf_typecheck_range_field_format(struct pldm_msgbuf_ro *ctx,
+					 enum pldm_range_field_format tag,
+					 void *_rff)
 {
 	static_assert(std::is_same<union_range_field_format, T>::value);
 	return pldm__msgbuf_extract_range_field_format(ctx, tag, _rff);
diff --git a/src/oem/meta/file_io.c b/src/oem/meta/file_io.c
index d3e7a6d..45b5c9e 100644
--- a/src/oem/meta/file_io.c
+++ b/src/oem/meta/file_io.c
@@ -21,7 +21,7 @@
 	const struct pldm_msg *msg, size_t payload_length,
 	struct pldm_oem_meta_file_io_write_req *req, size_t req_length)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 	int rc;
 
 	if (msg == NULL || req == NULL) {
@@ -98,7 +98,7 @@
 				     size_t payload_length,
 				     struct pldm_oem_meta_file_io_read_req *req)
 {
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RO_DEFINE_P(buf);
 
 	if (msg == NULL || req == NULL) {
 		return -EINVAL;
@@ -156,7 +156,7 @@
 	size_t resp_len, struct pldm_msg *responseMsg, size_t payload_length)
 {
 	int rc;
-	PLDM_MSGBUF_DEFINE_P(buf);
+	PLDM_MSGBUF_RW_DEFINE_P(buf);
 	struct pldm_header_info header = { 0 };
 
 	if (resp == NULL || responseMsg == NULL) {
diff --git a/tests/dsp/base.cpp b/tests/dsp/base.cpp
index a926104..0e274a8 100644
--- a/tests/dsp/base.cpp
+++ b/tests/dsp/base.cpp
@@ -1,3 +1,5 @@
+#include "msgbuf.hpp"
+
 #include <libpldm/base.h>
 #include <libpldm/pldm_types.h>
 
@@ -6,8 +8,6 @@
 #include <cstring>
 #include <vector>
 
-#include "msgbuf.h"
-
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -550,7 +550,7 @@
     constexpr uint32_t kSectionLength = 0x10;
 
     PLDM_MSG_DEFINE_P(msg, PLDM_MULTIPART_RECEIVE_REQ_BYTES);
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     // Header values don't matter for this test.
@@ -616,7 +616,7 @@
     constexpr uint8_t kFlag = PLDM_XFER_FIRST_PART;
 
     PLDM_MSG_DEFINE_P(msg, PLDM_MULTIPART_RECEIVE_REQ_BYTES);
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     // Header values don't matter for this test.
@@ -648,7 +648,7 @@
     constexpr uint8_t kFlag = PLDM_XFER_CURRENT_PART + 0x10;
 
     PLDM_MSG_DEFINE_P(msg, PLDM_MULTIPART_RECEIVE_REQ_BYTES);
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     // Header values don't matter for this test.
@@ -683,7 +683,7 @@
     constexpr uint32_t kSectionOffset = 0x0;
 
     PLDM_MSG_DEFINE_P(msg, PLDM_MULTIPART_RECEIVE_REQ_BYTES);
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     // Header values don't matter for this test.
@@ -720,7 +720,7 @@
     constexpr uint32_t kSectionOffset = 0x100;
 
     PLDM_MSG_DEFINE_P(msg, PLDM_MULTIPART_RECEIVE_REQ_BYTES);
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     // Header values don't matter for this test.
@@ -838,7 +838,7 @@
 
     struct pldm_base_multipart_receive_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length =
@@ -888,7 +888,7 @@
 
     struct pldm_base_multipart_receive_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length =
@@ -936,7 +936,7 @@
 
     struct pldm_base_multipart_receive_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length =
@@ -979,7 +979,7 @@
 
     struct pldm_base_multipart_receive_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     /*
@@ -1029,7 +1029,7 @@
 
     struct pldm_base_multipart_receive_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     /*
@@ -1630,7 +1630,7 @@
 
     struct pldm_base_negotiate_transfer_params_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length =
@@ -1672,7 +1672,7 @@
 
     struct pldm_base_negotiate_transfer_params_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length =
@@ -1715,7 +1715,7 @@
 
     struct pldm_base_negotiate_transfer_params_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length =
diff --git a/tests/dsp/file.cpp b/tests/dsp/file.cpp
index b8fe67f..6dc4296 100644
--- a/tests/dsp/file.cpp
+++ b/tests/dsp/file.cpp
@@ -1,12 +1,12 @@
+#include "msgbuf.hpp"
+
+#include <libpldm/base.h>
 #include <libpldm/file.h>
 #include <libpldm/pldm_types.h>
 
 #include <array>
 #include <cstdint>
 #include <cstring>
-#include <vector>
-
-#include "msgbuf.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -93,7 +93,7 @@
 
     struct pldm_file_df_open_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_OPEN_RESP_BYTES;
@@ -124,7 +124,7 @@
 
     struct pldm_file_df_open_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_OPEN_RESP_BYTES;
@@ -155,7 +155,7 @@
 
     struct pldm_file_df_open_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_OPEN_RESP_BYTES;
@@ -256,7 +256,7 @@
 
     struct pldm_file_df_close_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_CLOSE_RESP_BYTES;
@@ -285,7 +285,7 @@
 
     struct pldm_file_df_close_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_CLOSE_RESP_BYTES;
@@ -390,7 +390,7 @@
 
     struct pldm_file_df_heartbeat_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_HEARTBEAT_RESP_BYTES;
@@ -422,7 +422,7 @@
 
     struct pldm_file_df_heartbeat_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_HEARTBEAT_RESP_BYTES;
@@ -455,7 +455,7 @@
 
     struct pldm_file_df_heartbeat_resp resp_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_HEARTBEAT_RESP_BYTES;
@@ -568,7 +568,7 @@
 
     struct pldm_file_df_open_req req_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_OPEN_REQ_BYTES;
@@ -600,7 +600,7 @@
 
     struct pldm_file_df_open_req req_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_OPEN_REQ_BYTES;
@@ -632,7 +632,7 @@
 
     struct pldm_file_df_open_req req_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_OPEN_REQ_BYTES;
@@ -701,7 +701,7 @@
 
     struct pldm_file_df_close_req req_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_CLOSE_REQ_BYTES;
@@ -733,7 +733,7 @@
 
     struct pldm_file_df_close_req req_data = {};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
     static constexpr const size_t payload_length = PLDM_DF_CLOSE_REQ_BYTES;
diff --git a/tests/dsp/firmware_update.cpp b/tests/dsp/firmware_update.cpp
index 6d4f5a6..0fbd693 100644
--- a/tests/dsp/firmware_update.cpp
+++ b/tests/dsp/firmware_update.cpp
@@ -1,3 +1,5 @@
+#include "msgbuf.hpp"
+
 #include <endian.h>
 #include <libpldm/base.h>
 #include <libpldm/firmware_update.h>
@@ -15,8 +17,6 @@
 #include <string_view>
 #include <vector>
 
-#include "msgbuf.h"
-
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -1687,7 +1687,7 @@
     std::array<uint8_t, hdrSize + PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES>
         responseMsg{};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(buf, 0, responseMsg.data() + hdrSize,
                                 responseMsg.size() - hdrSize);
     EXPECT_EQ(rc, 0);
@@ -1733,7 +1733,7 @@
     std::array<uint8_t, hdrSize + PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES>
         responseMsg{};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(buf, 0, responseMsg.data() + hdrSize,
                                 responseMsg.size() - hdrSize);
     ASSERT_EQ(rc, 0);
@@ -1772,7 +1772,7 @@
                             2 /* Inject error length*/>
         responseMsg{};
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(buf, 0, responseMsg.data() + hdrSize,
                                 responseMsg.size() - hdrSize);
     ASSERT_EQ(rc, 0);
@@ -1848,7 +1848,7 @@
     PLDM_MSG_DEFINE_P(response, PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN);
     struct pldm_query_downstream_identifiers_resp resp_data = {};
     struct pldm_downstream_device_iter devs;
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc = 0;
 
     rc = pldm_msgbuf_init_errno(buf, 0, response->payload,
@@ -1890,7 +1890,7 @@
     struct pldm_query_downstream_identifiers_resp resp = {};
     struct pldm_downstream_device_iter devs;
     struct pldm_downstream_device dev;
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc = 0;
 
     rc = pldm_msgbuf_init_errno(buf, 0, response->payload,
@@ -1932,7 +1932,7 @@
     PLDM_MSG_DEFINE_P(response, payloadLen);
     struct pldm_downstream_device_iter devs;
     struct pldm_downstream_device dev;
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc = 0;
 
     rc = pldm_msgbuf_init_errno(buf, 0, response->payload, payloadLen);
@@ -2020,7 +2020,7 @@
     PLDM_MSG_DEFINE_P(response, payloadLen);
     struct pldm_downstream_device_iter devs;
     struct pldm_downstream_device dev;
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc = 0;
 
     rc = pldm_msgbuf_init_errno(buf, 0, response->payload, payloadLen);
@@ -2130,7 +2130,7 @@
     PLDM_MSG_DEFINE_P(response, payloadLen);
     struct pldm_downstream_device_iter devs;
     struct pldm_downstream_device dev;
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc = 0;
 
     rc = pldm_msgbuf_init_errno(buf, 0, response->payload, payloadLen);
@@ -2245,7 +2245,7 @@
     PLDM_MSG_DEFINE_P(response, payloadLen);
     struct pldm_downstream_device_iter devs;
     struct pldm_downstream_device dev;
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc = 0;
 
     rc = pldm_msgbuf_init_errno(buf, 0, response->payload, payloadLen);
@@ -2377,7 +2377,7 @@
     struct pldm_query_downstream_identifiers_resp resp_data = {};
     struct pldm_downstream_device_iter devs;
     PLDM_MSG_DEFINE_P(response, payloadLen);
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     void* devicesStart = NULL;
     size_t devicesLen;
     int rc = 0;
@@ -2421,7 +2421,7 @@
     struct pldm_query_downstream_identifiers_resp resp_data = {};
     struct pldm_downstream_device_iter devs;
     PLDM_MSG_DEFINE_P(response, payloadLen);
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc = 0;
 
     rc = pldm_msgbuf_init_errno(buf, 0, response->payload, payloadLen);
@@ -2516,7 +2516,7 @@
         downstreamDeviceParamTableLen;
 
     PLDM_MSG_DEFINE_P(response, payload_len);
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc = 0;
 
     rc = pldm_msgbuf_init_errno(buf, 0, response->payload, payload_len);
@@ -2625,7 +2625,7 @@
         downstreamDeviceParamTableLen;
 
     PLDM_MSG_DEFINE_P(response, payload_len);
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc = 0;
 
     rc = pldm_msgbuf_init_errno(buf, 0, response->payload, payload_len);
@@ -2788,7 +2788,7 @@
 
     int rc = 0;
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(buf, 0, responseMsg.data() + hdrSize,
                                 responseMsg.size() - hdrSize);
     ASSERT_EQ(rc, 0);
diff --git a/tests/dsp/pdr.cpp b/tests/dsp/pdr.cpp
index 0cd95dc..148e56f 100644
--- a/tests/dsp/pdr.cpp
+++ b/tests/dsp/pdr.cpp
@@ -1,7 +1,8 @@
+#include "msgbuf.hpp"
+
 #include <endian.h>
 #include <libpldm/pdr.h>
 #include <libpldm/platform.h>
-#include <msgbuf.h>
 
 #include <array>
 #include <cstdint>
@@ -46,7 +47,7 @@
     }
 } pldm_entity_test;
 
-static void getEntity(struct pldm_msgbuf* buf, pldm_entity_test& entity)
+static void getEntity(struct pldm_msgbuf_ro* buf, pldm_entity_test& entity)
 {
     pldm_msgbuf_extract_uint16(buf, entity.entity_type);
     pldm_msgbuf_extract_uint16(buf, entity.entity_instance_num);
@@ -54,7 +55,7 @@
 }
 
 static void
-    getAssociationPdrDetails(struct pldm_msgbuf* buf,
+    getAssociationPdrDetails(struct pldm_msgbuf_ro* buf,
                              pldm_association_pdr_test& association_pdr_test)
 {
     pldm_msgbuf_extract_uint32(buf, association_pdr_test.record_handle);
@@ -68,7 +69,7 @@
 }
 
 static void
-    verifyEntityAssociationPdr(struct pldm_msgbuf* buf,
+    verifyEntityAssociationPdr(struct pldm_msgbuf_ro* buf,
                                const pldm_association_pdr_test& association_pdr,
                                const pldm_entity_test& container_entity1,
                                const pldm_entity_test& child_entity1)
@@ -1766,8 +1767,8 @@
 
     pldm_pdr_find_record(repo, currRecHandle, &data, &size, &nextRecHandle);
 
-    struct pldm_msgbuf _buf;
-    struct pldm_msgbuf* buf = &_buf;
+    struct pldm_msgbuf_ro _buf;
+    struct pldm_msgbuf_ro* buf = &_buf;
 
     auto rc =
         pldm_msgbuf_init_errno(buf,
diff --git a/tests/dsp/platform.cpp b/tests/dsp/platform.cpp
index 13a3229..3b202f1 100644
--- a/tests/dsp/platform.cpp
+++ b/tests/dsp/platform.cpp
@@ -1,3 +1,5 @@
+#include "msgbuf.hpp"
+
 #include <endian.h>
 #include <libpldm/base.h>
 #include <libpldm/entity.h>
@@ -11,8 +13,6 @@
 #include <cstring>
 #include <vector>
 
-#include "msgbuf.h"
-
 #include <gtest/gtest.h>
 
 constexpr auto hdrSize = sizeof(pldm_msg_hdr);
@@ -468,10 +468,10 @@
     alignas(pldm_msg) unsigned char data[sizeof(pldm_msg_hdr) +
                                          PLDM_GET_PDR_MIN_RESP_BYTES +
                                          sizeof(recordData) - 1 + 1];
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
-    pldm_msg* msg = new (data) pldm_msg;
+    pldm_msg* msg = new (data) pldm_msg();
 
     rc = pldm_msgbuf_init_errno(buf, PLDM_GET_PDR_MIN_RESP_BYTES, msg->payload,
                                 sizeof(data) - sizeof(msg->hdr));
@@ -729,10 +729,10 @@
         data[sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REPOSITORY_INFO_RESP_BYTES];
     uint8_t updateTime[PLDM_TIMESTAMP104_SIZE] = {0};
     uint8_t oemUpdateTime[PLDM_TIMESTAMP104_SIZE] = {0};
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RW_DEFINE_P(buf);
     int rc;
 
-    pldm_msg* msg = new (data) pldm_msg;
+    pldm_msg* msg = new (data) pldm_msg();
 
     rc = pldm_msgbuf_init_errno(buf, PLDM_GET_PDR_REPOSITORY_INFO_RESP_BYTES,
                                 msg->payload, sizeof(data) - sizeof(msg->hdr));
@@ -1485,7 +1485,7 @@
         PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
     EXPECT_EQ(rc, PLDM_SUCCESS);
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RO_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(
         buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES, request->payload,
         PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
@@ -1523,7 +1523,7 @@
         PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
     EXPECT_EQ(rc, PLDM_SUCCESS);
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RO_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(
         buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES, request->payload,
         PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
@@ -1561,7 +1561,7 @@
         PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
     EXPECT_EQ(rc, PLDM_SUCCESS);
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RO_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(
         buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES, request->payload,
         PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
@@ -2033,7 +2033,7 @@
         eventDataIntegrityChecksum, response, payloadLength);
     EXPECT_EQ(rc, PLDM_SUCCESS);
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RO_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(
         buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES,
         response->payload, payloadLength);
@@ -2092,7 +2092,7 @@
         response, payloadLength);
     EXPECT_EQ(rc, PLDM_SUCCESS);
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RO_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(
         buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES,
         response->payload, payloadLength);
@@ -2131,7 +2131,7 @@
         response, payloadLength);
     EXPECT_EQ(rc, PLDM_SUCCESS);
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RO_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(
         buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES,
         response->payload, payloadLength);
@@ -2179,7 +2179,7 @@
         eventDataIntegrityChecksum, response, payloadLength);
     EXPECT_EQ(rc, PLDM_SUCCESS);
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RO_DEFINE_P(buf);
     rc = pldm_msgbuf_init_errno(
         buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES,
         response->payload, payloadLength);
@@ -2346,9 +2346,9 @@
     static constexpr const uint8_t eventData = 34;
     static constexpr const uint8_t Tid = 0x03;
     struct pldm_platform_event_message_req req;
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RO_DEFINE_P(buf);
+    const void* data;
     size_t len;
-    void* data;
 
     PLDM_MSG_DEFINE_P(request, PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
                                    sizeof(eventData));
@@ -2673,7 +2673,7 @@
 
     EXPECT_EQ(rc, PLDM_SUCCESS);
 
-    PLDM_MSGBUF_DEFINE_P(buf);
+    PLDM_MSGBUF_RO_DEFINE_P(buf);
 
     rc = pldm_msgbuf_init_errno(
         buf, PLDM_MSG_POLL_EVENT_LENGTH,
diff --git a/tests/fuzz/fd-fuzz.cpp b/tests/fuzz/fd-fuzz.cpp
index 9049ab8..258c27e 100644
--- a/tests/fuzz/fd-fuzz.cpp
+++ b/tests/fuzz/fd-fuzz.cpp
@@ -5,6 +5,8 @@
 #undef NDEBUG
 #endif
 
+#include "msgbuf.hpp"
+
 #include <libpldm/base.h>
 #include <libpldm/firmware_fd.h>
 #include <libpldm/firmware_update.h>
@@ -17,7 +19,6 @@
 #include <vector>
 
 #include "array.h"
-#include "msgbuf.h"
 
 /* Avoid out-of-memory, and
  * avoid wasting time on inputs larger than MCTP message limits */
@@ -48,7 +49,7 @@
 
 struct fuzz_ops_ctx
 {
-    struct pldm_msgbuf* fuzz_ctrl;
+    struct pldm_msgbuf_ro* fuzz_ctrl;
 
     /* Details of in-progress update, for consistency checking */
     bool current_update;
@@ -64,7 +65,7 @@
 /* Returns true with roughly `percent` chance */
 static bool fuzz_chance(struct fuzz_ops_ctx* ctx, uint8_t percent)
 {
-    uint8_t v;
+    uint8_t v = 0;
     assert(percent <= 100);
     int rc = pldm_msgbuf_extract_uint8(ctx->fuzz_ctrl, v);
     if (rc != 0)
@@ -368,8 +369,8 @@
 
 extern "C" int LLVMFuzzerTestOneInput(uint8_t* input, size_t len)
 {
-    PLDM_MSGBUF_DEFINE_P(fuzzproto);
-    PLDM_MSGBUF_DEFINE_P(fuzzctrl);
+    PLDM_MSGBUF_RO_DEFINE_P(fuzzproto);
+    PLDM_MSGBUF_RO_DEFINE_P(fuzzctrl);
     int rc;
 
     /* Split input into two parts. First FUZZCTRL_SIZE (0x400 bytes currently)
@@ -397,7 +398,7 @@
     while (true)
     {
         /* Arbitrary length send buffer */
-        uint32_t send_len;
+        uint32_t send_len = 0;
         rc = pldm_msgbuf_extract_uint32(fuzzctrl, send_len);
         if (rc)
         {
diff --git a/tests/meson.build b/tests/meson.build
index 0c3bc2b..7ded005 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -12,7 +12,10 @@
     gmock_dep = gtest_proj.dependency('gmock')
 endif
 
-test_include_dirs = [libpldm_include_dir, include_directories('../src')]
+test_include_dirs = [
+    libpldm_include_dir,
+    include_directories('../src', '../tests'),
+]
 
 tests = ['instance-id', 'msgbuf', 'responder', 'utils']
 
diff --git a/tests/msgbuf.cpp b/tests/msgbuf.cpp
index 67064fc..992475b 100644
--- a/tests/msgbuf.cpp
+++ b/tests/msgbuf.cpp
@@ -10,12 +10,12 @@
 #define NDEBUG 1
 #endif
 
-#include "msgbuf.h"
+#include "msgbuf.hpp"
 
 TEST(msgbuf, init_bad_minsize)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t buf[1] = {};
 
     EXPECT_NE(pldm_msgbuf_init_errno(ctx, sizeof(buf) + 1U, buf, sizeof(buf)),
@@ -24,8 +24,8 @@
 
 TEST(msgbuf, init_bad_len)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t buf[1] = {};
 
     EXPECT_NE(pldm_msgbuf_init_errno(ctx, sizeof(buf), buf, SIZE_MAX), 0);
@@ -33,8 +33,8 @@
 
 TEST(msgbuf, init_overflow)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     // NOLINTNEXTLINE(performance-no-int-to-ptr)
     void* buf = (void*)UINTPTR_MAX;
 
@@ -43,8 +43,8 @@
 
 TEST(msgbuf, init_success)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t buf[1] = {};
 
     EXPECT_EQ(pldm_msgbuf_init_errno(ctx, sizeof(buf), buf, sizeof(buf)), 0);
@@ -52,8 +52,8 @@
 
 TEST(msgbuf, destroy_none)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t buf[1] = {};
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctx, sizeof(buf), buf, sizeof(buf)), 0);
@@ -62,8 +62,8 @@
 
 TEST(msgbuf, destroy_exact)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {0xa5};
     uint8_t val;
 
@@ -75,8 +75,8 @@
 
 TEST(msgbuf, destroy_over)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {0xa5};
     uint8_t val;
 
@@ -89,8 +89,8 @@
 
 TEST(msgbuf, destroy_under)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[2] = {0x5a, 0xa5};
     uint8_t val;
 
@@ -102,8 +102,8 @@
 
 TEST(msgbuf, extract_one_uint8)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {0xa5};
     uint8_t val;
 
@@ -115,8 +115,8 @@
 
 TEST(msgbuf, extract_over_uint8)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {};
     uint8_t val;
 
@@ -127,8 +127,8 @@
 
 TEST(msgbuf, extract_under_uint8)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
 
     uint8_t buf[1] = {};
     uint8_t val;
@@ -141,8 +141,8 @@
 
 TEST(msgbuf, extract_one_int8)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     int8_t buf[1] = {-1};
     int8_t val;
 
@@ -154,8 +154,8 @@
 
 TEST(msgbuf, extract_over_int8)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     int8_t buf[1] = {};
     int8_t val;
 
@@ -166,8 +166,8 @@
 
 TEST(msgbuf, extract_under_int8)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
 
     uint8_t buf[1] = {};
     int8_t val;
@@ -180,8 +180,8 @@
 
 TEST(msgbuf, extract_one_uint16)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint16_t buf[1] = {htole16(0x5aa5)};
     uint16_t val = {};
 
@@ -193,8 +193,8 @@
 
 TEST(msgbuf, extract_under_uint16)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
 
     uint16_t buf[1] = {};
     uint16_t val;
@@ -207,8 +207,8 @@
 
 TEST(msgbuf, extract_over_uint16)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint16_t buf[1] = {};
     uint16_t val;
 
@@ -219,8 +219,8 @@
 
 TEST(msgbuf, extract_one_int16)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     int16_t buf[1] = {(int16_t)(htole16((uint16_t)INT16_MIN))};
     int16_t val;
 
@@ -232,8 +232,8 @@
 
 TEST(msgbuf, extract_over_int16)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     int16_t buf[1] = {};
     int16_t val;
 
@@ -244,8 +244,8 @@
 
 TEST(msgbuf, extract_under_int16)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
 
     int16_t buf[1] = {};
     int16_t val;
@@ -258,8 +258,8 @@
 
 TEST(msgbuf, extract_one_uint32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint32_t buf[1] = {htole32(0x5a00ffa5)};
     uint32_t val;
 
@@ -271,8 +271,8 @@
 
 TEST(msgbuf, extract_over_uint32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint32_t buf[1] = {};
     uint32_t val;
 
@@ -283,8 +283,8 @@
 
 TEST(msgbuf, extract_under_uint32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
 
     uint32_t buf[1] = {};
     uint32_t val;
@@ -297,8 +297,8 @@
 
 TEST(msgbuf, extract_one_int32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     int32_t buf[1] = {(int32_t)(htole32((uint32_t)(INT32_MIN)))};
     int32_t val;
 
@@ -310,8 +310,8 @@
 
 TEST(msgbuf, extract_over_int32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     int32_t buf[1] = {};
     int32_t val;
 
@@ -322,8 +322,8 @@
 
 TEST(msgbuf, extract_under_int32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
 
     int32_t buf[1] = {};
     int32_t val;
@@ -336,8 +336,8 @@
 
 TEST(msgbuf, extract_one_real32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint32_t buf[1] = {};
     uint32_t xform;
     real32_t val;
@@ -355,8 +355,8 @@
 
 TEST(msgbuf, extract_over_real32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     real32_t buf[1] = {};
     real32_t val;
 
@@ -367,8 +367,8 @@
 
 TEST(msgbuf, extract_under_real32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
 
     real32_t buf[1] = {};
     real32_t val;
@@ -381,8 +381,8 @@
 
 TEST(msgbuf, extract_array_uint8_buf0_req0)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {};
     uint8_t arr[1];
 
@@ -393,8 +393,8 @@
 
 TEST(msgbuf, extract_array_uint8_buf1_req1)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {};
     uint8_t arr[1];
 
@@ -407,8 +407,8 @@
 
 TEST(msgbuf, extract_array_uint8_buf1_req2)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {};
     uint8_t arr[2];
 
@@ -420,8 +420,8 @@
 
 TEST(msgbuf, extract_under_array_uint8)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {};
     uint8_t arr[1];
 
@@ -433,8 +433,8 @@
 
 TEST(msgbuf, extract_array_char_buf0_req0)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     char buf[1] = {'\0'};
     char arr[1] = {'1'};
 
@@ -445,8 +445,8 @@
 
 TEST(msgbuf, extract_array_char_buf1_req1)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     char buf[1] = {'\0'};
     char arr[1] = {'1'};
 
@@ -459,8 +459,8 @@
 
 TEST(msgbuf, extract_array_char_buf1_req2)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     char buf[1] = {'\0'};
     char arr[2] = {'1', '2'};
 
@@ -472,8 +472,8 @@
 
 TEST(msgbuf, extract_under_array_char)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     char buf[1] = {'\0'};
     char arr[1] = {'1'};
 
@@ -485,8 +485,8 @@
 
 TEST(msgbuf, consumed_under)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t buf[1] = {};
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
@@ -495,8 +495,8 @@
 
 TEST(msgbuf, consumed_exact)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {};
     uint8_t val;
 
@@ -507,8 +507,8 @@
 
 TEST(msgbuf, consumed_over)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {};
     uint8_t valid;
     uint8_t invalid;
@@ -521,8 +521,8 @@
 
 TEST(msgbuf, pldm_msgbuf_insert_int32_good)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     int32_t src = -12345;
     int32_t checkVal = 0;
     uint8_t buf[sizeof(int32_t)] = {};
@@ -530,8 +530,8 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_insert_int32(ctx, src), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_int32(ctxExtract, checkVal), 0);
@@ -543,8 +543,8 @@
 
 TEST(msgbuf, insert_under_int32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
 
     int32_t buf[1] = {};
     int32_t val = 0;
@@ -557,8 +557,8 @@
 
 TEST(msgbuf, pldm_msgbuf_insert_uint32_good)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint32_t src = 0xf1223344;
     uint32_t checkVal = 0;
     uint8_t buf[sizeof(uint32_t)] = {};
@@ -566,8 +566,8 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_insert_uint32(ctx, src), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint32(ctxExtract, checkVal), 0);
@@ -579,8 +579,8 @@
 
 TEST(msgbuf, insert_under_uint32)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
 
     uint32_t buf[1] = {};
     uint32_t val = 0;
@@ -593,8 +593,8 @@
 
 TEST(msgbuf, pldm_msgbuf_insert_uint16_good)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint16_t src = 0xf344;
     uint16_t checkVal = 0;
     uint8_t buf[sizeof(uint16_t)] = {};
@@ -602,8 +602,8 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(uint16_t)), 0);
     EXPECT_EQ(pldm_msgbuf_insert_uint16(ctx, src), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, checkVal), 0);
@@ -615,8 +615,8 @@
 
 TEST(msgbuf, insert_under_uint16)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
 
     uint16_t buf[1] = {};
     uint16_t val = 0;
@@ -629,8 +629,8 @@
 
 TEST(msgbuf, pldm_msgbuf_insert_int16_good)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     int16_t src = -12;
     int16_t checkVal = 0;
     uint8_t buf[sizeof(int16_t)] = {};
@@ -638,8 +638,8 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(uint16_t)), 0);
     EXPECT_EQ(pldm_msgbuf_insert_int16(ctx, src), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_int16(ctxExtract, checkVal), 0);
@@ -651,8 +651,8 @@
 
 TEST(msgbuf, insert_under_int16)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
 
     int16_t buf[1] = {};
     int16_t val = 0;
@@ -665,8 +665,8 @@
 
 TEST(msgbuf, pldm_msgbuf_insert_uint8_good)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t src = 0xf4;
     uint8_t checkVal = 0;
     uint8_t buf[sizeof(uint8_t)] = {};
@@ -674,8 +674,8 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_insert_uint8(ctx, src), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint8(ctxExtract, checkVal), 0);
@@ -687,8 +687,8 @@
 
 TEST(msgbuf, insert_under_uint8)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
 
     uint8_t buf[1] = {};
     uint8_t val = 0;
@@ -701,8 +701,8 @@
 
 TEST(msgbuf, pldm_msgbuf_insert_int8_good)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     int8_t src = -4;
     int8_t checkVal = 0;
     uint8_t buf[sizeof(int8_t)] = {};
@@ -710,8 +710,8 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_insert_int8(ctx, src), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_int8(ctxExtract, checkVal), 0);
@@ -723,8 +723,8 @@
 
 TEST(msgbuf, insert_under_int8)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
 
     int8_t buf[1] = {};
     int8_t val = 0;
@@ -737,8 +737,8 @@
 
 TEST(msgbuf, pldm_msgbuf_insert_array_uint8_good)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t src[6] = {0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
     uint8_t buf[6] = {};
     uint8_t retBuff[6] = {};
@@ -747,8 +747,8 @@
     EXPECT_EQ(
         pldm_msgbuf_insert_array_uint8(ctx, sizeof(src), src, sizeof(src)), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_array_uint8(ctxExtract, sizeof(retBuff),
@@ -762,8 +762,8 @@
 
 TEST(msgbuf, insert_under_array_uint8)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
 
     uint8_t buf[1] = {};
     uint8_t val[1] = {0};
@@ -777,8 +777,8 @@
 
 TEST(msgbuf, pldm_msgbuf_insert_array_char_good)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     char src[6] = {0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
     char buf[6] = {};
     char retBuff[6] = {};
@@ -787,8 +787,8 @@
     EXPECT_EQ(pldm_msgbuf_insert_array_char(ctx, sizeof(src), src, sizeof(src)),
               0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_array_char(ctxExtract, sizeof(retBuff),
@@ -802,8 +802,8 @@
 
 TEST(msgbuf, insert_under_array_char)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     char buf[1] = {};
     char val[1] = {0};
 
@@ -816,8 +816,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_required_good)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t src[6] = {0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
     uint8_t buf[6] = {0};
     const size_t required = 4;
@@ -829,13 +829,14 @@
     EXPECT_EQ(
         pldm_msgbuf_insert_array_uint8(ctx, sizeof(src), src, sizeof(src)), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
-    EXPECT_EQ(pldm_msgbuf_span_required(ctxExtract, required, (void**)&retBuff),
-              0);
+    EXPECT_EQ(
+        pldm_msgbuf_span_required(ctxExtract, required, (const void**)&retBuff),
+        0);
 
     EXPECT_EQ(memcmp(expectData, retBuff, required), 0);
     EXPECT_EQ(pldm_msgbuf_complete(ctxExtract), 0);
@@ -844,8 +845,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_required_bad)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t src[6] = {0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
     uint8_t buf[6] = {0};
     const size_t required = 4;
@@ -856,8 +857,8 @@
     EXPECT_EQ(
         pldm_msgbuf_insert_array_uint8(ctx, sizeof(src), src, sizeof(src)), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
@@ -869,8 +870,8 @@
 
 TEST(msgbuf, span_required_under)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
 
     uint8_t buf[1] = {};
     void* cursor = nullptr;
@@ -883,8 +884,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_string_ascii_good)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
     uint8_t src[9] = {0x11, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x77};
     constexpr size_t required = 6;
     const char expectData[required] = {0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00};
@@ -895,8 +896,9 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, src, sizeof(src)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
     EXPECT_EQ(0x2211, testVal);
-    EXPECT_EQ(pldm_msgbuf_span_string_ascii(ctxExtract, (void**)&retBuff, NULL),
-              0);
+    EXPECT_EQ(
+        pldm_msgbuf_span_string_ascii(ctxExtract, (const void**)&retBuff, NULL),
+        0);
     EXPECT_EQ(pldm_msgbuf_extract_uint8(ctxExtract, testVal1), 0);
     EXPECT_EQ(0x77, testVal1);
 
@@ -907,8 +909,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_string_ascii_good_with_length)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
     uint8_t src[9] = {0x11, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0x77};
     constexpr size_t required = 6;
     const char expectData[required] = {0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00};
@@ -920,9 +922,9 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, src, sizeof(src)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
     EXPECT_EQ(0x2211, testVal);
-    EXPECT_EQ(
-        pldm_msgbuf_span_string_ascii(ctxExtract, (void**)&retBuff, &length),
-        0);
+    EXPECT_EQ(pldm_msgbuf_span_string_ascii(ctxExtract, (const void**)&retBuff,
+                                            &length),
+              0);
     EXPECT_EQ(pldm_msgbuf_extract_uint8(ctxExtract, testVal1), 0);
     EXPECT_EQ(0x77, testVal1);
 
@@ -935,8 +937,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_string_ascii_allow_null_args)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
     uint8_t src[8] = {0x11, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00};
     uint16_t testVal;
 
@@ -949,8 +951,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_string_ascii_bad_no_terminator)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
     uint8_t src[8] = {0x11, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77};
     uint16_t testVal;
     char* retBuff = NULL;
@@ -958,15 +960,16 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, src, sizeof(src)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
     EXPECT_EQ(0x2211, testVal);
-    EXPECT_EQ(pldm_msgbuf_span_string_ascii(ctxExtract, (void**)&retBuff, NULL),
-              -EOVERFLOW);
+    EXPECT_EQ(
+        pldm_msgbuf_span_string_ascii(ctxExtract, (const void**)&retBuff, NULL),
+        -EOVERFLOW);
     EXPECT_EQ(pldm_msgbuf_complete(ctxExtract), -EOVERFLOW);
 }
 
 TEST(msgbuf, pldm_msgbuf_span_string_ascii_under)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_rw _ctxExtract;
+    struct pldm_msgbuf_rw* ctxExtract = &_ctxExtract;
 
     uint8_t src[1] = {};
     char* retBuff = NULL;
@@ -990,8 +993,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_string_utf16_good)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
     uint8_t src[] __attribute__((aligned(alignof(char16_t)))) = {
         0x11, 0x22, 0x11, 0x68, 0x22, 0x65, 0x33, 0x6c,
         0x44, 0x6c, 0x55, 0x6f, 0x00, 0x00, 0x34, 0x12};
@@ -1005,8 +1008,9 @@
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
     EXPECT_EQ(0x2211, testVal);
 
-    ASSERT_EQ(pldm_msgbuf_span_string_utf16(ctxExtract, (void**)&retBuff, NULL),
-              0);
+    ASSERT_EQ(
+        pldm_msgbuf_span_string_utf16(ctxExtract, (const void**)&retBuff, NULL),
+        0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal1), 0);
     EXPECT_EQ(0x1234, testVal1);
 
@@ -1018,8 +1022,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_string_utf16_good2)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
     uint8_t src[24] = {0x11, 0x22, 0x11, 0x68, 0x22, 0x65, 0x33, 0x6c,
                        0x44, 0x6c, 0x55, 0x6f, 0x00, 0x00, 0x34, 0x12,
                        0x44, 0x6c, 0x55, 0x6f, 0x00, 0x00, 0x34, 0x12};
@@ -1037,8 +1041,9 @@
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
     EXPECT_EQ(0x2211, testVal);
 
-    EXPECT_EQ(pldm_msgbuf_span_string_utf16(ctxExtract, (void**)&retBuff, NULL),
-              0);
+    EXPECT_EQ(
+        pldm_msgbuf_span_string_utf16(ctxExtract, (const void**)&retBuff, NULL),
+        0);
 
     ASSERT_EQ(0ul, (uintptr_t)retBuff & (alignof(char16_t) - 1));
     EXPECT_EQ(6ul, str16len((char16_t*)retBuff) + 1);
@@ -1049,9 +1054,9 @@
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal1), 0);
     EXPECT_EQ(0x1234, testVal1);
 
-    EXPECT_EQ(
-        pldm_msgbuf_span_string_utf16(ctxExtract, (void**)&retBuff1, &length),
-        0);
+    EXPECT_EQ(pldm_msgbuf_span_string_utf16(ctxExtract, (const void**)&retBuff1,
+                                            &length),
+              0);
 
     EXPECT_EQ(0ul, length % 2);
     EXPECT_EQ(memcmp(expectData1, retBuff1, length), 0);
@@ -1064,8 +1069,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_string_utf16_allow_null_args)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
     uint8_t src[14] = {0x11, 0x22, 0x11, 0x68, 0x22, 0x65, 0x33,
                        0x6c, 0x44, 0x6c, 0x55, 0x6f, 0x00, 0x00};
     uint16_t testVal;
@@ -1079,8 +1084,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_string_utf16_bad_no_terminator)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
     uint8_t src[14] = {0x11, 0x22, 0x11, 0x68, 0x22, 0x65, 0x33,
                        0x6c, 0x44, 0x6c, 0x55, 0x6f, 0x66, 0x77};
     uint16_t testVal;
@@ -1089,15 +1094,16 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, src, sizeof(src)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
     EXPECT_EQ(0x2211, testVal);
-    EXPECT_EQ(pldm_msgbuf_span_string_utf16(ctxExtract, (void**)&retBuff, NULL),
-              -EOVERFLOW);
+    EXPECT_EQ(
+        pldm_msgbuf_span_string_utf16(ctxExtract, (const void**)&retBuff, NULL),
+        -EOVERFLOW);
     EXPECT_EQ(pldm_msgbuf_complete(ctxExtract), -EOVERFLOW);
 }
 
 TEST(msgbuf, pldm_msgbuf_span_string_utf16_bad_odd_size)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
     uint8_t src[] = {0x11, 0x22, 0x11, 0x68, 0x22, 0x65, 0x33,
                      0x6c, 0x44, 0x6c, 0x55, 0x00, 0x00};
     uint16_t testVal;
@@ -1106,15 +1112,16 @@
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, src, sizeof(src)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
     EXPECT_EQ(0x2211, testVal);
-    EXPECT_EQ(pldm_msgbuf_span_string_utf16(ctxExtract, (void**)&retBuff, NULL),
-              -EOVERFLOW);
+    EXPECT_EQ(
+        pldm_msgbuf_span_string_utf16(ctxExtract, (const void**)&retBuff, NULL),
+        -EOVERFLOW);
     EXPECT_EQ(pldm_msgbuf_complete(ctxExtract), -EOVERFLOW);
 }
 
 TEST(msgbuf, pldm_msgbuf_span_string_utf16_mix)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
     uint8_t src[36] = {0x2,  0x65, 0x6e, 0x00, // Language Tag "en"
                        0x00, 0x53, 0x00, 0x30, 0x00, 0x53, 0x00,
                        0x58, 0x00, 0x00,                   // Entity Name "S0S"
@@ -1145,30 +1152,36 @@
     EXPECT_EQ(pldm_msgbuf_extract_uint8(ctxExtract, name_count), 0);
     EXPECT_EQ(0x2, name_count);
 
-    EXPECT_EQ(pldm_msgbuf_span_string_ascii(ctxExtract, (void**)&tag, NULL), 0);
+    EXPECT_EQ(
+        pldm_msgbuf_span_string_ascii(ctxExtract, (const void**)&tag, NULL), 0);
     EXPECT_EQ(strncmp(expectTag0, tag, strlen(tag) + 1), 0);
 
-    EXPECT_EQ(pldm_msgbuf_span_string_utf16(ctxExtract, (void**)&name, NULL),
-              0);
+    EXPECT_EQ(
+        pldm_msgbuf_span_string_utf16(ctxExtract, (const void**)&name, NULL),
+        0);
     ASSERT_EQ(0ul, (uintptr_t)name & (alignof(char16_t) - 1));
     EXPECT_EQ(5ul, str16len((char16_t*)name) + 1);
     EXPECT_EQ(memcmp(expectName0, name,
                      sizeof(char16_t) * (str16len((char16_t*)name) + 1)),
               0);
 
-    EXPECT_EQ(pldm_msgbuf_span_string_ascii(ctxExtract, (void**)&tag1, &length),
-              0);
-    EXPECT_EQ(strncmp(expectTag1, tag1, length), 0);
     EXPECT_EQ(
-        pldm_msgbuf_span_string_utf16(ctxExtract, (void**)&name1, &length), 0);
+        pldm_msgbuf_span_string_ascii(ctxExtract, (const void**)&tag1, &length),
+        0);
+    EXPECT_EQ(strncmp(expectTag1, tag1, length), 0);
+    EXPECT_EQ(pldm_msgbuf_span_string_utf16(ctxExtract, (const void**)&name1,
+                                            &length),
+              0);
     EXPECT_EQ(0ul, length % 2);
     EXPECT_EQ(memcmp(expectName1, name1, length), 0);
 
-    EXPECT_EQ(pldm_msgbuf_span_string_ascii(ctxExtract, (void**)&tag2, NULL),
-              0);
+    EXPECT_EQ(
+        pldm_msgbuf_span_string_ascii(ctxExtract, (const void**)&tag2, NULL),
+        0);
     EXPECT_EQ(strncmp(expectTag2, tag2, strlen(tag2) + 1), 0);
-    EXPECT_EQ(pldm_msgbuf_span_string_utf16(ctxExtract, (void**)&name2, NULL),
-              0);
+    EXPECT_EQ(
+        pldm_msgbuf_span_string_utf16(ctxExtract, (const void**)&name2, NULL),
+        0);
     ASSERT_EQ(0ul, (uintptr_t)name2 & (alignof(char16_t) - 1));
     EXPECT_EQ(4ul, str16len((char16_t*)name2) + 1);
     EXPECT_EQ(memcmp(expectName2, name2,
@@ -1183,8 +1196,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_string_utf16_under)
 {
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_rw _ctxExtract;
+    struct pldm_msgbuf_rw* ctxExtract = &_ctxExtract;
 
     uint8_t src[1] = {};
     char* retBuff = NULL;
@@ -1198,8 +1211,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_remaining_good)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t src[8] = {0x11, 0x22, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
     uint8_t buf[8] = {0};
     uint16_t testVal;
@@ -1211,14 +1224,14 @@
     EXPECT_EQ(
         pldm_msgbuf_insert_array_uint8(ctx, sizeof(src), src, sizeof(src)), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
-    EXPECT_EQ(
-        pldm_msgbuf_span_remaining(ctxExtract, (void**)&retBuff, &remaining),
-        0);
+    EXPECT_EQ(pldm_msgbuf_span_remaining(ctxExtract, (const void**)&retBuff,
+                                         &remaining),
+              0);
 
     EXPECT_EQ(remaining, sizeof(expectData));
     EXPECT_EQ(memcmp(expectData, retBuff, remaining), 0);
@@ -1228,8 +1241,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_remaining_bad)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t src[8] = {0x11, 0x22, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
     uint8_t buf[8] = {0};
     uint16_t testVal;
@@ -1238,8 +1251,8 @@
     EXPECT_EQ(
         pldm_msgbuf_insert_array_uint8(ctx, sizeof(src), src, sizeof(src)), 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)), 0);
     EXPECT_EQ(pldm_msgbuf_extract_uint16(ctxExtract, testVal), 0);
@@ -1250,8 +1263,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_until_0_1)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t buf[] = {1};
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
@@ -1261,8 +1274,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_until_0_1_p)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t buf[] = {1};
     void* start;
     size_t len;
@@ -1276,8 +1289,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_until_1_1)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[] = {1};
     uint8_t val;
 
@@ -1289,8 +1302,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_until_1_2)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[] = {0, 1};
     uint8_t val;
 
@@ -1303,8 +1316,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_until_1_3)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[] = {0, 1, 2};
     uint8_t val;
 
@@ -1317,8 +1330,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_until_2_3)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[] = {0, 1, 2};
     uint8_t val0;
     uint8_t val1;
@@ -1334,8 +1347,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_until_short)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t buf[] = {1};
 
     ASSERT_EQ(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)), 0);
@@ -1345,8 +1358,8 @@
 
 TEST(msgbuf, pldm_msgbuf_span_until_saturated)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[] = {1};
     uint16_t val;
 
@@ -1359,22 +1372,22 @@
 
 TEST(msgbuf, pldm_msgbuf_copy_good)
 {
-    struct pldm_msgbuf _src;
-    struct pldm_msgbuf* src = &_src;
+    struct pldm_msgbuf_ro _src;
+    struct pldm_msgbuf_ro* src = &_src;
     uint16_t buf[1] = {htole16(0x5aa5)};
 
     ASSERT_EQ(pldm_msgbuf_init_errno(src, sizeof(buf), buf, sizeof(buf)), 0);
 
-    struct pldm_msgbuf _dst;
-    struct pldm_msgbuf* dst = &_dst;
+    struct pldm_msgbuf_rw _dst;
+    struct pldm_msgbuf_rw* dst = &_dst;
     uint16_t checkVal = 0;
     uint8_t buf1[sizeof(buf)] = {};
 
     ASSERT_EQ(pldm_msgbuf_init_errno(dst, sizeof(buf1), buf1, sizeof(buf1)), 0);
     EXPECT_EQ(pldm_msgbuf_copy(dst, src, buf[0], name), 0);
 
-    ASSERT_EQ(pldm_msgbuf_init_errno(dst, sizeof(buf1), buf1, sizeof(buf1)), 0);
-    EXPECT_EQ(pldm_msgbuf_extract_uint16(dst, checkVal), 0);
+    ASSERT_EQ(pldm_msgbuf_init_errno(src, sizeof(buf1), buf1, sizeof(buf1)), 0);
+    EXPECT_EQ(pldm_msgbuf_extract_uint16(src, checkVal), 0);
 
     EXPECT_EQ(pldm_msgbuf_complete(src), 0);
     EXPECT_EQ(pldm_msgbuf_complete(dst), 0);
@@ -1384,10 +1397,10 @@
 
 TEST(msgbuf, pldm_msgbuf_copy_bad)
 {
-    struct pldm_msgbuf _src;
-    struct pldm_msgbuf* src = &_src;
-    struct pldm_msgbuf _dst;
-    struct pldm_msgbuf* dst = &_dst;
+    struct pldm_msgbuf_ro _src;
+    struct pldm_msgbuf_ro* src = &_src;
+    struct pldm_msgbuf_rw _dst;
+    struct pldm_msgbuf_rw* dst = &_dst;
     uint8_t buf[1] = {sizeof(uint8_t)};
     uint8_t buf1[1] = {sizeof(uint16_t)};
     uint16_t value = 8;
@@ -1405,10 +1418,10 @@
 {
     const char msg[] = "this is a message";
 
-    struct pldm_msgbuf _src;
-    struct pldm_msgbuf* src = &_src;
-    struct pldm_msgbuf _dst;
-    struct pldm_msgbuf* dst = &_dst;
+    struct pldm_msgbuf_ro _src;
+    struct pldm_msgbuf_ro* src = &_src;
+    struct pldm_msgbuf_rw _dst;
+    struct pldm_msgbuf_rw* dst = &_dst;
 
     char buf[sizeof(msg)] = {};
 
@@ -1424,10 +1437,10 @@
 {
     const char msg[] = "this is a message";
 
-    struct pldm_msgbuf _src;
-    struct pldm_msgbuf* src = &_src;
-    struct pldm_msgbuf _dst;
-    struct pldm_msgbuf* dst = &_dst;
+    struct pldm_msgbuf_ro _src;
+    struct pldm_msgbuf_ro* src = &_src;
+    struct pldm_msgbuf_rw _dst;
+    struct pldm_msgbuf_rw* dst = &_dst;
 
     char buf[sizeof(msg) + 1] = {};
 
@@ -1443,10 +1456,10 @@
 {
     const char msg[] = "this is a message";
 
-    struct pldm_msgbuf _src;
-    struct pldm_msgbuf* src = &_src;
-    struct pldm_msgbuf _dst;
-    struct pldm_msgbuf* dst = &_dst;
+    struct pldm_msgbuf_ro _src;
+    struct pldm_msgbuf_ro* src = &_src;
+    struct pldm_msgbuf_rw _dst;
+    struct pldm_msgbuf_rw* dst = &_dst;
 
     char buf[sizeof(msg) - 1] = {};
 
@@ -1461,10 +1474,10 @@
 {
     const char msg[] = {'a'};
 
-    struct pldm_msgbuf _src;
-    struct pldm_msgbuf* src = &_src;
-    struct pldm_msgbuf _dst;
-    struct pldm_msgbuf* dst = &_dst;
+    struct pldm_msgbuf_ro _src;
+    struct pldm_msgbuf_ro* src = &_src;
+    struct pldm_msgbuf_rw _dst;
+    struct pldm_msgbuf_rw* dst = &_dst;
 
     char buf[sizeof(msg)] = {};
 
@@ -1479,10 +1492,10 @@
 {
     const char16_t msg[] = u"this is a message";
 
-    struct pldm_msgbuf _src;
-    struct pldm_msgbuf* src = &_src;
-    struct pldm_msgbuf _dst;
-    struct pldm_msgbuf* dst = &_dst;
+    struct pldm_msgbuf_ro _src;
+    struct pldm_msgbuf_ro* src = &_src;
+    struct pldm_msgbuf_rw _dst;
+    struct pldm_msgbuf_rw* dst = &_dst;
 
     char buf[sizeof(msg)] = {};
 
@@ -1498,10 +1511,10 @@
 {
     const char16_t msg[] = u"this is a message";
 
-    struct pldm_msgbuf _src;
-    struct pldm_msgbuf* src = &_src;
-    struct pldm_msgbuf _dst;
-    struct pldm_msgbuf* dst = &_dst;
+    struct pldm_msgbuf_ro _src;
+    struct pldm_msgbuf_ro* src = &_src;
+    struct pldm_msgbuf_rw _dst;
+    struct pldm_msgbuf_rw* dst = &_dst;
 
     char buf[sizeof(msg) + 1] = {};
 
@@ -1517,10 +1530,10 @@
 {
     const char16_t msg[] = u"this is a message";
 
-    struct pldm_msgbuf _src;
-    struct pldm_msgbuf* src = &_src;
-    struct pldm_msgbuf _dst;
-    struct pldm_msgbuf* dst = &_dst;
+    struct pldm_msgbuf_ro _src;
+    struct pldm_msgbuf_ro* src = &_src;
+    struct pldm_msgbuf_rw _dst;
+    struct pldm_msgbuf_rw* dst = &_dst;
 
     char buf[sizeof(msg) - 1] = {};
 
@@ -1535,10 +1548,10 @@
 {
     const char16_t msg[] = {u'a'};
 
-    struct pldm_msgbuf _src;
-    struct pldm_msgbuf* src = &_src;
-    struct pldm_msgbuf _dst;
-    struct pldm_msgbuf* dst = &_dst;
+    struct pldm_msgbuf_ro _src;
+    struct pldm_msgbuf_ro* src = &_src;
+    struct pldm_msgbuf_rw _dst;
+    struct pldm_msgbuf_rw* dst = &_dst;
 
     char buf[sizeof(msg)] = {};
 
@@ -1551,7 +1564,7 @@
 
 TEST(msgbuf, extract_one_uint8_to_size)
 {
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RO_DEFINE_P(ctx);
     uint8_t buf[1] = {0xa5};
 
     size_t val;
@@ -1564,7 +1577,7 @@
 
 TEST(msgbuf, extract_under_uint8_to_size)
 {
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RO_DEFINE_P(ctx);
     uint8_t buf[1] = {};
     size_t val;
 
@@ -1576,7 +1589,7 @@
 
 TEST(msgbuf, extract_over_uint8_to_size)
 {
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RO_DEFINE_P(ctx);
     uint8_t buf[1] = {};
     size_t val;
 
@@ -1587,7 +1600,7 @@
 
 TEST(msgbuf, extract_one_uint16_to_size)
 {
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RO_DEFINE_P(ctx);
     uint16_t buf[1] = {htole16(0x5aa5)};
     size_t val;
 
@@ -1599,7 +1612,7 @@
 
 TEST(msgbuf, extract_under_uint16_to_size)
 {
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RO_DEFINE_P(ctx);
     uint16_t buf[1] = {};
     size_t val;
 
@@ -1611,7 +1624,7 @@
 
 TEST(msgbuf, extract_over_uint16_to_size)
 {
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RO_DEFINE_P(ctx);
     uint16_t buf[1] = {};
     size_t val;
 
@@ -1622,7 +1635,7 @@
 
 TEST(msgbuf, extract_one_uint32_to_size)
 {
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RO_DEFINE_P(ctx);
     uint32_t buf[1] = {htole32(0x5a00ffa5)};
     size_t val;
 
@@ -1634,7 +1647,7 @@
 
 TEST(msgbuf, extract_under_uint32_to_size)
 {
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RO_DEFINE_P(ctx);
     uint32_t buf[1] = {};
     size_t val;
 
@@ -1646,7 +1659,7 @@
 
 TEST(msgbuf, extract_over_uint32_to_size)
 {
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RO_DEFINE_P(ctx);
     uint32_t buf[1] = {};
     size_t val;
 
diff --git a/tests/msgbuf.hpp b/tests/msgbuf.hpp
new file mode 100644
index 0000000..1c11c96
--- /dev/null
+++ b/tests/msgbuf.hpp
@@ -0,0 +1,277 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+#ifndef PLDM_MSGBUF_HPP
+#define PLDM_MSGBUF_HPP
+
+#include <libpldm/compiler.h>
+
+#include "msgbuf/core.h"
+
+/*
+ * Use the C++ Function Overload to keep pldm_msgbuf related function consistent
+ * and to produce compile-time errors when the wrong pldm_msgbuf type is passed.
+ *
+ * Previously we cast away `const` in `pldm_msgbuf_init_error()`, which was a
+ * hack. Instead, introduce:
+ *   - pldm_msgbuf_ro: read-only buffer with a `const` cursor
+ *   - pldm_msgbuf_rw: read-write buffer with a non-const cursor
+ *
+ * `pldm_msgbuf_ro` is used by decode APIs to extract payloads into PLDM
+ * structures. `pldm_msgbuf_rw` is used by encode APIs to insert payloads from
+ * PLDM structures.
+ */
+
+#include <cstdint>
+#include <cstdio>
+#include <type_traits>
+
+// NOLINTBEGIN(bugprone-macro-parentheses)
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+#define PLDM__MSGBUF_DEFINE_P(name, mode)                                      \
+    struct pldm_msgbuf_##mode _##name LIBPLDM_CC_CLEANUP(                      \
+        pldm__msgbuf_##mode##_cleanup) = {NULL, INTMAX_MIN};                   \
+    auto* name = &(_##name)
+// NOLINTEND(bugprone-macro-parentheses)
+
+#define PLDM_MSGBUF_RO_DEFINE_P(name) PLDM__MSGBUF_DEFINE_P(name, ro)
+#define PLDM_MSGBUF_RW_DEFINE_P(name) PLDM__MSGBUF_DEFINE_P(name, rw)
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_init_errno(struct pldm_msgbuf_ro* ctx,
+                                                    size_t minsize,
+                                                    const void* buf, size_t len)
+{
+    return pldm_msgbuf_ro_init_errno(ctx, minsize, buf, len);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_init_errno(struct pldm_msgbuf_rw* ctx,
+                                                    size_t minsize,
+                                                    const void* buf, size_t len)
+{
+    return pldm_msgbuf_rw_init_errno(ctx, minsize, buf, len);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_validate(struct pldm_msgbuf_ro* ctx)
+{
+    return pldm_msgbuf_ro_validate(ctx);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_validate(struct pldm_msgbuf_rw* ctx)
+{
+    return pldm_msgbuf_rw_validate(ctx);
+}
+
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+LIBPLDM_CC_ALWAYS_INLINE int pldm__msgbuf_invalidate(struct pldm_msgbuf_ro* ctx)
+{
+    return pldm__msgbuf_ro_invalidate(ctx);
+}
+
+// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
+LIBPLDM_CC_ALWAYS_INLINE int pldm__msgbuf_invalidate(struct pldm_msgbuf_rw* ctx)
+{
+    return pldm__msgbuf_rw_invalidate(ctx);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_consumed(struct pldm_msgbuf_ro* ctx)
+{
+    return pldm_msgbuf_ro_consumed(ctx);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_consumed(struct pldm_msgbuf_rw* ctx)
+{
+    return pldm_msgbuf_rw_consumed(ctx);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_discard(struct pldm_msgbuf_ro* ctx,
+                                                 int error)
+{
+    return pldm_msgbuf_ro_discard(ctx, error);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_discard(struct pldm_msgbuf_rw* ctx,
+                                                 int error)
+{
+    return pldm_msgbuf_rw_discard(ctx, error);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_complete(struct pldm_msgbuf_ro* ctx)
+{
+    return pldm_msgbuf_ro_complete(ctx);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_complete(struct pldm_msgbuf_rw* ctx)
+{
+    return pldm_msgbuf_rw_complete(ctx);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_complete_consumed(struct pldm_msgbuf_ro* ctx)
+{
+    return pldm_msgbuf_ro_complete_consumed(ctx);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_complete_consumed(struct pldm_msgbuf_rw* ctx)
+{
+    return pldm_msgbuf_rw_complete_consumed(ctx);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_span_required(struct pldm_msgbuf_ro* ctx, size_t required,
+                              const void** cursor)
+{
+    return pldm_msgbuf_ro_span_required(ctx, required, cursor);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_span_required(struct pldm_msgbuf_rw* ctx, size_t required,
+                              void** cursor)
+{
+    return pldm_msgbuf_rw_span_required(ctx, required, cursor);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_span_string_ascii(struct pldm_msgbuf_rw* ctx, void** cursor,
+                                  size_t* length)
+{
+    return pldm_msgbuf_rw_span_string_ascii(ctx, cursor, length);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_span_string_ascii(struct pldm_msgbuf_ro* ctx,
+                                  const void** cursor, size_t* length)
+{
+    return pldm_msgbuf_ro_span_string_ascii(ctx, cursor, length);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_string_utf16(pldm_msgbuf_ro* ctx,
+                                                           const void** cursor,
+                                                           size_t* length)
+{
+    return pldm_msgbuf_ro_span_string_utf16(ctx, cursor, length);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_string_utf16(pldm_msgbuf_rw* ctx,
+                                                           void** cursor,
+                                                           size_t* length)
+{
+    return pldm_msgbuf_rw_span_string_utf16(ctx, cursor, length);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_span_remaining(struct pldm_msgbuf_rw* ctx, void** cursor,
+                               size_t* len)
+{
+    return pldm_msgbuf_rw_span_remaining(ctx, cursor, len);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_span_remaining(struct pldm_msgbuf_ro* ctx, const void** cursor,
+                               size_t* len)
+{
+    return pldm_msgbuf_ro_span_remaining(ctx, cursor, len);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_until(struct pldm_msgbuf_ro* ctx,
+                                                    size_t trailer,
+                                                    const void** cursor,
+                                                    size_t* length)
+{
+    return pldm_msgbuf_ro_span_until(ctx, trailer, cursor, length);
+}
+
+LIBPLDM_CC_ALWAYS_INLINE int pldm_msgbuf_span_until(struct pldm_msgbuf_rw* ctx,
+                                                    size_t trailer,
+                                                    void** cursor,
+                                                    size_t* length)
+{
+    return pldm_msgbuf_rw_span_until(ctx, trailer, cursor, length);
+}
+
+#define pldm_msgbuf_extract_typecheck(ty, fn, dst, ...)                        \
+    pldm_msgbuf_typecheck_##ty<decltype(dst)>(__VA_ARGS__)
+
+#define pldm_msgbuf_extract_uint8(ctx, dst)                                    \
+    pldm_msgbuf_extract_typecheck(uint8_t, pldm__msgbuf_extract_uint8, dst,    \
+                                  ctx, (void*)&(dst))
+
+#define pldm_msgbuf_extract_int8(ctx, dst)                                     \
+    pldm_msgbuf_extract_typecheck(int8_t, pldm__msgbuf_extract_int8, dst, ctx, \
+                                  (void*)&(dst))
+
+#define pldm_msgbuf_extract_uint16(ctx, dst)                                   \
+    pldm_msgbuf_extract_typecheck(uint16_t, pldm__msgbuf_extract_uint16, dst,  \
+                                  ctx, (void*)&(dst))
+
+#define pldm_msgbuf_extract_int16(ctx, dst)                                    \
+    pldm_msgbuf_extract_typecheck(int16_t, pldm__msgbuf_extract_int16, dst,    \
+                                  ctx, (void*)&(dst))
+
+#define pldm_msgbuf_extract_uint32(ctx, dst)                                   \
+    pldm_msgbuf_extract_typecheck(uint32_t, pldm__msgbuf_extract_uint32, dst,  \
+                                  ctx, (void*)&(dst))
+
+#define pldm_msgbuf_extract_int32(ctx, dst)                                    \
+    pldm_msgbuf_extract_typecheck(int32_t, pldm__msgbuf_extract_int32, dst,    \
+                                  ctx, (void*)&(dst))
+
+#define pldm_msgbuf_extract_real32(ctx, dst)                                   \
+    pldm_msgbuf_extract_typecheck(real32_t, pldm__msgbuf_extract_real32, dst,  \
+                                  ctx, (void*)&(dst))
+
+template <typename T>
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_typecheck_uint8_t(struct pldm_msgbuf_ro* ctx, void* buf)
+{
+    static_assert(std::is_same<uint8_t, T>::value);
+    return pldm__msgbuf_extract_uint8(ctx, buf);
+}
+
+template <typename T>
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_typecheck_int8_t(struct pldm_msgbuf_ro* ctx, void* buf)
+{
+    static_assert(std::is_same<int8_t, T>::value);
+    return pldm__msgbuf_extract_int8(ctx, buf);
+}
+
+template <typename T>
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_typecheck_uint16_t(struct pldm_msgbuf_ro* ctx, void* buf)
+{
+    static_assert(std::is_same<uint16_t, T>::value);
+    return pldm__msgbuf_extract_uint16(ctx, buf);
+}
+
+template <typename T>
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_typecheck_int16_t(struct pldm_msgbuf_ro* ctx, void* buf)
+{
+    static_assert(std::is_same<int16_t, T>::value);
+    return pldm__msgbuf_extract_int16(ctx, buf);
+}
+
+template <typename T>
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_typecheck_uint32_t(struct pldm_msgbuf_ro* ctx, void* buf)
+{
+    static_assert(std::is_same<uint32_t, T>::value);
+    return pldm__msgbuf_extract_uint32(ctx, buf);
+}
+
+template <typename T>
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_typecheck_int32_t(struct pldm_msgbuf_ro* ctx, void* buf)
+{
+    static_assert(std::is_same<int32_t, T>::value);
+    return pldm__msgbuf_extract_int32(ctx, buf);
+}
+
+template <typename T>
+LIBPLDM_CC_ALWAYS_INLINE int
+    pldm_msgbuf_typecheck_real32_t(struct pldm_msgbuf_ro* ctx, void* buf)
+{
+    static_assert(std::is_same<real32_t, T>::value);
+    return pldm__msgbuf_extract_real32(ctx, buf);
+}
+
+#endif /* BUF_HPP */
diff --git a/tests/msgbuf_generic.c b/tests/msgbuf_generic.c
index 62160f3..28c8a53 100644
--- a/tests/msgbuf_generic.c
+++ b/tests/msgbuf_generic.c
@@ -28,8 +28,8 @@
 
 static void test_msgbuf_extract_generic_uint8(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint8_t buf[1] = {0xa5};
     uint8_t val;
 
@@ -41,8 +41,8 @@
 
 static void test_msgbuf_extract_generic_int8(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     int8_t buf[1] = {-1};
     int8_t val;
 
@@ -54,8 +54,8 @@
 
 static void test_msgbuf_extract_generic_uint16(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint16_t buf[1] = {0x5aa5};
     uint16_t val;
 
@@ -67,8 +67,8 @@
 
 static void test_msgbuf_extract_generic_int16(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     int16_t buf[1] = {(int16_t)(htole16((uint16_t)INT16_MIN))};
     int16_t val;
 
@@ -80,8 +80,8 @@
 
 static void test_msgbuf_extract_generic_uint32(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint32_t buf[1] = {0x5a00ffa5};
     uint32_t val;
 
@@ -93,8 +93,8 @@
 
 static void test_msgbuf_extract_generic_int32(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     int32_t buf[1] = {(int32_t)(htole32((uint32_t)INT32_MIN))};
     int32_t val;
 
@@ -106,8 +106,8 @@
 
 static void test_msgbuf_extract_generic_real32(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint32_t buf[1];
     uint32_t xform;
     real32_t val;
@@ -125,8 +125,8 @@
 
 static void test_msgbuf_extract_array_generic_uint8(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_ro _ctx;
+    struct pldm_msgbuf_ro* ctx = &_ctx;
     uint32_t buf[1] = {0};
     uint8_t arr[1];
 
@@ -138,8 +138,8 @@
 
 static void test_msgbuf_insert_generic_int32(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     int32_t src = -12345;
     int32_t checkVal = 0;
     uint8_t buf[sizeof(int32_t)] = {0};
@@ -147,8 +147,8 @@
     expect(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_insert(ctx, src) == 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     expect(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_extract(ctxExtract, checkVal) == 0);
@@ -160,8 +160,8 @@
 
 static void test_msgbuf_insert_generic_uint32(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint32_t src = 0xf1223344;
     uint32_t checkVal = 0;
     uint8_t buf[sizeof(uint32_t)] = {0};
@@ -169,8 +169,8 @@
     expect(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_insert(ctx, src) == 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     expect(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_extract(ctxExtract, checkVal) == 0);
@@ -182,8 +182,8 @@
 
 static void test_msgbuf_insert_generic_uint16(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint16_t src = 0xf344;
     uint16_t checkVal = 0;
     uint8_t buf[sizeof(uint16_t)] = {0};
@@ -191,8 +191,8 @@
     expect(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(uint16_t)) == 0);
     expect(pldm_msgbuf_insert(ctx, src) == 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     expect(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_extract(ctxExtract, checkVal) == 0);
@@ -204,8 +204,8 @@
 
 static void test_msgbuf_insert_generic_int16(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     int16_t src = -12;
     int16_t checkVal = 0;
     uint8_t buf[sizeof(int16_t)] = {0};
@@ -213,8 +213,8 @@
     expect(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(uint16_t)) == 0);
     expect(pldm_msgbuf_insert(ctx, src) == 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     expect(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_extract(ctxExtract, checkVal) == 0);
@@ -226,8 +226,8 @@
 
 static void test_msgbuf_insert_generic_uint8(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t src = 0xf4;
     uint8_t checkVal = 0;
     uint8_t buf[sizeof(uint8_t)] = {0};
@@ -235,8 +235,8 @@
     expect(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_insert(ctx, src) == 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     expect(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_extract(ctxExtract, checkVal) == 0);
@@ -248,8 +248,8 @@
 
 static void test_msgbuf_insert_generic_int8(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     int8_t src = -4;
     int8_t checkVal = 0;
     uint8_t buf[sizeof(int8_t)] = {0};
@@ -257,8 +257,8 @@
     expect(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_insert(ctx, src) == 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     expect(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_extract(ctxExtract, checkVal) == 0);
@@ -270,8 +270,8 @@
 
 static void test_msgbuf_insert_array_generic_uint8(void)
 {
-    struct pldm_msgbuf _ctx;
-    struct pldm_msgbuf* ctx = &_ctx;
+    struct pldm_msgbuf_rw _ctx;
+    struct pldm_msgbuf_rw* ctx = &_ctx;
     uint8_t src[6] = {0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
     uint8_t buf[6] = {0};
     uint8_t retBuff[6] = {0};
@@ -279,8 +279,8 @@
     expect(pldm_msgbuf_init_errno(ctx, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_insert_array(ctx, sizeof(src), src, sizeof(src)) == 0);
 
-    struct pldm_msgbuf _ctxExtract;
-    struct pldm_msgbuf* ctxExtract = &_ctxExtract;
+    struct pldm_msgbuf_ro _ctxExtract;
+    struct pldm_msgbuf_ro* ctxExtract = &_ctxExtract;
 
     expect(pldm_msgbuf_init_errno(ctxExtract, 0, buf, sizeof(buf)) == 0);
     expect(pldm_msgbuf_extract_array(ctxExtract, sizeof(retBuff), retBuff,
diff --git a/tests/oem/meta/fileio.cpp b/tests/oem/meta/fileio.cpp
index 747f3be..845f0da 100644
--- a/tests/oem/meta/fileio.cpp
+++ b/tests/oem/meta/fileio.cpp
@@ -1,19 +1,21 @@
 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+
+#include "msgbuf.hpp"
+
 #include <endian.h>
+#include <libpldm/base.h>
 #include <libpldm/oem/meta/file_io.h>
 
 #include <cstdlib>
 #include <new>
 
-#include "msgbuf.h"
-
 #include "gmock/gmock.h"
 #include <gtest/gtest.h>
 
 TEST(DecodeOemMetaFileIoWriteReq, testGoodDecodeRequest)
 {
     constexpr const uint8_t postCode[4] = {0x93, 0xe0, 0x00, 0xea};
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RW_DEFINE_P(ctx);
     int rc;
 
     constexpr size_t encodedPayloadLen =
@@ -82,7 +84,7 @@
 
 TEST(DecodeOemMetaFileIoReadReq, testGoodDecodeRequest)
 {
-    PLDM_MSGBUF_DEFINE_P(ctx);
+    PLDM_MSGBUF_RW_DEFINE_P(ctx);
     int rc;
 
     constexpr size_t payloadLen = PLDM_OEM_META_FILE_IO_READ_REQ_MIN_LENGTH +