net: coap_client: Move send buffer into request context

Keep a separate buffer for each request context instead of having a
single common buffer for the entire client context. This allows to
simplify the retransmission logic, as parallel requests will no longer
overwrite the buffer for each other. That way, we can simply retransmit
the packet w/o a need to recreate it, and thus reach to the payload
pointer or callback.

This removes the requirement to keep the payload pointer, provided to
asynchronous coap_client_req() call, valid throughout the exchange
lifetime for simple cases (i.e. no block transfer used). In case of
block transfer, this is unavoidable and needs to be documented.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
diff --git a/include/zephyr/net/coap_client.h b/include/zephyr/net/coap_client.h
index b3065f6..1d3b959 100644
--- a/include/zephyr/net/coap_client.h
+++ b/include/zephyr/net/coap_client.h
@@ -74,7 +74,7 @@
  *
  * An optional callback for providing a payload for CoAP client requests. If set in
  * @ref coap_client_request, the CoAP client library will call this callback when
- * preparing a PUT/POST request (note that this is also true for retransmissions).
+ * preparing a PUT/POST request.
  *
  * When called, the library provides the application with the current payload offset
  * for the transfer and the payload block size. In return, the application sets the
@@ -155,6 +155,7 @@
 	struct coap_client_request coap_request;
 	struct coap_packet request;
 	uint8_t request_tag[COAP_TOKEN_MAX_LEN];
+	uint8_t send_buf[MAX_COAP_MSG_LEN];
 
 	/* For GETs with observe option set */
 	bool is_observe;
@@ -166,7 +167,6 @@
 	struct sockaddr address;
 	socklen_t socklen;
 	struct k_mutex lock;
-	uint8_t send_buf[MAX_COAP_MSG_LEN];
 	uint8_t recv_buf[MAX_COAP_MSG_LEN];
 	struct coap_client_internal_request requests[CONFIG_COAP_CLIENT_MAX_REQUESTS];
 	struct coap_option echo_option;
@@ -194,6 +194,10 @@
  * Once the callback is called with last block set as true, socket can be closed or
  * used for another query.
  *
+ * @note If block transfer is used, the @p payload pointer provided in @p req parameter has to
+ * remain valid throughout the transaction (i.e. until the last block or an error is reported).
+ * The library will need to access the payload pointer when sending consecutive payload blocks.
+ *
  * @param client Client instance.
  * @param sock Open socket file descriptor.
  * @param addr the destination address of the request, NULL if socket is already connected.
diff --git a/subsys/net/lib/coap/coap_client.c b/subsys/net/lib/coap/coap_client.c
index cdd20a8..9f6e689 100644
--- a/subsys/net/lib/coap/coap_client.c
+++ b/subsys/net/lib/coap/coap_client.c
@@ -206,7 +206,7 @@
 	int i;
 	bool block2 = false;
 
-	memset(client->send_buf, 0, sizeof(client->send_buf));
+	memset(internal_req->send_buf, 0, sizeof(internal_req->send_buf));
 
 	if (!reconstruct) {
 		uint8_t *token = coap_next_token();
@@ -216,7 +216,7 @@
 		memcpy(internal_req->request_token, token, internal_req->request_tkl);
 	}
 
-	ret = coap_packet_init(&internal_req->request, client->send_buf, MAX_COAP_MSG_LEN,
+	ret = coap_packet_init(&internal_req->request, internal_req->send_buf, MAX_COAP_MSG_LEN,
 			       1, req->confirmable ? COAP_TYPE_CON : COAP_TYPE_NON_CON,
 			       COAP_TOKEN_MAX_LEN, internal_req->request_token, req->method,
 			       internal_req->last_id);
@@ -569,17 +569,6 @@
 	    coap_pending_cycle(&internal_req->pending)) {
 		LOG_ERR("Timeout, retrying send");
 
-		/* Reset send block context as it was updated in previous init from packet */
-		if (internal_req->send_blk_ctx.total_size > 0) {
-			internal_req->send_blk_ctx.current = internal_req->offset;
-		}
-		ret = coap_client_init_request(client, &internal_req->coap_request,
-					       internal_req, true);
-		if (ret < 0) {
-			LOG_ERR("Error re-creating CoAP request %d", ret);
-			return ret;
-		}
-
 		ret = send_request(client->fd, internal_req->request.data,
 					internal_req->request.offset, 0, &client->address,
 					client->socklen);
@@ -759,8 +748,9 @@
 {
 	int ret;
 	struct coap_packet ack;
+	uint8_t ack_buf[COAP_FIXED_HEADER_SIZE + COAP_TOKEN_MAX_LEN];
 
-	ret = coap_ack_init(&ack, req, client->send_buf, MAX_COAP_MSG_LEN, response_code);
+	ret = coap_ack_init(&ack, req, ack_buf, sizeof(ack_buf), response_code);
 	if (ret < 0) {
 		LOG_ERR("Failed to initialize CoAP ACK-message");
 		return ret;
@@ -779,8 +769,9 @@
 {
 	int ret;
 	struct coap_packet rst;
+	uint8_t rst_buf[COAP_FIXED_HEADER_SIZE + COAP_TOKEN_MAX_LEN];
 
-	ret = coap_rst_init(&rst, req, client->send_buf, MAX_COAP_MSG_LEN);
+	ret = coap_rst_init(&rst, req, rst_buf, sizeof(rst_buf));
 	if (ret < 0) {
 		LOG_ERR("Failed to initialize CoAP RST-message");
 		return ret;