Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
coap.c
00001 00002 #include <stddef.h> 00003 #include <string.h> 00004 #include "coap.h" 00005 00006 00007 // 00008 // Getters 00009 // 00010 00011 coap_error coap_validate_pkt(coap_pdu *pdu) //uint8_t *pkt, size_t pkt_len) 00012 { 00013 coap_error err; 00014 size_t ol; 00015 uint8_t *ov; 00016 00017 pdu->opt_ptr = NULL; 00018 00019 if (pdu->len > pdu->max) 00020 return CE_INVALID_PACKET; 00021 00022 if (pdu->len < 4) 00023 return CE_INVALID_PACKET; 00024 00025 // Check Version 00026 if (coap_get_version(pdu) != 1) 00027 return CE_INVALID_PACKET; 00028 00029 // Check TKL 00030 if (coap_get_tkl(pdu) > 8) 00031 return CE_INVALID_PACKET; 00032 00033 // Check Options 00034 ov = pdu->buf + 4 + coap_get_tkl(pdu); 00035 ol = 0; 00036 while((err = coap_decode_option(ov + ol, pdu->len-(ov-pdu->buf), NULL, &ol, &ov)) != 0){ 00037 if (err == CE_NONE){ 00038 continue; 00039 } else if (err == CE_END_OF_PACKET){ 00040 break; 00041 } else if (err == CE_FOUND_PAYLOAD_MARKER){ 00042 // Payload Marker, but No Payload 00043 if (pdu->len == (ov + ol - pdu->buf)){ 00044 return CE_INVALID_PACKET; 00045 } else { 00046 break; 00047 } 00048 } else { 00049 return err; 00050 } 00051 } 00052 00053 return CE_NONE; 00054 } 00055 00056 uint64_t coap_get_token(coap_pdu *pdu) 00057 { 00058 uint8_t tkl; 00059 uint64_t token = 0; 00060 00061 // Extract TKL. 00062 tkl = pdu->buf[0] & 0x0F; 00063 00064 // Check that we were given enough packet. 00065 if (pdu->len < 4 + tkl) 00066 return 0; 00067 00068 // Set token. 00069 memcpy(&token, &pdu->buf[4], tkl); 00070 00071 return token; 00072 } 00073 00074 coap_option coap_get_option(coap_pdu *pdu, coap_option *last) 00075 { 00076 uint8_t *opt_ptr; 00077 coap_option option; 00078 coap_error err; 00079 00080 if (last != NULL && last->num != 0){ 00081 option.num = last->num; 00082 option.len = 0; 00083 option.val = NULL; 00084 00085 opt_ptr = last->val + last->len; 00086 } else { 00087 option.num = 0; 00088 option.len = 0; 00089 option.val = NULL; 00090 00091 opt_ptr = pdu->buf + 4 + coap_get_tkl(pdu); 00092 } 00093 00094 // If opt_ptr is outside pkt range, put it at first opt. 00095 if (opt_ptr > (pdu->buf + pdu->len) || opt_ptr <= pdu->buf){ 00096 opt_ptr = pdu->buf + 4 + coap_get_tkl(pdu); 00097 } 00098 00099 err = coap_decode_option(opt_ptr, pdu->len-(opt_ptr-pdu->buf), &option.num, &option.len, &option.val); 00100 00101 if (err != CE_NONE){ 00102 if (err == CE_FOUND_PAYLOAD_MARKER){ 00103 if (option.num == 0){ 00104 option.val = opt_ptr + 1; 00105 option.len = pdu->len-(opt_ptr-pdu->buf) - 1; 00106 } else { 00107 option.val = option.val + option.len; 00108 option.len = pdu->len - (option.val - pdu->buf); 00109 } 00110 } else { 00111 option.val = NULL; 00112 option.len = 0; 00113 } 00114 option.num = 0; 00115 } 00116 00117 opt_ptr = option.val + option.len; 00118 00119 return option; 00120 } 00121 00122 00123 coap_option coap_get_option_by_num(coap_pdu *pdu, coap_option_number num, uint8_t occ) 00124 { 00125 coap_option option; 00126 uint8_t i = 0; 00127 00128 option.num = 0; 00129 00130 do { 00131 option = coap_get_option(pdu, &option); 00132 00133 if (option.num == num) { 00134 i++; 00135 } else if (option.num > num) { 00136 option.num = 0; 00137 option.len = 0; 00138 option.val = NULL; 00139 break; 00140 } else if (option.num == 0) { 00141 break; 00142 } 00143 } while (i <= occ); 00144 00145 return option; 00146 } 00147 00148 00149 // 00150 // Decoding Functions (Intended for Internal Use) 00151 // 00152 00153 coap_error coap_decode_option(uint8_t *pkt_ptr, size_t pkt_len, 00154 uint16_t *option_number, size_t *option_length, uint8_t **value) 00155 { 00156 uint8_t *ptr = pkt_ptr; 00157 uint16_t delta, length; 00158 00159 // Check for end of Packet 00160 if (pkt_len == 0){ 00161 return CE_END_OF_PACKET; 00162 } 00163 00164 // Check for Payload Marker 00165 if (*ptr == 0xFF){ 00166 return CE_FOUND_PAYLOAD_MARKER; 00167 } 00168 00169 // Get Base Delta and Length 00170 delta = *ptr >> 4; 00171 length = *ptr & 0x0F; 00172 ptr++; 00173 00174 // Check for and Get Extended Delta 00175 if (delta < 13) { 00176 //delta = delta; 00177 }else if (delta == 13) { 00178 delta = *ptr + 13; 00179 ptr += 1; 00180 }else if (delta == 14) { 00181 delta = (*ptr << 8) + *(ptr+1) + 269; 00182 ptr += 2; 00183 }else{ 00184 return CE_INVALID_PACKET; 00185 } 00186 00187 // Check for and Get Extended Length 00188 if (length < 13) { 00189 //length = length; 00190 }else if (length == 13) { 00191 length = *ptr + 13; 00192 ptr += 1; 00193 }else if (length == 14) { 00194 length = (*ptr << 8) + *(ptr+1) + 269; 00195 ptr += 2; 00196 }else{ 00197 return CE_INVALID_PACKET; 00198 } 00199 00200 if (option_number != NULL) 00201 *option_number += delta; 00202 00203 if (option_length != NULL) 00204 *option_length = length; 00205 00206 if (value != NULL) 00207 *value = ptr; 00208 00209 return CE_NONE; 00210 } 00211 00212 00213 coap_payload coap_get_payload(coap_pdu *pdu) 00214 { 00215 00216 size_t offset = 4 + coap_get_tkl(pdu); 00217 coap_option option; 00218 coap_payload payload; 00219 coap_error err; 00220 00221 // Defaults 00222 payload.len = 0; 00223 payload.val = NULL; 00224 00225 // Find Last Option 00226 do { 00227 err = coap_decode_option(pdu->buf+offset, pdu->len-offset, NULL, &option.len, &option.val); 00228 if (err == CE_FOUND_PAYLOAD_MARKER || err == CE_END_OF_PACKET) 00229 break; 00230 00231 if (err != CE_NONE) 00232 return payload; 00233 00234 // Add this option header and value length to offset. 00235 offset += (option.val - (pdu->buf+offset)) + option.len; 00236 } while (1); 00237 00238 if (err == CE_FOUND_PAYLOAD_MARKER){ 00239 payload.len = pdu->len - offset - 1; 00240 payload.val = pdu->buf + offset + 1; 00241 } 00242 00243 return payload; 00244 } 00245 00246 00247 // 00248 // Setters 00249 // 00250 00251 coap_error coap_init_pdu(coap_pdu *pdu) 00252 { 00253 // Check that we were given enough packet. 00254 if (pdu->max < 4) 00255 return CE_INSUFFICIENT_BUFFER; 00256 00257 pdu->len = 0; 00258 memset(pdu->buf, 0, 4); 00259 00260 coap_set_version(pdu, COAP_V1); 00261 coap_set_type(pdu, CT_RST); 00262 coap_set_token(pdu, 0, 0); 00263 coap_set_code(pdu, CC_EMPTY); 00264 coap_set_mid(pdu, 0); 00265 00266 pdu->opt_ptr = NULL; 00267 00268 return CE_NONE; 00269 } 00270 00271 coap_error coap_set_version(coap_pdu *pdu, coap_version ver) 00272 { 00273 // Check that we were given enough packet. 00274 if (pdu->max < 1) 00275 return CE_INSUFFICIENT_BUFFER; 00276 00277 pdu->buf[0] = (ver << 6) | (pdu->buf[0] & 0x3F); 00278 00279 if (pdu->len < 1) 00280 pdu->len = 1; 00281 00282 return CE_NONE; 00283 } 00284 00285 coap_error coap_set_type(coap_pdu *pdu, coap_type mtype) 00286 { 00287 // Check that we were given enough packet. 00288 if (pdu->max < 1) 00289 return CE_INSUFFICIENT_BUFFER; 00290 00291 pdu->buf[0] = (mtype << 4) | (pdu->buf[0] & 0xCF); 00292 00293 if (pdu->len < 1) 00294 pdu->len = 1; 00295 00296 return CE_NONE; 00297 } 00298 00299 coap_error coap_set_code(coap_pdu *pdu, coap_code code) 00300 { 00301 // Check that we were given enough packet. 00302 if (pdu->max < 2) 00303 return CE_INSUFFICIENT_BUFFER; 00304 00305 pdu->buf[1] = code; 00306 00307 if (pdu->len < 2) 00308 pdu->len = 2; 00309 00310 return CE_NONE; 00311 } 00312 00313 coap_error coap_set_mid(coap_pdu *pdu, uint16_t mid) 00314 { 00315 // Check that we were given enough packet. 00316 if (pdu->max < 4) 00317 return CE_INSUFFICIENT_BUFFER; 00318 00319 pdu->buf[2] = mid >> 8; 00320 pdu->buf[3] = mid & 0xFF; 00321 00322 if (pdu->len < 4) 00323 pdu->len = 4; 00324 00325 return CE_NONE; 00326 } 00327 00328 coap_error coap_set_token(coap_pdu *pdu, uint64_t token, uint8_t tkl) 00329 { 00330 // Check that we were given enough buffer. 00331 if (pdu->max < 4 + tkl) 00332 return CE_INSUFFICIENT_BUFFER; 00333 00334 // Check token length for spec. 00335 if (tkl > 8) 00336 return CE_INVALID_PACKET; 00337 00338 // Check if we may need to make or take room. 00339 if (pdu->len > 4){ 00340 // Check that we were given enough buffer. 00341 if (pdu->max < pdu->len + (tkl - coap_get_tkl(pdu))) 00342 return CE_INSUFFICIENT_BUFFER; 00343 00344 // Move rest of packet to make room or take empty space. 00345 memmove(pdu->buf + 4 + tkl, pdu->buf + 4 + coap_get_tkl(pdu), pdu->len - 4 - coap_get_tkl(pdu)); 00346 } 00347 00348 // Set token. 00349 memcpy(pdu->buf+4, &token, tkl); 00350 00351 pdu->len += tkl - coap_get_tkl(pdu); 00352 00353 pdu->buf[0] = (tkl & 0x0F) | (pdu->buf[0] & 0xF0); 00354 00355 return CE_NONE; 00356 } 00357 00358 coap_error coap_add_option(coap_pdu *pdu, int32_t opt_num, uint8_t* value, uint16_t opt_len) 00359 { 00360 uint8_t *pkt_ptr, *fopt_val, nopt_hdr_len; 00361 uint16_t fopt_num, lopt_num; 00362 size_t fopt_len, opts_len; 00363 coap_error err; 00364 00365 // Set pointer to "zeroth option's value" which is really first option header. 00366 fopt_val = pdu->buf + 4 + coap_get_tkl(pdu); // ptr to start of options 00367 fopt_len = 0; 00368 00369 // Option number delta starts at zero. 00370 fopt_num = 0; 00371 00372 // Find insertion point 00373 do{ 00374 pkt_ptr = fopt_val + fopt_len; 00375 lopt_num = fopt_num; 00376 err = coap_decode_option(pkt_ptr, (pdu->len)-(pkt_ptr-pdu->buf), &fopt_num, &fopt_len, &fopt_val); 00377 }while (err == CE_NONE && fopt_num <= opt_num && (pkt_ptr-pdu->buf) + fopt_len < pdu->len); 00378 00379 if (err != CE_FOUND_PAYLOAD_MARKER && err != CE_END_OF_PACKET && err != CE_NONE) 00380 return err; 00381 00382 // Build New Header 00383 nopt_hdr_len = coap_compute_option_header_len(opt_num - lopt_num, opt_len); 00384 00385 // Check that we were given enough buffer. 00386 if (pdu->max < pdu->len + nopt_hdr_len + opt_len) 00387 return CE_INSUFFICIENT_BUFFER; 00388 00389 // Check if we're adding an option in the middle of a packet. 00390 // But seriously, don't do this. 00391 if (pdu->len != pkt_ptr- pdu->buf){ 00392 // Slide packet tail to make room. 00393 memmove(pkt_ptr + nopt_hdr_len + opt_len, pkt_ptr, pdu->len - (pkt_ptr - pdu->buf)); 00394 pdu->len += nopt_hdr_len + opt_len; 00395 00396 // Find Current Length of Remaining Options 00397 opts_len = pdu->len - (pkt_ptr-pdu->buf); 00398 00399 // Adjust the option deltas for the rest of the options. 00400 coap_adjust_option_deltas(pkt_ptr + nopt_hdr_len + opt_len, 00401 &opts_len, pdu->max - (pkt_ptr - pdu->buf), 00402 lopt_num - opt_num); 00403 00404 // Update Total Packet Length 00405 pdu->len += opts_len - (pdu->len - (pkt_ptr-pdu->buf)); 00406 }else{ 00407 // Update Packet Length 00408 pdu->len = pdu->len + nopt_hdr_len + opt_len; 00409 } 00410 00411 // Insert the Header 00412 coap_build_option_header(pkt_ptr, nopt_hdr_len, opt_num - lopt_num, opt_len); 00413 00414 // Insert the Value 00415 memcpy(pkt_ptr + nopt_hdr_len, value, opt_len); 00416 00417 return CE_NONE; 00418 } 00419 00420 coap_error coap_set_payload(coap_pdu *pdu, uint8_t *payload, size_t payload_len){ 00421 uint8_t *pkt_ptr, *fopt_val; 00422 uint16_t fopt_num; 00423 size_t fopt_len; 00424 coap_error err; 00425 00426 // Set pointer to "zeroth option's value" which is really first option header. 00427 fopt_val = pdu->buf + 4 + coap_get_tkl(pdu); 00428 fopt_len = 0; 00429 00430 // Option number delta starts at zero. 00431 fopt_num = 0; 00432 00433 // Find insertion point 00434 do{ 00435 pkt_ptr = fopt_val + fopt_len; 00436 err = coap_decode_option(pkt_ptr, (pdu->len)-(pkt_ptr-pdu->buf), &fopt_num, &fopt_len, &fopt_val); 00437 }while (err == CE_NONE && (pkt_ptr-pdu->buf) + fopt_len < pdu->len); 00438 00439 if (err != CE_FOUND_PAYLOAD_MARKER && err != CE_END_OF_PACKET && err != CE_NONE) 00440 return err; 00441 00442 if (err == CE_END_OF_PACKET){ 00443 // Check that we were given enough buffer. 00444 if (pdu->max < pdu->len + payload_len + 1) 00445 return CE_INSUFFICIENT_BUFFER; 00446 00447 *(pkt_ptr++) = 0xFF; 00448 }else if (err == CE_FOUND_PAYLOAD_MARKER){ 00449 // Check that we were given enough buffer. 00450 if (pdu->max < pdu->len + payload_len) 00451 return CE_INSUFFICIENT_BUFFER; 00452 } 00453 00454 pdu->len = (pkt_ptr - pdu->buf) + payload_len; 00455 memcpy(pkt_ptr, payload, payload_len); 00456 00457 return CE_NONE; 00458 } 00459 00460 coap_error coap_adjust_option_deltas(uint8_t *opts_start, size_t *opts_len, size_t max_len, int32_t offset) 00461 { 00462 uint8_t *ptr, *fopt_val; 00463 uint16_t fopt_num, nopt_num; 00464 size_t fopt_len; 00465 int8_t nhdr_len, fhdr_len; 00466 coap_error err; 00467 00468 fopt_val = opts_start; 00469 fopt_len = 0; 00470 fopt_num = 0; 00471 00472 do{ 00473 ptr = fopt_val + fopt_len; 00474 if (ptr - opts_start > *opts_len) 00475 break; 00476 00477 err = coap_decode_option(ptr, *opts_len-(ptr-opts_start), &fopt_num, &fopt_len, &fopt_val); 00478 00479 if (err == CE_FOUND_PAYLOAD_MARKER || err == CE_END_OF_PACKET) 00480 break; 00481 else if (err != CE_NONE) 00482 return err; 00483 00484 // New Option Number 00485 nopt_num = fopt_num + offset; 00486 00487 // Find the length of the found header. 00488 fhdr_len = fopt_val - ptr; 00489 00490 // Compute the length of the new header. 00491 nhdr_len = coap_compute_option_header_len(nopt_num, fopt_len); 00492 00493 // Make/Take room for new header size 00494 if (fhdr_len != nhdr_len){ 00495 if (max_len < *opts_len + (nhdr_len - fhdr_len)) 00496 return CE_INSUFFICIENT_BUFFER; 00497 00498 memmove(fopt_val + (nhdr_len - fhdr_len), fopt_val, fopt_len); 00499 00500 // Adjust Options Length 00501 *opts_len += (nhdr_len - fhdr_len); 00502 } 00503 00504 // Write New Header 00505 nhdr_len = coap_build_option_header(ptr, nhdr_len, nopt_num, fopt_len); 00506 00507 }while (1); 00508 00509 return CE_NONE; 00510 00511 } 00512 00513 int8_t coap_build_option_header(uint8_t *buf, size_t max_len, int32_t opt_delta, int32_t opt_len) 00514 { 00515 uint8_t *ptr, base_num, base_len; 00516 00517 if (max_len < 1) 00518 return CE_INSUFFICIENT_BUFFER; 00519 00520 ptr = buf+1; 00521 00522 if (opt_delta < 13) { 00523 base_num = opt_delta; 00524 }else if (opt_delta < 269) { 00525 if (max_len < ptr-buf + 1) 00526 return CE_INSUFFICIENT_BUFFER; 00527 00528 base_num = 13; 00529 *(ptr++) = opt_delta - 13; 00530 }else { 00531 if (max_len < ptr-buf + 2) 00532 return CE_INSUFFICIENT_BUFFER; 00533 00534 base_num = 14; 00535 *(ptr++) = (opt_delta - 269) >> 8; 00536 *(ptr++) = (opt_delta - 269) & 0xFF; 00537 } 00538 00539 if (opt_len < 13) { 00540 base_len = opt_len; 00541 }else if (opt_len < 269) { 00542 if (max_len < ptr-buf + 1) 00543 return CE_INSUFFICIENT_BUFFER; 00544 00545 base_len = 13; 00546 *(ptr++) = opt_len - 13; 00547 }else { 00548 if (max_len < ptr-buf + 2) 00549 return CE_INSUFFICIENT_BUFFER; 00550 00551 base_len = 14; 00552 *(ptr++) = (opt_len - 269) >> 8; 00553 *(ptr++) = (opt_len - 269) & 0xFF; 00554 } 00555 00556 buf[0] = (base_num << 4) | base_len; 00557 00558 00559 // Return the length of the new header. 00560 return ptr-buf; 00561 00562 } 00563 00564 int8_t coap_compute_option_header_len(int32_t opt_delta, int32_t opt_len) 00565 { 00566 int8_t len = 1; 00567 00568 if (opt_delta < 13) { 00569 }else if (opt_delta < 269) { 00570 len += 1; 00571 }else { 00572 len += 2; 00573 } 00574 00575 if (opt_len < 13) { 00576 }else if (opt_len < 269) { 00577 len += 1; 00578 }else { 00579 len += 2; 00580 } 00581 00582 return len; 00583 00584 } 00585
Generated on Tue Jul 12 2022 18:09:07 by
 1.7.2
 1.7.2