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