1c87c5fbaSopenharmony_ci/* coap_block.c -- block transfer
2c87c5fbaSopenharmony_ci *
3c87c5fbaSopenharmony_ci * Copyright (C) 2010--2012,2015-2023 Olaf Bergmann <bergmann@tzi.org> and others
4c87c5fbaSopenharmony_ci *
5c87c5fbaSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
6c87c5fbaSopenharmony_ci *
7c87c5fbaSopenharmony_ci * This file is part of the CoAP library libcoap. Please see
8c87c5fbaSopenharmony_ci * README for terms of use.
9c87c5fbaSopenharmony_ci */
10c87c5fbaSopenharmony_ci
11c87c5fbaSopenharmony_ci/**
12c87c5fbaSopenharmony_ci * @file coap_block.c
13c87c5fbaSopenharmony_ci * @brief CoAP Block handling
14c87c5fbaSopenharmony_ci */
15c87c5fbaSopenharmony_ci
16c87c5fbaSopenharmony_ci#include "coap3/coap_internal.h"
17c87c5fbaSopenharmony_ci
18c87c5fbaSopenharmony_ci#ifndef min
19c87c5fbaSopenharmony_ci#define min(a,b) ((a) < (b) ? (a) : (b))
20c87c5fbaSopenharmony_ci#endif
21c87c5fbaSopenharmony_ci
22c87c5fbaSopenharmony_ci#define STATE_TOKEN_BASE(t) ((t) & 0xffffffffffffULL)
23c87c5fbaSopenharmony_ci#define STATE_TOKEN_RETRY(t) ((uint64_t)(t) >> 48)
24c87c5fbaSopenharmony_ci#define STATE_TOKEN_FULL(t,r) (STATE_TOKEN_BASE(t) + ((uint64_t)(r) << 48))
25c87c5fbaSopenharmony_ci
26c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
27c87c5fbaSopenharmony_ciint
28c87c5fbaSopenharmony_cicoap_q_block_is_supported(void) {
29c87c5fbaSopenharmony_ci  return 1;
30c87c5fbaSopenharmony_ci}
31c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
32c87c5fbaSopenharmony_ciint
33c87c5fbaSopenharmony_cicoap_q_block_is_supported(void) {
34c87c5fbaSopenharmony_ci  return 0;
35c87c5fbaSopenharmony_ci}
36c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
37c87c5fbaSopenharmony_ci
38c87c5fbaSopenharmony_ciunsigned int
39c87c5fbaSopenharmony_cicoap_opt_block_num(const coap_opt_t *block_opt) {
40c87c5fbaSopenharmony_ci  unsigned int num = 0;
41c87c5fbaSopenharmony_ci  uint16_t len;
42c87c5fbaSopenharmony_ci
43c87c5fbaSopenharmony_ci  len = coap_opt_length(block_opt);
44c87c5fbaSopenharmony_ci
45c87c5fbaSopenharmony_ci  if (len == 0) {
46c87c5fbaSopenharmony_ci    return 0;
47c87c5fbaSopenharmony_ci  }
48c87c5fbaSopenharmony_ci
49c87c5fbaSopenharmony_ci  if (len > 1) {
50c87c5fbaSopenharmony_ci    num = coap_decode_var_bytes(coap_opt_value(block_opt),
51c87c5fbaSopenharmony_ci                                coap_opt_length(block_opt) - 1);
52c87c5fbaSopenharmony_ci  }
53c87c5fbaSopenharmony_ci
54c87c5fbaSopenharmony_ci  return (num << 4) | ((COAP_OPT_BLOCK_END_BYTE(block_opt) & 0xF0) >> 4);
55c87c5fbaSopenharmony_ci}
56c87c5fbaSopenharmony_ci
57c87c5fbaSopenharmony_ciint
58c87c5fbaSopenharmony_cicoap_get_block_b(const coap_session_t *session, const coap_pdu_t *pdu,
59c87c5fbaSopenharmony_ci                 coap_option_num_t number, coap_block_b_t *block) {
60c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
61c87c5fbaSopenharmony_ci  coap_opt_t *option;
62c87c5fbaSopenharmony_ci
63c87c5fbaSopenharmony_ci  assert(block);
64c87c5fbaSopenharmony_ci  memset(block, 0, sizeof(coap_block_b_t));
65c87c5fbaSopenharmony_ci
66c87c5fbaSopenharmony_ci  if (pdu && (option = coap_check_option(pdu, number, &opt_iter)) != NULL) {
67c87c5fbaSopenharmony_ci    unsigned int num;
68c87c5fbaSopenharmony_ci
69c87c5fbaSopenharmony_ci    if (COAP_OPT_BLOCK_MORE(option))
70c87c5fbaSopenharmony_ci      block->m = 1;
71c87c5fbaSopenharmony_ci    block->aszx = block->szx = COAP_OPT_BLOCK_SZX(option);
72c87c5fbaSopenharmony_ci    if (block->szx == 7) {
73c87c5fbaSopenharmony_ci      size_t length;
74c87c5fbaSopenharmony_ci      const uint8_t *data;
75c87c5fbaSopenharmony_ci
76c87c5fbaSopenharmony_ci      if (session == NULL || COAP_PROTO_NOT_RELIABLE(session->proto) ||
77c87c5fbaSopenharmony_ci          !(session->csm_bert_rem_support && session->csm_bert_loc_support))
78c87c5fbaSopenharmony_ci        /* No BERT support */
79c87c5fbaSopenharmony_ci        return 0;
80c87c5fbaSopenharmony_ci
81c87c5fbaSopenharmony_ci      block->szx = 6; /* BERT is 1024 block chunks */
82c87c5fbaSopenharmony_ci      block->bert = 1;
83c87c5fbaSopenharmony_ci      if (coap_get_data(pdu, &length, &data)) {
84c87c5fbaSopenharmony_ci        if (block->m && (length % 1024) != 0) {
85c87c5fbaSopenharmony_ci          coap_log_debug("block: Oversized packet - reduced to %zu from %zu\n",
86c87c5fbaSopenharmony_ci                         length - (length % 1024), length);
87c87c5fbaSopenharmony_ci          length -= length % 1024;
88c87c5fbaSopenharmony_ci        }
89c87c5fbaSopenharmony_ci        block->chunk_size = (uint32_t)length;
90c87c5fbaSopenharmony_ci      } else
91c87c5fbaSopenharmony_ci        block->chunk_size = 0;
92c87c5fbaSopenharmony_ci    } else {
93c87c5fbaSopenharmony_ci      block->chunk_size = (size_t)1 << (block->szx + 4);
94c87c5fbaSopenharmony_ci    }
95c87c5fbaSopenharmony_ci    block->defined = 1;
96c87c5fbaSopenharmony_ci
97c87c5fbaSopenharmony_ci    /* The block number is at most 20 bits, so values above 2^20 - 1
98c87c5fbaSopenharmony_ci     * are illegal. */
99c87c5fbaSopenharmony_ci    num = coap_opt_block_num(option);
100c87c5fbaSopenharmony_ci    if (num > 0xFFFFF) {
101c87c5fbaSopenharmony_ci      return 0;
102c87c5fbaSopenharmony_ci    }
103c87c5fbaSopenharmony_ci    block->num = num;
104c87c5fbaSopenharmony_ci    return 1;
105c87c5fbaSopenharmony_ci  }
106c87c5fbaSopenharmony_ci
107c87c5fbaSopenharmony_ci  return 0;
108c87c5fbaSopenharmony_ci}
109c87c5fbaSopenharmony_ci
110c87c5fbaSopenharmony_ciint
111c87c5fbaSopenharmony_cicoap_get_block(const coap_pdu_t *pdu, coap_option_num_t number,
112c87c5fbaSopenharmony_ci               coap_block_t *block) {
113c87c5fbaSopenharmony_ci  coap_block_b_t block_b;
114c87c5fbaSopenharmony_ci
115c87c5fbaSopenharmony_ci  assert(block);
116c87c5fbaSopenharmony_ci  memset(block, 0, sizeof(coap_block_t));
117c87c5fbaSopenharmony_ci
118c87c5fbaSopenharmony_ci  if (coap_get_block_b(NULL, pdu, number, &block_b)) {
119c87c5fbaSopenharmony_ci    block->num = block_b.num;
120c87c5fbaSopenharmony_ci    block->m   = block_b.m;
121c87c5fbaSopenharmony_ci    block->szx = block_b.szx;
122c87c5fbaSopenharmony_ci    return 1;
123c87c5fbaSopenharmony_ci  }
124c87c5fbaSopenharmony_ci  return 0;
125c87c5fbaSopenharmony_ci}
126c87c5fbaSopenharmony_ci
127c87c5fbaSopenharmony_cistatic int
128c87c5fbaSopenharmony_cisetup_block_b(coap_session_t *session, coap_pdu_t *pdu, coap_block_b_t *block,
129c87c5fbaSopenharmony_ci              unsigned int num,
130c87c5fbaSopenharmony_ci              unsigned int blk_size, size_t total) {
131c87c5fbaSopenharmony_ci  size_t token_options = pdu->data ? (size_t)(pdu->data - pdu->token) : pdu->used_size;
132c87c5fbaSopenharmony_ci  size_t avail = pdu->max_size - token_options;
133c87c5fbaSopenharmony_ci  unsigned int start = num << (blk_size + 4);
134c87c5fbaSopenharmony_ci  unsigned int can_use_bert = block->defined == 0 || block->bert;
135c87c5fbaSopenharmony_ci
136c87c5fbaSopenharmony_ci  assert(start <= total);
137c87c5fbaSopenharmony_ci  memset(block, 0, sizeof(*block));
138c87c5fbaSopenharmony_ci  block->num = num;
139c87c5fbaSopenharmony_ci  block->szx = block->aszx = blk_size;
140c87c5fbaSopenharmony_ci  if (can_use_bert && blk_size == 6 && avail >= 1024 && session != NULL &&
141c87c5fbaSopenharmony_ci      COAP_PROTO_RELIABLE(session->proto) &&
142c87c5fbaSopenharmony_ci      session->csm_bert_rem_support && session->csm_bert_loc_support) {
143c87c5fbaSopenharmony_ci    block->bert = 1;
144c87c5fbaSopenharmony_ci    block->aszx = 7;
145c87c5fbaSopenharmony_ci    block->chunk_size = (uint32_t)((avail / 1024) * 1024);
146c87c5fbaSopenharmony_ci  } else {
147c87c5fbaSopenharmony_ci    block->chunk_size = (size_t)1 << (blk_size + 4);
148c87c5fbaSopenharmony_ci    if (avail < block->chunk_size && (total - start) >= avail) {
149c87c5fbaSopenharmony_ci      /* Need to reduce block size */
150c87c5fbaSopenharmony_ci      unsigned int szx;
151c87c5fbaSopenharmony_ci      int new_blk_size;
152c87c5fbaSopenharmony_ci
153c87c5fbaSopenharmony_ci      if (avail < 16) {         /* bad luck, this is the smallest block size */
154c87c5fbaSopenharmony_ci        coap_log_debug("not enough space, even the smallest block does not fit (1)\n");
155c87c5fbaSopenharmony_ci        return 0;
156c87c5fbaSopenharmony_ci      }
157c87c5fbaSopenharmony_ci      new_blk_size = coap_flsll((long long)avail) - 5;
158c87c5fbaSopenharmony_ci      coap_log_debug("decrease block size for %zu to %d\n", avail, new_blk_size);
159c87c5fbaSopenharmony_ci      szx = block->szx;
160c87c5fbaSopenharmony_ci      block->szx = new_blk_size;
161c87c5fbaSopenharmony_ci      block->num <<= szx - block->szx;
162c87c5fbaSopenharmony_ci      block->chunk_size = (size_t)1 << (new_blk_size + 4);
163c87c5fbaSopenharmony_ci    }
164c87c5fbaSopenharmony_ci  }
165c87c5fbaSopenharmony_ci  block->m = block->chunk_size < total - start;
166c87c5fbaSopenharmony_ci  return 1;
167c87c5fbaSopenharmony_ci}
168c87c5fbaSopenharmony_ci
169c87c5fbaSopenharmony_ciint
170c87c5fbaSopenharmony_cicoap_write_block_opt(coap_block_t *block, coap_option_num_t number,
171c87c5fbaSopenharmony_ci                     coap_pdu_t *pdu, size_t data_length) {
172c87c5fbaSopenharmony_ci  size_t start;
173c87c5fbaSopenharmony_ci  unsigned char buf[4];
174c87c5fbaSopenharmony_ci  coap_block_b_t block_b;
175c87c5fbaSopenharmony_ci
176c87c5fbaSopenharmony_ci  assert(pdu);
177c87c5fbaSopenharmony_ci
178c87c5fbaSopenharmony_ci  start = block->num << (block->szx + 4);
179c87c5fbaSopenharmony_ci  if (block->num != 0 && data_length <= start) {
180c87c5fbaSopenharmony_ci    coap_log_debug("illegal block requested\n");
181c87c5fbaSopenharmony_ci    return -2;
182c87c5fbaSopenharmony_ci  }
183c87c5fbaSopenharmony_ci
184c87c5fbaSopenharmony_ci  assert(pdu->max_size > 0);
185c87c5fbaSopenharmony_ci
186c87c5fbaSopenharmony_ci  block_b.defined = 1;
187c87c5fbaSopenharmony_ci  block_b.bert = 0;
188c87c5fbaSopenharmony_ci  if (!setup_block_b(NULL, pdu, &block_b, block->num,
189c87c5fbaSopenharmony_ci                     block->szx, data_length))
190c87c5fbaSopenharmony_ci    return -3;
191c87c5fbaSopenharmony_ci
192c87c5fbaSopenharmony_ci  /* to re-encode the block option */
193c87c5fbaSopenharmony_ci  coap_update_option(pdu, number, coap_encode_var_safe(buf, sizeof(buf),
194c87c5fbaSopenharmony_ci                                                       ((block_b.num << 4) |
195c87c5fbaSopenharmony_ci                                                        (block_b.m << 3) |
196c87c5fbaSopenharmony_ci                                                        block_b.szx)),
197c87c5fbaSopenharmony_ci                     buf);
198c87c5fbaSopenharmony_ci
199c87c5fbaSopenharmony_ci  return 1;
200c87c5fbaSopenharmony_ci}
201c87c5fbaSopenharmony_ci
202c87c5fbaSopenharmony_ciint
203c87c5fbaSopenharmony_cicoap_write_block_b_opt(coap_session_t *session, coap_block_b_t *block,
204c87c5fbaSopenharmony_ci                       coap_option_num_t number,
205c87c5fbaSopenharmony_ci                       coap_pdu_t *pdu, size_t data_length) {
206c87c5fbaSopenharmony_ci  size_t start;
207c87c5fbaSopenharmony_ci  unsigned char buf[4];
208c87c5fbaSopenharmony_ci
209c87c5fbaSopenharmony_ci  assert(pdu);
210c87c5fbaSopenharmony_ci
211c87c5fbaSopenharmony_ci  start = block->num << (block->szx + 4);
212c87c5fbaSopenharmony_ci  if (block->num != 0 && data_length <= start) {
213c87c5fbaSopenharmony_ci    coap_log_debug("illegal block requested\n");
214c87c5fbaSopenharmony_ci    return -2;
215c87c5fbaSopenharmony_ci  }
216c87c5fbaSopenharmony_ci
217c87c5fbaSopenharmony_ci  assert(pdu->max_size > 0);
218c87c5fbaSopenharmony_ci
219c87c5fbaSopenharmony_ci  if (!setup_block_b(session, pdu, block, block->num,
220c87c5fbaSopenharmony_ci                     block->szx, data_length))
221c87c5fbaSopenharmony_ci    return -3;
222c87c5fbaSopenharmony_ci
223c87c5fbaSopenharmony_ci  /* to re-encode the block option */
224c87c5fbaSopenharmony_ci  coap_update_option(pdu, number, coap_encode_var_safe(buf, sizeof(buf),
225c87c5fbaSopenharmony_ci                                                       ((block->num << 4) |
226c87c5fbaSopenharmony_ci                                                        (block->m << 3) |
227c87c5fbaSopenharmony_ci                                                        block->aszx)),
228c87c5fbaSopenharmony_ci                     buf);
229c87c5fbaSopenharmony_ci
230c87c5fbaSopenharmony_ci  return 1;
231c87c5fbaSopenharmony_ci}
232c87c5fbaSopenharmony_ci
233c87c5fbaSopenharmony_ciint
234c87c5fbaSopenharmony_cicoap_add_block(coap_pdu_t *pdu, size_t len, const uint8_t *data,
235c87c5fbaSopenharmony_ci               unsigned int block_num, unsigned char block_szx) {
236c87c5fbaSopenharmony_ci  unsigned int start;
237c87c5fbaSopenharmony_ci  start = block_num << (block_szx + 4);
238c87c5fbaSopenharmony_ci
239c87c5fbaSopenharmony_ci  if (len <= start)
240c87c5fbaSopenharmony_ci    return 0;
241c87c5fbaSopenharmony_ci
242c87c5fbaSopenharmony_ci  return coap_add_data(pdu,
243c87c5fbaSopenharmony_ci                       min(len - start, ((size_t)1 << (block_szx + 4))),
244c87c5fbaSopenharmony_ci                       data + start);
245c87c5fbaSopenharmony_ci}
246c87c5fbaSopenharmony_ci
247c87c5fbaSopenharmony_ciint
248c87c5fbaSopenharmony_cicoap_add_block_b_data(coap_pdu_t *pdu, size_t len, const uint8_t *data,
249c87c5fbaSopenharmony_ci                      coap_block_b_t *block) {
250c87c5fbaSopenharmony_ci  unsigned int start = block->num << (block->szx + 4);
251c87c5fbaSopenharmony_ci  size_t max_size;
252c87c5fbaSopenharmony_ci
253c87c5fbaSopenharmony_ci  if (len <= start)
254c87c5fbaSopenharmony_ci    return 0;
255c87c5fbaSopenharmony_ci
256c87c5fbaSopenharmony_ci  if (block->bert) {
257c87c5fbaSopenharmony_ci    size_t token_options = pdu->data ? (size_t)(pdu->data - pdu->token) : pdu->used_size;
258c87c5fbaSopenharmony_ci    max_size = ((pdu->max_size - token_options) / 1024) * 1024;
259c87c5fbaSopenharmony_ci  } else {
260c87c5fbaSopenharmony_ci    max_size = (size_t)1 << (block->szx + 4);
261c87c5fbaSopenharmony_ci  }
262c87c5fbaSopenharmony_ci  block->chunk_size = (uint32_t)max_size;
263c87c5fbaSopenharmony_ci
264c87c5fbaSopenharmony_ci  return coap_add_data(pdu,
265c87c5fbaSopenharmony_ci                       min(len - start, max_size),
266c87c5fbaSopenharmony_ci                       data + start);
267c87c5fbaSopenharmony_ci}
268c87c5fbaSopenharmony_ci
269c87c5fbaSopenharmony_ci/*
270c87c5fbaSopenharmony_ci * Note that the COAP_OPTION_ have to be added in the correct order
271c87c5fbaSopenharmony_ci */
272c87c5fbaSopenharmony_civoid
273c87c5fbaSopenharmony_cicoap_add_data_blocked_response(const coap_pdu_t *request,
274c87c5fbaSopenharmony_ci                               coap_pdu_t *response,
275c87c5fbaSopenharmony_ci                               uint16_t media_type,
276c87c5fbaSopenharmony_ci                               int maxage,
277c87c5fbaSopenharmony_ci                               size_t length,
278c87c5fbaSopenharmony_ci                               const uint8_t *data
279c87c5fbaSopenharmony_ci                              ) {
280c87c5fbaSopenharmony_ci  coap_key_t etag;
281c87c5fbaSopenharmony_ci  unsigned char buf[4];
282c87c5fbaSopenharmony_ci  coap_block_t block2;
283c87c5fbaSopenharmony_ci  int block2_requested = 0;
284c87c5fbaSopenharmony_ci
285c87c5fbaSopenharmony_ci  memset(&block2, 0, sizeof(block2));
286c87c5fbaSopenharmony_ci  /*
287c87c5fbaSopenharmony_ci   * Need to check that a valid block is getting asked for so that the
288c87c5fbaSopenharmony_ci   * correct options are put into the PDU.
289c87c5fbaSopenharmony_ci   */
290c87c5fbaSopenharmony_ci  if (request) {
291c87c5fbaSopenharmony_ci    if (coap_get_block(request, COAP_OPTION_BLOCK2, &block2)) {
292c87c5fbaSopenharmony_ci      block2_requested = 1;
293c87c5fbaSopenharmony_ci      if (block2.num != 0 && length <= (block2.num << (block2.szx + 4))) {
294c87c5fbaSopenharmony_ci        coap_log_debug("Illegal block requested (%d > last = %zu)\n",
295c87c5fbaSopenharmony_ci                       block2.num,
296c87c5fbaSopenharmony_ci                       length >> (block2.szx + 4));
297c87c5fbaSopenharmony_ci        response->code = COAP_RESPONSE_CODE(400);
298c87c5fbaSopenharmony_ci        goto error;
299c87c5fbaSopenharmony_ci      }
300c87c5fbaSopenharmony_ci    }
301c87c5fbaSopenharmony_ci  }
302c87c5fbaSopenharmony_ci  response->code = COAP_RESPONSE_CODE(205);
303c87c5fbaSopenharmony_ci
304c87c5fbaSopenharmony_ci  /* add etag for the resource */
305c87c5fbaSopenharmony_ci  memset(etag, 0, sizeof(etag));
306c87c5fbaSopenharmony_ci  coap_hash(data, length, etag);
307c87c5fbaSopenharmony_ci  coap_insert_option(response, COAP_OPTION_ETAG, sizeof(etag), etag);
308c87c5fbaSopenharmony_ci
309c87c5fbaSopenharmony_ci  coap_insert_option(response, COAP_OPTION_CONTENT_FORMAT,
310c87c5fbaSopenharmony_ci                     coap_encode_var_safe(buf, sizeof(buf),
311c87c5fbaSopenharmony_ci                                          media_type),
312c87c5fbaSopenharmony_ci                     buf);
313c87c5fbaSopenharmony_ci
314c87c5fbaSopenharmony_ci  if (maxage >= 0) {
315c87c5fbaSopenharmony_ci    coap_insert_option(response,
316c87c5fbaSopenharmony_ci                       COAP_OPTION_MAXAGE,
317c87c5fbaSopenharmony_ci                       coap_encode_var_safe(buf, sizeof(buf), maxage), buf);
318c87c5fbaSopenharmony_ci  }
319c87c5fbaSopenharmony_ci
320c87c5fbaSopenharmony_ci  if (block2_requested) {
321c87c5fbaSopenharmony_ci    int res;
322c87c5fbaSopenharmony_ci
323c87c5fbaSopenharmony_ci    res = coap_write_block_opt(&block2, COAP_OPTION_BLOCK2, response, length);
324c87c5fbaSopenharmony_ci
325c87c5fbaSopenharmony_ci    switch (res) {
326c87c5fbaSopenharmony_ci    case -2:                        /* illegal block (caught above) */
327c87c5fbaSopenharmony_ci      response->code = COAP_RESPONSE_CODE(400);
328c87c5fbaSopenharmony_ci      goto error;
329c87c5fbaSopenharmony_ci    case -1:                        /* should really not happen */
330c87c5fbaSopenharmony_ci      assert(0);
331c87c5fbaSopenharmony_ci    /* fall through if assert is a no-op */
332c87c5fbaSopenharmony_ci    case -3:                        /* cannot handle request */
333c87c5fbaSopenharmony_ci      response->code = COAP_RESPONSE_CODE(500);
334c87c5fbaSopenharmony_ci      goto error;
335c87c5fbaSopenharmony_ci    default:                        /* everything is good */
336c87c5fbaSopenharmony_ci      ;
337c87c5fbaSopenharmony_ci    }
338c87c5fbaSopenharmony_ci
339c87c5fbaSopenharmony_ci    coap_add_option_internal(response,
340c87c5fbaSopenharmony_ci                             COAP_OPTION_SIZE2,
341c87c5fbaSopenharmony_ci                             coap_encode_var_safe8(buf, sizeof(buf), length),
342c87c5fbaSopenharmony_ci                             buf);
343c87c5fbaSopenharmony_ci
344c87c5fbaSopenharmony_ci    coap_add_block(response, length, data,
345c87c5fbaSopenharmony_ci                   block2.num, block2.szx);
346c87c5fbaSopenharmony_ci    return;
347c87c5fbaSopenharmony_ci  }
348c87c5fbaSopenharmony_ci
349c87c5fbaSopenharmony_ci  /*
350c87c5fbaSopenharmony_ci   * Block2 not requested
351c87c5fbaSopenharmony_ci   */
352c87c5fbaSopenharmony_ci  if (!coap_add_data(response, length, data)) {
353c87c5fbaSopenharmony_ci    /*
354c87c5fbaSopenharmony_ci     * Insufficient space to add in data - use block mode
355c87c5fbaSopenharmony_ci     * set initial block size, will be lowered by
356c87c5fbaSopenharmony_ci     * coap_write_block_opt() automatically
357c87c5fbaSopenharmony_ci     */
358c87c5fbaSopenharmony_ci    block2.num = 0;
359c87c5fbaSopenharmony_ci    block2.szx = 6;
360c87c5fbaSopenharmony_ci    coap_write_block_opt(&block2, COAP_OPTION_BLOCK2, response, length);
361c87c5fbaSopenharmony_ci
362c87c5fbaSopenharmony_ci    coap_add_option_internal(response,
363c87c5fbaSopenharmony_ci                             COAP_OPTION_SIZE2,
364c87c5fbaSopenharmony_ci                             coap_encode_var_safe8(buf, sizeof(buf), length),
365c87c5fbaSopenharmony_ci                             buf);
366c87c5fbaSopenharmony_ci
367c87c5fbaSopenharmony_ci    coap_add_block(response, length, data,
368c87c5fbaSopenharmony_ci                   block2.num, block2.szx);
369c87c5fbaSopenharmony_ci  }
370c87c5fbaSopenharmony_ci  return;
371c87c5fbaSopenharmony_ci
372c87c5fbaSopenharmony_cierror:
373c87c5fbaSopenharmony_ci  coap_add_data(response,
374c87c5fbaSopenharmony_ci                strlen(coap_response_phrase(response->code)),
375c87c5fbaSopenharmony_ci                (const unsigned char *)coap_response_phrase(response->code));
376c87c5fbaSopenharmony_ci}
377c87c5fbaSopenharmony_ci
378c87c5fbaSopenharmony_civoid
379c87c5fbaSopenharmony_cicoap_context_set_block_mode(coap_context_t *context,
380c87c5fbaSopenharmony_ci                            uint8_t block_mode) {
381c87c5fbaSopenharmony_ci  context->block_mode = (block_mode & (COAP_BLOCK_USE_LIBCOAP |
382c87c5fbaSopenharmony_ci                                       COAP_BLOCK_SINGLE_BODY |
383c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
384c87c5fbaSopenharmony_ci                                       COAP_BLOCK_TRY_Q_BLOCK |
385c87c5fbaSopenharmony_ci                                       COAP_BLOCK_USE_M_Q_BLOCK |
386c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
387c87c5fbaSopenharmony_ci                                       COAP_BLOCK_NO_PREEMPTIVE_RTAG));
388c87c5fbaSopenharmony_ci  if (!(block_mode & COAP_BLOCK_USE_LIBCOAP))
389c87c5fbaSopenharmony_ci    context->block_mode = 0;
390c87c5fbaSopenharmony_ci#if ! COAP_Q_BLOCK_SUPPORT
391c87c5fbaSopenharmony_ci  if (block_mode & (COAP_BLOCK_TRY_Q_BLOCK|COAP_BLOCK_USE_M_Q_BLOCK))
392c87c5fbaSopenharmony_ci    coap_log_debug("Q-Block support not compiled in - ignored\n");
393c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
394c87c5fbaSopenharmony_ci}
395c87c5fbaSopenharmony_ci
396c87c5fbaSopenharmony_ciCOAP_STATIC_INLINE int
397c87c5fbaSopenharmony_cifull_match(const uint8_t *a, size_t alen,
398c87c5fbaSopenharmony_ci           const uint8_t *b, size_t blen) {
399c87c5fbaSopenharmony_ci  return alen == blen && (alen == 0 || memcmp(a, b, alen) == 0);
400c87c5fbaSopenharmony_ci}
401c87c5fbaSopenharmony_ci
402c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
403c87c5fbaSopenharmony_ci
404c87c5fbaSopenharmony_ciint
405c87c5fbaSopenharmony_cicoap_cancel_observe(coap_session_t *session, coap_binary_t *token,
406c87c5fbaSopenharmony_ci                    coap_pdu_type_t type) {
407c87c5fbaSopenharmony_ci  coap_lg_crcv_t *lg_crcv, *q;
408c87c5fbaSopenharmony_ci
409c87c5fbaSopenharmony_ci  assert(session);
410c87c5fbaSopenharmony_ci  if (!session)
411c87c5fbaSopenharmony_ci    return 0;
412c87c5fbaSopenharmony_ci
413c87c5fbaSopenharmony_ci  if (!(session->block_mode & COAP_BLOCK_USE_LIBCOAP)) {
414c87c5fbaSopenharmony_ci    coap_log_debug("** %s: coap_cancel_observe: COAP_BLOCK_USE_LIBCOAP not enabled\n",
415c87c5fbaSopenharmony_ci                   coap_session_str(session));
416c87c5fbaSopenharmony_ci    return 0;
417c87c5fbaSopenharmony_ci  }
418c87c5fbaSopenharmony_ci
419c87c5fbaSopenharmony_ci  LL_FOREACH_SAFE(session->lg_crcv, lg_crcv, q) {
420c87c5fbaSopenharmony_ci    if (lg_crcv->observe_set) {
421c87c5fbaSopenharmony_ci      if ((!token && !lg_crcv->app_token->length) || (token &&
422c87c5fbaSopenharmony_ci                                                      coap_binary_equal(token, lg_crcv->app_token))) {
423c87c5fbaSopenharmony_ci        uint8_t buf[8];
424c87c5fbaSopenharmony_ci        coap_mid_t mid;
425c87c5fbaSopenharmony_ci        size_t size;
426c87c5fbaSopenharmony_ci        const uint8_t *data;
427c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
428c87c5fbaSopenharmony_ci        coap_block_b_t block;
429c87c5fbaSopenharmony_ci        int using_q_block1 = coap_get_block_b(session, &lg_crcv->pdu,
430c87c5fbaSopenharmony_ci                                              COAP_OPTION_Q_BLOCK1, &block);
431c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
432c87c5fbaSopenharmony_ci        coap_bin_const_t *otoken = lg_crcv->obs_token ?
433c87c5fbaSopenharmony_ci                                   lg_crcv->obs_token[0] ?
434c87c5fbaSopenharmony_ci                                   lg_crcv->obs_token[0] :
435c87c5fbaSopenharmony_ci                                   (coap_bin_const_t *)lg_crcv->app_token :
436c87c5fbaSopenharmony_ci                                   (coap_bin_const_t *)lg_crcv->app_token;
437c87c5fbaSopenharmony_ci        coap_pdu_t *pdu = coap_pdu_duplicate(&lg_crcv->pdu,
438c87c5fbaSopenharmony_ci                                             session,
439c87c5fbaSopenharmony_ci                                             otoken->length,
440c87c5fbaSopenharmony_ci                                             otoken->s,
441c87c5fbaSopenharmony_ci                                             NULL);
442c87c5fbaSopenharmony_ci
443c87c5fbaSopenharmony_ci        lg_crcv->observe_set = 0;
444c87c5fbaSopenharmony_ci        if (pdu == NULL)
445c87c5fbaSopenharmony_ci          return 0;
446c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
447c87c5fbaSopenharmony_ci        if (pdu->code == COAP_REQUEST_CODE_FETCH && using_q_block1) {
448c87c5fbaSopenharmony_ci          /* Have to make sure all gets through in case of packet loss */
449c87c5fbaSopenharmony_ci          pdu->type = COAP_MESSAGE_CON;
450c87c5fbaSopenharmony_ci        } else {
451c87c5fbaSopenharmony_ci          /* Need to make sure that this is the correct requested type */
452c87c5fbaSopenharmony_ci          pdu->type = type;
453c87c5fbaSopenharmony_ci        }
454c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
455c87c5fbaSopenharmony_ci        /* Need to make sure that this is the correct requested type */
456c87c5fbaSopenharmony_ci        pdu->type = type;
457c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
458c87c5fbaSopenharmony_ci
459c87c5fbaSopenharmony_ci        coap_update_option(pdu, COAP_OPTION_OBSERVE,
460c87c5fbaSopenharmony_ci                           coap_encode_var_safe(buf, sizeof(buf),
461c87c5fbaSopenharmony_ci                                                COAP_OBSERVE_CANCEL),
462c87c5fbaSopenharmony_ci                           buf);
463c87c5fbaSopenharmony_ci        if (coap_get_data(&lg_crcv->pdu, &size, &data))
464c87c5fbaSopenharmony_ci          coap_add_data_large_request(session, pdu, size, data, NULL, NULL);
465c87c5fbaSopenharmony_ci
466c87c5fbaSopenharmony_ci        /*
467c87c5fbaSopenharmony_ci         * Need to fix lg_xmit stateless token as using tokens from
468c87c5fbaSopenharmony_ci         * observe setup
469c87c5fbaSopenharmony_ci         */
470c87c5fbaSopenharmony_ci        if (pdu->lg_xmit)
471c87c5fbaSopenharmony_ci          pdu->lg_xmit->b.b1.state_token = lg_crcv->state_token;
472c87c5fbaSopenharmony_ci
473c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
474c87c5fbaSopenharmony_ci        /* See if large xmit using Q-Block1 (but not testing Q-Block1) */
475c87c5fbaSopenharmony_ci        if (using_q_block1) {
476c87c5fbaSopenharmony_ci          mid = coap_send_q_block1(session, block, pdu, COAP_SEND_INC_PDU);
477c87c5fbaSopenharmony_ci        } else {
478c87c5fbaSopenharmony_ci          mid = coap_send_internal(session, pdu);
479c87c5fbaSopenharmony_ci        }
480c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
481c87c5fbaSopenharmony_ci        mid = coap_send_internal(session, pdu);
482c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
483c87c5fbaSopenharmony_ci        if (mid != COAP_INVALID_MID)
484c87c5fbaSopenharmony_ci          return 1;
485c87c5fbaSopenharmony_ci        break;
486c87c5fbaSopenharmony_ci      }
487c87c5fbaSopenharmony_ci    }
488c87c5fbaSopenharmony_ci  }
489c87c5fbaSopenharmony_ci  return 0;
490c87c5fbaSopenharmony_ci}
491c87c5fbaSopenharmony_ci
492c87c5fbaSopenharmony_ci#if COAP_OSCORE_SUPPORT
493c87c5fbaSopenharmony_cicoap_mid_t
494c87c5fbaSopenharmony_cicoap_retransmit_oscore_pdu(coap_session_t *session,
495c87c5fbaSopenharmony_ci                           coap_pdu_t *pdu,
496c87c5fbaSopenharmony_ci                           coap_opt_t *echo) {
497c87c5fbaSopenharmony_ci  coap_lg_crcv_t *lg_crcv;
498c87c5fbaSopenharmony_ci  uint64_t token_match =
499c87c5fbaSopenharmony_ci      STATE_TOKEN_BASE(coap_decode_var_bytes8(pdu->actual_token.s,
500c87c5fbaSopenharmony_ci                                              pdu->actual_token.length));
501c87c5fbaSopenharmony_ci  uint8_t ltoken[8];
502c87c5fbaSopenharmony_ci  size_t ltoken_len;
503c87c5fbaSopenharmony_ci  uint64_t token;
504c87c5fbaSopenharmony_ci  const uint8_t *data;
505c87c5fbaSopenharmony_ci  size_t data_len;
506c87c5fbaSopenharmony_ci  coap_pdu_t *resend_pdu;
507c87c5fbaSopenharmony_ci  coap_block_b_t block;
508c87c5fbaSopenharmony_ci
509c87c5fbaSopenharmony_ci  LL_FOREACH(session->lg_crcv, lg_crcv) {
510c87c5fbaSopenharmony_ci    if (token_match != STATE_TOKEN_BASE(lg_crcv->state_token) &&
511c87c5fbaSopenharmony_ci        !coap_binary_equal(&pdu->actual_token, lg_crcv->app_token)) {
512c87c5fbaSopenharmony_ci      /* try out the next one */
513c87c5fbaSopenharmony_ci      continue;
514c87c5fbaSopenharmony_ci    }
515c87c5fbaSopenharmony_ci
516c87c5fbaSopenharmony_ci    /* lg_crcv found */
517c87c5fbaSopenharmony_ci
518c87c5fbaSopenharmony_ci    /* Re-send request with new token */
519c87c5fbaSopenharmony_ci    token = STATE_TOKEN_FULL(lg_crcv->state_token,
520c87c5fbaSopenharmony_ci                             ++lg_crcv->retry_counter);
521c87c5fbaSopenharmony_ci    ltoken_len = coap_encode_var_safe8(ltoken, sizeof(token), token);
522c87c5fbaSopenharmony_ci    /* There could be a Block option in pdu */
523c87c5fbaSopenharmony_ci    resend_pdu = coap_pdu_duplicate(pdu, session, ltoken_len,
524c87c5fbaSopenharmony_ci                                    ltoken, NULL);
525c87c5fbaSopenharmony_ci    if (!resend_pdu)
526c87c5fbaSopenharmony_ci      goto error;
527c87c5fbaSopenharmony_ci    if (echo) {
528c87c5fbaSopenharmony_ci      coap_insert_option(resend_pdu, COAP_OPTION_ECHO, coap_opt_length(echo),
529c87c5fbaSopenharmony_ci                         coap_opt_value(echo));
530c87c5fbaSopenharmony_ci    }
531c87c5fbaSopenharmony_ci    if (coap_get_data(&lg_crcv->pdu, &data_len, &data)) {
532c87c5fbaSopenharmony_ci      if (coap_get_block_b(session, resend_pdu, COAP_OPTION_BLOCK1, &block)) {
533c87c5fbaSopenharmony_ci        if (data_len > block.chunk_size && block.chunk_size != 0) {
534c87c5fbaSopenharmony_ci          data_len = block.chunk_size;
535c87c5fbaSopenharmony_ci        }
536c87c5fbaSopenharmony_ci      }
537c87c5fbaSopenharmony_ci      coap_add_data(resend_pdu, data_len, data);
538c87c5fbaSopenharmony_ci    }
539c87c5fbaSopenharmony_ci
540c87c5fbaSopenharmony_ci    return coap_send_internal(session, resend_pdu);
541c87c5fbaSopenharmony_ci  }
542c87c5fbaSopenharmony_cierror:
543c87c5fbaSopenharmony_ci  return COAP_INVALID_MID;
544c87c5fbaSopenharmony_ci}
545c87c5fbaSopenharmony_ci#endif /* COAP_OSCORE_SUPPORT */
546c87c5fbaSopenharmony_ci#endif /* COAP_CLIENT_SUPPORT */
547c87c5fbaSopenharmony_ci
548c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
549c87c5fbaSopenharmony_ci/*
550c87c5fbaSopenharmony_ci * Find the response lg_xmit
551c87c5fbaSopenharmony_ci */
552c87c5fbaSopenharmony_cicoap_lg_xmit_t *
553c87c5fbaSopenharmony_cicoap_find_lg_xmit_response(const coap_session_t *session,
554c87c5fbaSopenharmony_ci                           const coap_pdu_t *request,
555c87c5fbaSopenharmony_ci                           const coap_resource_t *resource,
556c87c5fbaSopenharmony_ci                           const coap_string_t *query) {
557c87c5fbaSopenharmony_ci  coap_lg_xmit_t *lg_xmit;
558c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
559c87c5fbaSopenharmony_ci  coap_opt_t *rtag_opt = coap_check_option(request,
560c87c5fbaSopenharmony_ci                                           COAP_OPTION_RTAG,
561c87c5fbaSopenharmony_ci                                           &opt_iter);
562c87c5fbaSopenharmony_ci  size_t rtag_length = rtag_opt ? coap_opt_length(rtag_opt) : 0;
563c87c5fbaSopenharmony_ci  const uint8_t *rtag = rtag_opt ? coap_opt_value(rtag_opt) : NULL;
564c87c5fbaSopenharmony_ci
565c87c5fbaSopenharmony_ci  LL_FOREACH(session->lg_xmit, lg_xmit) {
566c87c5fbaSopenharmony_ci    static coap_string_t empty = { 0, NULL};
567c87c5fbaSopenharmony_ci
568c87c5fbaSopenharmony_ci    if (COAP_PDU_IS_REQUEST(&lg_xmit->pdu) ||
569c87c5fbaSopenharmony_ci        resource != lg_xmit->b.b2.resource ||
570c87c5fbaSopenharmony_ci        request->code != lg_xmit->b.b2.request_method ||
571c87c5fbaSopenharmony_ci        !coap_string_equal(query ? query : &empty,
572c87c5fbaSopenharmony_ci                           lg_xmit->b.b2.query ?
573c87c5fbaSopenharmony_ci                           lg_xmit->b.b2.query : &empty)) {
574c87c5fbaSopenharmony_ci      /* try out the next one */
575c87c5fbaSopenharmony_ci      continue;
576c87c5fbaSopenharmony_ci    }
577c87c5fbaSopenharmony_ci    /* lg_xmit is a response */
578c87c5fbaSopenharmony_ci    if (rtag_opt || lg_xmit->b.b2.rtag_set == 1) {
579c87c5fbaSopenharmony_ci      if (!(rtag_opt && lg_xmit->b.b2.rtag_set == 1))
580c87c5fbaSopenharmony_ci        continue;
581c87c5fbaSopenharmony_ci      if (lg_xmit->b.b2.rtag_length != rtag_length ||
582c87c5fbaSopenharmony_ci          memcmp(lg_xmit->b.b2.rtag, rtag, rtag_length) != 0)
583c87c5fbaSopenharmony_ci        continue;
584c87c5fbaSopenharmony_ci    }
585c87c5fbaSopenharmony_ci    return lg_xmit;
586c87c5fbaSopenharmony_ci  }
587c87c5fbaSopenharmony_ci  return NULL;
588c87c5fbaSopenharmony_ci}
589c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
590c87c5fbaSopenharmony_ci
591c87c5fbaSopenharmony_cistatic int
592c87c5fbaSopenharmony_cicoap_add_data_large_internal(coap_session_t *session,
593c87c5fbaSopenharmony_ci                             const coap_pdu_t *request,
594c87c5fbaSopenharmony_ci                             coap_pdu_t *pdu,
595c87c5fbaSopenharmony_ci                             coap_resource_t *resource,
596c87c5fbaSopenharmony_ci                             const coap_string_t *query,
597c87c5fbaSopenharmony_ci                             int maxage,
598c87c5fbaSopenharmony_ci                             uint64_t etag,
599c87c5fbaSopenharmony_ci                             size_t length,
600c87c5fbaSopenharmony_ci                             const uint8_t *data,
601c87c5fbaSopenharmony_ci                             coap_release_large_data_t release_func,
602c87c5fbaSopenharmony_ci                             void *app_ptr,
603c87c5fbaSopenharmony_ci                             int single_request, coap_pdu_code_t request_method) {
604c87c5fbaSopenharmony_ci
605c87c5fbaSopenharmony_ci  ssize_t avail;
606c87c5fbaSopenharmony_ci  coap_block_b_t block;
607c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
608c87c5fbaSopenharmony_ci  coap_block_b_t alt_block;
609c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
610c87c5fbaSopenharmony_ci  size_t chunk;
611c87c5fbaSopenharmony_ci  coap_lg_xmit_t *lg_xmit = NULL;
612c87c5fbaSopenharmony_ci  uint8_t buf[8];
613c87c5fbaSopenharmony_ci  int have_block_defined = 0;
614c87c5fbaSopenharmony_ci  uint8_t blk_size;
615c87c5fbaSopenharmony_ci  uint16_t option;
616c87c5fbaSopenharmony_ci  size_t token_options;
617c87c5fbaSopenharmony_ci  coap_opt_t *opt;
618c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
619c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
620c87c5fbaSopenharmony_ci  uint16_t alt_option;
621c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
622c87c5fbaSopenharmony_ci
623c87c5fbaSopenharmony_ci  assert(pdu);
624c87c5fbaSopenharmony_ci  if (pdu->data) {
625c87c5fbaSopenharmony_ci    coap_log_warn("coap_add_data_large: PDU already contains data\n");
626c87c5fbaSopenharmony_ci    if (release_func)
627c87c5fbaSopenharmony_ci      release_func(session, app_ptr);
628c87c5fbaSopenharmony_ci    return 0;
629c87c5fbaSopenharmony_ci  }
630c87c5fbaSopenharmony_ci
631c87c5fbaSopenharmony_ci  if (!(session->block_mode & COAP_BLOCK_USE_LIBCOAP)) {
632c87c5fbaSopenharmony_ci    coap_log_debug("** %s: coap_add_data_large: COAP_BLOCK_USE_LIBCOAP not enabled\n",
633c87c5fbaSopenharmony_ci                   coap_session_str(session));
634c87c5fbaSopenharmony_ci    goto add_data;
635c87c5fbaSopenharmony_ci  }
636c87c5fbaSopenharmony_ci
637c87c5fbaSopenharmony_ci  /* A lot of the reliable code assumes type is CON */
638c87c5fbaSopenharmony_ci  if (COAP_PROTO_RELIABLE(session->proto) && pdu->type == COAP_MESSAGE_NON)
639c87c5fbaSopenharmony_ci    pdu->type = COAP_MESSAGE_CON;
640c87c5fbaSopenharmony_ci
641c87c5fbaSopenharmony_ci  /* Block NUM max 20 bits and block size is "2**(SZX + 4)"
642c87c5fbaSopenharmony_ci     and using SZX max of 6 gives maximum size = 1,073,740,800
643c87c5fbaSopenharmony_ci     CSM Max-Message-Size theoretical maximum = 4,294,967,295
644c87c5fbaSopenharmony_ci     So, if using blocks, we are limited to 1,073,740,800.
645c87c5fbaSopenharmony_ci   */
646c87c5fbaSopenharmony_ci#define MAX_BLK_LEN (((1 << 20) - 1) * (1 << (6 + 4)))
647c87c5fbaSopenharmony_ci
648c87c5fbaSopenharmony_ci  if (length > MAX_BLK_LEN) {
649c87c5fbaSopenharmony_ci    coap_log_warn("Size of large buffer restricted to 0x%x bytes\n", MAX_BLK_LEN);
650c87c5fbaSopenharmony_ci    length = MAX_BLK_LEN;
651c87c5fbaSopenharmony_ci  }
652c87c5fbaSopenharmony_ci
653c87c5fbaSopenharmony_ci  /* Determine the block size to use, adding in sensible options if needed */
654c87c5fbaSopenharmony_ci  if (COAP_PDU_IS_REQUEST(pdu)) {
655c87c5fbaSopenharmony_ci    coap_lg_xmit_t *q;
656c87c5fbaSopenharmony_ci
657c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
658c87c5fbaSopenharmony_ci    if (session->block_mode & (COAP_BLOCK_HAS_Q_BLOCK|COAP_BLOCK_TRY_Q_BLOCK)) {
659c87c5fbaSopenharmony_ci      option = COAP_OPTION_Q_BLOCK1;
660c87c5fbaSopenharmony_ci      alt_option = COAP_OPTION_BLOCK1;
661c87c5fbaSopenharmony_ci    } else {
662c87c5fbaSopenharmony_ci      option = COAP_OPTION_BLOCK1;
663c87c5fbaSopenharmony_ci      alt_option = COAP_OPTION_Q_BLOCK1;
664c87c5fbaSopenharmony_ci    }
665c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
666c87c5fbaSopenharmony_ci    if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK1, &block)) {
667c87c5fbaSopenharmony_ci      coap_remove_option(pdu, COAP_OPTION_Q_BLOCK1);
668c87c5fbaSopenharmony_ci    }
669c87c5fbaSopenharmony_ci    option = COAP_OPTION_BLOCK1;
670c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
671c87c5fbaSopenharmony_ci
672c87c5fbaSopenharmony_ci    /* See if this token is already in use for large bodies (unlikely) */
673c87c5fbaSopenharmony_ci    LL_FOREACH_SAFE(session->lg_xmit, lg_xmit, q) {
674c87c5fbaSopenharmony_ci      if (coap_binary_equal(&pdu->actual_token, lg_xmit->b.b1.app_token)) {
675c87c5fbaSopenharmony_ci        /* Unfortunately need to free this off as potential size change */
676c87c5fbaSopenharmony_ci        LL_DELETE(session->lg_xmit, lg_xmit);
677c87c5fbaSopenharmony_ci        coap_block_delete_lg_xmit(session, lg_xmit);
678c87c5fbaSopenharmony_ci        lg_xmit = NULL;
679c87c5fbaSopenharmony_ci        coap_handle_event(session->context, COAP_EVENT_XMIT_BLOCK_FAIL, session);
680c87c5fbaSopenharmony_ci        break;
681c87c5fbaSopenharmony_ci      }
682c87c5fbaSopenharmony_ci    }
683c87c5fbaSopenharmony_ci  } else {
684c87c5fbaSopenharmony_ci    /* Have to assume that it is a response even if code is 0.00 */
685c87c5fbaSopenharmony_ci    assert(resource);
686c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
687c87c5fbaSopenharmony_ci    if (session->block_mode & COAP_BLOCK_HAS_Q_BLOCK) {
688c87c5fbaSopenharmony_ci      option = COAP_OPTION_Q_BLOCK2;
689c87c5fbaSopenharmony_ci      alt_option = COAP_OPTION_BLOCK2;
690c87c5fbaSopenharmony_ci    } else {
691c87c5fbaSopenharmony_ci      option = COAP_OPTION_BLOCK2;
692c87c5fbaSopenharmony_ci      alt_option = COAP_OPTION_Q_BLOCK2;
693c87c5fbaSopenharmony_ci    }
694c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
695c87c5fbaSopenharmony_ci    if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK2, &block)) {
696c87c5fbaSopenharmony_ci      coap_remove_option(pdu, COAP_OPTION_Q_BLOCK2);
697c87c5fbaSopenharmony_ci    }
698c87c5fbaSopenharmony_ci    option = COAP_OPTION_BLOCK2;
699c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
700c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
701c87c5fbaSopenharmony_ci    /*
702c87c5fbaSopenharmony_ci     * Check if resource+query+rtag is already in use for large bodies
703c87c5fbaSopenharmony_ci     * (unlikely)
704c87c5fbaSopenharmony_ci     */
705c87c5fbaSopenharmony_ci    lg_xmit = coap_find_lg_xmit_response(session, request, resource, query);
706c87c5fbaSopenharmony_ci    if (lg_xmit) {
707c87c5fbaSopenharmony_ci      /* Unfortunately need to free this off as potential size change */
708c87c5fbaSopenharmony_ci      LL_DELETE(session->lg_xmit, lg_xmit);
709c87c5fbaSopenharmony_ci      coap_block_delete_lg_xmit(session, lg_xmit);
710c87c5fbaSopenharmony_ci      lg_xmit = NULL;
711c87c5fbaSopenharmony_ci      coap_handle_event(session->context, COAP_EVENT_XMIT_BLOCK_FAIL, session);
712c87c5fbaSopenharmony_ci    }
713c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
714c87c5fbaSopenharmony_ci  }
715c87c5fbaSopenharmony_ci#if COAP_OSCORE_SUPPORT
716c87c5fbaSopenharmony_ci  if (session->oscore_encryption) {
717c87c5fbaSopenharmony_ci    /* Need to convert Proxy-Uri to Proxy-Scheme option if needed */
718c87c5fbaSopenharmony_ci    if (COAP_PDU_IS_REQUEST(pdu) && !coap_rebuild_pdu_for_proxy(pdu))
719c87c5fbaSopenharmony_ci      goto fail;
720c87c5fbaSopenharmony_ci  }
721c87c5fbaSopenharmony_ci#endif /* COAP_OSCORE_SUPPORT */
722c87c5fbaSopenharmony_ci
723c87c5fbaSopenharmony_ci  token_options = pdu->data ? (size_t)(pdu->data - pdu->token) : pdu->used_size;
724c87c5fbaSopenharmony_ci  avail = pdu->max_size - token_options;
725c87c5fbaSopenharmony_ci  /* There may be a response with Echo option */
726c87c5fbaSopenharmony_ci  avail -= coap_opt_encode_size(COAP_OPTION_ECHO, 40);
727c87c5fbaSopenharmony_ci#if COAP_OSCORE_SUPPORT
728c87c5fbaSopenharmony_ci  avail -= coap_oscore_overhead(session, pdu);
729c87c5fbaSopenharmony_ci#endif /* COAP_OSCORE_SUPPORT */
730c87c5fbaSopenharmony_ci  /* May need token of length 8, so account for this */
731c87c5fbaSopenharmony_ci  avail -= (pdu->actual_token.length < 8) ? 8 - pdu->actual_token.length : 0;
732c87c5fbaSopenharmony_ci  blk_size = coap_flsll((long long)avail) - 4 - 1;
733c87c5fbaSopenharmony_ci  if (blk_size > 6)
734c87c5fbaSopenharmony_ci    blk_size = 6;
735c87c5fbaSopenharmony_ci
736c87c5fbaSopenharmony_ci  /* see if BlockX defined - if so update blk_size as given by app */
737c87c5fbaSopenharmony_ci  if (coap_get_block_b(session, pdu, option, &block)) {
738c87c5fbaSopenharmony_ci    if (block.szx < blk_size)
739c87c5fbaSopenharmony_ci      blk_size = block.szx;
740c87c5fbaSopenharmony_ci    have_block_defined = 1;
741c87c5fbaSopenharmony_ci  }
742c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
743c87c5fbaSopenharmony_ci  /* see if alternate BlockX defined */
744c87c5fbaSopenharmony_ci  if (coap_get_block_b(session, pdu, alt_option, &alt_block)) {
745c87c5fbaSopenharmony_ci    if (have_block_defined) {
746c87c5fbaSopenharmony_ci      /* Cannot have both options set */
747c87c5fbaSopenharmony_ci      coap_log_warn("Both BlockX and Q-BlockX cannot be set at the same time\n");
748c87c5fbaSopenharmony_ci      coap_remove_option(pdu, alt_option);
749c87c5fbaSopenharmony_ci    } else {
750c87c5fbaSopenharmony_ci      block = alt_block;
751c87c5fbaSopenharmony_ci      if (block.szx < blk_size)
752c87c5fbaSopenharmony_ci        blk_size = block.szx;
753c87c5fbaSopenharmony_ci      have_block_defined = 1;
754c87c5fbaSopenharmony_ci      option = alt_option;
755c87c5fbaSopenharmony_ci    }
756c87c5fbaSopenharmony_ci  }
757c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
758c87c5fbaSopenharmony_ci
759c87c5fbaSopenharmony_ci  if (avail < 16 && ((ssize_t)length > avail || have_block_defined)) {
760c87c5fbaSopenharmony_ci    /* bad luck, this is the smallest block size */
761c87c5fbaSopenharmony_ci    coap_log_debug("not enough space, even the smallest block does not fit (2)\n");
762c87c5fbaSopenharmony_ci    goto fail;
763c87c5fbaSopenharmony_ci  }
764c87c5fbaSopenharmony_ci
765c87c5fbaSopenharmony_ci  chunk = (size_t)1 << (blk_size + 4);
766c87c5fbaSopenharmony_ci  if (have_block_defined &&
767c87c5fbaSopenharmony_ci      (block.num != 0 || single_request)) {
768c87c5fbaSopenharmony_ci    /* App is defining a single block to send */
769c87c5fbaSopenharmony_ci    size_t rem;
770c87c5fbaSopenharmony_ci
771c87c5fbaSopenharmony_ci    if (length >= block.num * chunk) {
772c87c5fbaSopenharmony_ci      rem = chunk;
773c87c5fbaSopenharmony_ci      if (chunk > length - block.num * chunk)
774c87c5fbaSopenharmony_ci        rem = length - block.num * chunk;
775c87c5fbaSopenharmony_ci      if (!coap_add_data(pdu, rem, &data[block.num * chunk]))
776c87c5fbaSopenharmony_ci        goto fail;
777c87c5fbaSopenharmony_ci    }
778c87c5fbaSopenharmony_ci    if (release_func)
779c87c5fbaSopenharmony_ci      release_func(session, app_ptr);
780c87c5fbaSopenharmony_ci  } else if ((have_block_defined && length > chunk) || (ssize_t)length > avail) {
781c87c5fbaSopenharmony_ci    /* Only add in lg_xmit if more than one block needs to be handled */
782c87c5fbaSopenharmony_ci    size_t rem;
783c87c5fbaSopenharmony_ci
784c87c5fbaSopenharmony_ci    lg_xmit = coap_malloc_type(COAP_LG_XMIT, sizeof(coap_lg_xmit_t));
785c87c5fbaSopenharmony_ci    if (!lg_xmit)
786c87c5fbaSopenharmony_ci      goto fail;
787c87c5fbaSopenharmony_ci
788c87c5fbaSopenharmony_ci    /* Set up for displaying all the data in the pdu */
789c87c5fbaSopenharmony_ci    pdu->body_data = data;
790c87c5fbaSopenharmony_ci    pdu->body_length = length;
791c87c5fbaSopenharmony_ci    coap_log_debug("PDU presented by app.\n");
792c87c5fbaSopenharmony_ci    coap_show_pdu(COAP_LOG_DEBUG, pdu);
793c87c5fbaSopenharmony_ci    pdu->body_data = NULL;
794c87c5fbaSopenharmony_ci    pdu->body_length = 0;
795c87c5fbaSopenharmony_ci
796c87c5fbaSopenharmony_ci    coap_log_debug("** %s: lg_xmit %p initialized\n",
797c87c5fbaSopenharmony_ci                   coap_session_str(session), (void *)lg_xmit);
798c87c5fbaSopenharmony_ci    /* Update lg_xmit with large data information */
799c87c5fbaSopenharmony_ci    memset(lg_xmit, 0, sizeof(coap_lg_xmit_t));
800c87c5fbaSopenharmony_ci    lg_xmit->blk_size = blk_size;
801c87c5fbaSopenharmony_ci    lg_xmit->option = option;
802c87c5fbaSopenharmony_ci    lg_xmit->data = data;
803c87c5fbaSopenharmony_ci    lg_xmit->length = length;
804c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
805c87c5fbaSopenharmony_ci    lg_xmit->non_timeout_random_ticks =
806c87c5fbaSopenharmony_ci        coap_get_non_timeout_random_ticks(session);
807c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
808c87c5fbaSopenharmony_ci    lg_xmit->release_func = release_func;
809c87c5fbaSopenharmony_ci    lg_xmit->app_ptr = app_ptr;
810c87c5fbaSopenharmony_ci    pdu->lg_xmit = lg_xmit;
811c87c5fbaSopenharmony_ci    coap_ticks(&lg_xmit->last_obs);
812c87c5fbaSopenharmony_ci    coap_ticks(&lg_xmit->last_sent);
813c87c5fbaSopenharmony_ci    if (COAP_PDU_IS_REQUEST(pdu)) {
814c87c5fbaSopenharmony_ci      /* Need to keep original token for updating response PDUs */
815c87c5fbaSopenharmony_ci      lg_xmit->b.b1.app_token = coap_new_binary(pdu->actual_token.length);
816c87c5fbaSopenharmony_ci      if (!lg_xmit->b.b1.app_token)
817c87c5fbaSopenharmony_ci        goto fail;
818c87c5fbaSopenharmony_ci      memcpy(lg_xmit->b.b1.app_token->s, pdu->actual_token.s,
819c87c5fbaSopenharmony_ci             pdu->actual_token.length);
820c87c5fbaSopenharmony_ci      /*
821c87c5fbaSopenharmony_ci       * Need to set up new token for use during transmits
822c87c5fbaSopenharmony_ci       * RFC9177#section-5
823c87c5fbaSopenharmony_ci       */
824c87c5fbaSopenharmony_ci      lg_xmit->b.b1.count = 1;
825c87c5fbaSopenharmony_ci      lg_xmit->b.b1.state_token = STATE_TOKEN_FULL(++session->tx_token,
826c87c5fbaSopenharmony_ci                                                   lg_xmit->b.b1.count);
827c87c5fbaSopenharmony_ci      /*
828c87c5fbaSopenharmony_ci       * Token will be updated in pdu later as original pdu may be needed in
829c87c5fbaSopenharmony_ci       * coap_send()
830c87c5fbaSopenharmony_ci       */
831c87c5fbaSopenharmony_ci      coap_update_option(pdu,
832c87c5fbaSopenharmony_ci                         COAP_OPTION_SIZE1,
833c87c5fbaSopenharmony_ci                         coap_encode_var_safe(buf, sizeof(buf),
834c87c5fbaSopenharmony_ci                                              (unsigned int)length),
835c87c5fbaSopenharmony_ci                         buf);
836c87c5fbaSopenharmony_ci      if (!coap_check_option(pdu, COAP_OPTION_RTAG, &opt_iter))
837c87c5fbaSopenharmony_ci        coap_insert_option(pdu,
838c87c5fbaSopenharmony_ci                           COAP_OPTION_RTAG,
839c87c5fbaSopenharmony_ci                           coap_encode_var_safe(buf, sizeof(buf),
840c87c5fbaSopenharmony_ci                                                ++session->tx_rtag),
841c87c5fbaSopenharmony_ci                           buf);
842c87c5fbaSopenharmony_ci    } else {
843c87c5fbaSopenharmony_ci      /*
844c87c5fbaSopenharmony_ci       * resource+query+rtag match is used for Block2 large body transmissions
845c87c5fbaSopenharmony_ci       * token match is used for Block1 large body transmissions
846c87c5fbaSopenharmony_ci       */
847c87c5fbaSopenharmony_ci      lg_xmit->b.b2.resource = resource;
848c87c5fbaSopenharmony_ci      if (query) {
849c87c5fbaSopenharmony_ci        lg_xmit->b.b2.query = coap_new_string(query->length);
850c87c5fbaSopenharmony_ci        if (lg_xmit->b.b2.query) {
851c87c5fbaSopenharmony_ci          memcpy(lg_xmit->b.b2.query->s, query->s, query->length);
852c87c5fbaSopenharmony_ci        }
853c87c5fbaSopenharmony_ci      } else {
854c87c5fbaSopenharmony_ci        lg_xmit->b.b2.query = NULL;
855c87c5fbaSopenharmony_ci      }
856c87c5fbaSopenharmony_ci      opt = coap_check_option(request, COAP_OPTION_RTAG, &opt_iter);
857c87c5fbaSopenharmony_ci      if (opt) {
858c87c5fbaSopenharmony_ci        lg_xmit->b.b2.rtag_length = (uint8_t)min(coap_opt_length(opt),
859c87c5fbaSopenharmony_ci                                                 sizeof(lg_xmit->b.b2.rtag));
860c87c5fbaSopenharmony_ci        memcpy(lg_xmit->b.b2.rtag, coap_opt_value(opt), coap_opt_length(opt));
861c87c5fbaSopenharmony_ci        lg_xmit->b.b2.rtag_set = 1;
862c87c5fbaSopenharmony_ci      } else {
863c87c5fbaSopenharmony_ci        lg_xmit->b.b2.rtag_set = 0;
864c87c5fbaSopenharmony_ci      }
865c87c5fbaSopenharmony_ci      lg_xmit->b.b2.etag = etag;
866c87c5fbaSopenharmony_ci      lg_xmit->b.b2.request_method = request_method;
867c87c5fbaSopenharmony_ci      if (maxage >= 0) {
868c87c5fbaSopenharmony_ci        coap_tick_t now;
869c87c5fbaSopenharmony_ci
870c87c5fbaSopenharmony_ci        coap_ticks(&now);
871c87c5fbaSopenharmony_ci        lg_xmit->b.b2.maxage_expire = coap_ticks_to_rt(now) + maxage;
872c87c5fbaSopenharmony_ci      } else {
873c87c5fbaSopenharmony_ci        lg_xmit->b.b2.maxage_expire = 0;
874c87c5fbaSopenharmony_ci      }
875c87c5fbaSopenharmony_ci      coap_update_option(pdu,
876c87c5fbaSopenharmony_ci                         COAP_OPTION_SIZE2,
877c87c5fbaSopenharmony_ci                         coap_encode_var_safe(buf, sizeof(buf),
878c87c5fbaSopenharmony_ci                                              (unsigned int)length),
879c87c5fbaSopenharmony_ci                         buf);
880c87c5fbaSopenharmony_ci      if (etag == 0) {
881c87c5fbaSopenharmony_ci        if (++session->context->etag == 0)
882c87c5fbaSopenharmony_ci          ++session->context->etag;
883c87c5fbaSopenharmony_ci        etag = session->context->etag;
884c87c5fbaSopenharmony_ci      }
885c87c5fbaSopenharmony_ci      coap_update_option(pdu,
886c87c5fbaSopenharmony_ci                         COAP_OPTION_ETAG,
887c87c5fbaSopenharmony_ci                         coap_encode_var_safe8(buf, sizeof(buf), etag),
888c87c5fbaSopenharmony_ci                         buf);
889c87c5fbaSopenharmony_ci    }
890c87c5fbaSopenharmony_ci
891c87c5fbaSopenharmony_ci    if (!setup_block_b(session, pdu, &block, block.num,
892c87c5fbaSopenharmony_ci                       blk_size, lg_xmit->length))
893c87c5fbaSopenharmony_ci      goto fail;
894c87c5fbaSopenharmony_ci
895c87c5fbaSopenharmony_ci    /* Add in with requested block num, more bit and block size */
896c87c5fbaSopenharmony_ci    coap_update_option(pdu,
897c87c5fbaSopenharmony_ci                       lg_xmit->option,
898c87c5fbaSopenharmony_ci                       coap_encode_var_safe(buf, sizeof(buf),
899c87c5fbaSopenharmony_ci                                            (block.num << 4) | (block.m << 3) | block.aszx),
900c87c5fbaSopenharmony_ci                       buf);
901c87c5fbaSopenharmony_ci
902c87c5fbaSopenharmony_ci    /* Set up skeletal PDU to use as a basis for all the subsequent blocks */
903c87c5fbaSopenharmony_ci    memcpy(&lg_xmit->pdu, pdu, sizeof(lg_xmit->pdu));
904c87c5fbaSopenharmony_ci    lg_xmit->pdu.token = coap_malloc_type(COAP_PDU_BUF,
905c87c5fbaSopenharmony_ci                                          lg_xmit->pdu.used_size + lg_xmit->pdu.max_hdr_size);
906c87c5fbaSopenharmony_ci    if (!lg_xmit->pdu.token)
907c87c5fbaSopenharmony_ci      goto fail;
908c87c5fbaSopenharmony_ci
909c87c5fbaSopenharmony_ci    lg_xmit->pdu.alloc_size = lg_xmit->pdu.used_size;
910c87c5fbaSopenharmony_ci    lg_xmit->pdu.token += lg_xmit->pdu.max_hdr_size;
911c87c5fbaSopenharmony_ci    memcpy(lg_xmit->pdu.token, pdu->token, lg_xmit->pdu.used_size);
912c87c5fbaSopenharmony_ci    if (pdu->data)
913c87c5fbaSopenharmony_ci      lg_xmit->pdu.data = lg_xmit->pdu.token + (pdu->data - pdu->token);
914c87c5fbaSopenharmony_ci    lg_xmit->pdu.actual_token.s = lg_xmit->pdu.token + pdu->e_token_length -
915c87c5fbaSopenharmony_ci                                  pdu->actual_token.length;
916c87c5fbaSopenharmony_ci    lg_xmit->pdu.actual_token.length = pdu->actual_token.length;
917c87c5fbaSopenharmony_ci
918c87c5fbaSopenharmony_ci    /* Check we still have space after adding in some options */
919c87c5fbaSopenharmony_ci    token_options = pdu->data ? (size_t)(pdu->data - pdu->token) : pdu->used_size;
920c87c5fbaSopenharmony_ci    avail = pdu->max_size - token_options;
921c87c5fbaSopenharmony_ci    /* There may be a response with Echo option */
922c87c5fbaSopenharmony_ci    avail -= coap_opt_encode_size(COAP_OPTION_ECHO, 40);
923c87c5fbaSopenharmony_ci    /* May need token of length 8, so account for this */
924c87c5fbaSopenharmony_ci    avail -= (pdu->actual_token.length < 8) ? 8 - pdu->actual_token.length : 0;
925c87c5fbaSopenharmony_ci#if COAP_OSCORE_SUPPORT
926c87c5fbaSopenharmony_ci    avail -= coap_oscore_overhead(session, pdu);
927c87c5fbaSopenharmony_ci#endif /* COAP_OSCORE_SUPPORT */
928c87c5fbaSopenharmony_ci    if (avail < (ssize_t)chunk) {
929c87c5fbaSopenharmony_ci      /* chunk size change down */
930c87c5fbaSopenharmony_ci      if (avail < 16) {
931c87c5fbaSopenharmony_ci        coap_log_warn("not enough space, even the smallest block does not fit (3)\n");
932c87c5fbaSopenharmony_ci        goto fail;
933c87c5fbaSopenharmony_ci      }
934c87c5fbaSopenharmony_ci      blk_size = coap_flsll((long long)avail) - 4 - 1;
935c87c5fbaSopenharmony_ci      block.num = block.num << (lg_xmit->blk_size - blk_size);
936c87c5fbaSopenharmony_ci      lg_xmit->blk_size = blk_size;
937c87c5fbaSopenharmony_ci      chunk = (size_t)1 << (lg_xmit->blk_size + 4);
938c87c5fbaSopenharmony_ci      block.chunk_size = (uint32_t)chunk;
939c87c5fbaSopenharmony_ci      block.bert = 0;
940c87c5fbaSopenharmony_ci      coap_update_option(pdu,
941c87c5fbaSopenharmony_ci                         lg_xmit->option,
942c87c5fbaSopenharmony_ci                         coap_encode_var_safe(buf, sizeof(buf),
943c87c5fbaSopenharmony_ci                                              (block.num << 4) | (block.m << 3) | lg_xmit->blk_size),
944c87c5fbaSopenharmony_ci                         buf);
945c87c5fbaSopenharmony_ci    }
946c87c5fbaSopenharmony_ci
947c87c5fbaSopenharmony_ci    rem = block.chunk_size;
948c87c5fbaSopenharmony_ci    if (rem > lg_xmit->length - block.num * chunk)
949c87c5fbaSopenharmony_ci      rem = lg_xmit->length - block.num * chunk;
950c87c5fbaSopenharmony_ci    if (!coap_add_data(pdu, rem, &data[block.num * chunk]))
951c87c5fbaSopenharmony_ci      goto fail;
952c87c5fbaSopenharmony_ci
953c87c5fbaSopenharmony_ci    if (COAP_PDU_IS_REQUEST(pdu))
954c87c5fbaSopenharmony_ci      lg_xmit->b.b1.bert_size = rem;
955c87c5fbaSopenharmony_ci
956c87c5fbaSopenharmony_ci    lg_xmit->last_block = -1;
957c87c5fbaSopenharmony_ci
958c87c5fbaSopenharmony_ci    /* Link the new lg_xmit in */
959c87c5fbaSopenharmony_ci    LL_PREPEND(session->lg_xmit,lg_xmit);
960c87c5fbaSopenharmony_ci  } else {
961c87c5fbaSopenharmony_ci    /* No need to use blocks */
962c87c5fbaSopenharmony_ci    if (etag) {
963c87c5fbaSopenharmony_ci      coap_update_option(pdu,
964c87c5fbaSopenharmony_ci                         COAP_OPTION_ETAG,
965c87c5fbaSopenharmony_ci                         coap_encode_var_safe8(buf, sizeof(buf), etag),
966c87c5fbaSopenharmony_ci                         buf);
967c87c5fbaSopenharmony_ci    }
968c87c5fbaSopenharmony_ci    if (have_block_defined) {
969c87c5fbaSopenharmony_ci      coap_update_option(pdu,
970c87c5fbaSopenharmony_ci                         option,
971c87c5fbaSopenharmony_ci                         coap_encode_var_safe(buf, sizeof(buf),
972c87c5fbaSopenharmony_ci                                              (0 << 4) | (0 << 3) | blk_size), buf);
973c87c5fbaSopenharmony_ci    }
974c87c5fbaSopenharmony_ciadd_data:
975c87c5fbaSopenharmony_ci    if (!coap_add_data(pdu, length, data))
976c87c5fbaSopenharmony_ci      goto fail;
977c87c5fbaSopenharmony_ci
978c87c5fbaSopenharmony_ci    if (release_func)
979c87c5fbaSopenharmony_ci      release_func(session, app_ptr);
980c87c5fbaSopenharmony_ci  }
981c87c5fbaSopenharmony_ci  return 1;
982c87c5fbaSopenharmony_ci
983c87c5fbaSopenharmony_cifail:
984c87c5fbaSopenharmony_ci  if (lg_xmit) {
985c87c5fbaSopenharmony_ci    coap_block_delete_lg_xmit(session, lg_xmit);
986c87c5fbaSopenharmony_ci  } else if (release_func) {
987c87c5fbaSopenharmony_ci    release_func(session, app_ptr);
988c87c5fbaSopenharmony_ci  }
989c87c5fbaSopenharmony_ci  return 0;
990c87c5fbaSopenharmony_ci}
991c87c5fbaSopenharmony_ci
992c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
993c87c5fbaSopenharmony_ciint
994c87c5fbaSopenharmony_cicoap_add_data_large_request(coap_session_t *session,
995c87c5fbaSopenharmony_ci                            coap_pdu_t *pdu,
996c87c5fbaSopenharmony_ci                            size_t length,
997c87c5fbaSopenharmony_ci                            const uint8_t *data,
998c87c5fbaSopenharmony_ci                            coap_release_large_data_t release_func,
999c87c5fbaSopenharmony_ci                            void *app_ptr) {
1000c87c5fbaSopenharmony_ci  /*
1001c87c5fbaSopenharmony_ci   * Delay if session->doing_first is set.
1002c87c5fbaSopenharmony_ci   * E.g. Reliable and CSM not in yet for checking block support
1003c87c5fbaSopenharmony_ci   */
1004c87c5fbaSopenharmony_ci  if (coap_client_delay_first(session) == 0) {
1005c87c5fbaSopenharmony_ci    if (release_func)
1006c87c5fbaSopenharmony_ci      release_func(session, app_ptr);
1007c87c5fbaSopenharmony_ci    return 0;
1008c87c5fbaSopenharmony_ci  }
1009c87c5fbaSopenharmony_ci  return coap_add_data_large_internal(session, NULL, pdu, NULL, NULL, -1, 0,
1010c87c5fbaSopenharmony_ci                                      length, data, release_func, app_ptr, 0, 0);
1011c87c5fbaSopenharmony_ci}
1012c87c5fbaSopenharmony_ci#endif /* ! COAP_CLIENT_SUPPORT */
1013c87c5fbaSopenharmony_ci
1014c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
1015c87c5fbaSopenharmony_ciint
1016c87c5fbaSopenharmony_cicoap_add_data_large_response(coap_resource_t *resource,
1017c87c5fbaSopenharmony_ci                             coap_session_t *session,
1018c87c5fbaSopenharmony_ci                             const coap_pdu_t *request,
1019c87c5fbaSopenharmony_ci                             coap_pdu_t *response,
1020c87c5fbaSopenharmony_ci                             const coap_string_t *query,
1021c87c5fbaSopenharmony_ci                             uint16_t media_type,
1022c87c5fbaSopenharmony_ci                             int maxage,
1023c87c5fbaSopenharmony_ci                             uint64_t etag,
1024c87c5fbaSopenharmony_ci                             size_t length,
1025c87c5fbaSopenharmony_ci                             const uint8_t *data,
1026c87c5fbaSopenharmony_ci                             coap_release_large_data_t release_func,
1027c87c5fbaSopenharmony_ci                             void *app_ptr
1028c87c5fbaSopenharmony_ci                            ) {
1029c87c5fbaSopenharmony_ci  unsigned char buf[4];
1030c87c5fbaSopenharmony_ci  coap_block_b_t block;
1031c87c5fbaSopenharmony_ci  int block_requested = 0;
1032c87c5fbaSopenharmony_ci  int single_request = 0;
1033c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1034c87c5fbaSopenharmony_ci  uint16_t block_opt = (session->block_mode & COAP_BLOCK_HAS_Q_BLOCK) ?
1035c87c5fbaSopenharmony_ci                       COAP_OPTION_Q_BLOCK2 : COAP_OPTION_BLOCK2;
1036c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
1037c87c5fbaSopenharmony_ci  uint16_t block_opt = COAP_OPTION_BLOCK2;
1038c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
1039c87c5fbaSopenharmony_ci
1040c87c5fbaSopenharmony_ci  memset(&block, 0, sizeof(block));
1041c87c5fbaSopenharmony_ci  /*
1042c87c5fbaSopenharmony_ci   * Need to check that a valid block is getting asked for so that the
1043c87c5fbaSopenharmony_ci   * correct options are put into the PDU.
1044c87c5fbaSopenharmony_ci   */
1045c87c5fbaSopenharmony_ci  if (request) {
1046c87c5fbaSopenharmony_ci    if (coap_get_block_b(session, request, COAP_OPTION_BLOCK2, &block)) {
1047c87c5fbaSopenharmony_ci      block_requested = 1;
1048c87c5fbaSopenharmony_ci      if (block.num != 0 && length <= (block.num << (block.szx + 4))) {
1049c87c5fbaSopenharmony_ci        coap_log_debug("Illegal block requested (%d > last = %zu)\n",
1050c87c5fbaSopenharmony_ci                       block.num,
1051c87c5fbaSopenharmony_ci                       length >> (block.szx + 4));
1052c87c5fbaSopenharmony_ci        response->code = COAP_RESPONSE_CODE(400);
1053c87c5fbaSopenharmony_ci        goto error;
1054c87c5fbaSopenharmony_ci      }
1055c87c5fbaSopenharmony_ci    }
1056c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1057c87c5fbaSopenharmony_ci    else if (coap_get_block_b(session, request, COAP_OPTION_Q_BLOCK2, &block)) {
1058c87c5fbaSopenharmony_ci      block_requested = 1;
1059c87c5fbaSopenharmony_ci      if (block.num != 0 && length <= (block.num << (block.szx + 4))) {
1060c87c5fbaSopenharmony_ci        coap_log_debug("Illegal block requested (%d > last = %zu)\n",
1061c87c5fbaSopenharmony_ci                       block.num,
1062c87c5fbaSopenharmony_ci                       length >> (block.szx + 4));
1063c87c5fbaSopenharmony_ci        response->code = COAP_RESPONSE_CODE(400);
1064c87c5fbaSopenharmony_ci        goto error;
1065c87c5fbaSopenharmony_ci      }
1066c87c5fbaSopenharmony_ci      if (!(session->block_mode & COAP_BLOCK_HAS_Q_BLOCK)) {
1067c87c5fbaSopenharmony_ci        set_block_mode_has_q(session->block_mode);
1068c87c5fbaSopenharmony_ci        block_opt = COAP_OPTION_Q_BLOCK2;
1069c87c5fbaSopenharmony_ci      }
1070c87c5fbaSopenharmony_ci      if (block.m == 0)
1071c87c5fbaSopenharmony_ci        single_request = 1;
1072c87c5fbaSopenharmony_ci    }
1073c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1074c87c5fbaSopenharmony_ci  }
1075c87c5fbaSopenharmony_ci
1076c87c5fbaSopenharmony_ci  coap_insert_option(response, COAP_OPTION_CONTENT_FORMAT,
1077c87c5fbaSopenharmony_ci                     coap_encode_var_safe(buf, sizeof(buf),
1078c87c5fbaSopenharmony_ci                                          media_type),
1079c87c5fbaSopenharmony_ci                     buf);
1080c87c5fbaSopenharmony_ci
1081c87c5fbaSopenharmony_ci  if (maxage >= 0) {
1082c87c5fbaSopenharmony_ci    coap_insert_option(response,
1083c87c5fbaSopenharmony_ci                       COAP_OPTION_MAXAGE,
1084c87c5fbaSopenharmony_ci                       coap_encode_var_safe(buf, sizeof(buf), maxage), buf);
1085c87c5fbaSopenharmony_ci  }
1086c87c5fbaSopenharmony_ci
1087c87c5fbaSopenharmony_ci  if (block_requested) {
1088c87c5fbaSopenharmony_ci    int res;
1089c87c5fbaSopenharmony_ci
1090c87c5fbaSopenharmony_ci    res = coap_write_block_b_opt(session, &block, block_opt, response,
1091c87c5fbaSopenharmony_ci                                 length);
1092c87c5fbaSopenharmony_ci
1093c87c5fbaSopenharmony_ci    switch (res) {
1094c87c5fbaSopenharmony_ci    case -2:                        /* illegal block (caught above) */
1095c87c5fbaSopenharmony_ci      response->code = COAP_RESPONSE_CODE(400);
1096c87c5fbaSopenharmony_ci      goto error;
1097c87c5fbaSopenharmony_ci    case -1:                        /* should really not happen */
1098c87c5fbaSopenharmony_ci      assert(0);
1099c87c5fbaSopenharmony_ci    /* fall through if assert is a no-op */
1100c87c5fbaSopenharmony_ci    case -3:                        /* cannot handle request */
1101c87c5fbaSopenharmony_ci      response->code = COAP_RESPONSE_CODE(500);
1102c87c5fbaSopenharmony_ci      goto error;
1103c87c5fbaSopenharmony_ci    default:                        /* everything is good */
1104c87c5fbaSopenharmony_ci      ;
1105c87c5fbaSopenharmony_ci    }
1106c87c5fbaSopenharmony_ci  }
1107c87c5fbaSopenharmony_ci
1108c87c5fbaSopenharmony_ci  /* add data body */
1109c87c5fbaSopenharmony_ci  if (request &&
1110c87c5fbaSopenharmony_ci      !coap_add_data_large_internal(session, request, response, resource,
1111c87c5fbaSopenharmony_ci                                    query, maxage, etag, length, data,
1112c87c5fbaSopenharmony_ci                                    release_func, app_ptr, single_request,
1113c87c5fbaSopenharmony_ci                                    request->code)) {
1114c87c5fbaSopenharmony_ci    response->code = COAP_RESPONSE_CODE(500);
1115c87c5fbaSopenharmony_ci    goto error_released;
1116c87c5fbaSopenharmony_ci  }
1117c87c5fbaSopenharmony_ci
1118c87c5fbaSopenharmony_ci  return 1;
1119c87c5fbaSopenharmony_ci
1120c87c5fbaSopenharmony_cierror:
1121c87c5fbaSopenharmony_ci  if (release_func)
1122c87c5fbaSopenharmony_ci    release_func(session, app_ptr);
1123c87c5fbaSopenharmony_cierror_released:
1124c87c5fbaSopenharmony_ci#if COAP_ERROR_PHRASE_LENGTH > 0
1125c87c5fbaSopenharmony_ci  coap_add_data(response,
1126c87c5fbaSopenharmony_ci                strlen(coap_response_phrase(response->code)),
1127c87c5fbaSopenharmony_ci                (const unsigned char *)coap_response_phrase(response->code));
1128c87c5fbaSopenharmony_ci#endif /* COAP_ERROR_PHRASE_LENGTH > 0 */
1129c87c5fbaSopenharmony_ci  return 0;
1130c87c5fbaSopenharmony_ci}
1131c87c5fbaSopenharmony_ci#endif /* ! COAP_SERVER_SUPPORT */
1132c87c5fbaSopenharmony_ci
1133c87c5fbaSopenharmony_ci/*
1134c87c5fbaSopenharmony_ci * return 1 if there is a future expire time, else 0.
1135c87c5fbaSopenharmony_ci * update tim_rem with remaining value if return is 1.
1136c87c5fbaSopenharmony_ci */
1137c87c5fbaSopenharmony_ciint
1138c87c5fbaSopenharmony_cicoap_block_check_lg_xmit_timeouts(coap_session_t *session, coap_tick_t now,
1139c87c5fbaSopenharmony_ci                                  coap_tick_t *tim_rem) {
1140c87c5fbaSopenharmony_ci  coap_lg_xmit_t *p;
1141c87c5fbaSopenharmony_ci  coap_lg_xmit_t *q;
1142c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1143c87c5fbaSopenharmony_ci  coap_tick_t idle_timeout = 4 * COAP_NON_TIMEOUT_TICKS(session);
1144c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
1145c87c5fbaSopenharmony_ci  coap_tick_t idle_timeout = 8 * COAP_TICKS_PER_SECOND;
1146c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
1147c87c5fbaSopenharmony_ci  coap_tick_t partial_timeout = COAP_MAX_TRANSMIT_WAIT_TICKS(session);
1148c87c5fbaSopenharmony_ci  int ret = 0;
1149c87c5fbaSopenharmony_ci
1150c87c5fbaSopenharmony_ci  *tim_rem = -1;
1151c87c5fbaSopenharmony_ci
1152c87c5fbaSopenharmony_ci  LL_FOREACH_SAFE(session->lg_xmit, p, q) {
1153c87c5fbaSopenharmony_ci    if (p->last_all_sent) {
1154c87c5fbaSopenharmony_ci      if (p->last_all_sent + idle_timeout <= now) {
1155c87c5fbaSopenharmony_ci        /* Expire this entry */
1156c87c5fbaSopenharmony_ci        LL_DELETE(session->lg_xmit, p);
1157c87c5fbaSopenharmony_ci        coap_block_delete_lg_xmit(session, p);
1158c87c5fbaSopenharmony_ci      } else {
1159c87c5fbaSopenharmony_ci        /* Delay until the lg_xmit needs to expire */
1160c87c5fbaSopenharmony_ci        if (*tim_rem > p->last_all_sent + idle_timeout - now) {
1161c87c5fbaSopenharmony_ci          *tim_rem = p->last_all_sent + idle_timeout - now;
1162c87c5fbaSopenharmony_ci          ret = 1;
1163c87c5fbaSopenharmony_ci        }
1164c87c5fbaSopenharmony_ci      }
1165c87c5fbaSopenharmony_ci    } else if (p->last_sent) {
1166c87c5fbaSopenharmony_ci      if (p->last_sent + partial_timeout <= now) {
1167c87c5fbaSopenharmony_ci        /* Expire this entry */
1168c87c5fbaSopenharmony_ci        LL_DELETE(session->lg_xmit, p);
1169c87c5fbaSopenharmony_ci        coap_block_delete_lg_xmit(session, p);
1170c87c5fbaSopenharmony_ci        coap_handle_event(session->context, COAP_EVENT_XMIT_BLOCK_FAIL, session);
1171c87c5fbaSopenharmony_ci      } else {
1172c87c5fbaSopenharmony_ci        /* Delay until the lg_xmit needs to expire */
1173c87c5fbaSopenharmony_ci        if (*tim_rem > p->last_sent + partial_timeout - now) {
1174c87c5fbaSopenharmony_ci          *tim_rem = p->last_sent + partial_timeout - now;
1175c87c5fbaSopenharmony_ci          ret = 1;
1176c87c5fbaSopenharmony_ci        }
1177c87c5fbaSopenharmony_ci      }
1178c87c5fbaSopenharmony_ci    }
1179c87c5fbaSopenharmony_ci  }
1180c87c5fbaSopenharmony_ci  return ret;
1181c87c5fbaSopenharmony_ci}
1182c87c5fbaSopenharmony_ci
1183c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
1184c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1185c87c5fbaSopenharmony_cistatic coap_pdu_t *
1186c87c5fbaSopenharmony_cicoap_build_missing_pdu(coap_session_t *session, coap_lg_crcv_t *p) {
1187c87c5fbaSopenharmony_ci  coap_pdu_t *pdu;
1188c87c5fbaSopenharmony_ci  coap_opt_filter_t drop_options;
1189c87c5fbaSopenharmony_ci  uint64_t token = STATE_TOKEN_FULL(p->state_token, ++p->retry_counter);
1190c87c5fbaSopenharmony_ci  uint8_t buf[8];
1191c87c5fbaSopenharmony_ci  size_t len = coap_encode_var_safe8(buf, sizeof(token), token);
1192c87c5fbaSopenharmony_ci
1193c87c5fbaSopenharmony_ci  memset(&drop_options, 0, sizeof(coap_opt_filter_t));
1194c87c5fbaSopenharmony_ci  coap_option_filter_set(&drop_options, COAP_OPTION_Q_BLOCK2);
1195c87c5fbaSopenharmony_ci  coap_option_filter_set(&drop_options, COAP_OPTION_OBSERVE);
1196c87c5fbaSopenharmony_ci  pdu = coap_pdu_duplicate(&p->pdu, session, len, buf,
1197c87c5fbaSopenharmony_ci                           &drop_options);
1198c87c5fbaSopenharmony_ci  if (!pdu)
1199c87c5fbaSopenharmony_ci    return NULL;
1200c87c5fbaSopenharmony_ci  pdu->type = p->last_type;
1201c87c5fbaSopenharmony_ci  return pdu;
1202c87c5fbaSopenharmony_ci}
1203c87c5fbaSopenharmony_ci
1204c87c5fbaSopenharmony_cistatic void
1205c87c5fbaSopenharmony_cicoap_request_missing_q_block2(coap_session_t *session, coap_lg_crcv_t *lg_crcv) {
1206c87c5fbaSopenharmony_ci  uint8_t buf[8];
1207c87c5fbaSopenharmony_ci  uint32_t i;
1208c87c5fbaSopenharmony_ci  int block = -1; /* Last one seen */
1209c87c5fbaSopenharmony_ci  size_t sofar;
1210c87c5fbaSopenharmony_ci  size_t block_size;
1211c87c5fbaSopenharmony_ci  coap_pdu_t *pdu = NULL;
1212c87c5fbaSopenharmony_ci  int block_payload_set = -1;
1213c87c5fbaSopenharmony_ci
1214c87c5fbaSopenharmony_ci  if (session->block_mode & COAP_BLOCK_USE_M_Q_BLOCK) {
1215c87c5fbaSopenharmony_ci    /*
1216c87c5fbaSopenharmony_ci     * See if it is safe to use the single 'M' block variant of request
1217c87c5fbaSopenharmony_ci     *
1218c87c5fbaSopenharmony_ci     * If any blocks seen, then missing blocks are after range[0].end and
1219c87c5fbaSopenharmony_ci     * terminate on the last block or before range[1].begin if set.
1220c87c5fbaSopenharmony_ci     * If not defined or range[1].begin is in a different payload set then
1221c87c5fbaSopenharmony_ci     * safe to use M bit.
1222c87c5fbaSopenharmony_ci     */
1223c87c5fbaSopenharmony_ci    if (lg_crcv->rec_blocks.used &&
1224c87c5fbaSopenharmony_ci        (lg_crcv->rec_blocks.used < 2 ||
1225c87c5fbaSopenharmony_ci         ((lg_crcv->rec_blocks.range[0].end + 1) / COAP_MAX_PAYLOADS(session) !=
1226c87c5fbaSopenharmony_ci          (lg_crcv->rec_blocks.range[1].begin -1) / COAP_MAX_PAYLOADS(session)))) {
1227c87c5fbaSopenharmony_ci      block = lg_crcv->rec_blocks.range[0].end + 1;
1228c87c5fbaSopenharmony_ci      block_size = (size_t)1 << (lg_crcv->szx + 4);
1229c87c5fbaSopenharmony_ci      sofar = block * block_size;
1230c87c5fbaSopenharmony_ci      if (sofar < lg_crcv->total_len) {
1231c87c5fbaSopenharmony_ci        /* Ask for missing blocks */
1232c87c5fbaSopenharmony_ci        if (pdu == NULL) {
1233c87c5fbaSopenharmony_ci          pdu = coap_build_missing_pdu(session, lg_crcv);
1234c87c5fbaSopenharmony_ci          if (!pdu)
1235c87c5fbaSopenharmony_ci            return;
1236c87c5fbaSopenharmony_ci        }
1237c87c5fbaSopenharmony_ci        coap_insert_option(pdu, COAP_OPTION_Q_BLOCK2,
1238c87c5fbaSopenharmony_ci                           coap_encode_var_safe(buf, sizeof(buf),
1239c87c5fbaSopenharmony_ci                                                (block << 4) | (1 << 3) | lg_crcv->szx),
1240c87c5fbaSopenharmony_ci                           buf);
1241c87c5fbaSopenharmony_ci        block_payload_set = block / COAP_MAX_PAYLOADS(session);
1242c87c5fbaSopenharmony_ci        goto send_it;
1243c87c5fbaSopenharmony_ci      }
1244c87c5fbaSopenharmony_ci    }
1245c87c5fbaSopenharmony_ci  }
1246c87c5fbaSopenharmony_ci  block = -1;
1247c87c5fbaSopenharmony_ci  for (i = 0; i < lg_crcv->rec_blocks.used; i++) {
1248c87c5fbaSopenharmony_ci    if (block < (int)lg_crcv->rec_blocks.range[i].begin &&
1249c87c5fbaSopenharmony_ci        lg_crcv->rec_blocks.range[i].begin != 0) {
1250c87c5fbaSopenharmony_ci      /* Ask for missing blocks */
1251c87c5fbaSopenharmony_ci      if (pdu == NULL) {
1252c87c5fbaSopenharmony_ci        pdu = coap_build_missing_pdu(session, lg_crcv);
1253c87c5fbaSopenharmony_ci        if (!pdu)
1254c87c5fbaSopenharmony_ci          continue;
1255c87c5fbaSopenharmony_ci      }
1256c87c5fbaSopenharmony_ci      block++;
1257c87c5fbaSopenharmony_ci      if (block_payload_set == -1)
1258c87c5fbaSopenharmony_ci        block_payload_set = block / COAP_MAX_PAYLOADS(session);
1259c87c5fbaSopenharmony_ci      for (; block < (int)lg_crcv->rec_blocks.range[i].begin &&
1260c87c5fbaSopenharmony_ci           block_payload_set == (block / COAP_MAX_PAYLOADS(session)); block++) {
1261c87c5fbaSopenharmony_ci        coap_insert_option(pdu, COAP_OPTION_Q_BLOCK2,
1262c87c5fbaSopenharmony_ci                           coap_encode_var_safe(buf, sizeof(buf),
1263c87c5fbaSopenharmony_ci                                                (block << 4) | (0 << 3) | lg_crcv->szx),
1264c87c5fbaSopenharmony_ci                           buf);
1265c87c5fbaSopenharmony_ci      }
1266c87c5fbaSopenharmony_ci    }
1267c87c5fbaSopenharmony_ci    if (block < (int)lg_crcv->rec_blocks.range[i].end) {
1268c87c5fbaSopenharmony_ci      block = lg_crcv->rec_blocks.range[i].end;
1269c87c5fbaSopenharmony_ci    }
1270c87c5fbaSopenharmony_ci  }
1271c87c5fbaSopenharmony_ci  block_size = (size_t)1 << (lg_crcv->szx + 4);
1272c87c5fbaSopenharmony_ci  sofar = (block + 1) * block_size;
1273c87c5fbaSopenharmony_ci  if (sofar < lg_crcv->total_len) {
1274c87c5fbaSopenharmony_ci    /* Ask for trailing missing blocks */
1275c87c5fbaSopenharmony_ci    if (pdu == NULL) {
1276c87c5fbaSopenharmony_ci      pdu = coap_build_missing_pdu(session, lg_crcv);
1277c87c5fbaSopenharmony_ci      if (!pdu)
1278c87c5fbaSopenharmony_ci        return;
1279c87c5fbaSopenharmony_ci    }
1280c87c5fbaSopenharmony_ci    sofar = (lg_crcv->total_len + block_size - 1)/block_size;
1281c87c5fbaSopenharmony_ci    block++;
1282c87c5fbaSopenharmony_ci    if (block_payload_set == -1)
1283c87c5fbaSopenharmony_ci      block_payload_set = block / COAP_MAX_PAYLOADS(session);
1284c87c5fbaSopenharmony_ci    for (; block < (ssize_t)sofar &&
1285c87c5fbaSopenharmony_ci         block_payload_set == (block / COAP_MAX_PAYLOADS(session)); block++) {
1286c87c5fbaSopenharmony_ci      coap_insert_option(pdu, COAP_OPTION_Q_BLOCK2,
1287c87c5fbaSopenharmony_ci                         coap_encode_var_safe(buf, sizeof(buf),
1288c87c5fbaSopenharmony_ci                                              (block << 4) | (0 << 3) | lg_crcv->szx),
1289c87c5fbaSopenharmony_ci                         buf);
1290c87c5fbaSopenharmony_ci    }
1291c87c5fbaSopenharmony_ci  }
1292c87c5fbaSopenharmony_cisend_it:
1293c87c5fbaSopenharmony_ci  if (pdu)
1294c87c5fbaSopenharmony_ci    coap_send_internal(session, pdu);
1295c87c5fbaSopenharmony_ci  lg_crcv->rec_blocks.retry++;
1296c87c5fbaSopenharmony_ci  if (block_payload_set != -1)
1297c87c5fbaSopenharmony_ci    lg_crcv->rec_blocks.processing_payload_set = block_payload_set;
1298c87c5fbaSopenharmony_ci  coap_ticks(&lg_crcv->rec_blocks.last_seen);
1299c87c5fbaSopenharmony_ci}
1300c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1301c87c5fbaSopenharmony_ci
1302c87c5fbaSopenharmony_ci/*
1303c87c5fbaSopenharmony_ci * return 1 if there is a future expire time, else 0.
1304c87c5fbaSopenharmony_ci * update tim_rem with remaining value if return is 1.
1305c87c5fbaSopenharmony_ci */
1306c87c5fbaSopenharmony_ciint
1307c87c5fbaSopenharmony_cicoap_block_check_lg_crcv_timeouts(coap_session_t *session, coap_tick_t now,
1308c87c5fbaSopenharmony_ci                                  coap_tick_t *tim_rem) {
1309c87c5fbaSopenharmony_ci  coap_lg_crcv_t *p;
1310c87c5fbaSopenharmony_ci  coap_lg_crcv_t *q;
1311c87c5fbaSopenharmony_ci  coap_tick_t partial_timeout;
1312c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1313c87c5fbaSopenharmony_ci  coap_tick_t receive_timeout = COAP_NON_RECEIVE_TIMEOUT_TICKS(session);
1314c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1315c87c5fbaSopenharmony_ci  int ret = 0;
1316c87c5fbaSopenharmony_ci
1317c87c5fbaSopenharmony_ci  *tim_rem = -1;
1318c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1319c87c5fbaSopenharmony_ci  if (COAP_PROTO_NOT_RELIABLE(session->proto))
1320c87c5fbaSopenharmony_ci    partial_timeout = COAP_NON_PARTIAL_TIMEOUT_TICKS(session);
1321c87c5fbaSopenharmony_ci  else
1322c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1323c87c5fbaSopenharmony_ci    partial_timeout = COAP_MAX_TRANSMIT_WAIT_TICKS(session);
1324c87c5fbaSopenharmony_ci
1325c87c5fbaSopenharmony_ci  LL_FOREACH_SAFE(session->lg_crcv, p, q) {
1326c87c5fbaSopenharmony_ci    if (COAP_PROTO_RELIABLE(session->proto) || p->last_type != COAP_MESSAGE_NON)
1327c87c5fbaSopenharmony_ci      goto check_expire;
1328c87c5fbaSopenharmony_ci
1329c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1330c87c5fbaSopenharmony_ci    if (p->block_option == COAP_OPTION_Q_BLOCK2 && p->rec_blocks.used) {
1331c87c5fbaSopenharmony_ci      size_t scaled_timeout = receive_timeout *
1332c87c5fbaSopenharmony_ci                              ((size_t)1 << p->rec_blocks.retry);
1333c87c5fbaSopenharmony_ci
1334c87c5fbaSopenharmony_ci      if (p->rec_blocks.retry >= COAP_NON_MAX_RETRANSMIT(session)) {
1335c87c5fbaSopenharmony_ci        /* Done NON_MAX_RETRANSMIT retries */
1336c87c5fbaSopenharmony_ci        coap_update_token(&p->pdu, p->app_token->length, p->app_token->s);
1337c87c5fbaSopenharmony_ci        session->context->nack_handler(session, &p->pdu,
1338c87c5fbaSopenharmony_ci                                       COAP_NACK_TOO_MANY_RETRIES,
1339c87c5fbaSopenharmony_ci                                       p->pdu.mid);
1340c87c5fbaSopenharmony_ci        goto expire;
1341c87c5fbaSopenharmony_ci      }
1342c87c5fbaSopenharmony_ci      if (p->rec_blocks.last_seen + scaled_timeout <= now) {
1343c87c5fbaSopenharmony_ci        coap_request_missing_q_block2(session, p);
1344c87c5fbaSopenharmony_ci      } else {
1345c87c5fbaSopenharmony_ci        if (*tim_rem > p->rec_blocks.last_seen + scaled_timeout - now) {
1346c87c5fbaSopenharmony_ci          *tim_rem = p->rec_blocks.last_seen + scaled_timeout - now;
1347c87c5fbaSopenharmony_ci          ret = 1;
1348c87c5fbaSopenharmony_ci        }
1349c87c5fbaSopenharmony_ci      }
1350c87c5fbaSopenharmony_ci    }
1351c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1352c87c5fbaSopenharmony_ci    /* Used for Block2 and Q-Block2 */
1353c87c5fbaSopenharmony_cicheck_expire:
1354c87c5fbaSopenharmony_ci    if (!p->observe_set && p->last_used &&
1355c87c5fbaSopenharmony_ci        p->last_used + partial_timeout <= now) {
1356c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1357c87c5fbaSopenharmony_ciexpire:
1358c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1359c87c5fbaSopenharmony_ci      /* Expire this entry */
1360c87c5fbaSopenharmony_ci      LL_DELETE(session->lg_crcv, p);
1361c87c5fbaSopenharmony_ci      coap_block_delete_lg_crcv(session, p);
1362c87c5fbaSopenharmony_ci    } else if (!p->observe_set && p->last_used) {
1363c87c5fbaSopenharmony_ci      /* Delay until the lg_crcv needs to expire */
1364c87c5fbaSopenharmony_ci      if (*tim_rem > p->last_used + partial_timeout - now) {
1365c87c5fbaSopenharmony_ci        *tim_rem = p->last_used + partial_timeout - now;
1366c87c5fbaSopenharmony_ci        ret = 1;
1367c87c5fbaSopenharmony_ci      }
1368c87c5fbaSopenharmony_ci    }
1369c87c5fbaSopenharmony_ci  }
1370c87c5fbaSopenharmony_ci  return ret;
1371c87c5fbaSopenharmony_ci}
1372c87c5fbaSopenharmony_ci#endif /* COAP_CLIENT_SUPPORT */
1373c87c5fbaSopenharmony_ci
1374c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
1375c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1376c87c5fbaSopenharmony_cistatic coap_pdu_t *
1377c87c5fbaSopenharmony_cipdu_408_build(coap_session_t *session, coap_lg_srcv_t *p) {
1378c87c5fbaSopenharmony_ci  coap_pdu_t *pdu;
1379c87c5fbaSopenharmony_ci  uint8_t buf[4];
1380c87c5fbaSopenharmony_ci
1381c87c5fbaSopenharmony_ci  pdu = coap_pdu_init(COAP_MESSAGE_NON,
1382c87c5fbaSopenharmony_ci                      COAP_RESPONSE_CODE(408),
1383c87c5fbaSopenharmony_ci                      coap_new_message_id(session),
1384c87c5fbaSopenharmony_ci                      coap_session_max_pdu_size(session));
1385c87c5fbaSopenharmony_ci  if (!pdu)
1386c87c5fbaSopenharmony_ci    return NULL;
1387c87c5fbaSopenharmony_ci  if (p->last_token)
1388c87c5fbaSopenharmony_ci    coap_add_token(pdu, p->last_token->length, p->last_token->s);
1389c87c5fbaSopenharmony_ci  coap_add_option_internal(pdu, COAP_OPTION_CONTENT_TYPE,
1390c87c5fbaSopenharmony_ci                           coap_encode_var_safe(buf, sizeof(buf),
1391c87c5fbaSopenharmony_ci                                                COAP_MEDIATYPE_APPLICATION_MB_CBOR_SEQ),
1392c87c5fbaSopenharmony_ci                           buf);
1393c87c5fbaSopenharmony_ci  pdu->token[pdu->used_size++] = COAP_PAYLOAD_START;
1394c87c5fbaSopenharmony_ci  pdu->data = pdu->token + pdu->used_size;
1395c87c5fbaSopenharmony_ci  return pdu;
1396c87c5fbaSopenharmony_ci}
1397c87c5fbaSopenharmony_ci
1398c87c5fbaSopenharmony_cistatic int
1399c87c5fbaSopenharmony_ciadd_408_block(coap_pdu_t *pdu, int block) {
1400c87c5fbaSopenharmony_ci  size_t len;
1401c87c5fbaSopenharmony_ci  uint8_t val[8];
1402c87c5fbaSopenharmony_ci
1403c87c5fbaSopenharmony_ci  assert(block >= 0 && block < (1 << 20));
1404c87c5fbaSopenharmony_ci
1405c87c5fbaSopenharmony_ci  if (block < 0 || block >= (1 << 20)) {
1406c87c5fbaSopenharmony_ci    return 0;
1407c87c5fbaSopenharmony_ci  } else if (block < 24) {
1408c87c5fbaSopenharmony_ci    len = 1;
1409c87c5fbaSopenharmony_ci    val[0] = block;
1410c87c5fbaSopenharmony_ci  } else if (block < 0x100) {
1411c87c5fbaSopenharmony_ci    len = 2;
1412c87c5fbaSopenharmony_ci    val[0] = 24;
1413c87c5fbaSopenharmony_ci    val[1] = block;
1414c87c5fbaSopenharmony_ci  } else if (block < 0x10000) {
1415c87c5fbaSopenharmony_ci    len = 3;
1416c87c5fbaSopenharmony_ci    val[0] = 25;
1417c87c5fbaSopenharmony_ci    val[1] = block >> 8;
1418c87c5fbaSopenharmony_ci    val[2] = block & 0xff;
1419c87c5fbaSopenharmony_ci  } else { /* Largest block number is 2^^20 - 1 */
1420c87c5fbaSopenharmony_ci    len = 4;
1421c87c5fbaSopenharmony_ci    val[0] = 26;
1422c87c5fbaSopenharmony_ci    val[1] = block >> 16;
1423c87c5fbaSopenharmony_ci    val[2] = (block >> 8) & 0xff;
1424c87c5fbaSopenharmony_ci    val[3] = block & 0xff;
1425c87c5fbaSopenharmony_ci  }
1426c87c5fbaSopenharmony_ci  if (coap_pdu_check_resize(pdu, pdu->used_size + len)) {
1427c87c5fbaSopenharmony_ci    memcpy(&pdu->token[pdu->used_size], val, len);
1428c87c5fbaSopenharmony_ci    pdu->used_size += len;
1429c87c5fbaSopenharmony_ci    return 1;
1430c87c5fbaSopenharmony_ci  }
1431c87c5fbaSopenharmony_ci  return 0;
1432c87c5fbaSopenharmony_ci}
1433c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1434c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
1435c87c5fbaSopenharmony_ci
1436c87c5fbaSopenharmony_cistatic int
1437c87c5fbaSopenharmony_cicheck_if_received_block(coap_rblock_t *rec_blocks, uint32_t block_num) {
1438c87c5fbaSopenharmony_ci  uint32_t i;
1439c87c5fbaSopenharmony_ci
1440c87c5fbaSopenharmony_ci  for (i = 0; i < rec_blocks->used; i++) {
1441c87c5fbaSopenharmony_ci    if (block_num < rec_blocks->range[i].begin)
1442c87c5fbaSopenharmony_ci      return 0;
1443c87c5fbaSopenharmony_ci    if (block_num <= rec_blocks->range[i].end)
1444c87c5fbaSopenharmony_ci      return 1;
1445c87c5fbaSopenharmony_ci  }
1446c87c5fbaSopenharmony_ci  return 0;
1447c87c5fbaSopenharmony_ci}
1448c87c5fbaSopenharmony_ci
1449c87c5fbaSopenharmony_cistatic int
1450c87c5fbaSopenharmony_cicheck_all_blocks_in(coap_rblock_t *rec_blocks, size_t total_blocks) {
1451c87c5fbaSopenharmony_ci  uint32_t i;
1452c87c5fbaSopenharmony_ci  uint32_t block = 0;
1453c87c5fbaSopenharmony_ci
1454c87c5fbaSopenharmony_ci  for (i = 0; i < rec_blocks->used; i++) {
1455c87c5fbaSopenharmony_ci    if (block < rec_blocks->range[i].begin)
1456c87c5fbaSopenharmony_ci      return 0;
1457c87c5fbaSopenharmony_ci    if (block < rec_blocks->range[i].end)
1458c87c5fbaSopenharmony_ci      block = rec_blocks->range[i].end;
1459c87c5fbaSopenharmony_ci  }
1460c87c5fbaSopenharmony_ci  /* total_blocks counts from 1 */
1461c87c5fbaSopenharmony_ci  if (block + 1 < total_blocks)
1462c87c5fbaSopenharmony_ci    return 0;
1463c87c5fbaSopenharmony_ci
1464c87c5fbaSopenharmony_ci  return 1;
1465c87c5fbaSopenharmony_ci}
1466c87c5fbaSopenharmony_ci
1467c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
1468c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1469c87c5fbaSopenharmony_cistatic int
1470c87c5fbaSopenharmony_cicheck_all_blocks_in_for_payload_set(coap_session_t *session,
1471c87c5fbaSopenharmony_ci                                    coap_rblock_t *rec_blocks) {
1472c87c5fbaSopenharmony_ci  if (rec_blocks->used &&
1473c87c5fbaSopenharmony_ci      (rec_blocks->range[0].end + 1) / COAP_MAX_PAYLOADS(session) >
1474c87c5fbaSopenharmony_ci      rec_blocks->processing_payload_set)
1475c87c5fbaSopenharmony_ci    return 1;
1476c87c5fbaSopenharmony_ci  return 0;
1477c87c5fbaSopenharmony_ci}
1478c87c5fbaSopenharmony_ci
1479c87c5fbaSopenharmony_cistatic int
1480c87c5fbaSopenharmony_cicheck_any_blocks_next_payload_set(coap_session_t *session,
1481c87c5fbaSopenharmony_ci                                  coap_rblock_t *rec_blocks) {
1482c87c5fbaSopenharmony_ci  if (rec_blocks->used > 1 &&
1483c87c5fbaSopenharmony_ci      rec_blocks->range[1].begin / COAP_MAX_PAYLOADS(session) ==
1484c87c5fbaSopenharmony_ci      rec_blocks->processing_payload_set)
1485c87c5fbaSopenharmony_ci    return 1;
1486c87c5fbaSopenharmony_ci  return 0;
1487c87c5fbaSopenharmony_ci}
1488c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1489c87c5fbaSopenharmony_ci#endif /* COAP_CLIENT_SUPPORT */
1490c87c5fbaSopenharmony_ci
1491c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
1492c87c5fbaSopenharmony_ci/*
1493c87c5fbaSopenharmony_ci * return 1 if there is a future expire time, else 0.
1494c87c5fbaSopenharmony_ci * update tim_rem with remaining value if return is 1.
1495c87c5fbaSopenharmony_ci */
1496c87c5fbaSopenharmony_ciint
1497c87c5fbaSopenharmony_cicoap_block_check_lg_srcv_timeouts(coap_session_t *session, coap_tick_t now,
1498c87c5fbaSopenharmony_ci                                  coap_tick_t *tim_rem) {
1499c87c5fbaSopenharmony_ci  coap_lg_srcv_t *p;
1500c87c5fbaSopenharmony_ci  coap_lg_srcv_t *q;
1501c87c5fbaSopenharmony_ci  coap_tick_t partial_timeout;
1502c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1503c87c5fbaSopenharmony_ci  coap_tick_t receive_timeout = COAP_NON_RECEIVE_TIMEOUT_TICKS(session);
1504c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1505c87c5fbaSopenharmony_ci  int ret = 0;
1506c87c5fbaSopenharmony_ci
1507c87c5fbaSopenharmony_ci  *tim_rem = -1;
1508c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1509c87c5fbaSopenharmony_ci  if (COAP_PROTO_NOT_RELIABLE(session->proto))
1510c87c5fbaSopenharmony_ci    partial_timeout = COAP_NON_PARTIAL_TIMEOUT_TICKS(session);
1511c87c5fbaSopenharmony_ci  else
1512c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1513c87c5fbaSopenharmony_ci    partial_timeout = COAP_MAX_TRANSMIT_WAIT_TICKS(session);
1514c87c5fbaSopenharmony_ci
1515c87c5fbaSopenharmony_ci  LL_FOREACH_SAFE(session->lg_srcv, p, q) {
1516c87c5fbaSopenharmony_ci    if (COAP_PROTO_RELIABLE(session->proto) || p->last_type != COAP_MESSAGE_NON)
1517c87c5fbaSopenharmony_ci      goto check_expire;
1518c87c5fbaSopenharmony_ci
1519c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1520c87c5fbaSopenharmony_ci    if (p->block_option == COAP_OPTION_Q_BLOCK1 && p->rec_blocks.used) {
1521c87c5fbaSopenharmony_ci      size_t scaled_timeout = receive_timeout *
1522c87c5fbaSopenharmony_ci                              ((size_t)1 << p->rec_blocks.retry);
1523c87c5fbaSopenharmony_ci
1524c87c5fbaSopenharmony_ci      if (p->rec_blocks.retry >= COAP_NON_MAX_RETRANSMIT(session)) {
1525c87c5fbaSopenharmony_ci        /* Done NON_MAX_RETRANSMIT retries */
1526c87c5fbaSopenharmony_ci        goto expire;
1527c87c5fbaSopenharmony_ci      }
1528c87c5fbaSopenharmony_ci      if (p->rec_blocks.last_seen + scaled_timeout <= now) {
1529c87c5fbaSopenharmony_ci        uint32_t i;
1530c87c5fbaSopenharmony_ci        int block = -1; /* Last one seen */
1531c87c5fbaSopenharmony_ci        size_t block_size = (size_t)1 << (p->szx + 4);
1532c87c5fbaSopenharmony_ci        size_t final_block = (p->total_len + block_size - 1)/block_size - 1;
1533c87c5fbaSopenharmony_ci        size_t cur_payload;
1534c87c5fbaSopenharmony_ci        size_t last_payload_block;
1535c87c5fbaSopenharmony_ci        coap_pdu_t *pdu = NULL;
1536c87c5fbaSopenharmony_ci        size_t no_blocks = 0;
1537c87c5fbaSopenharmony_ci
1538c87c5fbaSopenharmony_ci        /* Need to count the number of missing blocks */
1539c87c5fbaSopenharmony_ci        for (i = 0; i < p->rec_blocks.used; i++) {
1540c87c5fbaSopenharmony_ci          if (block < (int)p->rec_blocks.range[i].begin &&
1541c87c5fbaSopenharmony_ci              p->rec_blocks.range[i].begin != 0) {
1542c87c5fbaSopenharmony_ci            block++;
1543c87c5fbaSopenharmony_ci            no_blocks += p->rec_blocks.range[i].begin - block;
1544c87c5fbaSopenharmony_ci          }
1545c87c5fbaSopenharmony_ci          if (block < (int)p->rec_blocks.range[i].end) {
1546c87c5fbaSopenharmony_ci            block = p->rec_blocks.range[i].end;
1547c87c5fbaSopenharmony_ci          }
1548c87c5fbaSopenharmony_ci        }
1549c87c5fbaSopenharmony_ci        if (no_blocks == 0 && block == (int)final_block)
1550c87c5fbaSopenharmony_ci          goto expire;
1551c87c5fbaSopenharmony_ci
1552c87c5fbaSopenharmony_ci        /* Include missing up to end of current payload or total amount */
1553c87c5fbaSopenharmony_ci        cur_payload = block / COAP_MAX_PAYLOADS(session);
1554c87c5fbaSopenharmony_ci        last_payload_block = (cur_payload + 1) * COAP_MAX_PAYLOADS(session) - 1;
1555c87c5fbaSopenharmony_ci        if (final_block > last_payload_block) {
1556c87c5fbaSopenharmony_ci          final_block = last_payload_block;
1557c87c5fbaSopenharmony_ci        }
1558c87c5fbaSopenharmony_ci        no_blocks += final_block - block;
1559c87c5fbaSopenharmony_ci        if (no_blocks == 0) {
1560c87c5fbaSopenharmony_ci          /* Add in the blocks out of the next payload */
1561c87c5fbaSopenharmony_ci          final_block = (p->total_len + block_size - 1)/block_size - 1;
1562c87c5fbaSopenharmony_ci          last_payload_block += COAP_MAX_PAYLOADS(session);
1563c87c5fbaSopenharmony_ci          if (final_block > last_payload_block) {
1564c87c5fbaSopenharmony_ci            final_block = last_payload_block;
1565c87c5fbaSopenharmony_ci          }
1566c87c5fbaSopenharmony_ci          no_blocks += final_block - block;
1567c87c5fbaSopenharmony_ci        }
1568c87c5fbaSopenharmony_ci        /* Ask for the missing blocks */
1569c87c5fbaSopenharmony_ci        block = -1;
1570c87c5fbaSopenharmony_ci        for (i = 0; i < p->rec_blocks.used; i++) {
1571c87c5fbaSopenharmony_ci          if (block < (int)p->rec_blocks.range[i].begin &&
1572c87c5fbaSopenharmony_ci              p->rec_blocks.range[i].begin != 0) {
1573c87c5fbaSopenharmony_ci            /* Report on missing blocks */
1574c87c5fbaSopenharmony_ci            if (pdu == NULL) {
1575c87c5fbaSopenharmony_ci              pdu = pdu_408_build(session, p);
1576c87c5fbaSopenharmony_ci              if (!pdu)
1577c87c5fbaSopenharmony_ci                continue;
1578c87c5fbaSopenharmony_ci            }
1579c87c5fbaSopenharmony_ci            block++;
1580c87c5fbaSopenharmony_ci            for (; block < (int)p->rec_blocks.range[i].begin; block++) {
1581c87c5fbaSopenharmony_ci              if (!add_408_block(pdu, block)) {
1582c87c5fbaSopenharmony_ci                break;
1583c87c5fbaSopenharmony_ci              }
1584c87c5fbaSopenharmony_ci            }
1585c87c5fbaSopenharmony_ci          }
1586c87c5fbaSopenharmony_ci          if (block < (int)p->rec_blocks.range[i].end) {
1587c87c5fbaSopenharmony_ci            block = p->rec_blocks.range[i].end;
1588c87c5fbaSopenharmony_ci          }
1589c87c5fbaSopenharmony_ci        }
1590c87c5fbaSopenharmony_ci        block++;
1591c87c5fbaSopenharmony_ci        for (; block <= (int)final_block; block++) {
1592c87c5fbaSopenharmony_ci          if (pdu == NULL) {
1593c87c5fbaSopenharmony_ci            pdu = pdu_408_build(session, p);
1594c87c5fbaSopenharmony_ci            if (!pdu)
1595c87c5fbaSopenharmony_ci              continue;
1596c87c5fbaSopenharmony_ci          }
1597c87c5fbaSopenharmony_ci          if (!add_408_block(pdu, block)) {
1598c87c5fbaSopenharmony_ci            break;
1599c87c5fbaSopenharmony_ci          }
1600c87c5fbaSopenharmony_ci        }
1601c87c5fbaSopenharmony_ci        if (pdu)
1602c87c5fbaSopenharmony_ci          coap_send_internal(session, pdu);
1603c87c5fbaSopenharmony_ci        p->rec_blocks.retry++;
1604c87c5fbaSopenharmony_ci        coap_ticks(&p->rec_blocks.last_seen);
1605c87c5fbaSopenharmony_ci      }
1606c87c5fbaSopenharmony_ci      if (*tim_rem > p->rec_blocks.last_seen + scaled_timeout - now) {
1607c87c5fbaSopenharmony_ci        *tim_rem = p->rec_blocks.last_seen + scaled_timeout - now;
1608c87c5fbaSopenharmony_ci        ret = 1;
1609c87c5fbaSopenharmony_ci      }
1610c87c5fbaSopenharmony_ci    }
1611c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1612c87c5fbaSopenharmony_ci    /* Used for Block1 and Q-Block1 */
1613c87c5fbaSopenharmony_cicheck_expire:
1614c87c5fbaSopenharmony_ci    if (p->last_used && p->last_used + partial_timeout <= now) {
1615c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1616c87c5fbaSopenharmony_ciexpire:
1617c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1618c87c5fbaSopenharmony_ci      /* Expire this entry */
1619c87c5fbaSopenharmony_ci      LL_DELETE(session->lg_srcv, p);
1620c87c5fbaSopenharmony_ci      coap_block_delete_lg_srcv(session, p);
1621c87c5fbaSopenharmony_ci    } else if (p->last_used) {
1622c87c5fbaSopenharmony_ci      /* Delay until the lg_srcv needs to expire */
1623c87c5fbaSopenharmony_ci      if (*tim_rem > p->last_used + partial_timeout - now) {
1624c87c5fbaSopenharmony_ci        *tim_rem = p->last_used + partial_timeout - now;
1625c87c5fbaSopenharmony_ci        ret = 1;
1626c87c5fbaSopenharmony_ci      }
1627c87c5fbaSopenharmony_ci    }
1628c87c5fbaSopenharmony_ci  }
1629c87c5fbaSopenharmony_ci  return ret;
1630c87c5fbaSopenharmony_ci}
1631c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
1632c87c5fbaSopenharmony_ci
1633c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1634c87c5fbaSopenharmony_ci/*
1635c87c5fbaSopenharmony_ci * pdu is always released before return IF COAP_SEND_INC_PDU
1636c87c5fbaSopenharmony_ci */
1637c87c5fbaSopenharmony_cicoap_mid_t
1638c87c5fbaSopenharmony_cicoap_send_q_blocks(coap_session_t *session,
1639c87c5fbaSopenharmony_ci                   coap_lg_xmit_t *lg_xmit,
1640c87c5fbaSopenharmony_ci                   coap_block_b_t block,
1641c87c5fbaSopenharmony_ci                   coap_pdu_t *pdu,
1642c87c5fbaSopenharmony_ci                   coap_send_pdu_t send_pdu) {
1643c87c5fbaSopenharmony_ci  coap_pdu_t *block_pdu = NULL;
1644c87c5fbaSopenharmony_ci  coap_opt_filter_t drop_options;
1645c87c5fbaSopenharmony_ci  coap_mid_t mid = COAP_INVALID_MID;
1646c87c5fbaSopenharmony_ci  uint64_t token = coap_decode_var_bytes8(pdu->actual_token.s,
1647c87c5fbaSopenharmony_ci                                          pdu->actual_token.length);
1648c87c5fbaSopenharmony_ci  const uint8_t *ptoken;
1649c87c5fbaSopenharmony_ci  uint8_t ltoken[8];
1650c87c5fbaSopenharmony_ci  size_t ltoken_length;
1651c87c5fbaSopenharmony_ci  uint32_t delayqueue_cnt = 0;
1652c87c5fbaSopenharmony_ci
1653c87c5fbaSopenharmony_ci  if (!lg_xmit) {
1654c87c5fbaSopenharmony_ci    if (send_pdu == COAP_SEND_INC_PDU)
1655c87c5fbaSopenharmony_ci      return coap_send_internal(session, pdu);
1656c87c5fbaSopenharmony_ci    return COAP_INVALID_MID;
1657c87c5fbaSopenharmony_ci  }
1658c87c5fbaSopenharmony_ci
1659c87c5fbaSopenharmony_ci  if (pdu->type == COAP_MESSAGE_CON) {
1660c87c5fbaSopenharmony_ci    coap_queue_t *delayqueue;
1661c87c5fbaSopenharmony_ci
1662c87c5fbaSopenharmony_ci    delayqueue_cnt = session->con_active +
1663c87c5fbaSopenharmony_ci                     (send_pdu == COAP_SEND_INC_PDU ? 1 : 0);
1664c87c5fbaSopenharmony_ci    LL_FOREACH(session->delayqueue, delayqueue) {
1665c87c5fbaSopenharmony_ci      delayqueue_cnt++;
1666c87c5fbaSopenharmony_ci    }
1667c87c5fbaSopenharmony_ci  }
1668c87c5fbaSopenharmony_ci  pdu->lg_xmit = lg_xmit;
1669c87c5fbaSopenharmony_ci  if (block.m &&
1670c87c5fbaSopenharmony_ci      ((pdu->type == COAP_MESSAGE_NON &&
1671c87c5fbaSopenharmony_ci        ((block.num + 1) % COAP_MAX_PAYLOADS(session)) + 1 !=
1672c87c5fbaSopenharmony_ci        COAP_MAX_PAYLOADS(session)) ||
1673c87c5fbaSopenharmony_ci       (pdu->type == COAP_MESSAGE_ACK &&
1674c87c5fbaSopenharmony_ci        lg_xmit->option == COAP_OPTION_Q_BLOCK2) ||
1675c87c5fbaSopenharmony_ci       (pdu->type == COAP_MESSAGE_CON &&
1676c87c5fbaSopenharmony_ci        delayqueue_cnt < COAP_NSTART(session)) ||
1677c87c5fbaSopenharmony_ci       COAP_PROTO_RELIABLE(session->proto))) {
1678c87c5fbaSopenharmony_ci    /* Allocate next pdu if there is headroom */
1679c87c5fbaSopenharmony_ci    if (COAP_PDU_IS_RESPONSE(pdu)) {
1680c87c5fbaSopenharmony_ci      ptoken = pdu->actual_token.s;
1681c87c5fbaSopenharmony_ci      ltoken_length = pdu->actual_token.length;
1682c87c5fbaSopenharmony_ci    } else {
1683c87c5fbaSopenharmony_ci      token = STATE_TOKEN_FULL(lg_xmit->b.b1.state_token,++lg_xmit->b.b1.count);
1684c87c5fbaSopenharmony_ci      ltoken_length = coap_encode_var_safe8(ltoken, sizeof(token), token);
1685c87c5fbaSopenharmony_ci      ptoken = ltoken;
1686c87c5fbaSopenharmony_ci    }
1687c87c5fbaSopenharmony_ci
1688c87c5fbaSopenharmony_ci    memset(&drop_options, 0, sizeof(coap_opt_filter_t));
1689c87c5fbaSopenharmony_ci    coap_option_filter_set(&drop_options, lg_xmit->option);
1690c87c5fbaSopenharmony_ci    block_pdu = coap_pdu_duplicate(pdu, session,
1691c87c5fbaSopenharmony_ci                                   ltoken_length,
1692c87c5fbaSopenharmony_ci                                   ptoken, &drop_options);
1693c87c5fbaSopenharmony_ci    if (block_pdu->type == COAP_MESSAGE_ACK)
1694c87c5fbaSopenharmony_ci      block_pdu->type = COAP_MESSAGE_CON;
1695c87c5fbaSopenharmony_ci  }
1696c87c5fbaSopenharmony_ci
1697c87c5fbaSopenharmony_ci  /* Send initial pdu (which deletes 'pdu') */
1698c87c5fbaSopenharmony_ci  if (send_pdu == COAP_SEND_INC_PDU &&
1699c87c5fbaSopenharmony_ci      (mid = coap_send_internal(session, pdu)) == COAP_INVALID_MID) {
1700c87c5fbaSopenharmony_ci    /* Not expected, underlying issue somewhere */
1701c87c5fbaSopenharmony_ci    coap_delete_pdu(block_pdu);
1702c87c5fbaSopenharmony_ci    return COAP_INVALID_MID;
1703c87c5fbaSopenharmony_ci  }
1704c87c5fbaSopenharmony_ci
1705c87c5fbaSopenharmony_ci  while (block_pdu) {
1706c87c5fbaSopenharmony_ci    coap_pdu_t *t_pdu = NULL;
1707c87c5fbaSopenharmony_ci    uint8_t buf[8];
1708c87c5fbaSopenharmony_ci    size_t chunk = ((size_t)1 << (lg_xmit->blk_size + 4));
1709c87c5fbaSopenharmony_ci
1710c87c5fbaSopenharmony_ci    block.num++;
1711c87c5fbaSopenharmony_ci    lg_xmit->offset = block.num * chunk;
1712c87c5fbaSopenharmony_ci    block.m = lg_xmit->offset + chunk < lg_xmit->length;
1713c87c5fbaSopenharmony_ci    if (block.m && ((block_pdu->type == COAP_MESSAGE_NON &&
1714c87c5fbaSopenharmony_ci                     (block.num % COAP_MAX_PAYLOADS(session)) + 1 !=
1715c87c5fbaSopenharmony_ci                     COAP_MAX_PAYLOADS(session)) ||
1716c87c5fbaSopenharmony_ci                    (block_pdu->type == COAP_MESSAGE_CON &&
1717c87c5fbaSopenharmony_ci                     delayqueue_cnt + 1 < COAP_NSTART(session)) ||
1718c87c5fbaSopenharmony_ci                    COAP_PROTO_RELIABLE(session->proto))) {
1719c87c5fbaSopenharmony_ci      /*
1720c87c5fbaSopenharmony_ci       * Send following block if
1721c87c5fbaSopenharmony_ci       *   NON and more in MAX_PAYLOADS
1722c87c5fbaSopenharmony_ci       *   CON and NSTART allows it (based on number in delayqueue)
1723c87c5fbaSopenharmony_ci       *   Reliable transport
1724c87c5fbaSopenharmony_ci       */
1725c87c5fbaSopenharmony_ci      if (COAP_PDU_IS_RESPONSE(block_pdu)) {
1726c87c5fbaSopenharmony_ci        ptoken = block_pdu->actual_token.s;
1727c87c5fbaSopenharmony_ci        ltoken_length = block_pdu->actual_token.length;
1728c87c5fbaSopenharmony_ci      } else {
1729c87c5fbaSopenharmony_ci        token = STATE_TOKEN_FULL(lg_xmit->b.b1.state_token,++lg_xmit->b.b1.count);
1730c87c5fbaSopenharmony_ci        ltoken_length = coap_encode_var_safe8(ltoken, sizeof(token), token);
1731c87c5fbaSopenharmony_ci        ptoken = ltoken;
1732c87c5fbaSopenharmony_ci      }
1733c87c5fbaSopenharmony_ci      t_pdu = coap_pdu_duplicate(block_pdu, session,
1734c87c5fbaSopenharmony_ci                                 ltoken_length, ptoken, &drop_options);
1735c87c5fbaSopenharmony_ci    }
1736c87c5fbaSopenharmony_ci    if (!coap_update_option(block_pdu, lg_xmit->option,
1737c87c5fbaSopenharmony_ci                            coap_encode_var_safe(buf,
1738c87c5fbaSopenharmony_ci                                                 sizeof(buf),
1739c87c5fbaSopenharmony_ci                                                 ((block.num) << 4) |
1740c87c5fbaSopenharmony_ci                                                 (block.m << 3) |
1741c87c5fbaSopenharmony_ci                                                 block.szx),
1742c87c5fbaSopenharmony_ci                            buf)) {
1743c87c5fbaSopenharmony_ci      coap_log_warn("Internal update issue option\n");
1744c87c5fbaSopenharmony_ci      coap_delete_pdu(block_pdu);
1745c87c5fbaSopenharmony_ci      coap_delete_pdu(t_pdu);
1746c87c5fbaSopenharmony_ci      break;
1747c87c5fbaSopenharmony_ci    }
1748c87c5fbaSopenharmony_ci
1749c87c5fbaSopenharmony_ci    if (!coap_add_block(block_pdu,
1750c87c5fbaSopenharmony_ci                        lg_xmit->length,
1751c87c5fbaSopenharmony_ci                        lg_xmit->data,
1752c87c5fbaSopenharmony_ci                        block.num,
1753c87c5fbaSopenharmony_ci                        block.szx)) {
1754c87c5fbaSopenharmony_ci      coap_log_warn("Internal update issue data\n");
1755c87c5fbaSopenharmony_ci      coap_delete_pdu(block_pdu);
1756c87c5fbaSopenharmony_ci      coap_delete_pdu(t_pdu);
1757c87c5fbaSopenharmony_ci      break;
1758c87c5fbaSopenharmony_ci    }
1759c87c5fbaSopenharmony_ci    if (COAP_PDU_IS_RESPONSE(block_pdu)) {
1760c87c5fbaSopenharmony_ci      lg_xmit->last_block = block.num;
1761c87c5fbaSopenharmony_ci    }
1762c87c5fbaSopenharmony_ci    mid = coap_send_internal(session, block_pdu);
1763c87c5fbaSopenharmony_ci    if (mid == COAP_INVALID_MID) {
1764c87c5fbaSopenharmony_ci      /* Not expected, underlying issue somewhere */
1765c87c5fbaSopenharmony_ci      coap_delete_pdu(t_pdu);
1766c87c5fbaSopenharmony_ci      return COAP_INVALID_MID;
1767c87c5fbaSopenharmony_ci    }
1768c87c5fbaSopenharmony_ci    block_pdu = t_pdu;
1769c87c5fbaSopenharmony_ci  }
1770c87c5fbaSopenharmony_ci  if (!block.m) {
1771c87c5fbaSopenharmony_ci    lg_xmit->last_payload = 0;
1772c87c5fbaSopenharmony_ci    coap_ticks(&lg_xmit->last_all_sent);
1773c87c5fbaSopenharmony_ci  } else
1774c87c5fbaSopenharmony_ci    coap_ticks(&lg_xmit->last_payload);
1775c87c5fbaSopenharmony_ci  return mid;
1776c87c5fbaSopenharmony_ci}
1777c87c5fbaSopenharmony_ci
1778c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
1779c87c5fbaSopenharmony_cicoap_tick_t
1780c87c5fbaSopenharmony_cicoap_block_check_q_block1_xmit(coap_session_t *session, coap_tick_t now) {
1781c87c5fbaSopenharmony_ci  coap_lg_xmit_t *lg_xmit;
1782c87c5fbaSopenharmony_ci  coap_lg_xmit_t *q;
1783c87c5fbaSopenharmony_ci  coap_tick_t timed_out;
1784c87c5fbaSopenharmony_ci  coap_tick_t tim_rem = (coap_tick_t)-1;
1785c87c5fbaSopenharmony_ci
1786c87c5fbaSopenharmony_ci  LL_FOREACH_SAFE(session->lg_xmit, lg_xmit, q) {
1787c87c5fbaSopenharmony_ci    coap_tick_t non_timeout = lg_xmit->non_timeout_random_ticks;
1788c87c5fbaSopenharmony_ci
1789c87c5fbaSopenharmony_ci    if (now < non_timeout)
1790c87c5fbaSopenharmony_ci      return non_timeout - now;
1791c87c5fbaSopenharmony_ci    timed_out = now - non_timeout;
1792c87c5fbaSopenharmony_ci
1793c87c5fbaSopenharmony_ci    if (lg_xmit->last_payload) {
1794c87c5fbaSopenharmony_ci      if (lg_xmit->last_payload <= timed_out) {
1795c87c5fbaSopenharmony_ci        /* Send off the next MAX_PAYLOAD set */
1796c87c5fbaSopenharmony_ci        coap_block_b_t block;
1797c87c5fbaSopenharmony_ci        size_t chunk = (size_t)1 << (lg_xmit->blk_size + 4);
1798c87c5fbaSopenharmony_ci
1799c87c5fbaSopenharmony_ci        memset(&block, 0, sizeof(block));
1800c87c5fbaSopenharmony_ci        block.num = (uint32_t)(lg_xmit->offset / chunk);
1801c87c5fbaSopenharmony_ci        block.m = lg_xmit->offset + chunk < lg_xmit->length;
1802c87c5fbaSopenharmony_ci        block.szx = lg_xmit->blk_size;
1803c87c5fbaSopenharmony_ci        coap_send_q_blocks(session, lg_xmit, block, &lg_xmit->pdu, COAP_SEND_SKIP_PDU);
1804c87c5fbaSopenharmony_ci        if (tim_rem > non_timeout)
1805c87c5fbaSopenharmony_ci          tim_rem = non_timeout;
1806c87c5fbaSopenharmony_ci      } else {
1807c87c5fbaSopenharmony_ci        /* Delay until the next MAX_PAYLOAD needs to be sent off */
1808c87c5fbaSopenharmony_ci        if (tim_rem > lg_xmit->last_payload - timed_out)
1809c87c5fbaSopenharmony_ci          tim_rem = lg_xmit->last_payload - timed_out;
1810c87c5fbaSopenharmony_ci      }
1811c87c5fbaSopenharmony_ci    } else if (lg_xmit->last_all_sent) {
1812c87c5fbaSopenharmony_ci      non_timeout = COAP_NON_TIMEOUT_TICKS(session);
1813c87c5fbaSopenharmony_ci      if (lg_xmit->last_all_sent + 4 * non_timeout <= now) {
1814c87c5fbaSopenharmony_ci        /* Expire this entry */
1815c87c5fbaSopenharmony_ci        LL_DELETE(session->lg_xmit, lg_xmit);
1816c87c5fbaSopenharmony_ci        coap_block_delete_lg_xmit(session, lg_xmit);
1817c87c5fbaSopenharmony_ci      } else {
1818c87c5fbaSopenharmony_ci        /* Delay until the lg_xmit needs to expire */
1819c87c5fbaSopenharmony_ci        if (tim_rem > lg_xmit->last_all_sent + 4 * non_timeout - now)
1820c87c5fbaSopenharmony_ci          tim_rem = lg_xmit->last_all_sent + 4 * non_timeout - now;
1821c87c5fbaSopenharmony_ci      }
1822c87c5fbaSopenharmony_ci    }
1823c87c5fbaSopenharmony_ci  }
1824c87c5fbaSopenharmony_ci  return tim_rem;
1825c87c5fbaSopenharmony_ci}
1826c87c5fbaSopenharmony_ci#endif /* COAP_CLIENT_SUPPORT */
1827c87c5fbaSopenharmony_ci
1828c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
1829c87c5fbaSopenharmony_cicoap_tick_t
1830c87c5fbaSopenharmony_cicoap_block_check_q_block2_xmit(coap_session_t *session, coap_tick_t now) {
1831c87c5fbaSopenharmony_ci  coap_lg_xmit_t *lg_xmit;
1832c87c5fbaSopenharmony_ci  coap_lg_xmit_t *q;
1833c87c5fbaSopenharmony_ci  coap_tick_t timed_out;
1834c87c5fbaSopenharmony_ci  coap_tick_t tim_rem = (coap_tick_t)-1;
1835c87c5fbaSopenharmony_ci
1836c87c5fbaSopenharmony_ci  LL_FOREACH_SAFE(session->lg_xmit, lg_xmit, q) {
1837c87c5fbaSopenharmony_ci    coap_tick_t non_timeout = lg_xmit->non_timeout_random_ticks;
1838c87c5fbaSopenharmony_ci
1839c87c5fbaSopenharmony_ci    if (now < non_timeout)
1840c87c5fbaSopenharmony_ci      return non_timeout - now;
1841c87c5fbaSopenharmony_ci    timed_out = now - non_timeout;
1842c87c5fbaSopenharmony_ci
1843c87c5fbaSopenharmony_ci    if (lg_xmit->last_payload) {
1844c87c5fbaSopenharmony_ci      if (lg_xmit->last_payload <= timed_out) {
1845c87c5fbaSopenharmony_ci        /* Send off the next MAX_PAYLOAD set */
1846c87c5fbaSopenharmony_ci        coap_block_b_t block;
1847c87c5fbaSopenharmony_ci        size_t chunk = (size_t)1 << (lg_xmit->blk_size + 4);
1848c87c5fbaSopenharmony_ci
1849c87c5fbaSopenharmony_ci        memset(&block, 0, sizeof(block));
1850c87c5fbaSopenharmony_ci        block.num = (uint32_t)(lg_xmit->offset / chunk);
1851c87c5fbaSopenharmony_ci        block.m = lg_xmit->offset + chunk < lg_xmit->length;
1852c87c5fbaSopenharmony_ci        block.szx = lg_xmit->blk_size;
1853c87c5fbaSopenharmony_ci        if (block.num == (uint32_t)lg_xmit->last_block)
1854c87c5fbaSopenharmony_ci          coap_send_q_blocks(session, lg_xmit, block, &lg_xmit->pdu, COAP_SEND_SKIP_PDU);
1855c87c5fbaSopenharmony_ci        if (tim_rem > non_timeout)
1856c87c5fbaSopenharmony_ci          tim_rem = non_timeout;
1857c87c5fbaSopenharmony_ci      } else {
1858c87c5fbaSopenharmony_ci        /* Delay until the next MAX_PAYLOAD needs to be sent off */
1859c87c5fbaSopenharmony_ci        if (tim_rem > lg_xmit->last_payload - timed_out)
1860c87c5fbaSopenharmony_ci          tim_rem = lg_xmit->last_payload - timed_out;
1861c87c5fbaSopenharmony_ci      }
1862c87c5fbaSopenharmony_ci    } else if (lg_xmit->last_all_sent) {
1863c87c5fbaSopenharmony_ci      non_timeout = COAP_NON_TIMEOUT_TICKS(session);
1864c87c5fbaSopenharmony_ci      if (lg_xmit->last_all_sent +  4 * non_timeout <= now) {
1865c87c5fbaSopenharmony_ci        /* Expire this entry */
1866c87c5fbaSopenharmony_ci        LL_DELETE(session->lg_xmit, lg_xmit);
1867c87c5fbaSopenharmony_ci        coap_block_delete_lg_xmit(session, lg_xmit);
1868c87c5fbaSopenharmony_ci      } else {
1869c87c5fbaSopenharmony_ci        /* Delay until the lg_xmit needs to expire */
1870c87c5fbaSopenharmony_ci        if (tim_rem > lg_xmit->last_all_sent + 4 * non_timeout - now)
1871c87c5fbaSopenharmony_ci          tim_rem = lg_xmit->last_all_sent + 4 * non_timeout - now;
1872c87c5fbaSopenharmony_ci      }
1873c87c5fbaSopenharmony_ci    }
1874c87c5fbaSopenharmony_ci  }
1875c87c5fbaSopenharmony_ci  return tim_rem;
1876c87c5fbaSopenharmony_ci}
1877c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
1878c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1879c87c5fbaSopenharmony_ci
1880c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
1881c87c5fbaSopenharmony_ci/*
1882c87c5fbaSopenharmony_ci * If Observe = 0, save the token away and return NULL
1883c87c5fbaSopenharmony_ci * Else If Observe = 1, return the saved token for this block
1884c87c5fbaSopenharmony_ci * Else, return NULL
1885c87c5fbaSopenharmony_ci */
1886c87c5fbaSopenharmony_cistatic coap_bin_const_t *
1887c87c5fbaSopenharmony_citrack_fetch_observe(coap_pdu_t *pdu, coap_lg_crcv_t *lg_crcv,
1888c87c5fbaSopenharmony_ci                    uint32_t block_num, coap_bin_const_t *token) {
1889c87c5fbaSopenharmony_ci  /* Need to handle Observe for large FETCH */
1890c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
1891c87c5fbaSopenharmony_ci  coap_opt_t *opt = coap_check_option(pdu, COAP_OPTION_OBSERVE,
1892c87c5fbaSopenharmony_ci                                      &opt_iter);
1893c87c5fbaSopenharmony_ci
1894c87c5fbaSopenharmony_ci  if (opt && lg_crcv) {
1895c87c5fbaSopenharmony_ci    int observe_action = -1;
1896c87c5fbaSopenharmony_ci    coap_bin_const_t **tmp;
1897c87c5fbaSopenharmony_ci
1898c87c5fbaSopenharmony_ci    observe_action = coap_decode_var_bytes(coap_opt_value(opt),
1899c87c5fbaSopenharmony_ci                                           coap_opt_length(opt));
1900c87c5fbaSopenharmony_ci    if (observe_action == COAP_OBSERVE_ESTABLISH) {
1901c87c5fbaSopenharmony_ci      /* Save the token in lg_crcv */
1902c87c5fbaSopenharmony_ci      tmp = coap_realloc_type(COAP_STRING, lg_crcv->obs_token,
1903c87c5fbaSopenharmony_ci                              (block_num + 1) * sizeof(lg_crcv->obs_token[0]));
1904c87c5fbaSopenharmony_ci      if (tmp == NULL)
1905c87c5fbaSopenharmony_ci        return NULL;
1906c87c5fbaSopenharmony_ci      lg_crcv->obs_token = tmp;
1907c87c5fbaSopenharmony_ci      if (block_num + 1 == lg_crcv->obs_token_cnt)
1908c87c5fbaSopenharmony_ci        coap_delete_bin_const(lg_crcv->obs_token[block_num]);
1909c87c5fbaSopenharmony_ci
1910c87c5fbaSopenharmony_ci      lg_crcv->obs_token_cnt = block_num + 1;
1911c87c5fbaSopenharmony_ci      lg_crcv->obs_token[block_num] = coap_new_bin_const(token->s,
1912c87c5fbaSopenharmony_ci                                                         token->length);
1913c87c5fbaSopenharmony_ci      if (lg_crcv->obs_token[block_num] == NULL)
1914c87c5fbaSopenharmony_ci        return NULL;
1915c87c5fbaSopenharmony_ci    } else if (observe_action == COAP_OBSERVE_CANCEL) {
1916c87c5fbaSopenharmony_ci      /* Use the token in lg_crcv */
1917c87c5fbaSopenharmony_ci      if (block_num < lg_crcv->obs_token_cnt) {
1918c87c5fbaSopenharmony_ci        if (lg_crcv->obs_token[block_num]) {
1919c87c5fbaSopenharmony_ci          return lg_crcv->obs_token[block_num];
1920c87c5fbaSopenharmony_ci        }
1921c87c5fbaSopenharmony_ci      }
1922c87c5fbaSopenharmony_ci    }
1923c87c5fbaSopenharmony_ci  }
1924c87c5fbaSopenharmony_ci  return NULL;
1925c87c5fbaSopenharmony_ci}
1926c87c5fbaSopenharmony_ci
1927c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1928c87c5fbaSopenharmony_cicoap_mid_t
1929c87c5fbaSopenharmony_cicoap_send_q_block1(coap_session_t *session,
1930c87c5fbaSopenharmony_ci                   coap_block_b_t block,
1931c87c5fbaSopenharmony_ci                   coap_pdu_t *request,
1932c87c5fbaSopenharmony_ci                   coap_send_pdu_t send_request) {
1933c87c5fbaSopenharmony_ci  /* Need to send up to MAX_PAYLOAD blocks if this is a Q_BLOCK1 */
1934c87c5fbaSopenharmony_ci  coap_lg_xmit_t *lg_xmit;
1935c87c5fbaSopenharmony_ci  uint64_t token_match =
1936c87c5fbaSopenharmony_ci      STATE_TOKEN_BASE(coap_decode_var_bytes8(request->actual_token.s,
1937c87c5fbaSopenharmony_ci                                              request->actual_token.length));
1938c87c5fbaSopenharmony_ci
1939c87c5fbaSopenharmony_ci  LL_FOREACH(session->lg_xmit, lg_xmit) {
1940c87c5fbaSopenharmony_ci    if (lg_xmit->option == COAP_OPTION_Q_BLOCK1 &&
1941c87c5fbaSopenharmony_ci        (token_match == STATE_TOKEN_BASE(lg_xmit->b.b1.state_token) ||
1942c87c5fbaSopenharmony_ci         token_match ==
1943c87c5fbaSopenharmony_ci         STATE_TOKEN_BASE(coap_decode_var_bytes8(lg_xmit->b.b1.app_token->s,
1944c87c5fbaSopenharmony_ci                                                 lg_xmit->b.b1.app_token->length))))
1945c87c5fbaSopenharmony_ci      break;
1946c87c5fbaSopenharmony_ci    /* try out the next one */
1947c87c5fbaSopenharmony_ci  }
1948c87c5fbaSopenharmony_ci  return coap_send_q_blocks(session, lg_xmit, block, request, send_request);
1949c87c5fbaSopenharmony_ci}
1950c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1951c87c5fbaSopenharmony_ci#endif /* COAP_CLIENT_SUPPORT */
1952c87c5fbaSopenharmony_ci
1953c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
1954c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1955c87c5fbaSopenharmony_ci/*
1956c87c5fbaSopenharmony_ci * response is always released before return IF COAP_SEND_INC_PDU
1957c87c5fbaSopenharmony_ci */
1958c87c5fbaSopenharmony_cicoap_mid_t
1959c87c5fbaSopenharmony_cicoap_send_q_block2(coap_session_t *session,
1960c87c5fbaSopenharmony_ci                   coap_resource_t *resource,
1961c87c5fbaSopenharmony_ci                   const coap_string_t *query,
1962c87c5fbaSopenharmony_ci                   coap_pdu_code_t request_method,
1963c87c5fbaSopenharmony_ci                   coap_block_b_t block,
1964c87c5fbaSopenharmony_ci                   coap_pdu_t *response,
1965c87c5fbaSopenharmony_ci                   coap_send_pdu_t send_response) {
1966c87c5fbaSopenharmony_ci  /* Need to send up to MAX_PAYLOAD blocks if this is a Q_BLOCK2 */
1967c87c5fbaSopenharmony_ci  coap_lg_xmit_t *lg_xmit;
1968c87c5fbaSopenharmony_ci  coap_string_t empty = { 0, NULL};
1969c87c5fbaSopenharmony_ci
1970c87c5fbaSopenharmony_ci  LL_FOREACH(session->lg_xmit, lg_xmit) {
1971c87c5fbaSopenharmony_ci    if (lg_xmit->option == COAP_OPTION_Q_BLOCK2 &&
1972c87c5fbaSopenharmony_ci        resource == lg_xmit->b.b2.resource &&
1973c87c5fbaSopenharmony_ci        request_method == lg_xmit->b.b2.request_method &&
1974c87c5fbaSopenharmony_ci        coap_string_equal(query ? query : &empty,
1975c87c5fbaSopenharmony_ci                          lg_xmit->b.b2.query ? lg_xmit->b.b2.query : &empty))
1976c87c5fbaSopenharmony_ci      break;
1977c87c5fbaSopenharmony_ci  }
1978c87c5fbaSopenharmony_ci  return coap_send_q_blocks(session, lg_xmit, block, response, send_response);
1979c87c5fbaSopenharmony_ci}
1980c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
1981c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
1982c87c5fbaSopenharmony_ci
1983c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
1984c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
1985c87c5fbaSopenharmony_ci/*
1986c87c5fbaSopenharmony_ci * Send out a test PDU for Q-Block.
1987c87c5fbaSopenharmony_ci */
1988c87c5fbaSopenharmony_cicoap_mid_t
1989c87c5fbaSopenharmony_cicoap_block_test_q_block(coap_session_t *session, coap_pdu_t *actual) {
1990c87c5fbaSopenharmony_ci  coap_pdu_t *pdu;
1991c87c5fbaSopenharmony_ci  uint8_t token[8];
1992c87c5fbaSopenharmony_ci  size_t token_len;
1993c87c5fbaSopenharmony_ci  uint8_t buf[4];
1994c87c5fbaSopenharmony_ci  coap_mid_t mid;
1995c87c5fbaSopenharmony_ci
1996c87c5fbaSopenharmony_ci#if NDEBUG
1997c87c5fbaSopenharmony_ci  (void)actual;
1998c87c5fbaSopenharmony_ci#endif /* NDEBUG */
1999c87c5fbaSopenharmony_ci  assert(session->block_mode & COAP_BLOCK_TRY_Q_BLOCK &&
2000c87c5fbaSopenharmony_ci         session->type == COAP_SESSION_TYPE_CLIENT &&
2001c87c5fbaSopenharmony_ci         COAP_PDU_IS_REQUEST(actual));
2002c87c5fbaSopenharmony_ci
2003c87c5fbaSopenharmony_ci  coap_log_debug("Testing for Q-Block support\n");
2004c87c5fbaSopenharmony_ci  /* RFC9177 Section 3.1 when checking if available */
2005c87c5fbaSopenharmony_ci  pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_CODE_GET,
2006c87c5fbaSopenharmony_ci                      coap_new_message_id(session),
2007c87c5fbaSopenharmony_ci                      coap_session_max_pdu_size(session));
2008c87c5fbaSopenharmony_ci  if (!pdu) {
2009c87c5fbaSopenharmony_ci    return COAP_INVALID_MID;
2010c87c5fbaSopenharmony_ci  }
2011c87c5fbaSopenharmony_ci
2012c87c5fbaSopenharmony_ci  coap_session_new_token(session, &token_len, token);
2013c87c5fbaSopenharmony_ci  coap_add_token(pdu, token_len, token);
2014c87c5fbaSopenharmony_ci  /* M needs to be unset as 'asking' for only the first block */
2015c87c5fbaSopenharmony_ci  coap_insert_option(pdu, COAP_OPTION_Q_BLOCK2,
2016c87c5fbaSopenharmony_ci                     coap_encode_var_safe(buf, sizeof(buf),
2017c87c5fbaSopenharmony_ci                                          (0 << 4) | (0 << 3) | 0),
2018c87c5fbaSopenharmony_ci                     buf);
2019c87c5fbaSopenharmony_ci  set_block_mode_probe_q(session->block_mode);
2020c87c5fbaSopenharmony_ci  mid = coap_send_internal(session, pdu);
2021c87c5fbaSopenharmony_ci  if (mid == COAP_INVALID_MID)
2022c87c5fbaSopenharmony_ci    return COAP_INVALID_MID;
2023c87c5fbaSopenharmony_ci  session->remote_test_mid = mid;
2024c87c5fbaSopenharmony_ci  return mid;
2025c87c5fbaSopenharmony_ci}
2026c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2027c87c5fbaSopenharmony_ci
2028c87c5fbaSopenharmony_cicoap_lg_crcv_t *
2029c87c5fbaSopenharmony_cicoap_block_new_lg_crcv(coap_session_t *session, coap_pdu_t *pdu,
2030c87c5fbaSopenharmony_ci                       coap_lg_xmit_t *lg_xmit) {
2031c87c5fbaSopenharmony_ci  coap_lg_crcv_t *lg_crcv;
2032c87c5fbaSopenharmony_ci  uint64_t state_token = STATE_TOKEN_FULL(++session->tx_token, 1);
2033c87c5fbaSopenharmony_ci  size_t token_options = pdu->data ? (size_t)(pdu->data - pdu->token) :
2034c87c5fbaSopenharmony_ci                         pdu->used_size;
2035c87c5fbaSopenharmony_ci  size_t data_len = lg_xmit ? lg_xmit->length :
2036c87c5fbaSopenharmony_ci                    pdu->data ?
2037c87c5fbaSopenharmony_ci                    pdu->used_size - (pdu->data - pdu->token) : 0;
2038c87c5fbaSopenharmony_ci
2039c87c5fbaSopenharmony_ci  lg_crcv = coap_malloc_type(COAP_LG_CRCV, sizeof(coap_lg_crcv_t));
2040c87c5fbaSopenharmony_ci
2041c87c5fbaSopenharmony_ci  if (lg_crcv == NULL)
2042c87c5fbaSopenharmony_ci    return NULL;
2043c87c5fbaSopenharmony_ci
2044c87c5fbaSopenharmony_ci  coap_log_debug("** %s: lg_crcv %p initialized - stateless token xxxx%012llx\n",
2045c87c5fbaSopenharmony_ci                 coap_session_str(session), (void *)lg_crcv,
2046c87c5fbaSopenharmony_ci                 STATE_TOKEN_BASE(state_token));
2047c87c5fbaSopenharmony_ci  memset(lg_crcv, 0, sizeof(coap_lg_crcv_t));
2048c87c5fbaSopenharmony_ci  lg_crcv->initial = 1;
2049c87c5fbaSopenharmony_ci  coap_ticks(&lg_crcv->last_used);
2050c87c5fbaSopenharmony_ci  /* Set up skeletal PDU to use as a basis for all the subsequent blocks */
2051c87c5fbaSopenharmony_ci  memcpy(&lg_crcv->pdu, pdu, sizeof(lg_crcv->pdu));
2052c87c5fbaSopenharmony_ci  /* Make sure that there is space for increased token + option change */
2053c87c5fbaSopenharmony_ci  lg_crcv->pdu.max_size = token_options + data_len + 9;
2054c87c5fbaSopenharmony_ci  lg_crcv->pdu.used_size = token_options + data_len;
2055c87c5fbaSopenharmony_ci  lg_crcv->pdu.token = coap_malloc_type(COAP_PDU_BUF,
2056c87c5fbaSopenharmony_ci                                        token_options + data_len + lg_crcv->pdu.max_hdr_size);
2057c87c5fbaSopenharmony_ci  if (!lg_crcv->pdu.token) {
2058c87c5fbaSopenharmony_ci    coap_block_delete_lg_crcv(session, lg_crcv);
2059c87c5fbaSopenharmony_ci    return NULL;
2060c87c5fbaSopenharmony_ci  }
2061c87c5fbaSopenharmony_ci  lg_crcv->pdu.token += lg_crcv->pdu.max_hdr_size;
2062c87c5fbaSopenharmony_ci  memcpy(lg_crcv->pdu.token, pdu->token, token_options);
2063c87c5fbaSopenharmony_ci  if (lg_crcv->pdu.data) {
2064c87c5fbaSopenharmony_ci    lg_crcv->pdu.data = lg_crcv->pdu.token + token_options;
2065c87c5fbaSopenharmony_ci    memcpy(lg_crcv->pdu.data, lg_xmit ? lg_xmit->data : pdu->data, data_len);
2066c87c5fbaSopenharmony_ci  }
2067c87c5fbaSopenharmony_ci
2068c87c5fbaSopenharmony_ci  /* Need to keep original token for updating response PDUs */
2069c87c5fbaSopenharmony_ci  lg_crcv->app_token = coap_new_binary(pdu->actual_token.length);
2070c87c5fbaSopenharmony_ci  if (!lg_crcv->app_token) {
2071c87c5fbaSopenharmony_ci    coap_block_delete_lg_crcv(session, lg_crcv);
2072c87c5fbaSopenharmony_ci    return NULL;
2073c87c5fbaSopenharmony_ci  }
2074c87c5fbaSopenharmony_ci  memcpy(lg_crcv->app_token->s, pdu->actual_token.s, pdu->actual_token.length);
2075c87c5fbaSopenharmony_ci
2076c87c5fbaSopenharmony_ci  /* Need to set up a base token for actual communications if retries needed */
2077c87c5fbaSopenharmony_ci  lg_crcv->retry_counter = 1;
2078c87c5fbaSopenharmony_ci  lg_crcv->state_token = state_token;
2079c87c5fbaSopenharmony_ci
2080c87c5fbaSopenharmony_ci  if (pdu->code == COAP_REQUEST_CODE_FETCH) {
2081c87c5fbaSopenharmony_ci    coap_bin_const_t *new_token;
2082c87c5fbaSopenharmony_ci
2083c87c5fbaSopenharmony_ci    /* Need to save/restore Observe Token for large FETCH */
2084c87c5fbaSopenharmony_ci    new_token = track_fetch_observe(pdu, lg_crcv, 0, &pdu->actual_token);
2085c87c5fbaSopenharmony_ci    if (new_token)
2086c87c5fbaSopenharmony_ci      coap_update_token(pdu, new_token->length, new_token->s);
2087c87c5fbaSopenharmony_ci  }
2088c87c5fbaSopenharmony_ci
2089c87c5fbaSopenharmony_ci  /* In case it is there - must not be in continuing request PDUs */
2090c87c5fbaSopenharmony_ci  coap_remove_option(&lg_crcv->pdu, COAP_OPTION_BLOCK1);
2091c87c5fbaSopenharmony_ci
2092c87c5fbaSopenharmony_ci  return lg_crcv;
2093c87c5fbaSopenharmony_ci}
2094c87c5fbaSopenharmony_ci
2095c87c5fbaSopenharmony_civoid
2096c87c5fbaSopenharmony_cicoap_block_delete_lg_crcv(coap_session_t *session,
2097c87c5fbaSopenharmony_ci                          coap_lg_crcv_t *lg_crcv) {
2098c87c5fbaSopenharmony_ci  size_t i;
2099c87c5fbaSopenharmony_ci
2100c87c5fbaSopenharmony_ci#if (COAP_MAX_LOGGING_LEVEL < _COAP_LOG_DEBUG)
2101c87c5fbaSopenharmony_ci  (void)session;
2102c87c5fbaSopenharmony_ci#endif
2103c87c5fbaSopenharmony_ci  if (lg_crcv == NULL)
2104c87c5fbaSopenharmony_ci    return;
2105c87c5fbaSopenharmony_ci
2106c87c5fbaSopenharmony_ci  if (lg_crcv->pdu.token)
2107c87c5fbaSopenharmony_ci    coap_free_type(COAP_PDU_BUF, lg_crcv->pdu.token - lg_crcv->pdu.max_hdr_size);
2108c87c5fbaSopenharmony_ci  coap_free_type(COAP_STRING, lg_crcv->body_data);
2109c87c5fbaSopenharmony_ci  coap_log_debug("** %s: lg_crcv %p released\n",
2110c87c5fbaSopenharmony_ci                 coap_session_str(session), (void *)lg_crcv);
2111c87c5fbaSopenharmony_ci  coap_delete_binary(lg_crcv->app_token);
2112c87c5fbaSopenharmony_ci  for (i = 0; i < lg_crcv->obs_token_cnt; i++) {
2113c87c5fbaSopenharmony_ci    coap_delete_bin_const(lg_crcv->obs_token[i]);
2114c87c5fbaSopenharmony_ci  }
2115c87c5fbaSopenharmony_ci  coap_free_type(COAP_STRING, lg_crcv->obs_token);
2116c87c5fbaSopenharmony_ci  coap_free_type(COAP_LG_CRCV, lg_crcv);
2117c87c5fbaSopenharmony_ci}
2118c87c5fbaSopenharmony_ci#endif /* COAP_CLIENT_SUPPORT */
2119c87c5fbaSopenharmony_ci
2120c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
2121c87c5fbaSopenharmony_civoid
2122c87c5fbaSopenharmony_cicoap_block_delete_lg_srcv(coap_session_t *session,
2123c87c5fbaSopenharmony_ci                          coap_lg_srcv_t *lg_srcv) {
2124c87c5fbaSopenharmony_ci#if (COAP_MAX_LOGGING_LEVEL < _COAP_LOG_DEBUG)
2125c87c5fbaSopenharmony_ci  (void)session;
2126c87c5fbaSopenharmony_ci#endif
2127c87c5fbaSopenharmony_ci  if (lg_srcv == NULL)
2128c87c5fbaSopenharmony_ci    return;
2129c87c5fbaSopenharmony_ci
2130c87c5fbaSopenharmony_ci  coap_delete_str_const(lg_srcv->uri_path);
2131c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2132c87c5fbaSopenharmony_ci  coap_delete_bin_const(lg_srcv->last_token);
2133c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2134c87c5fbaSopenharmony_ci  coap_free_type(COAP_STRING, lg_srcv->body_data);
2135c87c5fbaSopenharmony_ci  coap_log_debug("** %s: lg_srcv %p released\n",
2136c87c5fbaSopenharmony_ci                 coap_session_str(session), (void *)lg_srcv);
2137c87c5fbaSopenharmony_ci  coap_free_type(COAP_LG_SRCV, lg_srcv);
2138c87c5fbaSopenharmony_ci}
2139c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
2140c87c5fbaSopenharmony_ci
2141c87c5fbaSopenharmony_civoid
2142c87c5fbaSopenharmony_cicoap_block_delete_lg_xmit(coap_session_t *session,
2143c87c5fbaSopenharmony_ci                          coap_lg_xmit_t *lg_xmit) {
2144c87c5fbaSopenharmony_ci  if (lg_xmit == NULL)
2145c87c5fbaSopenharmony_ci    return;
2146c87c5fbaSopenharmony_ci
2147c87c5fbaSopenharmony_ci  if (lg_xmit->release_func) {
2148c87c5fbaSopenharmony_ci    lg_xmit->release_func(session, lg_xmit->app_ptr);
2149c87c5fbaSopenharmony_ci  }
2150c87c5fbaSopenharmony_ci  if (lg_xmit->pdu.token) {
2151c87c5fbaSopenharmony_ci    coap_free_type(COAP_PDU_BUF, lg_xmit->pdu.token - lg_xmit->pdu.max_hdr_size);
2152c87c5fbaSopenharmony_ci  }
2153c87c5fbaSopenharmony_ci  if (COAP_PDU_IS_REQUEST(&lg_xmit->pdu))
2154c87c5fbaSopenharmony_ci    coap_delete_binary(lg_xmit->b.b1.app_token);
2155c87c5fbaSopenharmony_ci  else
2156c87c5fbaSopenharmony_ci    coap_delete_string(lg_xmit->b.b2.query);
2157c87c5fbaSopenharmony_ci
2158c87c5fbaSopenharmony_ci  coap_log_debug("** %s: lg_xmit %p released\n",
2159c87c5fbaSopenharmony_ci                 coap_session_str(session), (void *)lg_xmit);
2160c87c5fbaSopenharmony_ci  coap_free_type(COAP_LG_XMIT, lg_xmit);
2161c87c5fbaSopenharmony_ci}
2162c87c5fbaSopenharmony_ci
2163c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
2164c87c5fbaSopenharmony_citypedef struct {
2165c87c5fbaSopenharmony_ci  uint32_t num;
2166c87c5fbaSopenharmony_ci  int is_continue;
2167c87c5fbaSopenharmony_ci} send_track;
2168c87c5fbaSopenharmony_ci
2169c87c5fbaSopenharmony_cistatic int
2170c87c5fbaSopenharmony_ciadd_block_send(uint32_t num, int is_continue, send_track *out_blocks,
2171c87c5fbaSopenharmony_ci               uint32_t *count, uint32_t max_count) {
2172c87c5fbaSopenharmony_ci  uint32_t i;
2173c87c5fbaSopenharmony_ci
2174c87c5fbaSopenharmony_ci  for (i = 0; i < *count && *count < max_count; i++) {
2175c87c5fbaSopenharmony_ci    if (num == out_blocks[i].num)
2176c87c5fbaSopenharmony_ci      return 0;
2177c87c5fbaSopenharmony_ci    else if (num < out_blocks[i].num) {
2178c87c5fbaSopenharmony_ci      if (*count - i > 1)
2179c87c5fbaSopenharmony_ci        memmove(&out_blocks[i], &out_blocks[i+1], *count - i -1);
2180c87c5fbaSopenharmony_ci      out_blocks[i].num = num;
2181c87c5fbaSopenharmony_ci      out_blocks[i].is_continue = is_continue;
2182c87c5fbaSopenharmony_ci      (*count)++;
2183c87c5fbaSopenharmony_ci      return 1;
2184c87c5fbaSopenharmony_ci    }
2185c87c5fbaSopenharmony_ci  }
2186c87c5fbaSopenharmony_ci  if (*count < max_count) {
2187c87c5fbaSopenharmony_ci    out_blocks[i].num = num;
2188c87c5fbaSopenharmony_ci    out_blocks[i].is_continue = is_continue;
2189c87c5fbaSopenharmony_ci    (*count)++;
2190c87c5fbaSopenharmony_ci    return 1;
2191c87c5fbaSopenharmony_ci  }
2192c87c5fbaSopenharmony_ci  return 0;
2193c87c5fbaSopenharmony_ci}
2194c87c5fbaSopenharmony_ci
2195c87c5fbaSopenharmony_ci/*
2196c87c5fbaSopenharmony_ci * Need to see if this is a request for the next block of a large body
2197c87c5fbaSopenharmony_ci * transfer.  If so, need to initiate the response with the next blocks
2198c87c5fbaSopenharmony_ci * and not trouble the application.
2199c87c5fbaSopenharmony_ci *
2200c87c5fbaSopenharmony_ci * If additional responses needed, then these are expicitly sent out and
2201c87c5fbaSopenharmony_ci * 'response' is updated to be the last response to be sent.  There can be
2202c87c5fbaSopenharmony_ci * multiple Q-Block2 in the request, as well as  the 'Continue' Q-Block2
2203c87c5fbaSopenharmony_ci * request.
2204c87c5fbaSopenharmony_ci *
2205c87c5fbaSopenharmony_ci * This is set up using coap_add_data_large_response()
2206c87c5fbaSopenharmony_ci *
2207c87c5fbaSopenharmony_ci * Server is sending a large data response to GET / observe (Block2)
2208c87c5fbaSopenharmony_ci *
2209c87c5fbaSopenharmony_ci * Return: 0 Call application handler
2210c87c5fbaSopenharmony_ci *         1 Do not call application handler - just send the built response
2211c87c5fbaSopenharmony_ci */
2212c87c5fbaSopenharmony_ciint
2213c87c5fbaSopenharmony_cicoap_handle_request_send_block(coap_session_t *session,
2214c87c5fbaSopenharmony_ci                               coap_pdu_t *pdu,
2215c87c5fbaSopenharmony_ci                               coap_pdu_t *response,
2216c87c5fbaSopenharmony_ci                               coap_resource_t *resource,
2217c87c5fbaSopenharmony_ci                               coap_string_t *query) {
2218c87c5fbaSopenharmony_ci  coap_lg_xmit_t *p = NULL;
2219c87c5fbaSopenharmony_ci  coap_block_b_t block;
2220c87c5fbaSopenharmony_ci  coap_block_b_t alt_block;
2221c87c5fbaSopenharmony_ci  uint16_t block_opt = 0;
2222c87c5fbaSopenharmony_ci  send_track *out_blocks = NULL;
2223c87c5fbaSopenharmony_ci  const char *error_phrase;
2224c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
2225c87c5fbaSopenharmony_ci  size_t chunk;
2226c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_b_iter;
2227c87c5fbaSopenharmony_ci  coap_opt_t *option;
2228c87c5fbaSopenharmony_ci  uint32_t request_cnt, i;
2229c87c5fbaSopenharmony_ci  coap_opt_t *etag_opt = NULL;
2230c87c5fbaSopenharmony_ci  coap_pdu_t *out_pdu = response;
2231c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2232c87c5fbaSopenharmony_ci  size_t max_block;
2233c87c5fbaSopenharmony_ci
2234c87c5fbaSopenharmony_ci  /* Is client indicating that it supports Q_BLOCK2 ? */
2235c87c5fbaSopenharmony_ci  if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK2, &block)) {
2236c87c5fbaSopenharmony_ci    if (!(session->block_mode & COAP_BLOCK_HAS_Q_BLOCK))
2237c87c5fbaSopenharmony_ci      set_block_mode_has_q(session->block_mode);
2238c87c5fbaSopenharmony_ci    block_opt = COAP_OPTION_Q_BLOCK2;
2239c87c5fbaSopenharmony_ci  }
2240c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2241c87c5fbaSopenharmony_ci  if (coap_get_block_b(session, pdu, COAP_OPTION_BLOCK2, &alt_block)) {
2242c87c5fbaSopenharmony_ci    if (block_opt) {
2243c87c5fbaSopenharmony_ci      coap_log_warn("Block2 and Q-Block2 cannot be in the same request\n");
2244c87c5fbaSopenharmony_ci      coap_add_data(response, sizeof("Both Block2 and Q-Block2 invalid")-1,
2245c87c5fbaSopenharmony_ci                    (const uint8_t *)"Both Block2 and Q-Block2 invalid");
2246c87c5fbaSopenharmony_ci      response->code = COAP_RESPONSE_CODE(400);
2247c87c5fbaSopenharmony_ci      goto skip_app_handler;
2248c87c5fbaSopenharmony_ci    }
2249c87c5fbaSopenharmony_ci    block = alt_block;
2250c87c5fbaSopenharmony_ci    block_opt = COAP_OPTION_BLOCK2;
2251c87c5fbaSopenharmony_ci  }
2252c87c5fbaSopenharmony_ci  if (block_opt == 0)
2253c87c5fbaSopenharmony_ci    return 0;
2254c87c5fbaSopenharmony_ci  if (block.num == 0) {
2255c87c5fbaSopenharmony_ci    /* Get a fresh copy of the data */
2256c87c5fbaSopenharmony_ci    return 0;
2257c87c5fbaSopenharmony_ci  }
2258c87c5fbaSopenharmony_ci  p = coap_find_lg_xmit_response(session, pdu, resource, query);
2259c87c5fbaSopenharmony_ci  if (p == NULL)
2260c87c5fbaSopenharmony_ci    return 0;
2261c87c5fbaSopenharmony_ci
2262c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2263c87c5fbaSopenharmony_ci  out_blocks = coap_malloc_type(COAP_STRING, sizeof(send_track) * COAP_MAX_PAYLOADS(session));
2264c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
2265c87c5fbaSopenharmony_ci  out_blocks = coap_malloc_type(COAP_STRING, sizeof(send_track));
2266c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
2267c87c5fbaSopenharmony_ci  if (!out_blocks) {
2268c87c5fbaSopenharmony_ci    goto internal_issue;
2269c87c5fbaSopenharmony_ci  }
2270c87c5fbaSopenharmony_ci
2271c87c5fbaSopenharmony_ci  /* lg_xmit (response) found */
2272c87c5fbaSopenharmony_ci
2273c87c5fbaSopenharmony_ci  etag_opt = coap_check_option(pdu, COAP_OPTION_ETAG, &opt_iter);
2274c87c5fbaSopenharmony_ci  if (etag_opt) {
2275c87c5fbaSopenharmony_ci    uint64_t etag = coap_decode_var_bytes8(coap_opt_value(etag_opt),
2276c87c5fbaSopenharmony_ci                                           coap_opt_length(etag_opt));
2277c87c5fbaSopenharmony_ci    if (etag != p->b.b2.etag) {
2278c87c5fbaSopenharmony_ci      /* Not a match - pass up to a higher level */
2279c87c5fbaSopenharmony_ci      return 0;
2280c87c5fbaSopenharmony_ci    }
2281c87c5fbaSopenharmony_ci    out_pdu->code = COAP_RESPONSE_CODE(203);
2282c87c5fbaSopenharmony_ci    coap_ticks(&p->last_sent);
2283c87c5fbaSopenharmony_ci    goto skip_app_handler;
2284c87c5fbaSopenharmony_ci  } else {
2285c87c5fbaSopenharmony_ci    out_pdu->code = p->pdu.code;
2286c87c5fbaSopenharmony_ci  }
2287c87c5fbaSopenharmony_ci  coap_ticks(&p->last_obs);
2288c87c5fbaSopenharmony_ci  p->last_all_sent = 0;
2289c87c5fbaSopenharmony_ci
2290c87c5fbaSopenharmony_ci  chunk = (size_t)1 << (p->blk_size + 4);
2291c87c5fbaSopenharmony_ci  if (block_opt) {
2292c87c5fbaSopenharmony_ci    if (block.bert) {
2293c87c5fbaSopenharmony_ci      coap_log_debug("found Block option, block is BERT, block nr. %u, M %d\n",
2294c87c5fbaSopenharmony_ci                     block.num, block.m);
2295c87c5fbaSopenharmony_ci    } else {
2296c87c5fbaSopenharmony_ci      coap_log_debug("found Block option, block size is %u, block nr. %u, M %d\n",
2297c87c5fbaSopenharmony_ci                     1 << (block.szx + 4), block.num, block.m);
2298c87c5fbaSopenharmony_ci    }
2299c87c5fbaSopenharmony_ci    if (block.bert == 0 && block.szx != p->blk_size) {
2300c87c5fbaSopenharmony_ci      if ((p->offset + chunk) % ((size_t)1 << (block.szx + 4)) == 0) {
2301c87c5fbaSopenharmony_ci        /*
2302c87c5fbaSopenharmony_ci         * Recompute the block number of the previous packet given
2303c87c5fbaSopenharmony_ci         * the new block size
2304c87c5fbaSopenharmony_ci         */
2305c87c5fbaSopenharmony_ci        block.num = (uint32_t)(((p->offset + chunk) >> (block.szx + 4)) - 1);
2306c87c5fbaSopenharmony_ci        p->blk_size = block.szx;
2307c87c5fbaSopenharmony_ci        chunk = (size_t)1 << (p->blk_size + 4);
2308c87c5fbaSopenharmony_ci        p->offset = block.num * chunk;
2309c87c5fbaSopenharmony_ci        coap_log_debug("new Block size is %u, block number %u completed\n",
2310c87c5fbaSopenharmony_ci                       1 << (block.szx + 4), block.num);
2311c87c5fbaSopenharmony_ci      } else {
2312c87c5fbaSopenharmony_ci        coap_log_debug("ignoring request to increase Block size, "
2313c87c5fbaSopenharmony_ci                       "next block is not aligned on requested block size "
2314c87c5fbaSopenharmony_ci                       "boundary. (%zu x %u mod %u = %zu (which is not 0)\n",
2315c87c5fbaSopenharmony_ci                       p->offset/chunk + 1, (1 << (p->blk_size + 4)),
2316c87c5fbaSopenharmony_ci                       (1 << (block.szx + 4)),
2317c87c5fbaSopenharmony_ci                       (p->offset + chunk) % ((size_t)1 << (block.szx + 4)));
2318c87c5fbaSopenharmony_ci      }
2319c87c5fbaSopenharmony_ci    }
2320c87c5fbaSopenharmony_ci  }
2321c87c5fbaSopenharmony_ci
2322c87c5fbaSopenharmony_ci  /*
2323c87c5fbaSopenharmony_ci   * Need to check if there are multiple Q-Block2 requests.  If so, they
2324c87c5fbaSopenharmony_ci   * need to be sent out in order of requests with the final request being
2325c87c5fbaSopenharmony_ci   * handled as per singular Block 2 request.
2326c87c5fbaSopenharmony_ci   */
2327c87c5fbaSopenharmony_ci  request_cnt = 0;
2328c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2329c87c5fbaSopenharmony_ci  max_block = (p->length + chunk - 1)/chunk;
2330c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2331c87c5fbaSopenharmony_ci  coap_option_iterator_init(pdu, &opt_b_iter, COAP_OPT_ALL);
2332c87c5fbaSopenharmony_ci  while ((option = coap_option_next(&opt_b_iter))) {
2333c87c5fbaSopenharmony_ci    unsigned int num;
2334c87c5fbaSopenharmony_ci    if (opt_b_iter.number != p->option)
2335c87c5fbaSopenharmony_ci      continue;
2336c87c5fbaSopenharmony_ci    num = coap_opt_block_num(option);
2337c87c5fbaSopenharmony_ci    if (num > 0xFFFFF) /* 20 bits max for num */
2338c87c5fbaSopenharmony_ci      continue;
2339c87c5fbaSopenharmony_ci    if (block.aszx != COAP_OPT_BLOCK_SZX(option)) {
2340c87c5fbaSopenharmony_ci      coap_add_data(response,
2341c87c5fbaSopenharmony_ci                    sizeof("Changing blocksize during request invalid")-1,
2342c87c5fbaSopenharmony_ci                    (const uint8_t *)"Changing blocksize during request invalid");
2343c87c5fbaSopenharmony_ci      response->code = COAP_RESPONSE_CODE(400);
2344c87c5fbaSopenharmony_ci      goto skip_app_handler;
2345c87c5fbaSopenharmony_ci    }
2346c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2347c87c5fbaSopenharmony_ci    if (COAP_OPT_BLOCK_MORE(option) && p->option == COAP_OPTION_Q_BLOCK2) {
2348c87c5fbaSopenharmony_ci      if ((num % COAP_MAX_PAYLOADS(session)) == 0) {
2349c87c5fbaSopenharmony_ci        if (num == 0) {
2350c87c5fbaSopenharmony_ci          /* This is a repeat request for everything - hmm */
2351c87c5fbaSopenharmony_ci          goto call_app_handler;
2352c87c5fbaSopenharmony_ci        }
2353c87c5fbaSopenharmony_ci        /* 'Continue' request */
2354c87c5fbaSopenharmony_ci        for (i = 0; i < COAP_MAX_PAYLOADS(session) &&
2355c87c5fbaSopenharmony_ci             num + i < max_block; i++) {
2356c87c5fbaSopenharmony_ci          add_block_send(num + i, 1, out_blocks, &request_cnt,
2357c87c5fbaSopenharmony_ci                         COAP_MAX_PAYLOADS(session));
2358c87c5fbaSopenharmony_ci          p->last_block = num + i;
2359c87c5fbaSopenharmony_ci        }
2360c87c5fbaSopenharmony_ci      } else {
2361c87c5fbaSopenharmony_ci        /* Requesting remaining payloads in this MAX_PAYLOADS */
2362c87c5fbaSopenharmony_ci        for (i = 0; i < COAP_MAX_PAYLOADS(session) -
2363c87c5fbaSopenharmony_ci             num % COAP_MAX_PAYLOADS(session) &&
2364c87c5fbaSopenharmony_ci             num + i < max_block; i++) {
2365c87c5fbaSopenharmony_ci          add_block_send(num + i, 0, out_blocks, &request_cnt,
2366c87c5fbaSopenharmony_ci                         COAP_MAX_PAYLOADS(session));
2367c87c5fbaSopenharmony_ci        }
2368c87c5fbaSopenharmony_ci      }
2369c87c5fbaSopenharmony_ci    } else
2370c87c5fbaSopenharmony_ci      add_block_send(num, 0, out_blocks, &request_cnt,
2371c87c5fbaSopenharmony_ci                     COAP_MAX_PAYLOADS(session));
2372c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
2373c87c5fbaSopenharmony_ci    add_block_send(num, 0, out_blocks, &request_cnt, 1);
2374c87c5fbaSopenharmony_ci    break;
2375c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
2376c87c5fbaSopenharmony_ci  }
2377c87c5fbaSopenharmony_ci  if (request_cnt == 0) {
2378c87c5fbaSopenharmony_ci    /* Block2 or Q-Block2 not found - give them the first block */
2379c87c5fbaSopenharmony_ci    block.szx = p->blk_size;
2380c87c5fbaSopenharmony_ci    p->offset = 0;
2381c87c5fbaSopenharmony_ci    out_blocks[0].num = 0;
2382c87c5fbaSopenharmony_ci    out_blocks[0].is_continue = 0;
2383c87c5fbaSopenharmony_ci    request_cnt = 1;
2384c87c5fbaSopenharmony_ci  }
2385c87c5fbaSopenharmony_ci
2386c87c5fbaSopenharmony_ci  for (i = 0; i < request_cnt; i++) {
2387c87c5fbaSopenharmony_ci    uint8_t buf[8];
2388c87c5fbaSopenharmony_ci
2389c87c5fbaSopenharmony_ci    block.num = out_blocks[i].num;
2390c87c5fbaSopenharmony_ci    p->offset = block.num * chunk;
2391c87c5fbaSopenharmony_ci
2392c87c5fbaSopenharmony_ci    if (i + 1 < request_cnt) {
2393c87c5fbaSopenharmony_ci      /* Need to set up a copy of the pdu to send */
2394c87c5fbaSopenharmony_ci      coap_opt_filter_t drop_options;
2395c87c5fbaSopenharmony_ci
2396c87c5fbaSopenharmony_ci      memset(&drop_options, 0, sizeof(coap_opt_filter_t));
2397c87c5fbaSopenharmony_ci      if (block.num != 0)
2398c87c5fbaSopenharmony_ci        coap_option_filter_set(&drop_options, COAP_OPTION_OBSERVE);
2399c87c5fbaSopenharmony_ci      if (out_blocks[i].is_continue) {
2400c87c5fbaSopenharmony_ci        out_pdu = coap_pdu_duplicate(&p->pdu, session, p->pdu.actual_token.length,
2401c87c5fbaSopenharmony_ci                                     p->pdu.actual_token.s, &drop_options);
2402c87c5fbaSopenharmony_ci      } else {
2403c87c5fbaSopenharmony_ci        out_pdu = coap_pdu_duplicate(&p->pdu, session, pdu->actual_token.length,
2404c87c5fbaSopenharmony_ci                                     pdu->actual_token.s, &drop_options);
2405c87c5fbaSopenharmony_ci      }
2406c87c5fbaSopenharmony_ci      if (!out_pdu) {
2407c87c5fbaSopenharmony_ci        goto internal_issue;
2408c87c5fbaSopenharmony_ci      }
2409c87c5fbaSopenharmony_ci    } else {
2410c87c5fbaSopenharmony_ci      if (out_blocks[i].is_continue)
2411c87c5fbaSopenharmony_ci        coap_update_token(response, p->pdu.actual_token.length,
2412c87c5fbaSopenharmony_ci                          p->pdu.actual_token.s);
2413c87c5fbaSopenharmony_ci      /*
2414c87c5fbaSopenharmony_ci       * Copy the options across and then fix the block option
2415c87c5fbaSopenharmony_ci       *
2416c87c5fbaSopenharmony_ci       * Need to drop Observe option if Block2 and block.num != 0
2417c87c5fbaSopenharmony_ci       */
2418c87c5fbaSopenharmony_ci      coap_option_iterator_init(&p->pdu, &opt_iter, COAP_OPT_ALL);
2419c87c5fbaSopenharmony_ci      while ((option = coap_option_next(&opt_iter))) {
2420c87c5fbaSopenharmony_ci        if (opt_iter.number == COAP_OPTION_OBSERVE && block.num != 0)
2421c87c5fbaSopenharmony_ci          continue;
2422c87c5fbaSopenharmony_ci        if (!coap_insert_option(response, opt_iter.number,
2423c87c5fbaSopenharmony_ci                                coap_opt_length(option),
2424c87c5fbaSopenharmony_ci                                coap_opt_value(option))) {
2425c87c5fbaSopenharmony_ci          goto internal_issue;
2426c87c5fbaSopenharmony_ci        }
2427c87c5fbaSopenharmony_ci      }
2428c87c5fbaSopenharmony_ci      out_pdu = response;
2429c87c5fbaSopenharmony_ci    }
2430c87c5fbaSopenharmony_ci    if (pdu->type == COAP_MESSAGE_NON)
2431c87c5fbaSopenharmony_ci      out_pdu->type = COAP_MESSAGE_NON;
2432c87c5fbaSopenharmony_ci    if (block.bert) {
2433c87c5fbaSopenharmony_ci      size_t token_options = pdu->data ? (size_t)(pdu->data - pdu->token) : pdu->used_size;
2434c87c5fbaSopenharmony_ci      block.m = (p->length - p->offset) >
2435c87c5fbaSopenharmony_ci                ((out_pdu->max_size - token_options) /1024) * 1024;
2436c87c5fbaSopenharmony_ci    } else {
2437c87c5fbaSopenharmony_ci      block.m = (p->offset + chunk) < p->length;
2438c87c5fbaSopenharmony_ci    }
2439c87c5fbaSopenharmony_ci    if (!coap_update_option(out_pdu, p->option,
2440c87c5fbaSopenharmony_ci                            coap_encode_var_safe(buf,
2441c87c5fbaSopenharmony_ci                                                 sizeof(buf),
2442c87c5fbaSopenharmony_ci                                                 (block.num << 4) |
2443c87c5fbaSopenharmony_ci                                                 (block.m << 3) |
2444c87c5fbaSopenharmony_ci                                                 block.aszx),
2445c87c5fbaSopenharmony_ci                            buf)) {
2446c87c5fbaSopenharmony_ci      goto internal_issue;
2447c87c5fbaSopenharmony_ci    }
2448c87c5fbaSopenharmony_ci    if (!(p->offset + chunk < p->length)) {
2449c87c5fbaSopenharmony_ci      /* Last block - keep in cache for 4 * ACK_TIMOUT */
2450c87c5fbaSopenharmony_ci      coap_ticks(&p->last_all_sent);
2451c87c5fbaSopenharmony_ci    }
2452c87c5fbaSopenharmony_ci    if (p->b.b2.maxage_expire) {
2453c87c5fbaSopenharmony_ci      coap_tick_t now;
2454c87c5fbaSopenharmony_ci      coap_time_t rem;
2455c87c5fbaSopenharmony_ci
2456c87c5fbaSopenharmony_ci      if (!(p->offset + chunk < p->length)) {
2457c87c5fbaSopenharmony_ci        /* Last block - keep in cache for 4 * ACK_TIMOUT */
2458c87c5fbaSopenharmony_ci        coap_ticks(&p->last_all_sent);
2459c87c5fbaSopenharmony_ci      }
2460c87c5fbaSopenharmony_ci      coap_ticks(&now);
2461c87c5fbaSopenharmony_ci      rem = coap_ticks_to_rt(now);
2462c87c5fbaSopenharmony_ci      if (p->b.b2.maxage_expire > rem) {
2463c87c5fbaSopenharmony_ci        rem = p->b.b2.maxage_expire - rem;
2464c87c5fbaSopenharmony_ci      } else {
2465c87c5fbaSopenharmony_ci        rem = 0;
2466c87c5fbaSopenharmony_ci        /* Entry needs to be expired */
2467c87c5fbaSopenharmony_ci        coap_ticks(&p->last_all_sent);
2468c87c5fbaSopenharmony_ci      }
2469c87c5fbaSopenharmony_ci      if (!coap_update_option(out_pdu, COAP_OPTION_MAXAGE,
2470c87c5fbaSopenharmony_ci                              coap_encode_var_safe8(buf,
2471c87c5fbaSopenharmony_ci                                                    sizeof(buf),
2472c87c5fbaSopenharmony_ci                                                    rem),
2473c87c5fbaSopenharmony_ci                              buf)) {
2474c87c5fbaSopenharmony_ci        goto internal_issue;
2475c87c5fbaSopenharmony_ci      }
2476c87c5fbaSopenharmony_ci    }
2477c87c5fbaSopenharmony_ci
2478c87c5fbaSopenharmony_ci    if (!etag_opt && !coap_add_block_b_data(out_pdu,
2479c87c5fbaSopenharmony_ci                                            p->length,
2480c87c5fbaSopenharmony_ci                                            p->data,
2481c87c5fbaSopenharmony_ci                                            &block)) {
2482c87c5fbaSopenharmony_ci      goto internal_issue;
2483c87c5fbaSopenharmony_ci    }
2484c87c5fbaSopenharmony_ci    if (i + 1 < request_cnt) {
2485c87c5fbaSopenharmony_ci      coap_ticks(&p->last_sent);
2486c87c5fbaSopenharmony_ci      coap_send_internal(session, out_pdu);
2487c87c5fbaSopenharmony_ci    }
2488c87c5fbaSopenharmony_ci  }
2489c87c5fbaSopenharmony_ci  coap_ticks(&p->last_payload);
2490c87c5fbaSopenharmony_ci  goto skip_app_handler;
2491c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2492c87c5fbaSopenharmony_cicall_app_handler:
2493c87c5fbaSopenharmony_ci  coap_free_type(COAP_STRING, out_blocks);
2494c87c5fbaSopenharmony_ci  return 0;
2495c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2496c87c5fbaSopenharmony_ci
2497c87c5fbaSopenharmony_ciinternal_issue:
2498c87c5fbaSopenharmony_ci  response->code = COAP_RESPONSE_CODE(500);
2499c87c5fbaSopenharmony_ci  error_phrase = coap_response_phrase(response->code);
2500c87c5fbaSopenharmony_ci  coap_add_data(response, strlen(error_phrase),
2501c87c5fbaSopenharmony_ci                (const uint8_t *)error_phrase);
2502c87c5fbaSopenharmony_ci  /* Keep in cache for 4 * ACK_TIMOUT incase of retry */
2503c87c5fbaSopenharmony_ci  if (p)
2504c87c5fbaSopenharmony_ci    coap_ticks(&p->last_all_sent);
2505c87c5fbaSopenharmony_ci
2506c87c5fbaSopenharmony_ciskip_app_handler:
2507c87c5fbaSopenharmony_ci  coap_free_type(COAP_STRING, out_blocks);
2508c87c5fbaSopenharmony_ci  return 1;
2509c87c5fbaSopenharmony_ci}
2510c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
2511c87c5fbaSopenharmony_ci
2512c87c5fbaSopenharmony_cistatic int
2513c87c5fbaSopenharmony_ciupdate_received_blocks(coap_rblock_t *rec_blocks, uint32_t block_num) {
2514c87c5fbaSopenharmony_ci  uint32_t i;
2515c87c5fbaSopenharmony_ci
2516c87c5fbaSopenharmony_ci  /* Reset as there is activity */
2517c87c5fbaSopenharmony_ci  rec_blocks->retry = 0;
2518c87c5fbaSopenharmony_ci
2519c87c5fbaSopenharmony_ci  for (i = 0; i < rec_blocks->used; i++) {
2520c87c5fbaSopenharmony_ci    if (block_num >= rec_blocks->range[i].begin &&
2521c87c5fbaSopenharmony_ci        block_num <= rec_blocks->range[i].end)
2522c87c5fbaSopenharmony_ci      break;
2523c87c5fbaSopenharmony_ci
2524c87c5fbaSopenharmony_ci    if (block_num < rec_blocks->range[i].begin) {
2525c87c5fbaSopenharmony_ci      if (block_num + 1 == rec_blocks->range[i].begin) {
2526c87c5fbaSopenharmony_ci        rec_blocks->range[i].begin = block_num;
2527c87c5fbaSopenharmony_ci      } else {
2528c87c5fbaSopenharmony_ci        /* Need to insert a new range */
2529c87c5fbaSopenharmony_ci        if (rec_blocks->used == COAP_RBLOCK_CNT -1)
2530c87c5fbaSopenharmony_ci          /* Too many losses */
2531c87c5fbaSopenharmony_ci          return 0;
2532c87c5fbaSopenharmony_ci        memmove(&rec_blocks->range[i+1], &rec_blocks->range[i],
2533c87c5fbaSopenharmony_ci                (rec_blocks->used - i) * sizeof(rec_blocks->range[0]));
2534c87c5fbaSopenharmony_ci        rec_blocks->range[i].begin = rec_blocks->range[i].end = block_num;
2535c87c5fbaSopenharmony_ci        rec_blocks->used++;
2536c87c5fbaSopenharmony_ci      }
2537c87c5fbaSopenharmony_ci      break;
2538c87c5fbaSopenharmony_ci    }
2539c87c5fbaSopenharmony_ci    if (block_num == rec_blocks->range[i].end + 1) {
2540c87c5fbaSopenharmony_ci      rec_blocks->range[i].end = block_num;
2541c87c5fbaSopenharmony_ci      if (i + 1 < rec_blocks->used) {
2542c87c5fbaSopenharmony_ci        if (rec_blocks->range[i+1].begin == block_num + 1) {
2543c87c5fbaSopenharmony_ci          /* Merge the 2 ranges */
2544c87c5fbaSopenharmony_ci          rec_blocks->range[i].end = rec_blocks->range[i+1].end;
2545c87c5fbaSopenharmony_ci          if (i+2 < rec_blocks->used) {
2546c87c5fbaSopenharmony_ci            memmove(&rec_blocks->range[i+1], &rec_blocks->range[i+2],
2547c87c5fbaSopenharmony_ci                    (rec_blocks->used - (i+2)) * sizeof(rec_blocks->range[0]));
2548c87c5fbaSopenharmony_ci          }
2549c87c5fbaSopenharmony_ci          rec_blocks->used--;
2550c87c5fbaSopenharmony_ci        }
2551c87c5fbaSopenharmony_ci      }
2552c87c5fbaSopenharmony_ci      break;
2553c87c5fbaSopenharmony_ci    }
2554c87c5fbaSopenharmony_ci  }
2555c87c5fbaSopenharmony_ci  if (i == rec_blocks->used) {
2556c87c5fbaSopenharmony_ci    if (rec_blocks->used == COAP_RBLOCK_CNT -1)
2557c87c5fbaSopenharmony_ci      /* Too many losses */
2558c87c5fbaSopenharmony_ci      return 0;
2559c87c5fbaSopenharmony_ci    rec_blocks->range[i].begin = rec_blocks->range[i].end = block_num;
2560c87c5fbaSopenharmony_ci    rec_blocks->used++;
2561c87c5fbaSopenharmony_ci  }
2562c87c5fbaSopenharmony_ci  coap_ticks(&rec_blocks->last_seen);
2563c87c5fbaSopenharmony_ci  return 1;
2564c87c5fbaSopenharmony_ci}
2565c87c5fbaSopenharmony_ci
2566c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
2567c87c5fbaSopenharmony_ci/*
2568c87c5fbaSopenharmony_ci * Need to check if this is a large PUT / POST using multiple blocks
2569c87c5fbaSopenharmony_ci *
2570c87c5fbaSopenharmony_ci * Server receiving PUT/POST etc. of a large amount of data (Block1)
2571c87c5fbaSopenharmony_ci *
2572c87c5fbaSopenharmony_ci * Return: 0 Call application handler
2573c87c5fbaSopenharmony_ci *         1 Do not call application handler - just send the built response
2574c87c5fbaSopenharmony_ci */
2575c87c5fbaSopenharmony_ciint
2576c87c5fbaSopenharmony_cicoap_handle_request_put_block(coap_context_t *context,
2577c87c5fbaSopenharmony_ci                              coap_session_t *session,
2578c87c5fbaSopenharmony_ci                              coap_pdu_t *pdu,
2579c87c5fbaSopenharmony_ci                              coap_pdu_t *response,
2580c87c5fbaSopenharmony_ci                              coap_resource_t *resource,
2581c87c5fbaSopenharmony_ci                              coap_string_t *uri_path,
2582c87c5fbaSopenharmony_ci                              coap_opt_t *observe,
2583c87c5fbaSopenharmony_ci                              int *added_block,
2584c87c5fbaSopenharmony_ci                              coap_lg_srcv_t **pfree_lg_srcv) {
2585c87c5fbaSopenharmony_ci  size_t length = 0;
2586c87c5fbaSopenharmony_ci  const uint8_t *data = NULL;
2587c87c5fbaSopenharmony_ci  size_t offset = 0;
2588c87c5fbaSopenharmony_ci  size_t total = 0;
2589c87c5fbaSopenharmony_ci  coap_block_b_t block;
2590c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
2591c87c5fbaSopenharmony_ci  uint16_t block_option = 0;
2592c87c5fbaSopenharmony_ci
2593c87c5fbaSopenharmony_ci  *added_block = 0;
2594c87c5fbaSopenharmony_ci  *pfree_lg_srcv = NULL;
2595c87c5fbaSopenharmony_ci  coap_get_data_large(pdu, &length, &data, &offset, &total);
2596c87c5fbaSopenharmony_ci  pdu->body_offset = 0;
2597c87c5fbaSopenharmony_ci  pdu->body_total = length;
2598c87c5fbaSopenharmony_ci
2599c87c5fbaSopenharmony_ci  if (coap_get_block_b(session, pdu, COAP_OPTION_BLOCK1, &block)) {
2600c87c5fbaSopenharmony_ci    block_option = COAP_OPTION_BLOCK1;
2601c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2602c87c5fbaSopenharmony_ci    if (coap_check_option(pdu, COAP_OPTION_Q_BLOCK1, &opt_iter)) {
2603c87c5fbaSopenharmony_ci      /* Cannot handle Q-Block1 as well */
2604c87c5fbaSopenharmony_ci      coap_add_data(response, sizeof("Block1 + Q-Block1 together")-1,
2605c87c5fbaSopenharmony_ci                    (const uint8_t *)"Block1 + Q-Block1 together");
2606c87c5fbaSopenharmony_ci      response->code = COAP_RESPONSE_CODE(402);
2607c87c5fbaSopenharmony_ci      goto skip_app_handler;
2608c87c5fbaSopenharmony_ci    }
2609c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2610c87c5fbaSopenharmony_ci  }
2611c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2612c87c5fbaSopenharmony_ci  else if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK1, &block)) {
2613c87c5fbaSopenharmony_ci    block_option = COAP_OPTION_Q_BLOCK1;
2614c87c5fbaSopenharmony_ci    set_block_mode_has_q(session->block_mode);
2615c87c5fbaSopenharmony_ci  }
2616c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2617c87c5fbaSopenharmony_ci  if (block_option) {
2618c87c5fbaSopenharmony_ci    coap_lg_srcv_t *p;
2619c87c5fbaSopenharmony_ci    coap_opt_t *size_opt = coap_check_option(pdu,
2620c87c5fbaSopenharmony_ci                                             COAP_OPTION_SIZE1,
2621c87c5fbaSopenharmony_ci                                             &opt_iter);
2622c87c5fbaSopenharmony_ci    coap_opt_t *fmt_opt = coap_check_option(pdu,
2623c87c5fbaSopenharmony_ci                                            COAP_OPTION_CONTENT_FORMAT,
2624c87c5fbaSopenharmony_ci                                            &opt_iter);
2625c87c5fbaSopenharmony_ci    uint16_t fmt = fmt_opt ? coap_decode_var_bytes(coap_opt_value(fmt_opt),
2626c87c5fbaSopenharmony_ci                                                   coap_opt_length(fmt_opt)) :
2627c87c5fbaSopenharmony_ci                   COAP_MEDIATYPE_TEXT_PLAIN;
2628c87c5fbaSopenharmony_ci    coap_opt_t *rtag_opt = coap_check_option(pdu,
2629c87c5fbaSopenharmony_ci                                             COAP_OPTION_RTAG,
2630c87c5fbaSopenharmony_ci                                             &opt_iter);
2631c87c5fbaSopenharmony_ci    size_t rtag_length = rtag_opt ? coap_opt_length(rtag_opt) : 0;
2632c87c5fbaSopenharmony_ci    const uint8_t *rtag = rtag_opt ? coap_opt_value(rtag_opt) : NULL;
2633c87c5fbaSopenharmony_ci
2634c87c5fbaSopenharmony_ci    if (length > block.chunk_size) {
2635c87c5fbaSopenharmony_ci      coap_log_debug("block: Oversized packet - reduced to %"PRIu32" from %zu\n",
2636c87c5fbaSopenharmony_ci                     block.chunk_size, length);
2637c87c5fbaSopenharmony_ci      length = block.chunk_size;
2638c87c5fbaSopenharmony_ci    }
2639c87c5fbaSopenharmony_ci    total = size_opt ? coap_decode_var_bytes(coap_opt_value(size_opt),
2640c87c5fbaSopenharmony_ci                                             coap_opt_length(size_opt)) : 0;
2641c87c5fbaSopenharmony_ci    offset = block.num << (block.szx + 4);
2642c87c5fbaSopenharmony_ci
2643c87c5fbaSopenharmony_ci    LL_FOREACH(session->lg_srcv, p) {
2644c87c5fbaSopenharmony_ci      if (rtag_opt || p->rtag_set == 1) {
2645c87c5fbaSopenharmony_ci        if (!(rtag_opt && p->rtag_set == 1))
2646c87c5fbaSopenharmony_ci          continue;
2647c87c5fbaSopenharmony_ci        if (p->rtag_length != rtag_length ||
2648c87c5fbaSopenharmony_ci            memcmp(p->rtag, rtag, rtag_length) != 0)
2649c87c5fbaSopenharmony_ci          continue;
2650c87c5fbaSopenharmony_ci      }
2651c87c5fbaSopenharmony_ci      if (resource == p->resource) {
2652c87c5fbaSopenharmony_ci        break;
2653c87c5fbaSopenharmony_ci      }
2654c87c5fbaSopenharmony_ci      if ((p->resource == context->unknown_resource ||
2655c87c5fbaSopenharmony_ci           resource == context->proxy_uri_resource) &&
2656c87c5fbaSopenharmony_ci          coap_string_equal(uri_path, p->uri_path))
2657c87c5fbaSopenharmony_ci        break;
2658c87c5fbaSopenharmony_ci    }
2659c87c5fbaSopenharmony_ci    if (!p && block.num != 0) {
2660c87c5fbaSopenharmony_ci      /* random access - no need to track */
2661c87c5fbaSopenharmony_ci      pdu->body_data = data;
2662c87c5fbaSopenharmony_ci      pdu->body_length = length;
2663c87c5fbaSopenharmony_ci      pdu->body_offset = offset;
2664c87c5fbaSopenharmony_ci      pdu->body_total = length + offset + (block.m ? 1 : 0);
2665c87c5fbaSopenharmony_ci    }
2666c87c5fbaSopenharmony_ci    /* Do not do this if this is a single block */
2667c87c5fbaSopenharmony_ci    else if (!p && !(offset == 0 && block.m == 0)) {
2668c87c5fbaSopenharmony_ci      p = coap_malloc_type(COAP_LG_SRCV, sizeof(coap_lg_srcv_t));
2669c87c5fbaSopenharmony_ci      if (p == NULL) {
2670c87c5fbaSopenharmony_ci        coap_add_data(response, sizeof("Memory issue")-1,
2671c87c5fbaSopenharmony_ci                      (const uint8_t *)"Memory issue");
2672c87c5fbaSopenharmony_ci        response->code = COAP_RESPONSE_CODE(500);
2673c87c5fbaSopenharmony_ci        goto skip_app_handler;
2674c87c5fbaSopenharmony_ci      }
2675c87c5fbaSopenharmony_ci      coap_log_debug("** %s: lg_srcv %p initialized\n",
2676c87c5fbaSopenharmony_ci                     coap_session_str(session), (void *)p);
2677c87c5fbaSopenharmony_ci      memset(p, 0, sizeof(coap_lg_srcv_t));
2678c87c5fbaSopenharmony_ci      coap_ticks(&p->last_used);
2679c87c5fbaSopenharmony_ci      p->resource = resource;
2680c87c5fbaSopenharmony_ci      if (resource == context->unknown_resource ||
2681c87c5fbaSopenharmony_ci          resource == context->proxy_uri_resource)
2682c87c5fbaSopenharmony_ci        p->uri_path = coap_new_str_const(uri_path->s, uri_path->length);
2683c87c5fbaSopenharmony_ci      p->content_format = fmt;
2684c87c5fbaSopenharmony_ci      p->total_len = total;
2685c87c5fbaSopenharmony_ci      p->amount_so_far = length;
2686c87c5fbaSopenharmony_ci      p->szx = block.szx;
2687c87c5fbaSopenharmony_ci      p->block_option = block_option;
2688c87c5fbaSopenharmony_ci      if (observe) {
2689c87c5fbaSopenharmony_ci        p->observe_length = min(coap_opt_length(observe), 3);
2690c87c5fbaSopenharmony_ci        memcpy(p->observe, coap_opt_value(observe), p->observe_length);
2691c87c5fbaSopenharmony_ci        p->observe_set = 1;
2692c87c5fbaSopenharmony_ci      }
2693c87c5fbaSopenharmony_ci      if (rtag_opt) {
2694c87c5fbaSopenharmony_ci        p->rtag_length = coap_opt_length(rtag_opt);
2695c87c5fbaSopenharmony_ci        memcpy(p->rtag, coap_opt_value(rtag_opt), p->rtag_length);
2696c87c5fbaSopenharmony_ci        p->rtag_set = 1;
2697c87c5fbaSopenharmony_ci      }
2698c87c5fbaSopenharmony_ci      p->body_data = NULL;
2699c87c5fbaSopenharmony_ci      LL_PREPEND(session->lg_srcv, p);
2700c87c5fbaSopenharmony_ci    }
2701c87c5fbaSopenharmony_ci    if (p) {
2702c87c5fbaSopenharmony_ci      if (fmt != p->content_format) {
2703c87c5fbaSopenharmony_ci        coap_add_data(response, sizeof("Content-Format mismatch")-1,
2704c87c5fbaSopenharmony_ci                      (const uint8_t *)"Content-Format mismatch");
2705c87c5fbaSopenharmony_ci        response->code = COAP_RESPONSE_CODE(408);
2706c87c5fbaSopenharmony_ci        goto free_lg_srcv;
2707c87c5fbaSopenharmony_ci      }
2708c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2709c87c5fbaSopenharmony_ci      if (block_option == COAP_OPTION_Q_BLOCK1) {
2710c87c5fbaSopenharmony_ci        if (total != p->total_len) {
2711c87c5fbaSopenharmony_ci          coap_add_data(response, sizeof("Size1 mismatch")-1,
2712c87c5fbaSopenharmony_ci                        (const uint8_t *)"Size1 mismatch");
2713c87c5fbaSopenharmony_ci          response->code = COAP_RESPONSE_CODE(408);
2714c87c5fbaSopenharmony_ci          goto free_lg_srcv;
2715c87c5fbaSopenharmony_ci        }
2716c87c5fbaSopenharmony_ci      }
2717c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2718c87c5fbaSopenharmony_ci      p->last_mid = pdu->mid;
2719c87c5fbaSopenharmony_ci      p->last_type = pdu->type;
2720c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2721c87c5fbaSopenharmony_ci      coap_delete_bin_const(p->last_token);
2722c87c5fbaSopenharmony_ci      p->last_token = coap_new_bin_const(pdu->actual_token.s,
2723c87c5fbaSopenharmony_ci                                         pdu->actual_token.length);
2724c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2725c87c5fbaSopenharmony_ci      if (session->block_mode &
2726c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2727c87c5fbaSopenharmony_ci          (COAP_BLOCK_SINGLE_BODY|COAP_BLOCK_HAS_Q_BLOCK) ||
2728c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
2729c87c5fbaSopenharmony_ci          (COAP_BLOCK_SINGLE_BODY) ||
2730c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
2731c87c5fbaSopenharmony_ci          block.bert) {
2732c87c5fbaSopenharmony_ci        size_t chunk = (size_t)1 << (block.szx + 4);
2733c87c5fbaSopenharmony_ci        int update_data = 0;
2734c87c5fbaSopenharmony_ci        unsigned int saved_num = block.num;
2735c87c5fbaSopenharmony_ci        size_t saved_offset = offset;
2736c87c5fbaSopenharmony_ci
2737c87c5fbaSopenharmony_ci        while (offset < saved_offset + length) {
2738c87c5fbaSopenharmony_ci          if (!check_if_received_block(&p->rec_blocks, block.num)) {
2739c87c5fbaSopenharmony_ci            /* Update list of blocks received */
2740c87c5fbaSopenharmony_ci            if (!update_received_blocks(&p->rec_blocks, block.num)) {
2741c87c5fbaSopenharmony_ci              coap_handle_event(context, COAP_EVENT_PARTIAL_BLOCK, session);
2742c87c5fbaSopenharmony_ci              coap_add_data(response, sizeof("Too many missing blocks")-1,
2743c87c5fbaSopenharmony_ci                            (const uint8_t *)"Too many missing blocks");
2744c87c5fbaSopenharmony_ci              response->code = COAP_RESPONSE_CODE(408);
2745c87c5fbaSopenharmony_ci              goto free_lg_srcv;
2746c87c5fbaSopenharmony_ci            }
2747c87c5fbaSopenharmony_ci            update_data = 1;
2748c87c5fbaSopenharmony_ci          }
2749c87c5fbaSopenharmony_ci          block.num++;
2750c87c5fbaSopenharmony_ci          offset = block.num << (block.szx + 4);
2751c87c5fbaSopenharmony_ci        }
2752c87c5fbaSopenharmony_ci        block.num--;
2753c87c5fbaSopenharmony_ci        if (update_data) {
2754c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2755c87c5fbaSopenharmony_ci          p->rec_blocks.processing_payload_set =
2756c87c5fbaSopenharmony_ci              block.num / COAP_MAX_PAYLOADS(session);
2757c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2758c87c5fbaSopenharmony_ci          /* Update saved data */
2759c87c5fbaSopenharmony_ci          if (p->total_len < saved_offset + length) {
2760c87c5fbaSopenharmony_ci            p->total_len = saved_offset + length;
2761c87c5fbaSopenharmony_ci          }
2762c87c5fbaSopenharmony_ci          p->body_data = coap_block_build_body(p->body_data, length, data,
2763c87c5fbaSopenharmony_ci                                               saved_offset, p->total_len);
2764c87c5fbaSopenharmony_ci          if (!p->body_data)
2765c87c5fbaSopenharmony_ci            goto call_app_handler;
2766c87c5fbaSopenharmony_ci
2767c87c5fbaSopenharmony_ci        }
2768c87c5fbaSopenharmony_ci        if (block.m ||
2769c87c5fbaSopenharmony_ci            !check_all_blocks_in(&p->rec_blocks,
2770c87c5fbaSopenharmony_ci                                 (uint32_t)(p->total_len + chunk -1)/chunk)) {
2771c87c5fbaSopenharmony_ci          /* Not all the payloads of the body have arrived */
2772c87c5fbaSopenharmony_ci          if (block.m) {
2773c87c5fbaSopenharmony_ci            uint8_t buf[4];
2774c87c5fbaSopenharmony_ci
2775c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2776c87c5fbaSopenharmony_ci            if (block_option == COAP_OPTION_Q_BLOCK1) {
2777c87c5fbaSopenharmony_ci              if (check_all_blocks_in(&p->rec_blocks,
2778c87c5fbaSopenharmony_ci                                      (uint32_t)(p->total_len + chunk -1)/chunk)) {
2779c87c5fbaSopenharmony_ci                goto give_app_data;
2780c87c5fbaSopenharmony_ci              }
2781c87c5fbaSopenharmony_ci              if (p->rec_blocks.used == 1 &&
2782c87c5fbaSopenharmony_ci                  (p->rec_blocks.range[0].end % COAP_MAX_PAYLOADS(session)) + 1
2783c87c5fbaSopenharmony_ci                  == COAP_MAX_PAYLOADS(session)) {
2784c87c5fbaSopenharmony_ci                /* Blocks could arrive in wrong order */
2785c87c5fbaSopenharmony_ci                block.num = p->rec_blocks.range[0].end;
2786c87c5fbaSopenharmony_ci              } else {
2787c87c5fbaSopenharmony_ci                /* The remote end will be sending the next one unless this
2788c87c5fbaSopenharmony_ci                   is a MAX_PAYLOADS and all previous have been received */
2789c87c5fbaSopenharmony_ci                goto skip_app_handler;
2790c87c5fbaSopenharmony_ci              }
2791c87c5fbaSopenharmony_ci              if (COAP_PROTO_RELIABLE(session->proto) ||
2792c87c5fbaSopenharmony_ci                  pdu->type != COAP_MESSAGE_NON)
2793c87c5fbaSopenharmony_ci                goto skip_app_handler;
2794c87c5fbaSopenharmony_ci            }
2795c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2796c87c5fbaSopenharmony_ci            /* Ask for the next block */
2797c87c5fbaSopenharmony_ci            coap_insert_option(response, block_option,
2798c87c5fbaSopenharmony_ci                               coap_encode_var_safe(buf, sizeof(buf),
2799c87c5fbaSopenharmony_ci                                                    (saved_num << 4) |
2800c87c5fbaSopenharmony_ci                                                    (block.m << 3) |
2801c87c5fbaSopenharmony_ci                                                    block.aszx),
2802c87c5fbaSopenharmony_ci                               buf);
2803c87c5fbaSopenharmony_ci            response->code = COAP_RESPONSE_CODE(231);
2804c87c5fbaSopenharmony_ci            goto skip_app_handler;
2805c87c5fbaSopenharmony_ci          }
2806c87c5fbaSopenharmony_ci          goto skip_app_handler;
2807c87c5fbaSopenharmony_ci        }
2808c87c5fbaSopenharmony_ci
2809c87c5fbaSopenharmony_ci        /*
2810c87c5fbaSopenharmony_ci         * Remove the Block1 option as passing all of the data to
2811c87c5fbaSopenharmony_ci         * application layer. Add back in observe option if appropriate.
2812c87c5fbaSopenharmony_ci         * Adjust all other information.
2813c87c5fbaSopenharmony_ci         */
2814c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2815c87c5fbaSopenharmony_cigive_app_data:
2816c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2817c87c5fbaSopenharmony_ci        if (p->observe_set) {
2818c87c5fbaSopenharmony_ci          coap_update_option(pdu, COAP_OPTION_OBSERVE,
2819c87c5fbaSopenharmony_ci                             p->observe_length, p->observe);
2820c87c5fbaSopenharmony_ci        }
2821c87c5fbaSopenharmony_ci        coap_remove_option(pdu, block_option);
2822c87c5fbaSopenharmony_ci        pdu->body_data = p->body_data->s;
2823c87c5fbaSopenharmony_ci        pdu->body_length = p->total_len;
2824c87c5fbaSopenharmony_ci        pdu->body_offset = 0;
2825c87c5fbaSopenharmony_ci        pdu->body_total = p->total_len;
2826c87c5fbaSopenharmony_ci        coap_log_debug("Server app version of updated PDU\n");
2827c87c5fbaSopenharmony_ci        coap_show_pdu(COAP_LOG_DEBUG, pdu);
2828c87c5fbaSopenharmony_ci        *pfree_lg_srcv = p;
2829c87c5fbaSopenharmony_ci        goto call_app_handler;
2830c87c5fbaSopenharmony_ci      } else {
2831c87c5fbaSopenharmony_ci        /* No need to update body_data and body_length as a single PDU */
2832c87c5fbaSopenharmony_ci        pdu->body_offset = offset;
2833c87c5fbaSopenharmony_ci        /* Exact match if last block */
2834c87c5fbaSopenharmony_ci        if (block.m) {
2835c87c5fbaSopenharmony_ci          uint8_t buf[4];
2836c87c5fbaSopenharmony_ci
2837c87c5fbaSopenharmony_ci          if (total > offset + length + block.m)
2838c87c5fbaSopenharmony_ci            pdu->body_total = total;
2839c87c5fbaSopenharmony_ci          else
2840c87c5fbaSopenharmony_ci            pdu->body_total = offset + length + block.m;
2841c87c5fbaSopenharmony_ci
2842c87c5fbaSopenharmony_ci          coap_insert_option(response, block_option,
2843c87c5fbaSopenharmony_ci                             coap_encode_var_safe(buf, sizeof(buf),
2844c87c5fbaSopenharmony_ci                                                  (block.num << 4) |
2845c87c5fbaSopenharmony_ci                                                  (block.m << 3) |
2846c87c5fbaSopenharmony_ci                                                  block.aszx),
2847c87c5fbaSopenharmony_ci                             buf);
2848c87c5fbaSopenharmony_ci          *added_block = 1;
2849c87c5fbaSopenharmony_ci          goto call_app_handler;
2850c87c5fbaSopenharmony_ci        } else {
2851c87c5fbaSopenharmony_ci          pdu->body_total = offset + length + block.m;
2852c87c5fbaSopenharmony_ci        }
2853c87c5fbaSopenharmony_ci      }
2854c87c5fbaSopenharmony_ci
2855c87c5fbaSopenharmony_ci      if (block.m == 0) {
2856c87c5fbaSopenharmony_ci        /* Last chunk - free off all */
2857c87c5fbaSopenharmony_ci        coap_ticks(&p->last_used);
2858c87c5fbaSopenharmony_ci      }
2859c87c5fbaSopenharmony_ci      goto call_app_handler;
2860c87c5fbaSopenharmony_ci
2861c87c5fbaSopenharmony_cifree_lg_srcv:
2862c87c5fbaSopenharmony_ci      LL_DELETE(session->lg_srcv, p);
2863c87c5fbaSopenharmony_ci      coap_block_delete_lg_srcv(session, p);
2864c87c5fbaSopenharmony_ci      goto skip_app_handler;
2865c87c5fbaSopenharmony_ci    }
2866c87c5fbaSopenharmony_ci  }
2867c87c5fbaSopenharmony_cicall_app_handler:
2868c87c5fbaSopenharmony_ci  return 0;
2869c87c5fbaSopenharmony_ci
2870c87c5fbaSopenharmony_ciskip_app_handler:
2871c87c5fbaSopenharmony_ci  return 1;
2872c87c5fbaSopenharmony_ci}
2873c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
2874c87c5fbaSopenharmony_ci
2875c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
2876c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
2877c87c5fbaSopenharmony_cistatic uint32_t
2878c87c5fbaSopenharmony_ciderive_cbor_value(const uint8_t **bp, size_t rem_len) {
2879c87c5fbaSopenharmony_ci  uint32_t value = **bp & 0x1f;
2880c87c5fbaSopenharmony_ci  (*bp)++;
2881c87c5fbaSopenharmony_ci  if (value < 24) {
2882c87c5fbaSopenharmony_ci    return value;
2883c87c5fbaSopenharmony_ci  } else if (value == 24) {
2884c87c5fbaSopenharmony_ci    if (rem_len < 2)
2885c87c5fbaSopenharmony_ci      return (uint32_t)-1;
2886c87c5fbaSopenharmony_ci    value = **bp;
2887c87c5fbaSopenharmony_ci    (*bp)++;
2888c87c5fbaSopenharmony_ci    return value;
2889c87c5fbaSopenharmony_ci  } else if (value == 25) {
2890c87c5fbaSopenharmony_ci    if (rem_len < 3)
2891c87c5fbaSopenharmony_ci      return (uint32_t)-1;
2892c87c5fbaSopenharmony_ci    value = **bp << 8;
2893c87c5fbaSopenharmony_ci    (*bp)++;
2894c87c5fbaSopenharmony_ci    value |= **bp;
2895c87c5fbaSopenharmony_ci    (*bp)++;
2896c87c5fbaSopenharmony_ci    return value;
2897c87c5fbaSopenharmony_ci  }
2898c87c5fbaSopenharmony_ci  if (rem_len < 4)
2899c87c5fbaSopenharmony_ci    return (uint32_t)-1;
2900c87c5fbaSopenharmony_ci  value = **bp << 24;
2901c87c5fbaSopenharmony_ci  (*bp)++;
2902c87c5fbaSopenharmony_ci  value = **bp << 16;
2903c87c5fbaSopenharmony_ci  (*bp)++;
2904c87c5fbaSopenharmony_ci  value = **bp << 8;
2905c87c5fbaSopenharmony_ci  (*bp)++;
2906c87c5fbaSopenharmony_ci  value |= **bp;
2907c87c5fbaSopenharmony_ci  (*bp)++;
2908c87c5fbaSopenharmony_ci  return value;
2909c87c5fbaSopenharmony_ci}
2910c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
2911c87c5fbaSopenharmony_ci
2912c87c5fbaSopenharmony_cistatic int
2913c87c5fbaSopenharmony_cicheck_freshness(coap_session_t *session, coap_pdu_t *rcvd, coap_pdu_t *sent,
2914c87c5fbaSopenharmony_ci                coap_lg_xmit_t *lg_xmit, coap_lg_crcv_t *lg_crcv) {
2915c87c5fbaSopenharmony_ci  /* Check for Echo option for freshness */
2916c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
2917c87c5fbaSopenharmony_ci  coap_opt_t *opt = coap_check_option(rcvd, COAP_OPTION_ECHO, &opt_iter);
2918c87c5fbaSopenharmony_ci
2919c87c5fbaSopenharmony_ci  if (opt) {
2920c87c5fbaSopenharmony_ci    if (sent || lg_xmit || lg_crcv) {
2921c87c5fbaSopenharmony_ci      /* Need to retransmit original request with Echo option added */
2922c87c5fbaSopenharmony_ci      coap_pdu_t *echo_pdu;
2923c87c5fbaSopenharmony_ci      coap_mid_t mid;
2924c87c5fbaSopenharmony_ci      const uint8_t *data;
2925c87c5fbaSopenharmony_ci      size_t data_len;
2926c87c5fbaSopenharmony_ci      int have_data = 0;
2927c87c5fbaSopenharmony_ci      uint8_t ltoken[8];
2928c87c5fbaSopenharmony_ci      size_t ltoken_len;
2929c87c5fbaSopenharmony_ci      uint64_t token;
2930c87c5fbaSopenharmony_ci
2931c87c5fbaSopenharmony_ci      if (sent) {
2932c87c5fbaSopenharmony_ci        if (coap_get_data(sent, &data_len, &data))
2933c87c5fbaSopenharmony_ci          have_data = 1;
2934c87c5fbaSopenharmony_ci      } else if (lg_xmit) {
2935c87c5fbaSopenharmony_ci        sent = &lg_xmit->pdu;
2936c87c5fbaSopenharmony_ci        if (lg_xmit->length) {
2937c87c5fbaSopenharmony_ci          size_t blk_size = (size_t)1 << (lg_xmit->blk_size + 4);
2938c87c5fbaSopenharmony_ci          size_t offset = (lg_xmit->last_block + 1) * blk_size;
2939c87c5fbaSopenharmony_ci          have_data = 1;
2940c87c5fbaSopenharmony_ci          data = &lg_xmit->data[offset];
2941c87c5fbaSopenharmony_ci          data_len = (lg_xmit->length - offset) > blk_size ? blk_size :
2942c87c5fbaSopenharmony_ci                     lg_xmit->length - offset;
2943c87c5fbaSopenharmony_ci        }
2944c87c5fbaSopenharmony_ci      } else { /* lg_crcv */
2945c87c5fbaSopenharmony_ci        sent = &lg_crcv->pdu;
2946c87c5fbaSopenharmony_ci        if (coap_get_data(sent, &data_len, &data))
2947c87c5fbaSopenharmony_ci          have_data = 1;
2948c87c5fbaSopenharmony_ci      }
2949c87c5fbaSopenharmony_ci      if (lg_xmit) {
2950c87c5fbaSopenharmony_ci        token = STATE_TOKEN_FULL(lg_xmit->b.b1.state_token,
2951c87c5fbaSopenharmony_ci                                 ++lg_xmit->b.b1.count);
2952c87c5fbaSopenharmony_ci      } else {
2953c87c5fbaSopenharmony_ci        token = STATE_TOKEN_FULL(lg_crcv->state_token,
2954c87c5fbaSopenharmony_ci                                 ++lg_crcv->retry_counter);
2955c87c5fbaSopenharmony_ci      }
2956c87c5fbaSopenharmony_ci      ltoken_len = coap_encode_var_safe8(ltoken, sizeof(token), token);
2957c87c5fbaSopenharmony_ci      echo_pdu = coap_pdu_duplicate(sent, session, ltoken_len, ltoken, NULL);
2958c87c5fbaSopenharmony_ci      if (!echo_pdu)
2959c87c5fbaSopenharmony_ci        return 0;
2960c87c5fbaSopenharmony_ci      if (!coap_insert_option(echo_pdu, COAP_OPTION_ECHO,
2961c87c5fbaSopenharmony_ci                              coap_opt_length(opt), coap_opt_value(opt)))
2962c87c5fbaSopenharmony_ci        goto not_sent;
2963c87c5fbaSopenharmony_ci      if (have_data) {
2964c87c5fbaSopenharmony_ci        coap_add_data(echo_pdu, data_len, data);
2965c87c5fbaSopenharmony_ci      }
2966c87c5fbaSopenharmony_ci      /* Need to track Observe token change if Observe */
2967c87c5fbaSopenharmony_ci      track_fetch_observe(echo_pdu, lg_crcv, 0, &echo_pdu->actual_token);
2968c87c5fbaSopenharmony_ci#if COAP_OSCORE_SUPPORT
2969c87c5fbaSopenharmony_ci      if (session->oscore_encryption &&
2970c87c5fbaSopenharmony_ci          (opt = coap_check_option(echo_pdu, COAP_OPTION_OBSERVE, &opt_iter)) &&
2971c87c5fbaSopenharmony_ci          coap_decode_var_bytes(coap_opt_value(opt), coap_opt_length(opt) == 0)) {
2972c87c5fbaSopenharmony_ci        /* Need to update the base PDU's Token for closing down Observe */
2973c87c5fbaSopenharmony_ci        if (lg_xmit) {
2974c87c5fbaSopenharmony_ci          lg_xmit->b.b1.state_token = token;
2975c87c5fbaSopenharmony_ci        } else {
2976c87c5fbaSopenharmony_ci          lg_crcv->state_token = token;
2977c87c5fbaSopenharmony_ci        }
2978c87c5fbaSopenharmony_ci      }
2979c87c5fbaSopenharmony_ci#endif /* COAP_OSCORE_SUPPORT */
2980c87c5fbaSopenharmony_ci      mid = coap_send_internal(session, echo_pdu);
2981c87c5fbaSopenharmony_ci      if (mid == COAP_INVALID_MID)
2982c87c5fbaSopenharmony_ci        goto not_sent;
2983c87c5fbaSopenharmony_ci      return 1;
2984c87c5fbaSopenharmony_ci    } else {
2985c87c5fbaSopenharmony_ci      /* Need to save Echo option value to add to next reansmission */
2986c87c5fbaSopenharmony_cinot_sent:
2987c87c5fbaSopenharmony_ci      coap_delete_bin_const(session->echo);
2988c87c5fbaSopenharmony_ci      session->echo = coap_new_bin_const(coap_opt_value(opt),
2989c87c5fbaSopenharmony_ci                                         coap_opt_length(opt));
2990c87c5fbaSopenharmony_ci    }
2991c87c5fbaSopenharmony_ci  }
2992c87c5fbaSopenharmony_ci  return 0;
2993c87c5fbaSopenharmony_ci}
2994c87c5fbaSopenharmony_ci
2995c87c5fbaSopenharmony_cistatic void
2996c87c5fbaSopenharmony_citrack_echo(coap_session_t *session, coap_pdu_t *rcvd) {
2997c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
2998c87c5fbaSopenharmony_ci  coap_opt_t *opt = coap_check_option(rcvd, COAP_OPTION_ECHO, &opt_iter);
2999c87c5fbaSopenharmony_ci
3000c87c5fbaSopenharmony_ci  if (opt) {
3001c87c5fbaSopenharmony_ci    coap_delete_bin_const(session->echo);
3002c87c5fbaSopenharmony_ci    session->echo = coap_new_bin_const(coap_opt_value(opt),
3003c87c5fbaSopenharmony_ci                                       coap_opt_length(opt));
3004c87c5fbaSopenharmony_ci  }
3005c87c5fbaSopenharmony_ci}
3006c87c5fbaSopenharmony_ci
3007c87c5fbaSopenharmony_ci/*
3008c87c5fbaSopenharmony_ci * Need to see if this is a response to a large body request transfer. If so,
3009c87c5fbaSopenharmony_ci * need to initiate the request containing the next block and not trouble the
3010c87c5fbaSopenharmony_ci * application.  Note that Token must unique per request/response.
3011c87c5fbaSopenharmony_ci *
3012c87c5fbaSopenharmony_ci * Client receives large data acknowledgement from server (Block1)
3013c87c5fbaSopenharmony_ci *
3014c87c5fbaSopenharmony_ci * This is set up using coap_add_data_large_request()
3015c87c5fbaSopenharmony_ci *
3016c87c5fbaSopenharmony_ci * Client is using GET etc.
3017c87c5fbaSopenharmony_ci *
3018c87c5fbaSopenharmony_ci * Return: 0 Call application handler
3019c87c5fbaSopenharmony_ci *         1 Do not call application handler - just send the built response
3020c87c5fbaSopenharmony_ci */
3021c87c5fbaSopenharmony_ciint
3022c87c5fbaSopenharmony_cicoap_handle_response_send_block(coap_session_t *session, coap_pdu_t *sent,
3023c87c5fbaSopenharmony_ci                                coap_pdu_t *rcvd) {
3024c87c5fbaSopenharmony_ci  coap_lg_xmit_t *p;
3025c87c5fbaSopenharmony_ci  coap_lg_xmit_t *q;
3026c87c5fbaSopenharmony_ci  uint64_t token_match =
3027c87c5fbaSopenharmony_ci      STATE_TOKEN_BASE(coap_decode_var_bytes8(rcvd->actual_token.s,
3028c87c5fbaSopenharmony_ci                                              rcvd->actual_token.length));
3029c87c5fbaSopenharmony_ci  coap_lg_crcv_t *lg_crcv = NULL;
3030c87c5fbaSopenharmony_ci
3031c87c5fbaSopenharmony_ci  LL_FOREACH_SAFE(session->lg_xmit, p, q) {
3032c87c5fbaSopenharmony_ci    if (!COAP_PDU_IS_REQUEST(&p->pdu) ||
3033c87c5fbaSopenharmony_ci        (token_match != STATE_TOKEN_BASE(p->b.b1.state_token) &&
3034c87c5fbaSopenharmony_ci         token_match !=
3035c87c5fbaSopenharmony_ci         STATE_TOKEN_BASE(coap_decode_var_bytes8(p->b.b1.app_token->s,
3036c87c5fbaSopenharmony_ci                                                 p->b.b1.app_token->length)))) {
3037c87c5fbaSopenharmony_ci      /* try out the next one */
3038c87c5fbaSopenharmony_ci      continue;
3039c87c5fbaSopenharmony_ci    }
3040c87c5fbaSopenharmony_ci    /* lg_xmit found */
3041c87c5fbaSopenharmony_ci    size_t chunk = (size_t)1 << (p->blk_size + 4);
3042c87c5fbaSopenharmony_ci    coap_block_b_t block;
3043c87c5fbaSopenharmony_ci
3044c87c5fbaSopenharmony_ci    if (COAP_RESPONSE_CLASS(rcvd->code) == 2 &&
3045c87c5fbaSopenharmony_ci        coap_get_block_b(session, rcvd, p->option, &block)) {
3046c87c5fbaSopenharmony_ci
3047c87c5fbaSopenharmony_ci      if (block.bert) {
3048c87c5fbaSopenharmony_ci        coap_log_debug("found Block option, block is BERT, block nr. %u (%zu)\n",
3049c87c5fbaSopenharmony_ci                       block.num, p->b.b1.bert_size);
3050c87c5fbaSopenharmony_ci      } else {
3051c87c5fbaSopenharmony_ci        coap_log_debug("found Block option, block size is %u, block nr. %u\n",
3052c87c5fbaSopenharmony_ci                       1 << (block.szx + 4), block.num);
3053c87c5fbaSopenharmony_ci      }
3054c87c5fbaSopenharmony_ci      if (block.szx != p->blk_size) {
3055c87c5fbaSopenharmony_ci        if ((p->offset + chunk) % ((size_t)1 << (block.szx + 4)) == 0) {
3056c87c5fbaSopenharmony_ci          /*
3057c87c5fbaSopenharmony_ci           * Recompute the block number of the previous packet given the
3058c87c5fbaSopenharmony_ci           * new block size
3059c87c5fbaSopenharmony_ci           */
3060c87c5fbaSopenharmony_ci          block.num = (uint32_t)(((p->offset + chunk) >> (block.szx + 4)) - 1);
3061c87c5fbaSopenharmony_ci          p->blk_size = block.szx;
3062c87c5fbaSopenharmony_ci          chunk = (size_t)1 << (p->blk_size + 4);
3063c87c5fbaSopenharmony_ci          p->offset = block.num * chunk;
3064c87c5fbaSopenharmony_ci          coap_log_debug("new Block size is %u, block number %u completed\n",
3065c87c5fbaSopenharmony_ci                         1 << (block.szx + 4), block.num);
3066c87c5fbaSopenharmony_ci          block.bert = 0;
3067c87c5fbaSopenharmony_ci          block.aszx = block.szx;
3068c87c5fbaSopenharmony_ci        } else {
3069c87c5fbaSopenharmony_ci          coap_log_debug("ignoring request to increase Block size, "
3070c87c5fbaSopenharmony_ci                         "next block is not aligned on requested block size boundary. "
3071c87c5fbaSopenharmony_ci                         "(%zu x %u mod %u = %zu != 0)\n",
3072c87c5fbaSopenharmony_ci                         p->offset/chunk + 1, (1 << (p->blk_size + 4)),
3073c87c5fbaSopenharmony_ci                         (1 << (block.szx + 4)),
3074c87c5fbaSopenharmony_ci                         (p->offset + chunk) % ((size_t)1 << (block.szx + 4)));
3075c87c5fbaSopenharmony_ci        }
3076c87c5fbaSopenharmony_ci      }
3077c87c5fbaSopenharmony_ci      track_echo(session, rcvd);
3078c87c5fbaSopenharmony_ci      if (p->last_block == (int)block.num &&
3079c87c5fbaSopenharmony_ci          p->option != COAP_OPTION_Q_BLOCK1) {
3080c87c5fbaSopenharmony_ci        /*
3081c87c5fbaSopenharmony_ci         * Duplicate Block1 ACK
3082c87c5fbaSopenharmony_ci         *
3083c87c5fbaSopenharmony_ci         * RFCs not clear here, but on a lossy connection, there could
3084c87c5fbaSopenharmony_ci         * be multiple Block1 ACKs, causing the client to retransmit the
3085c87c5fbaSopenharmony_ci         * same block multiple times, or the server retransmitting the
3086c87c5fbaSopenharmony_ci         * same ACK.
3087c87c5fbaSopenharmony_ci         *
3088c87c5fbaSopenharmony_ci         * Once a block has been ACKd, there is no need to retransmit it.
3089c87c5fbaSopenharmony_ci         */
3090c87c5fbaSopenharmony_ci        return 1;
3091c87c5fbaSopenharmony_ci      }
3092c87c5fbaSopenharmony_ci      if (block.bert)
3093c87c5fbaSopenharmony_ci        block.num += (unsigned int)(p->b.b1.bert_size / 1024 - 1);
3094c87c5fbaSopenharmony_ci      p->last_block = block.num;
3095c87c5fbaSopenharmony_ci      p->offset = (block.num + 1) * chunk;
3096c87c5fbaSopenharmony_ci      if (p->offset < p->length) {
3097c87c5fbaSopenharmony_ci        /* Build the next PDU request based off the skeletal PDU */
3098c87c5fbaSopenharmony_ci        uint8_t buf[8];
3099c87c5fbaSopenharmony_ci        coap_pdu_t *pdu;
3100c87c5fbaSopenharmony_ci        uint64_t token = STATE_TOKEN_FULL(p->b.b1.state_token, ++p->b.b1.count);
3101c87c5fbaSopenharmony_ci        size_t len = coap_encode_var_safe8(buf, sizeof(token), token);
3102c87c5fbaSopenharmony_ci
3103c87c5fbaSopenharmony_ci        if (p->pdu.code == COAP_REQUEST_CODE_FETCH) {
3104c87c5fbaSopenharmony_ci          /* Need to handle Observe for large FETCH */
3105c87c5fbaSopenharmony_ci          LL_FOREACH(session->lg_crcv, lg_crcv) {
3106c87c5fbaSopenharmony_ci            if (coap_binary_equal(p->b.b1.app_token, lg_crcv->app_token)) {
3107c87c5fbaSopenharmony_ci              coap_bin_const_t *new_token;
3108c87c5fbaSopenharmony_ci              coap_bin_const_t ctoken = { len, buf };
3109c87c5fbaSopenharmony_ci
3110c87c5fbaSopenharmony_ci              /* Need to save/restore Observe Token for large FETCH */
3111c87c5fbaSopenharmony_ci              new_token = track_fetch_observe(&p->pdu, lg_crcv, block.num + 1,
3112c87c5fbaSopenharmony_ci                                              &ctoken);
3113c87c5fbaSopenharmony_ci              if (new_token) {
3114c87c5fbaSopenharmony_ci                assert(len <= sizeof(buf));
3115c87c5fbaSopenharmony_ci                len = new_token->length;
3116c87c5fbaSopenharmony_ci                memcpy(buf, new_token->s, len);
3117c87c5fbaSopenharmony_ci              }
3118c87c5fbaSopenharmony_ci              break;
3119c87c5fbaSopenharmony_ci            }
3120c87c5fbaSopenharmony_ci          }
3121c87c5fbaSopenharmony_ci        }
3122c87c5fbaSopenharmony_ci        pdu = coap_pdu_duplicate(&p->pdu, session, len, buf, NULL);
3123c87c5fbaSopenharmony_ci        if (!pdu)
3124c87c5fbaSopenharmony_ci          goto fail_body;
3125c87c5fbaSopenharmony_ci
3126c87c5fbaSopenharmony_ci        block.num++;
3127c87c5fbaSopenharmony_ci        if (block.bert) {
3128c87c5fbaSopenharmony_ci          size_t token_options = pdu->data ? (size_t)(pdu->data - pdu->token) :
3129c87c5fbaSopenharmony_ci                                 pdu->used_size;
3130c87c5fbaSopenharmony_ci          block.m = (p->length - p->offset) >
3131c87c5fbaSopenharmony_ci                    ((pdu->max_size - token_options) /1024) * 1024;
3132c87c5fbaSopenharmony_ci        } else {
3133c87c5fbaSopenharmony_ci          block.m = (p->offset + chunk) < p->length;
3134c87c5fbaSopenharmony_ci        }
3135c87c5fbaSopenharmony_ci        coap_update_option(pdu, p->option,
3136c87c5fbaSopenharmony_ci                           coap_encode_var_safe(buf, sizeof(buf),
3137c87c5fbaSopenharmony_ci                                                (block.num << 4) |
3138c87c5fbaSopenharmony_ci                                                (block.m << 3) |
3139c87c5fbaSopenharmony_ci                                                block.aszx),
3140c87c5fbaSopenharmony_ci                           buf);
3141c87c5fbaSopenharmony_ci
3142c87c5fbaSopenharmony_ci        if (!coap_add_block_b_data(pdu,
3143c87c5fbaSopenharmony_ci                                   p->length,
3144c87c5fbaSopenharmony_ci                                   p->data,
3145c87c5fbaSopenharmony_ci                                   &block))
3146c87c5fbaSopenharmony_ci          goto fail_body;
3147c87c5fbaSopenharmony_ci        p->b.b1.bert_size = block.chunk_size;
3148c87c5fbaSopenharmony_ci        coap_ticks(&p->last_sent);
3149c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3150c87c5fbaSopenharmony_ci        if (p->option == COAP_OPTION_Q_BLOCK1 &&
3151c87c5fbaSopenharmony_ci            pdu->type == COAP_MESSAGE_NON) {
3152c87c5fbaSopenharmony_ci          if (coap_send_q_block1(session, block, pdu,
3153c87c5fbaSopenharmony_ci                                 COAP_SEND_INC_PDU) == COAP_INVALID_MID)
3154c87c5fbaSopenharmony_ci            goto fail_body;
3155c87c5fbaSopenharmony_ci          return 1;
3156c87c5fbaSopenharmony_ci        } else if (coap_send_internal(session, pdu) == COAP_INVALID_MID)
3157c87c5fbaSopenharmony_ci          goto fail_body;
3158c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
3159c87c5fbaSopenharmony_ci        if (coap_send_internal(session, pdu) == COAP_INVALID_MID)
3160c87c5fbaSopenharmony_ci          goto fail_body;
3161c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
3162c87c5fbaSopenharmony_ci        return 1;
3163c87c5fbaSopenharmony_ci      }
3164c87c5fbaSopenharmony_ci    } else if (rcvd->code == COAP_RESPONSE_CODE(401)) {
3165c87c5fbaSopenharmony_ci      if (check_freshness(session, rcvd, sent, p, NULL))
3166c87c5fbaSopenharmony_ci        return 1;
3167c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3168c87c5fbaSopenharmony_ci    } else if (rcvd->code == COAP_RESPONSE_CODE(402)) {
3169c87c5fbaSopenharmony_ci      /* Q-Block1 or Q-Block2 not present in p - duplicate error ? */
3170c87c5fbaSopenharmony_ci      if (coap_get_block_b(session, rcvd, COAP_OPTION_Q_BLOCK2, &block) ||
3171c87c5fbaSopenharmony_ci          coap_get_block_b(session, rcvd, COAP_OPTION_Q_BLOCK1, &block))
3172c87c5fbaSopenharmony_ci        return 1;
3173c87c5fbaSopenharmony_ci    } else if (rcvd->code == COAP_RESPONSE_CODE(408) &&
3174c87c5fbaSopenharmony_ci               p->option == COAP_OPTION_Q_BLOCK1) {
3175c87c5fbaSopenharmony_ci      size_t length;
3176c87c5fbaSopenharmony_ci      const uint8_t *data;
3177c87c5fbaSopenharmony_ci      coap_opt_iterator_t opt_iter;
3178c87c5fbaSopenharmony_ci      coap_opt_t *fmt_opt = coap_check_option(rcvd,
3179c87c5fbaSopenharmony_ci                                              COAP_OPTION_CONTENT_FORMAT,
3180c87c5fbaSopenharmony_ci                                              &opt_iter);
3181c87c5fbaSopenharmony_ci      uint16_t fmt = fmt_opt ?
3182c87c5fbaSopenharmony_ci                     coap_decode_var_bytes(coap_opt_value(fmt_opt),
3183c87c5fbaSopenharmony_ci                                           coap_opt_length(fmt_opt)) :
3184c87c5fbaSopenharmony_ci                     COAP_MEDIATYPE_TEXT_PLAIN;
3185c87c5fbaSopenharmony_ci
3186c87c5fbaSopenharmony_ci      if (fmt != COAP_MEDIATYPE_APPLICATION_MB_CBOR_SEQ)
3187c87c5fbaSopenharmony_ci        goto fail_body;
3188c87c5fbaSopenharmony_ci
3189c87c5fbaSopenharmony_ci      if (COAP_PROTO_RELIABLE(session->proto) ||
3190c87c5fbaSopenharmony_ci          rcvd->type != COAP_MESSAGE_NON) {
3191c87c5fbaSopenharmony_ci        coap_log_debug("Unexpected 4.08 - protocol violation - ignore\n");
3192c87c5fbaSopenharmony_ci        return 1;
3193c87c5fbaSopenharmony_ci      }
3194c87c5fbaSopenharmony_ci
3195c87c5fbaSopenharmony_ci      if (coap_get_data(rcvd, &length, &data)) {
3196c87c5fbaSopenharmony_ci        /* Need to decode CBOR to work out what blocks to re-send */
3197c87c5fbaSopenharmony_ci        const uint8_t *bp = data;
3198c87c5fbaSopenharmony_ci        uint32_t i;
3199c87c5fbaSopenharmony_ci        uint8_t buf[8];
3200c87c5fbaSopenharmony_ci        coap_pdu_t *pdu;
3201c87c5fbaSopenharmony_ci        uint64_t token = coap_decode_var_bytes8(rcvd->actual_token.s,
3202c87c5fbaSopenharmony_ci                                                rcvd->actual_token.length);
3203c87c5fbaSopenharmony_ci        uint8_t ltoken[8];
3204c87c5fbaSopenharmony_ci        size_t ltoken_length;
3205c87c5fbaSopenharmony_ci
3206c87c5fbaSopenharmony_ci        for (i = 0; (bp < data + length) &&
3207c87c5fbaSopenharmony_ci             i < COAP_MAX_PAYLOADS(session); i++) {
3208c87c5fbaSopenharmony_ci          if ((*bp & 0xc0) != 0x00) /* uint(value) */
3209c87c5fbaSopenharmony_ci            goto fail_cbor;
3210c87c5fbaSopenharmony_ci          block.num = derive_cbor_value(&bp, data + length - bp);
3211c87c5fbaSopenharmony_ci          coap_log_debug("Q-Block1: Missing block %d\n", block.num);
3212c87c5fbaSopenharmony_ci          if (block.num > (1 << 20) -1)
3213c87c5fbaSopenharmony_ci            goto fail_cbor;
3214c87c5fbaSopenharmony_ci          block.m = (block.num + 1) * chunk < p->length;
3215c87c5fbaSopenharmony_ci          block.szx = p->blk_size;
3216c87c5fbaSopenharmony_ci
3217c87c5fbaSopenharmony_ci          /* Build the next PDU request based off the skeletal PDU */
3218c87c5fbaSopenharmony_ci          token = STATE_TOKEN_FULL(p->b.b1.state_token,++p->b.b1.count);
3219c87c5fbaSopenharmony_ci          ltoken_length = coap_encode_var_safe8(ltoken, sizeof(token), token);
3220c87c5fbaSopenharmony_ci          pdu = coap_pdu_duplicate(&p->pdu, session, ltoken_length,
3221c87c5fbaSopenharmony_ci                                   ltoken, NULL);
3222c87c5fbaSopenharmony_ci          if (!pdu)
3223c87c5fbaSopenharmony_ci            goto fail_body;
3224c87c5fbaSopenharmony_ci
3225c87c5fbaSopenharmony_ci          coap_update_option(pdu, p->option,
3226c87c5fbaSopenharmony_ci                             coap_encode_var_safe(buf, sizeof(buf),
3227c87c5fbaSopenharmony_ci                                                  (block.num << 4) |
3228c87c5fbaSopenharmony_ci                                                  (block.m << 3) |
3229c87c5fbaSopenharmony_ci                                                  block.szx),
3230c87c5fbaSopenharmony_ci                             buf);
3231c87c5fbaSopenharmony_ci
3232c87c5fbaSopenharmony_ci          if (!coap_add_block(pdu,
3233c87c5fbaSopenharmony_ci                              p->length,
3234c87c5fbaSopenharmony_ci                              p->data,
3235c87c5fbaSopenharmony_ci                              block.num,
3236c87c5fbaSopenharmony_ci                              block.szx))
3237c87c5fbaSopenharmony_ci            goto fail_body;
3238c87c5fbaSopenharmony_ci          if (coap_send_internal(session, pdu) == COAP_INVALID_MID)
3239c87c5fbaSopenharmony_ci            goto fail_body;
3240c87c5fbaSopenharmony_ci        }
3241c87c5fbaSopenharmony_ci        return 1;
3242c87c5fbaSopenharmony_ci      }
3243c87c5fbaSopenharmony_cifail_cbor:
3244c87c5fbaSopenharmony_ci      coap_log_info("Invalid application/missing-blocks+cbor-seq\n");
3245c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3246c87c5fbaSopenharmony_ci    }
3247c87c5fbaSopenharmony_ci    goto lg_xmit_finished;
3248c87c5fbaSopenharmony_ci  } /* end of LL_FOREACH_SAFE */
3249c87c5fbaSopenharmony_ci  return 0;
3250c87c5fbaSopenharmony_ci
3251c87c5fbaSopenharmony_cifail_body:
3252c87c5fbaSopenharmony_ci  coap_handle_event(session->context, COAP_EVENT_XMIT_BLOCK_FAIL, session);
3253c87c5fbaSopenharmony_ci  /* There has been an internal error of some sort */
3254c87c5fbaSopenharmony_ci  rcvd->code = COAP_RESPONSE_CODE(500);
3255c87c5fbaSopenharmony_cilg_xmit_finished:
3256c87c5fbaSopenharmony_ci  if (session->lg_crcv) {
3257c87c5fbaSopenharmony_ci    LL_FOREACH(session->lg_crcv, lg_crcv) {
3258c87c5fbaSopenharmony_ci      if (STATE_TOKEN_BASE(p->b.b1.state_token) ==
3259c87c5fbaSopenharmony_ci          STATE_TOKEN_BASE(lg_crcv->state_token)) {
3260c87c5fbaSopenharmony_ci        /* In case of observe */
3261c87c5fbaSopenharmony_ci        lg_crcv->state_token = p->b.b1.state_token;
3262c87c5fbaSopenharmony_ci        break;
3263c87c5fbaSopenharmony_ci      }
3264c87c5fbaSopenharmony_ci    }
3265c87c5fbaSopenharmony_ci  }
3266c87c5fbaSopenharmony_ci  if (!lg_crcv) {
3267c87c5fbaSopenharmony_ci    /* need to put back original token into rcvd */
3268c87c5fbaSopenharmony_ci    if (p->b.b1.app_token)
3269c87c5fbaSopenharmony_ci      coap_update_token(rcvd, p->b.b1.app_token->length,
3270c87c5fbaSopenharmony_ci                        p->b.b1.app_token->s);
3271c87c5fbaSopenharmony_ci    coap_log_debug("Client app version of updated PDU\n");
3272c87c5fbaSopenharmony_ci    coap_show_pdu(COAP_LOG_DEBUG, rcvd);
3273c87c5fbaSopenharmony_ci  }
3274c87c5fbaSopenharmony_ci
3275c87c5fbaSopenharmony_ci  LL_DELETE(session->lg_xmit, p);
3276c87c5fbaSopenharmony_ci  coap_block_delete_lg_xmit(session, p);
3277c87c5fbaSopenharmony_ci  return 0;
3278c87c5fbaSopenharmony_ci}
3279c87c5fbaSopenharmony_ci#endif /* COAP_CLIENT_SUPPORT */
3280c87c5fbaSopenharmony_ci
3281c87c5fbaSopenharmony_ci/*
3282c87c5fbaSopenharmony_ci * Re-assemble payloads into a body
3283c87c5fbaSopenharmony_ci */
3284c87c5fbaSopenharmony_cicoap_binary_t *
3285c87c5fbaSopenharmony_cicoap_block_build_body(coap_binary_t *body_data, size_t length,
3286c87c5fbaSopenharmony_ci                      const uint8_t *data, size_t offset, size_t total) {
3287c87c5fbaSopenharmony_ci  if (data == NULL)
3288c87c5fbaSopenharmony_ci    return NULL;
3289c87c5fbaSopenharmony_ci  if (body_data == NULL && total) {
3290c87c5fbaSopenharmony_ci    body_data = coap_new_binary(total);
3291c87c5fbaSopenharmony_ci  }
3292c87c5fbaSopenharmony_ci  if (body_data == NULL)
3293c87c5fbaSopenharmony_ci    return NULL;
3294c87c5fbaSopenharmony_ci
3295c87c5fbaSopenharmony_ci  /* Update saved data */
3296c87c5fbaSopenharmony_ci  if (offset + length <= total && body_data->length >= total) {
3297c87c5fbaSopenharmony_ci    memcpy(&body_data->s[offset], data, length);
3298c87c5fbaSopenharmony_ci  } else {
3299c87c5fbaSopenharmony_ci    /*
3300c87c5fbaSopenharmony_ci     * total may be inaccurate as per
3301c87c5fbaSopenharmony_ci     * https://rfc-editor.org/rfc/rfc7959#section-4
3302c87c5fbaSopenharmony_ci     * o In a request carrying a Block1 Option, to indicate the current
3303c87c5fbaSopenharmony_ci     *   estimate the client has of the total size of the resource
3304c87c5fbaSopenharmony_ci     *   representation, measured in bytes ("size indication").
3305c87c5fbaSopenharmony_ci     * o In a response carrying a Block2 Option, to indicate the current
3306c87c5fbaSopenharmony_ci     *   estimate the server has of the total size of the resource
3307c87c5fbaSopenharmony_ci     *   representation, measured in bytes ("size indication").
3308c87c5fbaSopenharmony_ci     */
3309c87c5fbaSopenharmony_ci    coap_binary_t *new = coap_resize_binary(body_data, offset + length);
3310c87c5fbaSopenharmony_ci
3311c87c5fbaSopenharmony_ci    if (new) {
3312c87c5fbaSopenharmony_ci      body_data = new;
3313c87c5fbaSopenharmony_ci      memcpy(&body_data->s[offset], data, length);
3314c87c5fbaSopenharmony_ci    } else {
3315c87c5fbaSopenharmony_ci      coap_delete_binary(body_data);
3316c87c5fbaSopenharmony_ci      return NULL;
3317c87c5fbaSopenharmony_ci    }
3318c87c5fbaSopenharmony_ci  }
3319c87c5fbaSopenharmony_ci  return body_data;
3320c87c5fbaSopenharmony_ci}
3321c87c5fbaSopenharmony_ci
3322c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
3323c87c5fbaSopenharmony_ci/*
3324c87c5fbaSopenharmony_ci * Need to see if this is a large body response to a request. If so,
3325c87c5fbaSopenharmony_ci * need to initiate the request for the next block and not trouble the
3326c87c5fbaSopenharmony_ci * application.  Note that Token must be unique per request/response.
3327c87c5fbaSopenharmony_ci *
3328c87c5fbaSopenharmony_ci * This is set up using coap_send()
3329c87c5fbaSopenharmony_ci * Client receives large data from server ((Q-)Block2)
3330c87c5fbaSopenharmony_ci *
3331c87c5fbaSopenharmony_ci * Return: 0 Call application handler
3332c87c5fbaSopenharmony_ci *         1 Do not call application handler - just sent the next request
3333c87c5fbaSopenharmony_ci */
3334c87c5fbaSopenharmony_ciint
3335c87c5fbaSopenharmony_cicoap_handle_response_get_block(coap_context_t *context,
3336c87c5fbaSopenharmony_ci                               coap_session_t *session,
3337c87c5fbaSopenharmony_ci                               coap_pdu_t *sent,
3338c87c5fbaSopenharmony_ci                               coap_pdu_t *rcvd,
3339c87c5fbaSopenharmony_ci                               coap_recurse_t recursive) {
3340c87c5fbaSopenharmony_ci  coap_lg_crcv_t *p;
3341c87c5fbaSopenharmony_ci  coap_block_b_t block;
3342c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3343c87c5fbaSopenharmony_ci  coap_block_b_t qblock;
3344c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3345c87c5fbaSopenharmony_ci  int have_block = 0;
3346c87c5fbaSopenharmony_ci  uint16_t block_opt = 0;
3347c87c5fbaSopenharmony_ci  size_t offset;
3348c87c5fbaSopenharmony_ci  int ack_rst_sent = 0;
3349c87c5fbaSopenharmony_ci  uint64_t token_match =
3350c87c5fbaSopenharmony_ci      STATE_TOKEN_BASE(coap_decode_var_bytes8(rcvd->actual_token.s,
3351c87c5fbaSopenharmony_ci                                              rcvd->actual_token.length));
3352c87c5fbaSopenharmony_ci
3353c87c5fbaSopenharmony_ci  memset(&block, 0, sizeof(block));
3354c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3355c87c5fbaSopenharmony_ci  memset(&qblock, 0, sizeof(qblock));
3356c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3357c87c5fbaSopenharmony_ci  LL_FOREACH(session->lg_crcv, p) {
3358c87c5fbaSopenharmony_ci    size_t chunk = 0;
3359c87c5fbaSopenharmony_ci    uint8_t buf[8];
3360c87c5fbaSopenharmony_ci    coap_opt_iterator_t opt_iter;
3361c87c5fbaSopenharmony_ci
3362c87c5fbaSopenharmony_ci    if (token_match != STATE_TOKEN_BASE(p->state_token) &&
3363c87c5fbaSopenharmony_ci        !coap_binary_equal(&rcvd->actual_token, p->app_token)) {
3364c87c5fbaSopenharmony_ci      /* try out the next one */
3365c87c5fbaSopenharmony_ci      continue;
3366c87c5fbaSopenharmony_ci    }
3367c87c5fbaSopenharmony_ci
3368c87c5fbaSopenharmony_ci    /* lg_crcv found */
3369c87c5fbaSopenharmony_ci
3370c87c5fbaSopenharmony_ci    if (COAP_RESPONSE_CLASS(rcvd->code) == 2) {
3371c87c5fbaSopenharmony_ci      size_t length;
3372c87c5fbaSopenharmony_ci      const uint8_t *data;
3373c87c5fbaSopenharmony_ci      coap_opt_t *size_opt = coap_check_option(rcvd, COAP_OPTION_SIZE2,
3374c87c5fbaSopenharmony_ci                                               &opt_iter);
3375c87c5fbaSopenharmony_ci      size_t size2 = size_opt ?
3376c87c5fbaSopenharmony_ci                     coap_decode_var_bytes(coap_opt_value(size_opt),
3377c87c5fbaSopenharmony_ci                                           coap_opt_length(size_opt)) : 0;
3378c87c5fbaSopenharmony_ci
3379c87c5fbaSopenharmony_ci      /* length and data are cleared on error */
3380c87c5fbaSopenharmony_ci      (void)coap_get_data(rcvd, &length, &data);
3381c87c5fbaSopenharmony_ci      rcvd->body_offset = 0;
3382c87c5fbaSopenharmony_ci      rcvd->body_total = length;
3383c87c5fbaSopenharmony_ci      if (coap_get_block_b(session, rcvd, COAP_OPTION_BLOCK2, &block)) {
3384c87c5fbaSopenharmony_ci        have_block = 1;
3385c87c5fbaSopenharmony_ci        block_opt = COAP_OPTION_BLOCK2;
3386c87c5fbaSopenharmony_ci      }
3387c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3388c87c5fbaSopenharmony_ci      if (coap_get_block_b(session, rcvd, COAP_OPTION_Q_BLOCK2, &qblock)) {
3389c87c5fbaSopenharmony_ci        if (have_block) {
3390c87c5fbaSopenharmony_ci          coap_log_warn("Both Block1 and Q-Block1 not supported in a response\n");
3391c87c5fbaSopenharmony_ci        }
3392c87c5fbaSopenharmony_ci        have_block = 1;
3393c87c5fbaSopenharmony_ci        block_opt = COAP_OPTION_Q_BLOCK2;
3394c87c5fbaSopenharmony_ci        block = qblock;
3395c87c5fbaSopenharmony_ci        /* server indicating that it supports Q_BLOCK */
3396c87c5fbaSopenharmony_ci        if (!(session->block_mode & COAP_BLOCK_HAS_Q_BLOCK)) {
3397c87c5fbaSopenharmony_ci          set_block_mode_has_q(session->block_mode);
3398c87c5fbaSopenharmony_ci        }
3399c87c5fbaSopenharmony_ci      }
3400c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3401c87c5fbaSopenharmony_ci      track_echo(session, rcvd);
3402c87c5fbaSopenharmony_ci      if (have_block && (block.m || length)) {
3403c87c5fbaSopenharmony_ci        coap_opt_t *fmt_opt = coap_check_option(rcvd,
3404c87c5fbaSopenharmony_ci                                                COAP_OPTION_CONTENT_FORMAT,
3405c87c5fbaSopenharmony_ci                                                &opt_iter);
3406c87c5fbaSopenharmony_ci        uint16_t fmt = fmt_opt ?
3407c87c5fbaSopenharmony_ci                       coap_decode_var_bytes(coap_opt_value(fmt_opt),
3408c87c5fbaSopenharmony_ci                                             coap_opt_length(fmt_opt)) :
3409c87c5fbaSopenharmony_ci                       COAP_MEDIATYPE_TEXT_PLAIN;
3410c87c5fbaSopenharmony_ci        coap_opt_t *etag_opt = coap_check_option(rcvd,
3411c87c5fbaSopenharmony_ci                                                 COAP_OPTION_ETAG,
3412c87c5fbaSopenharmony_ci                                                 &opt_iter);
3413c87c5fbaSopenharmony_ci        size_t saved_offset;
3414c87c5fbaSopenharmony_ci        int updated_block;
3415c87c5fbaSopenharmony_ci
3416c87c5fbaSopenharmony_ci        if (length > block.chunk_size) {
3417c87c5fbaSopenharmony_ci          coap_log_debug("block: Oversized packet - reduced to %"PRIu32" from %zu\n",
3418c87c5fbaSopenharmony_ci                         block.chunk_size, length);
3419c87c5fbaSopenharmony_ci          length = block.chunk_size;
3420c87c5fbaSopenharmony_ci        }
3421c87c5fbaSopenharmony_ci        /* Possibility that Size2 not sent, or is too small */
3422c87c5fbaSopenharmony_ci        chunk = (size_t)1 << (block.szx + 4);
3423c87c5fbaSopenharmony_ci        offset = block.num * chunk;
3424c87c5fbaSopenharmony_ci        if (size2 < (offset + length)) {
3425c87c5fbaSopenharmony_ci          if (block.m)
3426c87c5fbaSopenharmony_ci            size2 = offset + length + 1;
3427c87c5fbaSopenharmony_ci          else
3428c87c5fbaSopenharmony_ci            size2 = offset + length;
3429c87c5fbaSopenharmony_ci        }
3430c87c5fbaSopenharmony_ci        saved_offset = offset;
3431c87c5fbaSopenharmony_ci
3432c87c5fbaSopenharmony_ci        if (p->initial) {
3433c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3434c87c5fbaSopenharmony_cireinit:
3435c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3436c87c5fbaSopenharmony_ci          p->initial = 0;
3437c87c5fbaSopenharmony_ci          if (p->body_data) {
3438c87c5fbaSopenharmony_ci            coap_free_type(COAP_STRING, p->body_data);
3439c87c5fbaSopenharmony_ci            p->body_data = NULL;
3440c87c5fbaSopenharmony_ci          }
3441c87c5fbaSopenharmony_ci          if (etag_opt) {
3442c87c5fbaSopenharmony_ci            p->etag_length = coap_opt_length(etag_opt);
3443c87c5fbaSopenharmony_ci            memcpy(p->etag, coap_opt_value(etag_opt), p->etag_length);
3444c87c5fbaSopenharmony_ci            p->etag_set = 1;
3445c87c5fbaSopenharmony_ci          } else {
3446c87c5fbaSopenharmony_ci            p->etag_set = 0;
3447c87c5fbaSopenharmony_ci          }
3448c87c5fbaSopenharmony_ci          p->total_len = size2;
3449c87c5fbaSopenharmony_ci          p->content_format = fmt;
3450c87c5fbaSopenharmony_ci          p->szx = block.szx;
3451c87c5fbaSopenharmony_ci          p->block_option = block_opt;
3452c87c5fbaSopenharmony_ci          p->last_type = rcvd->type;
3453c87c5fbaSopenharmony_ci          p->rec_blocks.used = 0;
3454c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3455c87c5fbaSopenharmony_ci          p->rec_blocks.processing_payload_set = 0;
3456c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3457c87c5fbaSopenharmony_ci        }
3458c87c5fbaSopenharmony_ci        if (p->total_len < size2)
3459c87c5fbaSopenharmony_ci          p->total_len = size2;
3460c87c5fbaSopenharmony_ci
3461c87c5fbaSopenharmony_ci        if (etag_opt) {
3462c87c5fbaSopenharmony_ci          if (!full_match(coap_opt_value(etag_opt),
3463c87c5fbaSopenharmony_ci                          coap_opt_length(etag_opt),
3464c87c5fbaSopenharmony_ci                          p->etag, p->etag_length)) {
3465c87c5fbaSopenharmony_ci            /* body of data has changed - need to restart request */
3466c87c5fbaSopenharmony_ci            coap_pdu_t *pdu;
3467c87c5fbaSopenharmony_ci            uint64_t token = STATE_TOKEN_FULL(p->state_token,
3468c87c5fbaSopenharmony_ci                                              ++p->retry_counter);
3469c87c5fbaSopenharmony_ci            size_t len = coap_encode_var_safe8(buf, sizeof(token), token);
3470c87c5fbaSopenharmony_ci            coap_opt_filter_t drop_options;
3471c87c5fbaSopenharmony_ci
3472c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3473c87c5fbaSopenharmony_ci            if (block_opt == COAP_OPTION_Q_BLOCK2)
3474c87c5fbaSopenharmony_ci              goto reinit;
3475c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3476c87c5fbaSopenharmony_ci
3477c87c5fbaSopenharmony_ci            coap_log_warn("Data body updated during receipt - new request started\n");
3478c87c5fbaSopenharmony_ci            if (!(session->block_mode & COAP_BLOCK_SINGLE_BODY))
3479c87c5fbaSopenharmony_ci              coap_handle_event(context, COAP_EVENT_PARTIAL_BLOCK, session);
3480c87c5fbaSopenharmony_ci
3481c87c5fbaSopenharmony_ci            p->initial = 1;
3482c87c5fbaSopenharmony_ci            coap_free_type(COAP_STRING, p->body_data);
3483c87c5fbaSopenharmony_ci            p->body_data = NULL;
3484c87c5fbaSopenharmony_ci
3485c87c5fbaSopenharmony_ci            coap_session_new_token(session, &len, buf);
3486c87c5fbaSopenharmony_ci            memset(&drop_options, 0, sizeof(coap_opt_filter_t));
3487c87c5fbaSopenharmony_ci            coap_option_filter_set(&drop_options, COAP_OPTION_OBSERVE);
3488c87c5fbaSopenharmony_ci            pdu = coap_pdu_duplicate(&p->pdu, session, len, buf, &drop_options);
3489c87c5fbaSopenharmony_ci            if (!pdu)
3490c87c5fbaSopenharmony_ci              goto fail_resp;
3491c87c5fbaSopenharmony_ci
3492c87c5fbaSopenharmony_ci            coap_update_option(pdu, block_opt,
3493c87c5fbaSopenharmony_ci                               coap_encode_var_safe(buf, sizeof(buf),
3494c87c5fbaSopenharmony_ci                                                    (0 << 4) | (0 << 3) | block.aszx),
3495c87c5fbaSopenharmony_ci                               buf);
3496c87c5fbaSopenharmony_ci
3497c87c5fbaSopenharmony_ci            if (coap_send_internal(session, pdu) == COAP_INVALID_MID)
3498c87c5fbaSopenharmony_ci              goto fail_resp;
3499c87c5fbaSopenharmony_ci
3500c87c5fbaSopenharmony_ci            goto skip_app_handler;
3501c87c5fbaSopenharmony_ci          }
3502c87c5fbaSopenharmony_ci        } else if (p->etag_set) {
3503c87c5fbaSopenharmony_ci          /* Cannot handle this change in ETag to not being there */
3504c87c5fbaSopenharmony_ci          coap_log_warn("Not all blocks have ETag option\n");
3505c87c5fbaSopenharmony_ci          goto fail_resp;
3506c87c5fbaSopenharmony_ci        }
3507c87c5fbaSopenharmony_ci
3508c87c5fbaSopenharmony_ci        if (fmt != p->content_format) {
3509c87c5fbaSopenharmony_ci          coap_log_warn("Content-Format option mismatch\n");
3510c87c5fbaSopenharmony_ci          goto fail_resp;
3511c87c5fbaSopenharmony_ci        }
3512c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3513c87c5fbaSopenharmony_ci        if (block_opt == COAP_OPTION_Q_BLOCK2 && size2 != p->total_len) {
3514c87c5fbaSopenharmony_ci          coap_log_warn("Size2 option mismatch\n");
3515c87c5fbaSopenharmony_ci          goto fail_resp;
3516c87c5fbaSopenharmony_ci        }
3517c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3518c87c5fbaSopenharmony_ci        if (block.num == 0) {
3519c87c5fbaSopenharmony_ci          coap_opt_t *obs_opt = coap_check_option(rcvd,
3520c87c5fbaSopenharmony_ci                                                  COAP_OPTION_OBSERVE,
3521c87c5fbaSopenharmony_ci                                                  &opt_iter);
3522c87c5fbaSopenharmony_ci          if (obs_opt) {
3523c87c5fbaSopenharmony_ci            p->observe_length = min(coap_opt_length(obs_opt), 3);
3524c87c5fbaSopenharmony_ci            memcpy(p->observe, coap_opt_value(obs_opt), p->observe_length);
3525c87c5fbaSopenharmony_ci            p->observe_set = 1;
3526c87c5fbaSopenharmony_ci          } else {
3527c87c5fbaSopenharmony_ci            p->observe_set = 0;
3528c87c5fbaSopenharmony_ci          }
3529c87c5fbaSopenharmony_ci        }
3530c87c5fbaSopenharmony_ci        updated_block = 0;
3531c87c5fbaSopenharmony_ci        while (offset < saved_offset + length) {
3532c87c5fbaSopenharmony_ci          if (!check_if_received_block(&p->rec_blocks, block.num)) {
3533c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3534c87c5fbaSopenharmony_ci            uint32_t this_payload_set = block.num / COAP_MAX_PAYLOADS(session);
3535c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3536c87c5fbaSopenharmony_ci
3537c87c5fbaSopenharmony_ci            coap_log_debug("found Block option, block size is %u, block nr. %u\n",
3538c87c5fbaSopenharmony_ci                           1 << (block.szx + 4), block.num);
3539c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3540c87c5fbaSopenharmony_ci            if (block_opt == COAP_OPTION_Q_BLOCK2 && p->rec_blocks.used &&
3541c87c5fbaSopenharmony_ci                this_payload_set > p->rec_blocks.processing_payload_set &&
3542c87c5fbaSopenharmony_ci                this_payload_set != p->rec_blocks.latest_payload_set) {
3543c87c5fbaSopenharmony_ci              coap_request_missing_q_block2(session, p);
3544c87c5fbaSopenharmony_ci            }
3545c87c5fbaSopenharmony_ci            p->rec_blocks.latest_payload_set = this_payload_set;
3546c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3547c87c5fbaSopenharmony_ci            /* Update list of blocks received */
3548c87c5fbaSopenharmony_ci            if (!update_received_blocks(&p->rec_blocks, block.num)) {
3549c87c5fbaSopenharmony_ci              coap_handle_event(context, COAP_EVENT_PARTIAL_BLOCK, session);
3550c87c5fbaSopenharmony_ci              goto fail_resp;
3551c87c5fbaSopenharmony_ci            }
3552c87c5fbaSopenharmony_ci            updated_block = 1;
3553c87c5fbaSopenharmony_ci          }
3554c87c5fbaSopenharmony_ci          block.num++;
3555c87c5fbaSopenharmony_ci          offset = block.num << (block.szx + 4);
3556c87c5fbaSopenharmony_ci          if (!block.bert && block_opt != COAP_OPTION_Q_BLOCK2)
3557c87c5fbaSopenharmony_ci            break;
3558c87c5fbaSopenharmony_ci        }
3559c87c5fbaSopenharmony_ci        block.num--;
3560c87c5fbaSopenharmony_ci        /* Only process if not duplicate block */
3561c87c5fbaSopenharmony_ci        if (updated_block) {
3562c87c5fbaSopenharmony_ci          if ((session->block_mode & COAP_SINGLE_BLOCK_OR_Q) || block.bert) {
3563c87c5fbaSopenharmony_ci            if (size2 < saved_offset + length) {
3564c87c5fbaSopenharmony_ci              size2 = saved_offset + length;
3565c87c5fbaSopenharmony_ci            }
3566c87c5fbaSopenharmony_ci            p->body_data = coap_block_build_body(p->body_data, length, data,
3567c87c5fbaSopenharmony_ci                                                 saved_offset, size2);
3568c87c5fbaSopenharmony_ci            if (p->body_data == NULL) {
3569c87c5fbaSopenharmony_ci              goto fail_resp;
3570c87c5fbaSopenharmony_ci            }
3571c87c5fbaSopenharmony_ci          }
3572c87c5fbaSopenharmony_ci          if (block.m || !check_all_blocks_in(&p->rec_blocks,
3573c87c5fbaSopenharmony_ci                                              (size2 + chunk -1) / chunk)) {
3574c87c5fbaSopenharmony_ci            /* Not all the payloads of the body have arrived */
3575c87c5fbaSopenharmony_ci            size_t len;
3576c87c5fbaSopenharmony_ci            coap_pdu_t *pdu;
3577c87c5fbaSopenharmony_ci            uint64_t token;
3578c87c5fbaSopenharmony_ci
3579c87c5fbaSopenharmony_ci            if (block.m) {
3580c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3581c87c5fbaSopenharmony_ci              if (block_opt == COAP_OPTION_Q_BLOCK2) {
3582c87c5fbaSopenharmony_ci                /* Blocks could arrive in wrong order */
3583c87c5fbaSopenharmony_ci                if (check_all_blocks_in(&p->rec_blocks,
3584c87c5fbaSopenharmony_ci                                        (size2 + chunk -1) / chunk)) {
3585c87c5fbaSopenharmony_ci                  goto give_to_app;
3586c87c5fbaSopenharmony_ci                }
3587c87c5fbaSopenharmony_ci                if (check_all_blocks_in_for_payload_set(session,
3588c87c5fbaSopenharmony_ci                                                        &p->rec_blocks)) {
3589c87c5fbaSopenharmony_ci                  block.num = p->rec_blocks.range[0].end;
3590c87c5fbaSopenharmony_ci                  /* Now requesting next payload */
3591c87c5fbaSopenharmony_ci                  p->rec_blocks.processing_payload_set =
3592c87c5fbaSopenharmony_ci                      block.num / COAP_MAX_PAYLOADS(session) + 1;
3593c87c5fbaSopenharmony_ci                  if (check_any_blocks_next_payload_set(session,
3594c87c5fbaSopenharmony_ci                                                        &p->rec_blocks)) {
3595c87c5fbaSopenharmony_ci                    /* Need to ask for them individually */
3596c87c5fbaSopenharmony_ci                    coap_request_missing_q_block2(session, p);
3597c87c5fbaSopenharmony_ci                    goto skip_app_handler;
3598c87c5fbaSopenharmony_ci                  }
3599c87c5fbaSopenharmony_ci                } else {
3600c87c5fbaSopenharmony_ci                  /* The remote end will be sending the next one unless this
3601c87c5fbaSopenharmony_ci                     is a MAX_PAYLOADS and all previous have been received */
3602c87c5fbaSopenharmony_ci                  goto skip_app_handler;
3603c87c5fbaSopenharmony_ci                }
3604c87c5fbaSopenharmony_ci                if (COAP_PROTO_RELIABLE(session->proto) ||
3605c87c5fbaSopenharmony_ci                    rcvd->type != COAP_MESSAGE_NON)
3606c87c5fbaSopenharmony_ci                  goto skip_app_handler;
3607c87c5fbaSopenharmony_ci
3608c87c5fbaSopenharmony_ci              } else
3609c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3610c87c5fbaSopenharmony_ci                block.m = 0;
3611c87c5fbaSopenharmony_ci
3612c87c5fbaSopenharmony_ci              /* Ask for the next block */
3613c87c5fbaSopenharmony_ci              token = STATE_TOKEN_FULL(p->state_token, ++p->retry_counter);
3614c87c5fbaSopenharmony_ci              len = coap_encode_var_safe8(buf, sizeof(token), token);
3615c87c5fbaSopenharmony_ci              pdu = coap_pdu_duplicate(&p->pdu, session, len, buf, NULL);
3616c87c5fbaSopenharmony_ci              if (!pdu)
3617c87c5fbaSopenharmony_ci                goto fail_resp;
3618c87c5fbaSopenharmony_ci
3619c87c5fbaSopenharmony_ci              if (rcvd->type == COAP_MESSAGE_NON)
3620c87c5fbaSopenharmony_ci                pdu->type = COAP_MESSAGE_NON; /* Server is using NON */
3621c87c5fbaSopenharmony_ci
3622c87c5fbaSopenharmony_ci              /* Only sent with the first block */
3623c87c5fbaSopenharmony_ci              coap_remove_option(pdu, COAP_OPTION_OBSERVE);
3624c87c5fbaSopenharmony_ci
3625c87c5fbaSopenharmony_ci              coap_update_option(pdu, block_opt,
3626c87c5fbaSopenharmony_ci                                 coap_encode_var_safe(buf, sizeof(buf),
3627c87c5fbaSopenharmony_ci                                                      ((block.num + 1) << 4) |
3628c87c5fbaSopenharmony_ci                                                      (block.m << 3) | block.aszx),
3629c87c5fbaSopenharmony_ci                                 buf);
3630c87c5fbaSopenharmony_ci
3631c87c5fbaSopenharmony_ci              if (coap_send_internal(session, pdu) == COAP_INVALID_MID)
3632c87c5fbaSopenharmony_ci                goto fail_resp;
3633c87c5fbaSopenharmony_ci            }
3634c87c5fbaSopenharmony_ci            if ((session->block_mode & COAP_SINGLE_BLOCK_OR_Q) ||  block.bert)
3635c87c5fbaSopenharmony_ci              goto skip_app_handler;
3636c87c5fbaSopenharmony_ci
3637c87c5fbaSopenharmony_ci            /* need to put back original token into rcvd */
3638c87c5fbaSopenharmony_ci            coap_update_token(rcvd, p->app_token->length, p->app_token->s);
3639c87c5fbaSopenharmony_ci            rcvd->body_offset = saved_offset;
3640c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3641c87c5fbaSopenharmony_ci            rcvd->body_total = block_opt == COAP_OPTION_Q_BLOCK2 ?
3642c87c5fbaSopenharmony_ci                               p->total_len : size2;
3643c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
3644c87c5fbaSopenharmony_ci            rcvd->body_total = size2;
3645c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
3646c87c5fbaSopenharmony_ci            coap_log_debug("Client app version of updated PDU\n");
3647c87c5fbaSopenharmony_ci            coap_show_pdu(COAP_LOG_DEBUG, rcvd);
3648c87c5fbaSopenharmony_ci            goto call_app_handler;
3649c87c5fbaSopenharmony_ci          }
3650c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3651c87c5fbaSopenharmony_cigive_to_app:
3652c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3653c87c5fbaSopenharmony_ci          if ((session->block_mode & COAP_SINGLE_BLOCK_OR_Q) || block.bert) {
3654c87c5fbaSopenharmony_ci            /* Pretend that there is no block */
3655c87c5fbaSopenharmony_ci            coap_remove_option(rcvd, block_opt);
3656c87c5fbaSopenharmony_ci            if (p->observe_set) {
3657c87c5fbaSopenharmony_ci              coap_update_option(rcvd, COAP_OPTION_OBSERVE,
3658c87c5fbaSopenharmony_ci                                 p->observe_length, p->observe);
3659c87c5fbaSopenharmony_ci            }
3660c87c5fbaSopenharmony_ci            rcvd->body_data = p->body_data->s;
3661c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3662c87c5fbaSopenharmony_ci            rcvd->body_length = block_opt == COAP_OPTION_Q_BLOCK2 ?
3663c87c5fbaSopenharmony_ci                                p->total_len : saved_offset + length;
3664c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
3665c87c5fbaSopenharmony_ci            rcvd->body_length = saved_offset + length;
3666c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
3667c87c5fbaSopenharmony_ci            rcvd->body_offset = 0;
3668c87c5fbaSopenharmony_ci            rcvd->body_total = rcvd->body_length;
3669c87c5fbaSopenharmony_ci          } else {
3670c87c5fbaSopenharmony_ci            rcvd->body_offset = saved_offset;
3671c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3672c87c5fbaSopenharmony_ci            rcvd->body_total = block_opt == COAP_OPTION_Q_BLOCK2 ?
3673c87c5fbaSopenharmony_ci                               p->total_len : size2;
3674c87c5fbaSopenharmony_ci#else /* ! COAP_Q_BLOCK_SUPPORT */
3675c87c5fbaSopenharmony_ci            rcvd->body_total = size2;
3676c87c5fbaSopenharmony_ci#endif /* ! COAP_Q_BLOCK_SUPPORT */
3677c87c5fbaSopenharmony_ci          }
3678c87c5fbaSopenharmony_ci          if (context->response_handler) {
3679c87c5fbaSopenharmony_ci            /* need to put back original token into rcvd */
3680c87c5fbaSopenharmony_ci            if (!coap_binary_equal(&rcvd->actual_token, p->app_token)) {
3681c87c5fbaSopenharmony_ci              coap_update_token(rcvd, p->app_token->length, p->app_token->s);
3682c87c5fbaSopenharmony_ci              coap_log_debug("Client app version of updated PDU\n");
3683c87c5fbaSopenharmony_ci              coap_show_pdu(COAP_LOG_DEBUG, rcvd);
3684c87c5fbaSopenharmony_ci            }
3685c87c5fbaSopenharmony_ci            if (context->response_handler(session, sent, rcvd,
3686c87c5fbaSopenharmony_ci                                          rcvd->mid) == COAP_RESPONSE_FAIL)
3687c87c5fbaSopenharmony_ci              coap_send_rst(session, rcvd);
3688c87c5fbaSopenharmony_ci            else
3689c87c5fbaSopenharmony_ci              coap_send_ack(session, rcvd);
3690c87c5fbaSopenharmony_ci          } else {
3691c87c5fbaSopenharmony_ci            coap_send_ack(session, rcvd);
3692c87c5fbaSopenharmony_ci          }
3693c87c5fbaSopenharmony_ci          ack_rst_sent = 1;
3694c87c5fbaSopenharmony_ci          if (p->observe_set == 0) {
3695c87c5fbaSopenharmony_ci            /* Expire this entry */
3696c87c5fbaSopenharmony_ci            LL_DELETE(session->lg_crcv, p);
3697c87c5fbaSopenharmony_ci            coap_block_delete_lg_crcv(session, p);
3698c87c5fbaSopenharmony_ci            goto skip_app_handler;
3699c87c5fbaSopenharmony_ci          }
3700c87c5fbaSopenharmony_ci          /* Set up for the next data body as observing */
3701c87c5fbaSopenharmony_ci          p->initial = 1;
3702c87c5fbaSopenharmony_ci          if (p->body_data) {
3703c87c5fbaSopenharmony_ci            coap_free_type(COAP_STRING, p->body_data);
3704c87c5fbaSopenharmony_ci            p->body_data = NULL;
3705c87c5fbaSopenharmony_ci          }
3706c87c5fbaSopenharmony_ci        }
3707c87c5fbaSopenharmony_ci        coap_ticks(&p->last_used);
3708c87c5fbaSopenharmony_ci        goto skip_app_handler;
3709c87c5fbaSopenharmony_ci      } else {
3710c87c5fbaSopenharmony_ci        coap_opt_t *obs_opt = coap_check_option(rcvd,
3711c87c5fbaSopenharmony_ci                                                COAP_OPTION_OBSERVE,
3712c87c5fbaSopenharmony_ci                                                &opt_iter);
3713c87c5fbaSopenharmony_ci        if (obs_opt) {
3714c87c5fbaSopenharmony_ci          p->observe_length = min(coap_opt_length(obs_opt), 3);
3715c87c5fbaSopenharmony_ci          memcpy(p->observe, coap_opt_value(obs_opt), p->observe_length);
3716c87c5fbaSopenharmony_ci          p->observe_set = 1;
3717c87c5fbaSopenharmony_ci        } else {
3718c87c5fbaSopenharmony_ci          p->observe_set = 0;
3719c87c5fbaSopenharmony_ci          if (!coap_binary_equal(&rcvd->actual_token, p->app_token)) {
3720c87c5fbaSopenharmony_ci            /* need to put back original token into rcvd */
3721c87c5fbaSopenharmony_ci            coap_update_token(rcvd, p->app_token->length, p->app_token->s);
3722c87c5fbaSopenharmony_ci            coap_log_debug("PDU presented to app.\n");
3723c87c5fbaSopenharmony_ci            coap_show_pdu(COAP_LOG_DEBUG, rcvd);
3724c87c5fbaSopenharmony_ci          }
3725c87c5fbaSopenharmony_ci          /* Expire this entry */
3726c87c5fbaSopenharmony_ci          goto expire_lg_crcv;
3727c87c5fbaSopenharmony_ci        }
3728c87c5fbaSopenharmony_ci      }
3729c87c5fbaSopenharmony_ci      coap_ticks(&p->last_used);
3730c87c5fbaSopenharmony_ci    } else if (rcvd->code == COAP_RESPONSE_CODE(401)) {
3731c87c5fbaSopenharmony_ci#if COAP_OSCORE_SUPPORT
3732c87c5fbaSopenharmony_ci      if (check_freshness(session, rcvd,
3733c87c5fbaSopenharmony_ci                          (session->oscore_encryption == 0) ? sent : NULL,
3734c87c5fbaSopenharmony_ci                          NULL, p))
3735c87c5fbaSopenharmony_ci#else /* !COAP_OSCORE_SUPPORT */
3736c87c5fbaSopenharmony_ci      if (check_freshness(session, rcvd, sent, NULL, p))
3737c87c5fbaSopenharmony_ci#endif /* !COAP_OSCORE_SUPPORT */
3738c87c5fbaSopenharmony_ci        goto skip_app_handler;
3739c87c5fbaSopenharmony_ci      goto expire_lg_crcv;
3740c87c5fbaSopenharmony_ci    } else {
3741c87c5fbaSopenharmony_ci      /* Not 2.xx or 4.01 - assume it is a failure of some sort */
3742c87c5fbaSopenharmony_ci      goto expire_lg_crcv;
3743c87c5fbaSopenharmony_ci    }
3744c87c5fbaSopenharmony_ci    if (!block.m && !p->observe_set) {
3745c87c5fbaSopenharmony_cifail_resp:
3746c87c5fbaSopenharmony_ci      /* lg_crcv no longer required - cache it for 1 sec */
3747c87c5fbaSopenharmony_ci      coap_ticks(&p->last_used);
3748c87c5fbaSopenharmony_ci      p->last_used = p->last_used - COAP_MAX_TRANSMIT_WAIT_TICKS(session) +
3749c87c5fbaSopenharmony_ci                     COAP_TICKS_PER_SECOND;
3750c87c5fbaSopenharmony_ci    }
3751c87c5fbaSopenharmony_ci    /* need to put back original token into rcvd */
3752c87c5fbaSopenharmony_ci    if (!coap_binary_equal(&rcvd->actual_token, p->app_token)) {
3753c87c5fbaSopenharmony_ci      coap_update_token(rcvd, p->app_token->length, p->app_token->s);
3754c87c5fbaSopenharmony_ci      coap_log_debug("Client app version of updated PDU (3)\n");
3755c87c5fbaSopenharmony_ci      coap_show_pdu(COAP_LOG_DEBUG, rcvd);
3756c87c5fbaSopenharmony_ci    }
3757c87c5fbaSopenharmony_ci    break;
3758c87c5fbaSopenharmony_ci  } /* LL_FOREACH() */
3759c87c5fbaSopenharmony_ci
3760c87c5fbaSopenharmony_ci  /* Check if receiving a block response and if blocks can be set up */
3761c87c5fbaSopenharmony_ci  if (recursive == COAP_RECURSE_OK && !p) {
3762c87c5fbaSopenharmony_ci    if (!sent) {
3763c87c5fbaSopenharmony_ci      if (coap_get_block_b(session, rcvd, COAP_OPTION_BLOCK2, &block)
3764c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3765c87c5fbaSopenharmony_ci          ||
3766c87c5fbaSopenharmony_ci          coap_get_block_b(session, rcvd, COAP_OPTION_Q_BLOCK2, &block)
3767c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3768c87c5fbaSopenharmony_ci         ) {
3769c87c5fbaSopenharmony_ci        coap_log_debug("** %s: large body receive internal issue\n",
3770c87c5fbaSopenharmony_ci                       coap_session_str(session));
3771c87c5fbaSopenharmony_ci        goto skip_app_handler;
3772c87c5fbaSopenharmony_ci      }
3773c87c5fbaSopenharmony_ci    } else if (COAP_RESPONSE_CLASS(rcvd->code) == 2) {
3774c87c5fbaSopenharmony_ci      if (coap_get_block_b(session, rcvd, COAP_OPTION_BLOCK2, &block)) {
3775c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3776c87c5fbaSopenharmony_ci        if (session->block_mode & COAP_BLOCK_PROBE_Q_BLOCK) {
3777c87c5fbaSopenharmony_ci          set_block_mode_drop_q(session->block_mode);
3778c87c5fbaSopenharmony_ci          coap_log_debug("Q-Block support disabled\n");
3779c87c5fbaSopenharmony_ci        }
3780c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3781c87c5fbaSopenharmony_ci        have_block = 1;
3782c87c5fbaSopenharmony_ci        block_opt = COAP_OPTION_BLOCK2;
3783c87c5fbaSopenharmony_ci        if (block.num != 0) {
3784c87c5fbaSopenharmony_ci          /* Assume random access and just give the single response to app */
3785c87c5fbaSopenharmony_ci          size_t length;
3786c87c5fbaSopenharmony_ci          const uint8_t *data;
3787c87c5fbaSopenharmony_ci          size_t chunk = (size_t)1 << (block.szx + 4);
3788c87c5fbaSopenharmony_ci
3789c87c5fbaSopenharmony_ci          coap_get_data(rcvd, &length, &data);
3790c87c5fbaSopenharmony_ci          rcvd->body_offset = block.num*chunk;
3791c87c5fbaSopenharmony_ci          rcvd->body_total = block.num*chunk + length + (block.m ? 1 : 0);
3792c87c5fbaSopenharmony_ci          goto call_app_handler;
3793c87c5fbaSopenharmony_ci        }
3794c87c5fbaSopenharmony_ci      }
3795c87c5fbaSopenharmony_ci#if COAP_Q_BLOCK_SUPPORT
3796c87c5fbaSopenharmony_ci      else if (coap_get_block_b(session, rcvd, COAP_OPTION_Q_BLOCK2, &block)) {
3797c87c5fbaSopenharmony_ci        have_block = 1;
3798c87c5fbaSopenharmony_ci        block_opt = COAP_OPTION_Q_BLOCK2;
3799c87c5fbaSopenharmony_ci        /* server indicating that it supports Q_BLOCK2 */
3800c87c5fbaSopenharmony_ci        if (!(session->block_mode & COAP_BLOCK_HAS_Q_BLOCK)) {
3801c87c5fbaSopenharmony_ci          set_block_mode_has_q(session->block_mode);
3802c87c5fbaSopenharmony_ci        }
3803c87c5fbaSopenharmony_ci      }
3804c87c5fbaSopenharmony_ci#endif /* COAP_Q_BLOCK_SUPPORT */
3805c87c5fbaSopenharmony_ci      if (have_block) {
3806c87c5fbaSopenharmony_ci        coap_lg_crcv_t *lg_crcv = coap_block_new_lg_crcv(session, sent, NULL);
3807c87c5fbaSopenharmony_ci
3808c87c5fbaSopenharmony_ci        if (lg_crcv) {
3809c87c5fbaSopenharmony_ci          LL_PREPEND(session->lg_crcv, lg_crcv);
3810c87c5fbaSopenharmony_ci          return coap_handle_response_get_block(context, session, sent, rcvd,
3811c87c5fbaSopenharmony_ci                                                COAP_RECURSE_NO);
3812c87c5fbaSopenharmony_ci        }
3813c87c5fbaSopenharmony_ci      }
3814c87c5fbaSopenharmony_ci      track_echo(session, rcvd);
3815c87c5fbaSopenharmony_ci    } else if (rcvd->code == COAP_RESPONSE_CODE(401)) {
3816c87c5fbaSopenharmony_ci      coap_lg_crcv_t *lg_crcv = coap_block_new_lg_crcv(session, sent, NULL);
3817c87c5fbaSopenharmony_ci
3818c87c5fbaSopenharmony_ci      if (lg_crcv) {
3819c87c5fbaSopenharmony_ci        LL_PREPEND(session->lg_crcv, lg_crcv);
3820c87c5fbaSopenharmony_ci        return coap_handle_response_get_block(context, session, sent, rcvd,
3821c87c5fbaSopenharmony_ci                                              COAP_RECURSE_NO);
3822c87c5fbaSopenharmony_ci      }
3823c87c5fbaSopenharmony_ci    }
3824c87c5fbaSopenharmony_ci  }
3825c87c5fbaSopenharmony_ci  return 0;
3826c87c5fbaSopenharmony_ci
3827c87c5fbaSopenharmony_ciexpire_lg_crcv:
3828c87c5fbaSopenharmony_ci  /* need to put back original token into rcvd */
3829c87c5fbaSopenharmony_ci  if (!coap_binary_equal(&rcvd->actual_token, p->app_token)) {
3830c87c5fbaSopenharmony_ci    coap_update_token(rcvd, p->app_token->length, p->app_token->s);
3831c87c5fbaSopenharmony_ci    coap_log_debug("Client app version of updated PDU\n");
3832c87c5fbaSopenharmony_ci    coap_show_pdu(COAP_LOG_DEBUG, rcvd);
3833c87c5fbaSopenharmony_ci  }
3834c87c5fbaSopenharmony_ci  /* Expire this entry */
3835c87c5fbaSopenharmony_ci  LL_DELETE(session->lg_crcv, p);
3836c87c5fbaSopenharmony_ci  coap_block_delete_lg_crcv(session, p);
3837c87c5fbaSopenharmony_ci
3838c87c5fbaSopenharmony_cicall_app_handler:
3839c87c5fbaSopenharmony_ci  return 0;
3840c87c5fbaSopenharmony_ci
3841c87c5fbaSopenharmony_ciskip_app_handler:
3842c87c5fbaSopenharmony_ci  if (!ack_rst_sent)
3843c87c5fbaSopenharmony_ci    coap_send_ack(session, rcvd);
3844c87c5fbaSopenharmony_ci  return 1;
3845c87c5fbaSopenharmony_ci}
3846c87c5fbaSopenharmony_ci#endif /* COAP_CLIENT_SUPPORT */
3847c87c5fbaSopenharmony_ci
3848c87c5fbaSopenharmony_ci#if COAP_SERVER_SUPPORT
3849c87c5fbaSopenharmony_ci/* Check if lg_xmit generated and update PDU code if so */
3850c87c5fbaSopenharmony_civoid
3851c87c5fbaSopenharmony_cicoap_check_code_lg_xmit(const coap_session_t *session,
3852c87c5fbaSopenharmony_ci                        const coap_pdu_t *request,
3853c87c5fbaSopenharmony_ci                        coap_pdu_t *response, const coap_resource_t *resource,
3854c87c5fbaSopenharmony_ci                        const coap_string_t *query) {
3855c87c5fbaSopenharmony_ci  coap_lg_xmit_t *lg_xmit;
3856c87c5fbaSopenharmony_ci
3857c87c5fbaSopenharmony_ci  if (response->code == 0)
3858c87c5fbaSopenharmony_ci    return;
3859c87c5fbaSopenharmony_ci  lg_xmit = coap_find_lg_xmit_response(session, request, resource, query);
3860c87c5fbaSopenharmony_ci  if (lg_xmit && lg_xmit->pdu.code == 0) {
3861c87c5fbaSopenharmony_ci    lg_xmit->pdu.code = response->code;
3862c87c5fbaSopenharmony_ci    return;
3863c87c5fbaSopenharmony_ci  }
3864c87c5fbaSopenharmony_ci}
3865c87c5fbaSopenharmony_ci#endif /* COAP_SERVER_SUPPORT */
3866c87c5fbaSopenharmony_ci
3867c87c5fbaSopenharmony_ci#if COAP_CLIENT_SUPPORT
3868c87c5fbaSopenharmony_civoid
3869c87c5fbaSopenharmony_cicoap_check_update_token(coap_session_t *session, coap_pdu_t *pdu) {
3870c87c5fbaSopenharmony_ci  uint64_t token_match =
3871c87c5fbaSopenharmony_ci      STATE_TOKEN_BASE(coap_decode_var_bytes8(pdu->actual_token.s,
3872c87c5fbaSopenharmony_ci                                              pdu->actual_token.length));
3873c87c5fbaSopenharmony_ci  coap_lg_xmit_t *lg_xmit;
3874c87c5fbaSopenharmony_ci  coap_lg_crcv_t *lg_crcv;
3875c87c5fbaSopenharmony_ci
3876c87c5fbaSopenharmony_ci  if (session->lg_crcv) {
3877c87c5fbaSopenharmony_ci    LL_FOREACH(session->lg_crcv, lg_crcv) {
3878c87c5fbaSopenharmony_ci      if (coap_binary_equal(&pdu->actual_token, lg_crcv->app_token))
3879c87c5fbaSopenharmony_ci        return;
3880c87c5fbaSopenharmony_ci      if (token_match == STATE_TOKEN_BASE(lg_crcv->state_token)) {
3881c87c5fbaSopenharmony_ci        coap_update_token(pdu, lg_crcv->app_token->length,
3882c87c5fbaSopenharmony_ci                          lg_crcv->app_token->s);
3883c87c5fbaSopenharmony_ci        coap_log_debug("Client app version of updated PDU\n");
3884c87c5fbaSopenharmony_ci        coap_show_pdu(COAP_LOG_DEBUG, pdu);
3885c87c5fbaSopenharmony_ci        return;
3886c87c5fbaSopenharmony_ci      }
3887c87c5fbaSopenharmony_ci    }
3888c87c5fbaSopenharmony_ci  }
3889c87c5fbaSopenharmony_ci  if (COAP_PDU_IS_REQUEST(pdu) && session->lg_xmit) {
3890c87c5fbaSopenharmony_ci    LL_FOREACH(session->lg_xmit, lg_xmit) {
3891c87c5fbaSopenharmony_ci      if (coap_binary_equal(&pdu->actual_token, lg_xmit->b.b1.app_token))
3892c87c5fbaSopenharmony_ci        return;
3893c87c5fbaSopenharmony_ci      if (token_match == STATE_TOKEN_BASE(lg_xmit->b.b1.state_token)) {
3894c87c5fbaSopenharmony_ci        coap_update_token(pdu, lg_xmit->b.b1.app_token->length,
3895c87c5fbaSopenharmony_ci                          lg_xmit->b.b1.app_token->s);
3896c87c5fbaSopenharmony_ci        coap_log_debug("Client app version of updated PDU\n");
3897c87c5fbaSopenharmony_ci        coap_show_pdu(COAP_LOG_DEBUG, pdu);
3898c87c5fbaSopenharmony_ci        return;
3899c87c5fbaSopenharmony_ci      }
3900c87c5fbaSopenharmony_ci    }
3901c87c5fbaSopenharmony_ci  }
3902c87c5fbaSopenharmony_ci}
3903c87c5fbaSopenharmony_ci#endif /* ! COAP_CLIENT_SUPPORT */
3904