Patrick Barrett / libexositecoap
Committer:
Patrick Barrett
Date:
Fri Dec 19 15:43:03 2014 -0600
Revision:
7:f9df43829cea
Child:
22:6a6810897eb9
make picocoap a subtree instead of submodule

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Patrick Barrett 7:f9df43829cea 1
Patrick Barrett 7:f9df43829cea 2 #include <stddef.h>
Patrick Barrett 7:f9df43829cea 3 #include <string.h>
Patrick Barrett 7:f9df43829cea 4 #include "coap.h"
Patrick Barrett 7:f9df43829cea 5
Patrick Barrett 7:f9df43829cea 6
Patrick Barrett 7:f9df43829cea 7 //
Patrick Barrett 7:f9df43829cea 8 // Getters
Patrick Barrett 7:f9df43829cea 9 //
Patrick Barrett 7:f9df43829cea 10
Patrick Barrett 7:f9df43829cea 11 coap_error coap_validate_pkt(coap_pdu *pdu) //uint8_t *pkt, size_t pkt_len)
Patrick Barrett 7:f9df43829cea 12 {
Patrick Barrett 7:f9df43829cea 13 coap_error err;
Patrick Barrett 7:f9df43829cea 14 size_t ol;
Patrick Barrett 7:f9df43829cea 15 uint8_t *ov;
Patrick Barrett 7:f9df43829cea 16
Patrick Barrett 7:f9df43829cea 17 pdu->opt_ptr = NULL;
Patrick Barrett 7:f9df43829cea 18
Patrick Barrett 7:f9df43829cea 19 if (pdu->len > pdu->max)
Patrick Barrett 7:f9df43829cea 20 return CE_INVALID_PACKET;
Patrick Barrett 7:f9df43829cea 21
Patrick Barrett 7:f9df43829cea 22 if (pdu->len < 4)
Patrick Barrett 7:f9df43829cea 23 return CE_INVALID_PACKET;
Patrick Barrett 7:f9df43829cea 24
Patrick Barrett 7:f9df43829cea 25 // Check Version
Patrick Barrett 7:f9df43829cea 26 if (coap_get_version(pdu) != 1)
Patrick Barrett 7:f9df43829cea 27 return CE_INVALID_PACKET;
Patrick Barrett 7:f9df43829cea 28
Patrick Barrett 7:f9df43829cea 29 // Check TKL
Patrick Barrett 7:f9df43829cea 30 if (coap_get_tkl(pdu) > 8)
Patrick Barrett 7:f9df43829cea 31 return CE_INVALID_PACKET;
Patrick Barrett 7:f9df43829cea 32
Patrick Barrett 7:f9df43829cea 33 // Check Options
Patrick Barrett 7:f9df43829cea 34 ov = pdu->buf + 4 + coap_get_tkl(pdu);
Patrick Barrett 7:f9df43829cea 35 ol = 0;
Patrick Barrett 7:f9df43829cea 36 while((err = coap_decode_option(ov + ol, pdu->len-(ov-pdu->buf), NULL, &ol, &ov)) != 0){
Patrick Barrett 7:f9df43829cea 37 if (err == CE_NONE){
Patrick Barrett 7:f9df43829cea 38 continue;
Patrick Barrett 7:f9df43829cea 39 } else if (err == CE_END_OF_PACKET){
Patrick Barrett 7:f9df43829cea 40 break;
Patrick Barrett 7:f9df43829cea 41 } else if (err == CE_FOUND_PAYLOAD_MARKER){
Patrick Barrett 7:f9df43829cea 42 // Payload Marker, but No Payload
Patrick Barrett 7:f9df43829cea 43 if (pdu->len == (ov + ol - pdu->buf)){
Patrick Barrett 7:f9df43829cea 44 return CE_INVALID_PACKET;
Patrick Barrett 7:f9df43829cea 45 } else {
Patrick Barrett 7:f9df43829cea 46 break;
Patrick Barrett 7:f9df43829cea 47 }
Patrick Barrett 7:f9df43829cea 48 } else {
Patrick Barrett 7:f9df43829cea 49 return err;
Patrick Barrett 7:f9df43829cea 50 }
Patrick Barrett 7:f9df43829cea 51 }
Patrick Barrett 7:f9df43829cea 52
Patrick Barrett 7:f9df43829cea 53 return CE_NONE;
Patrick Barrett 7:f9df43829cea 54 }
Patrick Barrett 7:f9df43829cea 55
Patrick Barrett 7:f9df43829cea 56 uint64_t coap_get_token(coap_pdu *pdu)
Patrick Barrett 7:f9df43829cea 57 {
Patrick Barrett 7:f9df43829cea 58 uint8_t tkl;
Patrick Barrett 7:f9df43829cea 59 uint64_t token = 0;
Patrick Barrett 7:f9df43829cea 60
Patrick Barrett 7:f9df43829cea 61 // Extract TKL.
Patrick Barrett 7:f9df43829cea 62 tkl = pdu->buf[0] & 0x0F;
Patrick Barrett 7:f9df43829cea 63
Patrick Barrett 7:f9df43829cea 64 // Check that we were given enough packet.
Patrick Barrett 7:f9df43829cea 65 if (pdu->len < 4 + tkl)
Patrick Barrett 7:f9df43829cea 66 return 0;
Patrick Barrett 7:f9df43829cea 67
Patrick Barrett 7:f9df43829cea 68 // Set token.
Patrick Barrett 7:f9df43829cea 69 memcpy(&token, &pdu->buf[4], tkl);
Patrick Barrett 7:f9df43829cea 70
Patrick Barrett 7:f9df43829cea 71 return token;
Patrick Barrett 7:f9df43829cea 72 }
Patrick Barrett 7:f9df43829cea 73
Patrick Barrett 7:f9df43829cea 74 coap_option coap_get_option(coap_pdu *pdu, coap_option *last)
Patrick Barrett 7:f9df43829cea 75 {
Patrick Barrett 7:f9df43829cea 76 uint8_t *opt_ptr;
Patrick Barrett 7:f9df43829cea 77 coap_option option;
Patrick Barrett 7:f9df43829cea 78 coap_error err;
Patrick Barrett 7:f9df43829cea 79
Patrick Barrett 7:f9df43829cea 80 if (last != NULL && last->num != 0){
Patrick Barrett 7:f9df43829cea 81 option.num = last->num;
Patrick Barrett 7:f9df43829cea 82 option.len = 0;
Patrick Barrett 7:f9df43829cea 83 option.val = NULL;
Patrick Barrett 7:f9df43829cea 84
Patrick Barrett 7:f9df43829cea 85 opt_ptr = last->val + last->len;
Patrick Barrett 7:f9df43829cea 86 } else {
Patrick Barrett 7:f9df43829cea 87 option.num = 0;
Patrick Barrett 7:f9df43829cea 88 option.len = 0;
Patrick Barrett 7:f9df43829cea 89 option.val = NULL;
Patrick Barrett 7:f9df43829cea 90
Patrick Barrett 7:f9df43829cea 91 opt_ptr = pdu->buf + 4 + coap_get_tkl(pdu);
Patrick Barrett 7:f9df43829cea 92 }
Patrick Barrett 7:f9df43829cea 93
Patrick Barrett 7:f9df43829cea 94 // If opt_ptr is outside pkt range, put it at first opt.
Patrick Barrett 7:f9df43829cea 95 if (opt_ptr > (pdu->buf + pdu->len) || opt_ptr <= pdu->buf){
Patrick Barrett 7:f9df43829cea 96 opt_ptr = pdu->buf + 4 + coap_get_tkl(pdu);
Patrick Barrett 7:f9df43829cea 97 }
Patrick Barrett 7:f9df43829cea 98
Patrick Barrett 7:f9df43829cea 99 err = coap_decode_option(opt_ptr, pdu->len-(opt_ptr-pdu->buf), &option.num, &option.len, &option.val);
Patrick Barrett 7:f9df43829cea 100
Patrick Barrett 7:f9df43829cea 101 if (err != CE_NONE){
Patrick Barrett 7:f9df43829cea 102 if (err == CE_FOUND_PAYLOAD_MARKER){
Patrick Barrett 7:f9df43829cea 103 if (option.num == 0){
Patrick Barrett 7:f9df43829cea 104 option.val = opt_ptr + 1;
Patrick Barrett 7:f9df43829cea 105 option.len = pdu->len-(opt_ptr-pdu->buf) - 1;
Patrick Barrett 7:f9df43829cea 106 } else {
Patrick Barrett 7:f9df43829cea 107 option.val = option.val + option.len;
Patrick Barrett 7:f9df43829cea 108 option.len = pdu->len - (option.val - pdu->buf);
Patrick Barrett 7:f9df43829cea 109 }
Patrick Barrett 7:f9df43829cea 110 } else {
Patrick Barrett 7:f9df43829cea 111 option.val = NULL;
Patrick Barrett 7:f9df43829cea 112 option.len = 0;
Patrick Barrett 7:f9df43829cea 113 }
Patrick Barrett 7:f9df43829cea 114 option.num = 0;
Patrick Barrett 7:f9df43829cea 115 }
Patrick Barrett 7:f9df43829cea 116
Patrick Barrett 7:f9df43829cea 117 opt_ptr = option.val + option.len;
Patrick Barrett 7:f9df43829cea 118
Patrick Barrett 7:f9df43829cea 119 return option;
Patrick Barrett 7:f9df43829cea 120 }
Patrick Barrett 7:f9df43829cea 121
Patrick Barrett 7:f9df43829cea 122
Patrick Barrett 7:f9df43829cea 123 coap_option coap_get_option_by_num(coap_pdu *pdu, coap_option_number num, uint8_t occ)
Patrick Barrett 7:f9df43829cea 124 {
Patrick Barrett 7:f9df43829cea 125 coap_option option;
Patrick Barrett 7:f9df43829cea 126 uint8_t i = 0;
Patrick Barrett 7:f9df43829cea 127
Patrick Barrett 7:f9df43829cea 128 option.num = 0;
Patrick Barrett 7:f9df43829cea 129
Patrick Barrett 7:f9df43829cea 130 do {
Patrick Barrett 7:f9df43829cea 131 option = coap_get_option(pdu, &option);
Patrick Barrett 7:f9df43829cea 132
Patrick Barrett 7:f9df43829cea 133 if (option.num == num) {
Patrick Barrett 7:f9df43829cea 134 i++;
Patrick Barrett 7:f9df43829cea 135 }
Patrick Barrett 7:f9df43829cea 136 } while (i < occ);
Patrick Barrett 7:f9df43829cea 137
Patrick Barrett 7:f9df43829cea 138 return option;
Patrick Barrett 7:f9df43829cea 139 }
Patrick Barrett 7:f9df43829cea 140
Patrick Barrett 7:f9df43829cea 141
Patrick Barrett 7:f9df43829cea 142 //
Patrick Barrett 7:f9df43829cea 143 // Decoding Functions (Intended for Internal Use)
Patrick Barrett 7:f9df43829cea 144 //
Patrick Barrett 7:f9df43829cea 145
Patrick Barrett 7:f9df43829cea 146 coap_error coap_decode_option(uint8_t *pkt_ptr, size_t pkt_len,
Patrick Barrett 7:f9df43829cea 147 uint16_t *option_number, size_t *option_length, uint8_t **value)
Patrick Barrett 7:f9df43829cea 148 {
Patrick Barrett 7:f9df43829cea 149 uint8_t *ptr = pkt_ptr;
Patrick Barrett 7:f9df43829cea 150 uint16_t delta, length;
Patrick Barrett 7:f9df43829cea 151
Patrick Barrett 7:f9df43829cea 152 // Check for end of Packet
Patrick Barrett 7:f9df43829cea 153 if (pkt_len == 0){
Patrick Barrett 7:f9df43829cea 154 return CE_END_OF_PACKET;
Patrick Barrett 7:f9df43829cea 155 }
Patrick Barrett 7:f9df43829cea 156
Patrick Barrett 7:f9df43829cea 157 // Check for Payload Marker
Patrick Barrett 7:f9df43829cea 158 if (*ptr == 0xFF){
Patrick Barrett 7:f9df43829cea 159 return CE_FOUND_PAYLOAD_MARKER;
Patrick Barrett 7:f9df43829cea 160 }
Patrick Barrett 7:f9df43829cea 161
Patrick Barrett 7:f9df43829cea 162 // Get Base Delta and Length
Patrick Barrett 7:f9df43829cea 163 delta = *ptr >> 4;
Patrick Barrett 7:f9df43829cea 164 length = *ptr & 0x0F;
Patrick Barrett 7:f9df43829cea 165 ptr++;
Patrick Barrett 7:f9df43829cea 166
Patrick Barrett 7:f9df43829cea 167 // Check for and Get Extended Delta
Patrick Barrett 7:f9df43829cea 168 if (delta < 13) {
Patrick Barrett 7:f9df43829cea 169 //delta = delta;
Patrick Barrett 7:f9df43829cea 170 }else if (delta == 13) {
Patrick Barrett 7:f9df43829cea 171 delta = *ptr + 13;
Patrick Barrett 7:f9df43829cea 172 ptr += 1;
Patrick Barrett 7:f9df43829cea 173 }else if (delta == 14) {
Patrick Barrett 7:f9df43829cea 174 delta = (*ptr << 8) + *(ptr+1) + 269;
Patrick Barrett 7:f9df43829cea 175 ptr += 2;
Patrick Barrett 7:f9df43829cea 176 }else{
Patrick Barrett 7:f9df43829cea 177 return CE_INVALID_PACKET;
Patrick Barrett 7:f9df43829cea 178 }
Patrick Barrett 7:f9df43829cea 179
Patrick Barrett 7:f9df43829cea 180 // Check for and Get Extended Length
Patrick Barrett 7:f9df43829cea 181 if (length < 13) {
Patrick Barrett 7:f9df43829cea 182 //length = length;
Patrick Barrett 7:f9df43829cea 183 }else if (length == 13) {
Patrick Barrett 7:f9df43829cea 184 length = *ptr + 13;
Patrick Barrett 7:f9df43829cea 185 ptr += 1;
Patrick Barrett 7:f9df43829cea 186 }else if (length == 14) {
Patrick Barrett 7:f9df43829cea 187 length = (*ptr << 8) + *(ptr+1) + 269;
Patrick Barrett 7:f9df43829cea 188 ptr += 2;
Patrick Barrett 7:f9df43829cea 189 }else{
Patrick Barrett 7:f9df43829cea 190 return CE_INVALID_PACKET;
Patrick Barrett 7:f9df43829cea 191 }
Patrick Barrett 7:f9df43829cea 192
Patrick Barrett 7:f9df43829cea 193 if (option_number != NULL)
Patrick Barrett 7:f9df43829cea 194 *option_number += delta;
Patrick Barrett 7:f9df43829cea 195
Patrick Barrett 7:f9df43829cea 196 if (option_length != NULL)
Patrick Barrett 7:f9df43829cea 197 *option_length = length;
Patrick Barrett 7:f9df43829cea 198
Patrick Barrett 7:f9df43829cea 199 if (value != NULL)
Patrick Barrett 7:f9df43829cea 200 *value = ptr;
Patrick Barrett 7:f9df43829cea 201
Patrick Barrett 7:f9df43829cea 202 return CE_NONE;
Patrick Barrett 7:f9df43829cea 203 }
Patrick Barrett 7:f9df43829cea 204
Patrick Barrett 7:f9df43829cea 205
Patrick Barrett 7:f9df43829cea 206 coap_payload coap_get_payload(coap_pdu *pdu)
Patrick Barrett 7:f9df43829cea 207 {
Patrick Barrett 7:f9df43829cea 208
Patrick Barrett 7:f9df43829cea 209 size_t offset = 4 + coap_get_tkl(pdu);
Patrick Barrett 7:f9df43829cea 210 coap_option option;
Patrick Barrett 7:f9df43829cea 211 coap_payload payload;
Patrick Barrett 7:f9df43829cea 212 coap_error err;
Patrick Barrett 7:f9df43829cea 213
Patrick Barrett 7:f9df43829cea 214 // Defaults
Patrick Barrett 7:f9df43829cea 215 payload.len = 0;
Patrick Barrett 7:f9df43829cea 216 payload.val = NULL;
Patrick Barrett 7:f9df43829cea 217
Patrick Barrett 7:f9df43829cea 218 // Find Last Option
Patrick Barrett 7:f9df43829cea 219 do {
Patrick Barrett 7:f9df43829cea 220 err = coap_decode_option(pdu->buf+offset, pdu->len-offset, NULL, &option.len, &option.val);
Patrick Barrett 7:f9df43829cea 221 if (err == CE_FOUND_PAYLOAD_MARKER || err == CE_END_OF_PACKET)
Patrick Barrett 7:f9df43829cea 222 break;
Patrick Barrett 7:f9df43829cea 223
Patrick Barrett 7:f9df43829cea 224 if (err != CE_NONE)
Patrick Barrett 7:f9df43829cea 225 return payload;
Patrick Barrett 7:f9df43829cea 226
Patrick Barrett 7:f9df43829cea 227 // Add this option header and value length to offset.
Patrick Barrett 7:f9df43829cea 228 offset += (option.val - (pdu->buf+offset)) + option.len;
Patrick Barrett 7:f9df43829cea 229 } while (1);
Patrick Barrett 7:f9df43829cea 230
Patrick Barrett 7:f9df43829cea 231 if (err == CE_FOUND_PAYLOAD_MARKER){
Patrick Barrett 7:f9df43829cea 232 payload.len = pdu->len - offset - 1;
Patrick Barrett 7:f9df43829cea 233 payload.val = pdu->buf + offset + 1;
Patrick Barrett 7:f9df43829cea 234 }
Patrick Barrett 7:f9df43829cea 235
Patrick Barrett 7:f9df43829cea 236 return payload;
Patrick Barrett 7:f9df43829cea 237 }
Patrick Barrett 7:f9df43829cea 238
Patrick Barrett 7:f9df43829cea 239
Patrick Barrett 7:f9df43829cea 240 //
Patrick Barrett 7:f9df43829cea 241 // Setters
Patrick Barrett 7:f9df43829cea 242 //
Patrick Barrett 7:f9df43829cea 243
Patrick Barrett 7:f9df43829cea 244 coap_error coap_init_pdu(coap_pdu *pdu)
Patrick Barrett 7:f9df43829cea 245 {
Patrick Barrett 7:f9df43829cea 246 // Check that we were given enough packet.
Patrick Barrett 7:f9df43829cea 247 if (pdu->max < 4)
Patrick Barrett 7:f9df43829cea 248 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 249
Patrick Barrett 7:f9df43829cea 250 coap_set_version(pdu, COAP_V1);
Patrick Barrett 7:f9df43829cea 251 coap_set_type(pdu, CT_RST);
Patrick Barrett 7:f9df43829cea 252 coap_set_token(pdu, 0, 0);
Patrick Barrett 7:f9df43829cea 253 coap_set_code(pdu, CC_EMPTY);
Patrick Barrett 7:f9df43829cea 254 coap_set_mid(pdu, 0);
Patrick Barrett 7:f9df43829cea 255
Patrick Barrett 7:f9df43829cea 256 pdu->len = 4;
Patrick Barrett 7:f9df43829cea 257 pdu->opt_ptr = NULL;
Patrick Barrett 7:f9df43829cea 258
Patrick Barrett 7:f9df43829cea 259 return CE_NONE;
Patrick Barrett 7:f9df43829cea 260 }
Patrick Barrett 7:f9df43829cea 261
Patrick Barrett 7:f9df43829cea 262 coap_error coap_set_version(coap_pdu *pdu, coap_version ver)
Patrick Barrett 7:f9df43829cea 263 {
Patrick Barrett 7:f9df43829cea 264 // Check that we were given enough packet.
Patrick Barrett 7:f9df43829cea 265 if (pdu->max < 1)
Patrick Barrett 7:f9df43829cea 266 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 267
Patrick Barrett 7:f9df43829cea 268 pdu->buf[0] = (ver << 6) | (pdu->buf[0] & 0x3F);
Patrick Barrett 7:f9df43829cea 269
Patrick Barrett 7:f9df43829cea 270 if (pdu->len < 1)
Patrick Barrett 7:f9df43829cea 271 pdu->len = 1;
Patrick Barrett 7:f9df43829cea 272
Patrick Barrett 7:f9df43829cea 273 return CE_NONE;
Patrick Barrett 7:f9df43829cea 274 }
Patrick Barrett 7:f9df43829cea 275
Patrick Barrett 7:f9df43829cea 276 coap_error coap_set_type(coap_pdu *pdu, coap_type mtype)
Patrick Barrett 7:f9df43829cea 277 {
Patrick Barrett 7:f9df43829cea 278 // Check that we were given enough packet.
Patrick Barrett 7:f9df43829cea 279 if (pdu->max < 1)
Patrick Barrett 7:f9df43829cea 280 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 281
Patrick Barrett 7:f9df43829cea 282 pdu->buf[0] = (mtype << 4) | (pdu->buf[0] & 0xCF);
Patrick Barrett 7:f9df43829cea 283
Patrick Barrett 7:f9df43829cea 284 if (pdu->len < 1)
Patrick Barrett 7:f9df43829cea 285 pdu->len = 1;
Patrick Barrett 7:f9df43829cea 286
Patrick Barrett 7:f9df43829cea 287 return CE_NONE;
Patrick Barrett 7:f9df43829cea 288 }
Patrick Barrett 7:f9df43829cea 289
Patrick Barrett 7:f9df43829cea 290 coap_error coap_set_code(coap_pdu *pdu, coap_code code)
Patrick Barrett 7:f9df43829cea 291 {
Patrick Barrett 7:f9df43829cea 292 // Check that we were given enough packet.
Patrick Barrett 7:f9df43829cea 293 if (pdu->max < 2)
Patrick Barrett 7:f9df43829cea 294 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 295
Patrick Barrett 7:f9df43829cea 296 pdu->buf[1] = code;
Patrick Barrett 7:f9df43829cea 297
Patrick Barrett 7:f9df43829cea 298 if (pdu->len < 2)
Patrick Barrett 7:f9df43829cea 299 pdu->len = 2;
Patrick Barrett 7:f9df43829cea 300
Patrick Barrett 7:f9df43829cea 301 return CE_NONE;
Patrick Barrett 7:f9df43829cea 302 }
Patrick Barrett 7:f9df43829cea 303
Patrick Barrett 7:f9df43829cea 304 coap_error coap_set_mid(coap_pdu *pdu, uint16_t mid)
Patrick Barrett 7:f9df43829cea 305 {
Patrick Barrett 7:f9df43829cea 306 // Check that we were given enough packet.
Patrick Barrett 7:f9df43829cea 307 if (pdu->max < 4)
Patrick Barrett 7:f9df43829cea 308 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 309
Patrick Barrett 7:f9df43829cea 310 pdu->buf[2] = mid >> 8;
Patrick Barrett 7:f9df43829cea 311 pdu->buf[3] = mid & 0xFF;
Patrick Barrett 7:f9df43829cea 312
Patrick Barrett 7:f9df43829cea 313 if (pdu->len < 4)
Patrick Barrett 7:f9df43829cea 314 pdu->len = 4;
Patrick Barrett 7:f9df43829cea 315
Patrick Barrett 7:f9df43829cea 316 return CE_NONE;
Patrick Barrett 7:f9df43829cea 317 }
Patrick Barrett 7:f9df43829cea 318
Patrick Barrett 7:f9df43829cea 319 coap_error coap_set_token(coap_pdu *pdu, uint64_t token, uint8_t tkl)
Patrick Barrett 7:f9df43829cea 320 {
Patrick Barrett 7:f9df43829cea 321 // Check that we were given enough buffer.
Patrick Barrett 7:f9df43829cea 322 if (pdu->max < 4 + tkl)
Patrick Barrett 7:f9df43829cea 323 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 324
Patrick Barrett 7:f9df43829cea 325 // Check token length for spec.
Patrick Barrett 7:f9df43829cea 326 if (tkl > 8)
Patrick Barrett 7:f9df43829cea 327 return CE_INVALID_PACKET;
Patrick Barrett 7:f9df43829cea 328
Patrick Barrett 7:f9df43829cea 329 // Check if we may need to make or take room.
Patrick Barrett 7:f9df43829cea 330 if (pdu->len > 4){
Patrick Barrett 7:f9df43829cea 331 // Check that we were given enough buffer.
Patrick Barrett 7:f9df43829cea 332 if (pdu->max < pdu->len + (tkl - coap_get_tkl(pdu)))
Patrick Barrett 7:f9df43829cea 333 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 334
Patrick Barrett 7:f9df43829cea 335 // Move rest of packet to make room or take empty space.
Patrick Barrett 7:f9df43829cea 336 memmove(pdu->buf + 4 + tkl, pdu->buf + 4 + coap_get_tkl(pdu), pdu->len - 4 - coap_get_tkl(pdu));
Patrick Barrett 7:f9df43829cea 337 }
Patrick Barrett 7:f9df43829cea 338
Patrick Barrett 7:f9df43829cea 339 // Set token.
Patrick Barrett 7:f9df43829cea 340 memcpy(pdu->buf+4, &token, tkl);
Patrick Barrett 7:f9df43829cea 341
Patrick Barrett 7:f9df43829cea 342 pdu->len += tkl - coap_get_tkl(pdu);
Patrick Barrett 7:f9df43829cea 343
Patrick Barrett 7:f9df43829cea 344 pdu->buf[0] = (tkl & 0x0F) | (pdu->buf[0] & 0xF0);
Patrick Barrett 7:f9df43829cea 345
Patrick Barrett 7:f9df43829cea 346 return CE_NONE;
Patrick Barrett 7:f9df43829cea 347 }
Patrick Barrett 7:f9df43829cea 348
Patrick Barrett 7:f9df43829cea 349 coap_error coap_add_option(coap_pdu *pdu, int32_t opt_num, uint8_t* value, uint16_t opt_len)
Patrick Barrett 7:f9df43829cea 350 {
Patrick Barrett 7:f9df43829cea 351 uint8_t *pkt_ptr, *fopt_val, nopt_hdr_len;
Patrick Barrett 7:f9df43829cea 352 uint16_t fopt_num, lopt_num;
Patrick Barrett 7:f9df43829cea 353 size_t fopt_len, opts_len;
Patrick Barrett 7:f9df43829cea 354 coap_error err;
Patrick Barrett 7:f9df43829cea 355
Patrick Barrett 7:f9df43829cea 356 // Set pointer to "zeroth option's value" which is really first option header.
Patrick Barrett 7:f9df43829cea 357 fopt_val = pdu->buf + 4 + coap_get_tkl(pdu); // ptr to start of options
Patrick Barrett 7:f9df43829cea 358 fopt_len = 0;
Patrick Barrett 7:f9df43829cea 359
Patrick Barrett 7:f9df43829cea 360 // Option number delta starts at zero.
Patrick Barrett 7:f9df43829cea 361 fopt_num = 0;
Patrick Barrett 7:f9df43829cea 362
Patrick Barrett 7:f9df43829cea 363 // Find insertion point
Patrick Barrett 7:f9df43829cea 364 do{
Patrick Barrett 7:f9df43829cea 365 pkt_ptr = fopt_val + fopt_len;
Patrick Barrett 7:f9df43829cea 366 lopt_num = fopt_num;
Patrick Barrett 7:f9df43829cea 367 err = coap_decode_option(pkt_ptr, (pdu->len)-(pkt_ptr-pdu->buf), &fopt_num, &fopt_len, &fopt_val);
Patrick Barrett 7:f9df43829cea 368 }while (err == CE_NONE && fopt_num <= opt_num && (pkt_ptr-pdu->buf) + fopt_len < pdu->len);
Patrick Barrett 7:f9df43829cea 369
Patrick Barrett 7:f9df43829cea 370 if (err != CE_FOUND_PAYLOAD_MARKER && err != CE_END_OF_PACKET && err != CE_NONE)
Patrick Barrett 7:f9df43829cea 371 return err;
Patrick Barrett 7:f9df43829cea 372
Patrick Barrett 7:f9df43829cea 373 // Build New Header
Patrick Barrett 7:f9df43829cea 374 nopt_hdr_len = coap_compute_option_header_len(opt_num - lopt_num, opt_len);
Patrick Barrett 7:f9df43829cea 375
Patrick Barrett 7:f9df43829cea 376 // Check that we were given enough buffer.
Patrick Barrett 7:f9df43829cea 377 if (pdu->max < pdu->len + nopt_hdr_len + opt_len)
Patrick Barrett 7:f9df43829cea 378 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 379
Patrick Barrett 7:f9df43829cea 380 // Check if we're adding an option in the middle of a packet.
Patrick Barrett 7:f9df43829cea 381 // But seriously, don't do this.
Patrick Barrett 7:f9df43829cea 382 if (pdu->len != pkt_ptr- pdu->buf){
Patrick Barrett 7:f9df43829cea 383 // Slide packet tail to make room.
Patrick Barrett 7:f9df43829cea 384 memmove(pkt_ptr + nopt_hdr_len + opt_len, pkt_ptr, pdu->len - (pkt_ptr - pdu->buf));
Patrick Barrett 7:f9df43829cea 385 pdu->len += nopt_hdr_len + opt_len;
Patrick Barrett 7:f9df43829cea 386
Patrick Barrett 7:f9df43829cea 387 // Find Current Length of Remaining Options
Patrick Barrett 7:f9df43829cea 388 opts_len = pdu->len - (pkt_ptr-pdu->buf);
Patrick Barrett 7:f9df43829cea 389
Patrick Barrett 7:f9df43829cea 390 // Adjust the option deltas for the rest of the options.
Patrick Barrett 7:f9df43829cea 391 coap_adjust_option_deltas(pkt_ptr + nopt_hdr_len + opt_len,
Patrick Barrett 7:f9df43829cea 392 &opts_len, pdu->max - (pkt_ptr - pdu->buf),
Patrick Barrett 7:f9df43829cea 393 lopt_num - opt_num);
Patrick Barrett 7:f9df43829cea 394
Patrick Barrett 7:f9df43829cea 395 // Update Total Packet Length
Patrick Barrett 7:f9df43829cea 396 pdu->len += opts_len - (pdu->len - (pkt_ptr-pdu->buf));
Patrick Barrett 7:f9df43829cea 397 }else{
Patrick Barrett 7:f9df43829cea 398 // Update Packet Length
Patrick Barrett 7:f9df43829cea 399 pdu->len = pdu->len + nopt_hdr_len + opt_len;
Patrick Barrett 7:f9df43829cea 400 }
Patrick Barrett 7:f9df43829cea 401
Patrick Barrett 7:f9df43829cea 402 // Insert the Header
Patrick Barrett 7:f9df43829cea 403 coap_build_option_header(pkt_ptr, nopt_hdr_len, opt_num - lopt_num, opt_len);
Patrick Barrett 7:f9df43829cea 404
Patrick Barrett 7:f9df43829cea 405 // Insert the Value
Patrick Barrett 7:f9df43829cea 406 memcpy(pkt_ptr + nopt_hdr_len, value, opt_len);
Patrick Barrett 7:f9df43829cea 407
Patrick Barrett 7:f9df43829cea 408 return CE_NONE;
Patrick Barrett 7:f9df43829cea 409 }
Patrick Barrett 7:f9df43829cea 410
Patrick Barrett 7:f9df43829cea 411 coap_error coap_set_payload(coap_pdu *pdu, uint8_t *payload, size_t payload_len){
Patrick Barrett 7:f9df43829cea 412 uint8_t *pkt_ptr, *fopt_val;
Patrick Barrett 7:f9df43829cea 413 uint16_t fopt_num;
Patrick Barrett 7:f9df43829cea 414 size_t fopt_len;
Patrick Barrett 7:f9df43829cea 415 coap_error err;
Patrick Barrett 7:f9df43829cea 416
Patrick Barrett 7:f9df43829cea 417 // Set pointer to "zeroth option's value" which is really first option header.
Patrick Barrett 7:f9df43829cea 418 fopt_val = pdu->buf + 4 + coap_get_tkl(pdu);
Patrick Barrett 7:f9df43829cea 419 fopt_len = 0;
Patrick Barrett 7:f9df43829cea 420
Patrick Barrett 7:f9df43829cea 421 // Option number delta starts at zero.
Patrick Barrett 7:f9df43829cea 422 fopt_num = 0;
Patrick Barrett 7:f9df43829cea 423
Patrick Barrett 7:f9df43829cea 424 // Find insertion point
Patrick Barrett 7:f9df43829cea 425 do{
Patrick Barrett 7:f9df43829cea 426 pkt_ptr = fopt_val + fopt_len;
Patrick Barrett 7:f9df43829cea 427 err = coap_decode_option(pkt_ptr, (pdu->len)-(pkt_ptr-pdu->buf), &fopt_num, &fopt_len, &fopt_val);
Patrick Barrett 7:f9df43829cea 428 }while (err == CE_NONE && (pkt_ptr-pdu->buf) + fopt_len < pdu->len);
Patrick Barrett 7:f9df43829cea 429
Patrick Barrett 7:f9df43829cea 430 if (err != CE_FOUND_PAYLOAD_MARKER && err != CE_END_OF_PACKET && err != CE_NONE)
Patrick Barrett 7:f9df43829cea 431 return err;
Patrick Barrett 7:f9df43829cea 432
Patrick Barrett 7:f9df43829cea 433 if (err == CE_END_OF_PACKET){
Patrick Barrett 7:f9df43829cea 434 // Check that we were given enough buffer.
Patrick Barrett 7:f9df43829cea 435 if (pdu->max < pdu->len + payload_len + 1)
Patrick Barrett 7:f9df43829cea 436 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 437
Patrick Barrett 7:f9df43829cea 438 *(pkt_ptr++) = 0xFF;
Patrick Barrett 7:f9df43829cea 439 }else if (err == CE_FOUND_PAYLOAD_MARKER){
Patrick Barrett 7:f9df43829cea 440 // Check that we were given enough buffer.
Patrick Barrett 7:f9df43829cea 441 if (pdu->max < pdu->len + payload_len)
Patrick Barrett 7:f9df43829cea 442 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 443 }
Patrick Barrett 7:f9df43829cea 444
Patrick Barrett 7:f9df43829cea 445 pdu->len = (pkt_ptr - pdu->buf) + payload_len;
Patrick Barrett 7:f9df43829cea 446 memcpy(pkt_ptr, payload, payload_len);
Patrick Barrett 7:f9df43829cea 447
Patrick Barrett 7:f9df43829cea 448 return CE_NONE;
Patrick Barrett 7:f9df43829cea 449 }
Patrick Barrett 7:f9df43829cea 450
Patrick Barrett 7:f9df43829cea 451 coap_error coap_adjust_option_deltas(uint8_t *opts_start, size_t *opts_len, size_t max_len, int32_t offset)
Patrick Barrett 7:f9df43829cea 452 {
Patrick Barrett 7:f9df43829cea 453 uint8_t *ptr, *fopt_val;
Patrick Barrett 7:f9df43829cea 454 uint16_t fopt_num, nopt_num;
Patrick Barrett 7:f9df43829cea 455 size_t fopt_len;
Patrick Barrett 7:f9df43829cea 456 int8_t nhdr_len, fhdr_len;
Patrick Barrett 7:f9df43829cea 457 coap_error err;
Patrick Barrett 7:f9df43829cea 458
Patrick Barrett 7:f9df43829cea 459 fopt_val = opts_start;
Patrick Barrett 7:f9df43829cea 460 fopt_len = 0;
Patrick Barrett 7:f9df43829cea 461 fopt_num = 0;
Patrick Barrett 7:f9df43829cea 462
Patrick Barrett 7:f9df43829cea 463 do{
Patrick Barrett 7:f9df43829cea 464 ptr = fopt_val + fopt_len;
Patrick Barrett 7:f9df43829cea 465 if (ptr - opts_start > *opts_len)
Patrick Barrett 7:f9df43829cea 466 break;
Patrick Barrett 7:f9df43829cea 467
Patrick Barrett 7:f9df43829cea 468 err = coap_decode_option(ptr, *opts_len-(ptr-opts_start), &fopt_num, &fopt_len, &fopt_val);
Patrick Barrett 7:f9df43829cea 469
Patrick Barrett 7:f9df43829cea 470 if (err == CE_FOUND_PAYLOAD_MARKER || err == CE_END_OF_PACKET)
Patrick Barrett 7:f9df43829cea 471 break;
Patrick Barrett 7:f9df43829cea 472 else if (err != CE_NONE)
Patrick Barrett 7:f9df43829cea 473 return err;
Patrick Barrett 7:f9df43829cea 474
Patrick Barrett 7:f9df43829cea 475 // New Option Number
Patrick Barrett 7:f9df43829cea 476 nopt_num = fopt_num + offset;
Patrick Barrett 7:f9df43829cea 477
Patrick Barrett 7:f9df43829cea 478 // Find the length of the found header.
Patrick Barrett 7:f9df43829cea 479 fhdr_len = fopt_val - ptr;
Patrick Barrett 7:f9df43829cea 480
Patrick Barrett 7:f9df43829cea 481 // Compute the length of the new header.
Patrick Barrett 7:f9df43829cea 482 nhdr_len = coap_compute_option_header_len(nopt_num, fopt_len);
Patrick Barrett 7:f9df43829cea 483
Patrick Barrett 7:f9df43829cea 484 // Make/Take room for new header size
Patrick Barrett 7:f9df43829cea 485 if (fhdr_len != nhdr_len){
Patrick Barrett 7:f9df43829cea 486 if (max_len < *opts_len + (nhdr_len - fhdr_len))
Patrick Barrett 7:f9df43829cea 487 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 488
Patrick Barrett 7:f9df43829cea 489 memmove(fopt_val + (nhdr_len - fhdr_len), fopt_val, fopt_len);
Patrick Barrett 7:f9df43829cea 490
Patrick Barrett 7:f9df43829cea 491 // Adjust Options Length
Patrick Barrett 7:f9df43829cea 492 *opts_len += (nhdr_len - fhdr_len);
Patrick Barrett 7:f9df43829cea 493 }
Patrick Barrett 7:f9df43829cea 494
Patrick Barrett 7:f9df43829cea 495 // Write New Header
Patrick Barrett 7:f9df43829cea 496 nhdr_len = coap_build_option_header(ptr, nhdr_len, nopt_num, fopt_len);
Patrick Barrett 7:f9df43829cea 497
Patrick Barrett 7:f9df43829cea 498 }while (1);
Patrick Barrett 7:f9df43829cea 499
Patrick Barrett 7:f9df43829cea 500 return CE_NONE;
Patrick Barrett 7:f9df43829cea 501
Patrick Barrett 7:f9df43829cea 502 }
Patrick Barrett 7:f9df43829cea 503
Patrick Barrett 7:f9df43829cea 504 int8_t coap_build_option_header(uint8_t *buf, size_t max_len, int32_t opt_delta, int32_t opt_len)
Patrick Barrett 7:f9df43829cea 505 {
Patrick Barrett 7:f9df43829cea 506 uint8_t *ptr, base_num, base_len;
Patrick Barrett 7:f9df43829cea 507
Patrick Barrett 7:f9df43829cea 508 if (max_len < 1)
Patrick Barrett 7:f9df43829cea 509 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 510
Patrick Barrett 7:f9df43829cea 511 ptr = buf+1;
Patrick Barrett 7:f9df43829cea 512
Patrick Barrett 7:f9df43829cea 513 if (opt_delta < 13) {
Patrick Barrett 7:f9df43829cea 514 base_num = opt_delta;
Patrick Barrett 7:f9df43829cea 515 }else if (opt_delta < 269) {
Patrick Barrett 7:f9df43829cea 516 if (max_len < ptr-buf + 1)
Patrick Barrett 7:f9df43829cea 517 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 518
Patrick Barrett 7:f9df43829cea 519 base_num = 13;
Patrick Barrett 7:f9df43829cea 520 *(ptr++) = opt_delta - 13;
Patrick Barrett 7:f9df43829cea 521 }else {
Patrick Barrett 7:f9df43829cea 522 if (max_len < ptr-buf + 2)
Patrick Barrett 7:f9df43829cea 523 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 524
Patrick Barrett 7:f9df43829cea 525 base_num = 14;
Patrick Barrett 7:f9df43829cea 526 *(ptr++) = (opt_delta - 269) >> 8;
Patrick Barrett 7:f9df43829cea 527 *(ptr++) = (opt_delta - 269) & 0xFF;
Patrick Barrett 7:f9df43829cea 528 }
Patrick Barrett 7:f9df43829cea 529
Patrick Barrett 7:f9df43829cea 530 if (opt_len < 13) {
Patrick Barrett 7:f9df43829cea 531 base_len = opt_len;
Patrick Barrett 7:f9df43829cea 532 }else if (opt_len < 269) {
Patrick Barrett 7:f9df43829cea 533 if (max_len < ptr-buf + 1)
Patrick Barrett 7:f9df43829cea 534 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 535
Patrick Barrett 7:f9df43829cea 536 base_len = 13;
Patrick Barrett 7:f9df43829cea 537 *(ptr++) = opt_len - 13;
Patrick Barrett 7:f9df43829cea 538 }else {
Patrick Barrett 7:f9df43829cea 539 if (max_len < ptr-buf + 2)
Patrick Barrett 7:f9df43829cea 540 return CE_INSUFFICIENT_BUFFER;
Patrick Barrett 7:f9df43829cea 541
Patrick Barrett 7:f9df43829cea 542 base_len = 14;
Patrick Barrett 7:f9df43829cea 543 *(ptr++) = (opt_len - 269) >> 8;
Patrick Barrett 7:f9df43829cea 544 *(ptr++) = (opt_len - 269) & 0xFF;
Patrick Barrett 7:f9df43829cea 545 }
Patrick Barrett 7:f9df43829cea 546
Patrick Barrett 7:f9df43829cea 547 buf[0] = (base_num << 4) | base_len;
Patrick Barrett 7:f9df43829cea 548
Patrick Barrett 7:f9df43829cea 549
Patrick Barrett 7:f9df43829cea 550 // Return the length of the new header.
Patrick Barrett 7:f9df43829cea 551 return ptr-buf;
Patrick Barrett 7:f9df43829cea 552
Patrick Barrett 7:f9df43829cea 553 }
Patrick Barrett 7:f9df43829cea 554
Patrick Barrett 7:f9df43829cea 555 int8_t coap_compute_option_header_len(int32_t opt_delta, int32_t opt_len)
Patrick Barrett 7:f9df43829cea 556 {
Patrick Barrett 7:f9df43829cea 557 int8_t len = 1;
Patrick Barrett 7:f9df43829cea 558
Patrick Barrett 7:f9df43829cea 559 if (opt_delta < 13) {
Patrick Barrett 7:f9df43829cea 560 }else if (opt_delta < 269) {
Patrick Barrett 7:f9df43829cea 561 len += 1;
Patrick Barrett 7:f9df43829cea 562 }else {
Patrick Barrett 7:f9df43829cea 563 len += 2;
Patrick Barrett 7:f9df43829cea 564 }
Patrick Barrett 7:f9df43829cea 565
Patrick Barrett 7:f9df43829cea 566 if (opt_len < 13) {
Patrick Barrett 7:f9df43829cea 567 }else if (opt_len < 269) {
Patrick Barrett 7:f9df43829cea 568 len += 1;
Patrick Barrett 7:f9df43829cea 569 }else {
Patrick Barrett 7:f9df43829cea 570 len += 2;
Patrick Barrett 7:f9df43829cea 571 }
Patrick Barrett 7:f9df43829cea 572
Patrick Barrett 7:f9df43829cea 573 return len;
Patrick Barrett 7:f9df43829cea 574
Patrick Barrett 7:f9df43829cea 575 }
Patrick Barrett 7:f9df43829cea 576