Skip to content

Commit 6277a39

Browse files
LukasWoodtlicarlescufi
authored andcommitted
net: coap: Add function for removing CoAP options
The provided function allows to remove a CoAP option in a message. This is useful for reusing parts of a message. Signed-off-by: Lukas Woodtli <[email protected]>
1 parent 137a7ed commit 6277a39

File tree

3 files changed

+462
-1
lines changed

3 files changed

+462
-1
lines changed

include/zephyr/net/coap.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,16 @@ int coap_find_options(const struct coap_packet *cpkt, uint16_t code,
457457
int coap_packet_append_option(struct coap_packet *cpkt, uint16_t code,
458458
const uint8_t *value, uint16_t len);
459459

460+
/**
461+
* @brief Remove an option from the packet.
462+
*
463+
* @param cpkt Packet to be updated
464+
* @param code Option code to remove from the packet, see #coap_option_num
465+
*
466+
* @return 0 in case of success or negative in case of error.
467+
*/
468+
int coap_packet_remove_option(struct coap_packet *cpkt, uint16_t code);
469+
460470
/**
461471
* @brief Converts an option to its integer representation.
462472
*

subsys/net/lib/coap/coap.c

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ int coap_packet_append_option(struct coap_packet *cpkt, uint16_t code,
335335
code = (code == cpkt->delta) ? 0 : code - cpkt->delta;
336336
}
337337

338-
r = encode_option(cpkt, code, value, len, cpkt->offset);
338+
r = encode_option(cpkt, code, value, len, cpkt->hdr_len + cpkt->opt_len);
339339
if (r < 0) {
340340
return -EINVAL;
341341
}
@@ -605,6 +605,111 @@ static int parse_option(uint8_t *data, uint16_t offset, uint16_t *pos,
605605
return r;
606606
}
607607

608+
/* Remove the raw data of an option. Also adjusting offsets.
609+
* But not adjusting code delta of the option after the removed one.
610+
*/
611+
static void remove_option_data(struct coap_packet *cpkt,
612+
const uint16_t to_offset,
613+
const uint16_t from_offset)
614+
{
615+
const uint16_t move_size = from_offset - to_offset;
616+
617+
memmove(cpkt->data + to_offset, cpkt->data + from_offset, cpkt->offset - from_offset);
618+
cpkt->opt_len -= move_size;
619+
cpkt->offset -= move_size;
620+
}
621+
622+
/* Remove an option (that is not the last one).
623+
* Also adjusting the code delta of the option following the removed one.
624+
*/
625+
static int remove_middle_option(struct coap_packet *cpkt,
626+
uint16_t offset,
627+
uint16_t opt_delta,
628+
const uint16_t previous_offset,
629+
const uint16_t previous_code)
630+
{
631+
int r;
632+
struct coap_option option;
633+
uint16_t opt_len = 0;
634+
635+
/* get the option after the removed one */
636+
r = parse_option(cpkt->data, offset, &offset, cpkt->hdr_len + cpkt->opt_len,
637+
&opt_delta, &opt_len, &option);
638+
if (r < 0) {
639+
return -EILSEQ;
640+
}
641+
642+
/* clear requested option and the one after (delta changed) */
643+
remove_option_data(cpkt, previous_offset, offset);
644+
645+
/* reinsert option that comes after the removed option (with adjusted delta) */
646+
r = encode_option(cpkt, option.delta - previous_code, option.value, option.len,
647+
previous_offset);
648+
if (r < 0) {
649+
return -EINVAL;
650+
}
651+
cpkt->opt_len += r;
652+
653+
return 0;
654+
}
655+
int coap_packet_remove_option(struct coap_packet *cpkt, uint16_t code)
656+
{
657+
uint16_t offset = cpkt->hdr_len;
658+
uint16_t opt_delta = 0;
659+
uint16_t opt_len = 0;
660+
uint16_t previous_offset = cpkt->hdr_len;
661+
uint16_t previous_code = 0;
662+
struct coap_option option;
663+
int r;
664+
665+
if (!cpkt) {
666+
return -EINVAL;
667+
}
668+
669+
if (cpkt->opt_len == 0) {
670+
return 0;
671+
}
672+
673+
if (code > cpkt->delta) {
674+
return 0;
675+
}
676+
677+
/* Find the requested option */
678+
while (offset < cpkt->hdr_len + cpkt->opt_len) {
679+
r = parse_option(cpkt->data, offset, &offset, cpkt->hdr_len + cpkt->opt_len,
680+
&opt_delta, &opt_len, &option);
681+
if (r < 0) {
682+
return -EILSEQ;
683+
}
684+
685+
if (opt_delta == code) {
686+
break;
687+
}
688+
689+
if (opt_delta > code) {
690+
return 0;
691+
}
692+
693+
previous_code = opt_delta;
694+
previous_offset = offset;
695+
}
696+
697+
/* Check if the found option is the last option */
698+
if (cpkt->opt_len > opt_len) {
699+
/* not last option */
700+
r = remove_middle_option(cpkt, offset, opt_delta, previous_offset, previous_code);
701+
if (r < 0) {
702+
return r;
703+
}
704+
} else {
705+
/* last option */
706+
remove_option_data(cpkt, previous_offset, cpkt->hdr_len + cpkt->opt_len);
707+
cpkt->delta = previous_code;
708+
}
709+
710+
return 0;
711+
}
712+
608713
int coap_packet_parse(struct coap_packet *cpkt, uint8_t *data, uint16_t len,
609714
struct coap_option *options, uint8_t opt_num)
610715
{

0 commit comments

Comments
 (0)