1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

nanocoap: introduce coap_opt_remove()

This commit is contained in:
Martine Lenders 2022-03-29 17:49:17 +02:00
parent 6849e33854
commit 00fdd8a146
No known key found for this signature in database
GPG Key ID: 2134D77A5336DD80
2 changed files with 95 additions and 0 deletions

View File

@ -927,6 +927,7 @@ static inline unsigned coap_szx2size(unsigned szx)
/**
* @name Functions -- Options Write Packet API
* @anchor net_nanocoap_opt_add
*
* Use a coap_pkt_t struct to manage writing Options to the PDU.
*
@ -1266,6 +1267,25 @@ static inline ssize_t coap_opt_add_uri_path_buffer(coap_pkt_t *pkt,
* @return -ENOSPC if no buffer space for payload marker
*/
ssize_t coap_opt_finish(coap_pkt_t *pkt, uint16_t flags);
/**
* @brief Removes an option previously added with function in
* [the coap_opt_add_...() group](@ref net_nanocoap_opt_add)
*
* @param[in] pkt Packet to remove option from.
* @param[in] optnum Option number of the option to remove. If the option appears more than once,
* the first occurrence will be removed
*
* @pre pkt != NULL
* @pre The packet was finished using @ref coap_opt_finish() and any payload is in its final
* configuration.
*
* @return The new size of the packet with option of number @p optnum removed. In turn this means
* if there is no such option in the packet, the original size of the packet will be
* removed.
* @return -EINVAL if there was a parsing error for the existing options
*/
ssize_t coap_opt_remove(coap_pkt_t *pkt, uint16_t optnum);
/**@}*/
/**

View File

@ -982,6 +982,81 @@ ssize_t coap_opt_finish(coap_pkt_t *pkt, uint16_t flags)
return pkt->payload - (uint8_t *)pkt->hdr;
}
ssize_t coap_opt_remove(coap_pkt_t *pkt, uint16_t opt_num)
{
assert(pkt);
coap_optpos_t *optpos = pkt->options;
coap_optpos_t *prev_opt = NULL;
unsigned opt_count = pkt->options_len;
uint8_t *start_old = NULL; /* First byte that is memmoved: content of next
* option, payload marker or end of message */
uint8_t *start_new = NULL; /* memmove destination: content after rewritten
* next option header, or offset of removed option */
while (opt_count--) {
if ((start_old == NULL) && (optpos->opt_num == opt_num)) {
unsigned new_hdr_len, old_hdr_len;
int option_len;
uint8_t *opt_start;
uint16_t old_delta, new_delta;
if (opt_count == 0) {
/* this is the last option => use payload / end pointer as old start */
start_old = (pkt->payload_len) ? pkt->payload - 1 : pkt->payload;
start_new = (uint8_t *)pkt->hdr + optpos->offset;
break;
}
if (prev_opt == NULL) {
/* this is the first option => new_delta is just opt_num of next option */
new_delta = optpos[1].opt_num;
} else {
new_delta = optpos[1].opt_num - prev_opt->opt_num;
}
prev_opt = optpos;
optpos++;
opt_count--;
/* select start of next option */
opt_start = (uint8_t *)pkt->hdr + optpos->offset;
start_old = _parse_option(pkt, opt_start, &old_delta, &option_len);
old_hdr_len = start_old - opt_start;
/* select start of to be deleted option and set delta/length of next option */
start_new = (uint8_t *)pkt->hdr + prev_opt->offset;
*start_new = 0;
/* write new_delta value to option header: 4 upper bits of header (shift 4) +
* 1 or 2 optional bytes depending on delta value) */
new_hdr_len = _put_delta_optlen(start_new, 1, 4, new_delta);
/* write option length to option header: 4 lower bits of header (shift 0) +
* 1 or 2 optional bytes depending of the length of the option */
new_hdr_len = _put_delta_optlen(start_new, new_hdr_len, 0, option_len);
start_new += new_hdr_len;
/* account for header length change in next option */
optpos->offset -= (new_hdr_len - old_hdr_len);
}
/* start_old implies start_new */
if (start_old != NULL) {
assert(start_new);
/* adapt options array for removed option */
memcpy(prev_opt, optpos, sizeof(*prev_opt));
prev_opt->offset -= (start_old - start_new);
}
prev_opt = optpos;
optpos++;
}
if (start_old != NULL) {
size_t move_size = (pkt->payload - start_old) + pkt->payload_len;
pkt->options_len--;
if (move_size > 0) {
memmove(start_new, start_old, move_size);
}
pkt->payload -= (start_old - start_new);
}
return (pkt->payload - ((uint8_t *)pkt->hdr)) + pkt->payload_len;
}
ssize_t coap_payload_put_bytes(coap_pkt_t *pkt, const void *data, size_t len)
{
if (pkt->payload_len < len) {