@@ -335,7 +335,7 @@ int coap_packet_append_option(struct coap_packet *cpkt, uint16_t code,
335
335
code = (code == cpkt -> delta ) ? 0 : code - cpkt -> delta ;
336
336
}
337
337
338
- r = encode_option (cpkt , code , value , len , cpkt -> offset );
338
+ r = encode_option (cpkt , code , value , len , cpkt -> hdr_len + cpkt -> opt_len );
339
339
if (r < 0 ) {
340
340
return - EINVAL ;
341
341
}
@@ -605,6 +605,111 @@ static int parse_option(uint8_t *data, uint16_t offset, uint16_t *pos,
605
605
return r ;
606
606
}
607
607
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
+
608
713
int coap_packet_parse (struct coap_packet * cpkt , uint8_t * data , uint16_t len ,
609
714
struct coap_option * options , uint8_t opt_num )
610
715
{
0 commit comments