diff --git a/sys/include/net/nanocoap.h b/sys/include/net/nanocoap.h index 6f4daa40f0..cf53564acc 100644 --- a/sys/include/net/nanocoap.h +++ b/sys/include/net/nanocoap.h @@ -717,6 +717,26 @@ size_t coap_blockwise_put_bytes(coap_block_slicer_t *slicer, uint8_t *bufpos, */ size_t coap_blockwise_put_char(coap_block_slicer_t *slicer, uint8_t *bufpos, char c); +/** + * @brief Block option getter + * + * This function gets a CoAP packet's block option and parses it into a helper + * structure. + * + * If no block option is present in @p pkt, the values in @p block will be + * initialized with zero. That implies both block->offset and block->more are + * also valid in that case, as packet with offset==0 and more==0 means it contains + * all the payload for the corresponding request. + * + * @param[in] pkt pkt to work on + * @param[out] block ptr to preallocated coap_block1_t structure + * @param[in] option block1 or block2 + * + * @returns 0 if block option not present + * @returns 1 if structure has been filled + */ +int coap_get_block(coap_pkt_t *pkt, coap_block1_t *block, uint16_t option); + /** * @brief Block1 option getter * @@ -729,23 +749,29 @@ size_t coap_blockwise_put_char(coap_block_slicer_t *slicer, uint8_t *bufpos, cha * all the payload for the corresponding request. * * @param[in] pkt pkt to work on - * @param[out] block1 ptr to preallocated coap_block1_t structure + * @param[out] block ptr to preallocated coap_block1_t structure * * @returns 0 if block1 option not present * @returns 1 if structure has been filled */ -int coap_get_block1(coap_pkt_t *pkt, coap_block1_t *block1); +static inline int coap_get_block1(coap_pkt_t *pkt, coap_block1_t *block) +{ + return coap_get_block(pkt, block, COAP_OPT_BLOCK1); +} /** * @brief Block2 option getter * * @param[in] pkt pkt to work on - * @param[out] block2 ptr to preallocated coap_block1_t structure + * @param[out] block ptr to preallocated coap_block1_t structure * * @returns 0 if block2 option not present * @returns 1 if structure has been filled */ -int coap_get_block2(coap_pkt_t *pkt, coap_block1_t *block2); +static inline int coap_get_block2(coap_pkt_t *pkt, coap_block1_t *block) +{ + return coap_get_block(pkt, block, COAP_OPT_BLOCK2); +} /** * @brief Generic block option getter @@ -1039,17 +1065,18 @@ static inline size_t coap_opt_put_block2(uint8_t *buf, uint16_t lastonum, } /** - * @brief Insert block option into buffer from block struct + * @brief Encode the given uint option into buffer * - * @param[in] buf buffer to write to - * @param[in] lastonum last option number (must be < @p option) - * @param[in] block block option attribute struct - * @param[in] option option number (block1 or block2) + * @param[out] buf buffer to write to + * @param[in] lastonum number of previous option (for delta calculation), + * or 0 for first option + * @param[in] onum number of option + * @param[in] value value to encode * * @returns amount of bytes written to @p buf */ -size_t coap_opt_put_block_object(uint8_t *buf, uint16_t lastonum, - coap_block1_t *block, uint16_t option); +size_t coap_opt_put_uint(uint8_t *buf, uint16_t lastonum, uint16_t onum, + uint32_t value); /** * @brief Insert block1 option into buffer in control usage @@ -1063,7 +1090,8 @@ size_t coap_opt_put_block_object(uint8_t *buf, uint16_t lastonum, static inline size_t coap_opt_put_block1_control(uint8_t *buf, uint16_t lastonum, coap_block1_t *block) { - return coap_opt_put_block_object(buf, lastonum, block, COAP_OPT_BLOCK1); + return coap_opt_put_uint(buf, lastonum, COAP_OPT_BLOCK1, + (block->blknum << 4) | block->szx | (block->more ? 0x8 : 0)); } /** @@ -1080,8 +1108,9 @@ static inline size_t coap_opt_put_block1_control(uint8_t *buf, uint16_t lastonum static inline size_t coap_opt_put_block2_control(uint8_t *buf, uint16_t lastonum, coap_block1_t *block) { - block->more = 0; - return coap_opt_put_block_object(buf, lastonum, block, COAP_OPT_BLOCK2); + /* block.more must be zero, so no need to 'or' it in */ + return coap_opt_put_uint(buf, lastonum, COAP_OPT_BLOCK2, + (block->blknum << 4) | block->szx); } /** @@ -1216,7 +1245,12 @@ size_t coap_put_option(uint8_t *buf, uint16_t lastonum, uint16_t onum, const uin * * @returns amount of bytes written to @p buf */ -size_t coap_put_option_block1(uint8_t *buf, uint16_t lastonum, unsigned blknum, unsigned szx, int more); +static inline size_t coap_put_option_block1(uint8_t *buf, uint16_t lastonum, + unsigned blknum, unsigned szx, int more) +{ + return coap_opt_put_uint(buf, lastonum, COAP_OPT_BLOCK1, + (blknum << 4) | szx | (more ? 0x8 : 0)); +} /** * @brief Insert content type option into buffer @@ -1228,7 +1262,11 @@ size_t coap_put_option_block1(uint8_t *buf, uint16_t lastonum, unsigned blknum, * * @returns amount of bytes written to @p buf */ -size_t coap_put_option_ct(uint8_t *buf, uint16_t lastonum, uint16_t content_type); +static inline size_t coap_put_option_ct(uint8_t *buf, uint16_t lastonum, + uint16_t content_type) +{ + return coap_opt_put_uint(buf, lastonum, COAP_OPT_CONTENT_FORMAT, content_type); +} /**@}*/ diff --git a/sys/net/application_layer/nanocoap/nanocoap.c b/sys/net/application_layer/nanocoap/nanocoap.c index f5090e2a77..df0853c349 100644 --- a/sys/net/application_layer/nanocoap/nanocoap.c +++ b/sys/net/application_layer/nanocoap/nanocoap.c @@ -26,6 +26,7 @@ #include #include +#include "bitarithm.h" #include "net/nanocoap.h" #define ENABLE_DEBUG (0) @@ -653,35 +654,20 @@ size_t coap_put_option(uint8_t *buf, uint16_t lastonum, uint16_t onum, const uin return (size_t)n; } -size_t coap_put_option_ct(uint8_t *buf, uint16_t lastonum, uint16_t content_type) -{ - if (content_type == 0) { - return coap_put_option(buf, lastonum, COAP_OPT_CONTENT_FORMAT, NULL, 0); - } - else if (content_type <= 255) { - uint8_t tmp = content_type; - return coap_put_option(buf, lastonum, COAP_OPT_CONTENT_FORMAT, &tmp, sizeof(tmp)); - } - else { - return coap_put_option(buf, lastonum, COAP_OPT_CONTENT_FORMAT, (uint8_t *)&content_type, sizeof(content_type)); - } -} - static unsigned _size2szx(size_t size) { - unsigned szx = 0; assert(size <= 1024); - while (size) { - size = size >> 1; - szx++; - } - /* Size exponent + 1 */ - assert(szx >= 5); - return szx - 5; + /* We must wait to subract the szx offset of 4 until after the assert below. + * Input should be a power of two, but if not it may have a stray low order + * '1' bit that would invalidate the subtraction. */ + unsigned szx = bitarithm_lsb(size); + + assert(szx >= 4); + return szx - 4; } -static unsigned _slicer_blknum(coap_block_slicer_t *slicer) +static unsigned _slicer2blkopt(coap_block_slicer_t *slicer, bool more) { size_t blksize = slicer->end - slicer->start; size_t start = slicer->start; @@ -691,51 +677,23 @@ static unsigned _slicer_blknum(coap_block_slicer_t *slicer) start -= blksize; blknum++; } - return blknum; + + return (blknum << 4) | _size2szx(blksize) | (more ? 0x8 : 0); } -static size_t coap_put_option_block(uint8_t *buf, uint16_t lastonum, unsigned blknum, unsigned szx, int more, uint16_t option) +int coap_get_block(coap_pkt_t *pkt, coap_block1_t *block, uint16_t option) { - uint32_t blkopt = (blknum << 4) | szx | (more ? 0x8 : 0); - size_t olen = _encode_uint(&blkopt); - - return coap_put_option(buf, lastonum, option, (uint8_t *)&blkopt, olen); -} - -size_t coap_put_option_block1(uint8_t *buf, uint16_t lastonum, unsigned blknum, unsigned szx, int more) -{ - return coap_put_option_block(buf, lastonum, blknum, szx, more, COAP_OPT_BLOCK1); -} - -int coap_get_block(coap_pkt_t *pkt, coap_block1_t *block, uint16_t blkopt) -{ - uint32_t blknum; - unsigned szx; - - block->more = coap_get_blockopt(pkt, blkopt, &blknum, &szx); + block->more = coap_get_blockopt(pkt, option, &block->blknum, &block->szx); if (block->more >= 0) { - block->offset = blknum << (szx + 4); + block->offset = block->blknum << (block->szx + 4); } else { block->offset = 0; } - block->blknum = blknum; - block->szx = szx; - return (block->more >= 0); } -int coap_get_block1(coap_pkt_t *pkt, coap_block1_t *block) -{ - return coap_get_block(pkt, block, COAP_OPT_BLOCK1); -} - -int coap_get_block2(coap_pkt_t *pkt, coap_block1_t *block) -{ - return coap_get_block(pkt, block, COAP_OPT_BLOCK2); -} - size_t coap_put_block1_ok(uint8_t *pkt_pos, coap_block1_t *block1, uint16_t lastonum) { if (block1->more >= 1) { @@ -749,23 +707,9 @@ size_t coap_put_block1_ok(uint8_t *pkt_pos, coap_block1_t *block1, uint16_t last size_t coap_opt_put_block(uint8_t *buf, uint16_t lastonum, coap_block_slicer_t *slicer, bool more, uint16_t option) { - coap_block1_t block; - - coap_block_object_init(&block, _slicer_blknum(slicer), - slicer->end - slicer->start, more); - slicer->opt = buf; - return coap_opt_put_block_object(buf, lastonum, &block, option); -} - -size_t coap_opt_put_block_object(uint8_t *buf, uint16_t lastonum, - coap_block1_t *block, uint16_t option) -{ - uint32_t blkopt = (block->blknum << 4) | block->szx | (block->more ? 0x8 : 0); - size_t olen = _encode_uint(&blkopt); - - return coap_put_option(buf, lastonum, option, (uint8_t *)&blkopt, olen); + return coap_opt_put_uint(buf, lastonum, option, _slicer2blkopt(slicer, more)); } size_t coap_opt_put_string(uint8_t *buf, uint16_t lastonum, uint16_t optnum, @@ -810,6 +754,14 @@ size_t coap_opt_put_string(uint8_t *buf, uint16_t lastonum, uint16_t optnum, return bufpos - buf; } +size_t coap_opt_put_uint(uint8_t *buf, uint16_t lastonum, uint16_t onum, + uint32_t value) +{ + unsigned uint_len = _encode_uint(&value); + + return coap_put_option(buf, lastonum, onum, (uint8_t *)&value, uint_len); +} + /* Common functionality for addition of an option */ static ssize_t _add_opt_pkt(coap_pkt_t *pkt, uint16_t optnum, const uint8_t *val, size_t val_len) @@ -900,13 +852,9 @@ ssize_t coap_opt_add_uint(coap_pkt_t *pkt, uint16_t optnum, uint32_t value) ssize_t coap_opt_add_block(coap_pkt_t *pkt, coap_block_slicer_t *slicer, bool more, uint16_t option) { - uint32_t blkopt = (_slicer_blknum(slicer) << 4); - blkopt |= _size2szx(slicer->end - slicer->start); - blkopt |= (more ? 0x8 : 0); - slicer->opt = pkt->payload; - return coap_opt_add_uint(pkt, option, blkopt); + return coap_opt_add_uint(pkt, option, _slicer2blkopt(slicer, more)); } ssize_t coap_opt_finish(coap_pkt_t *pkt, uint16_t flags) @@ -932,6 +880,7 @@ void coap_block_object_init(coap_block1_t *block, size_t blknum, size_t blksize, block->szx = _size2szx(blksize); block->blknum = blknum; block->more = more; + block->offset = block->blknum << (block->szx + 4); } void coap_block_slicer_init(coap_block_slicer_t *slicer, size_t blknum, @@ -969,12 +918,7 @@ void coap_block_finish(coap_block_slicer_t *slicer, uint16_t option) uint8_t *pos = slicer->opt + 1; uint16_t delta = _decode_value(*slicer->opt >> 4, &pos, slicer->opt + 3); - /* Calculate the block uint value inline here rather than through - * coap_opt_put_block(). Conserves stack and avoids importing Buffer API - * functions when using Packet API. */ - uint32_t blkopt = (_slicer_blknum(slicer) << 4); - blkopt |= _size2szx(slicer->end - slicer->start); - blkopt |= ((slicer->cur > slicer->end) ? 0x8 : 0); + uint32_t blkopt = _slicer2blkopt(slicer, slicer->cur > slicer->end); size_t olen = _encode_uint(&blkopt); coap_put_option(slicer->opt, option - delta, option, (uint8_t *)&blkopt, olen);