tlv_msg.c (17000B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: tlv_msg.c 8 * Purpose: TLV Message Utility 9 */ 10 11 #include <sal/core/libc.h> 12 #include <bcm/error.h> 13 #include <appl/cputrans/tlv_msg.h> 14 15 #define UINT8_SIZE (sizeof(uint8)) 16 #define UINT16_SIZE (sizeof(uint16)) 17 #define UINT32_SIZE (sizeof(uint32)) 18 19 #define TLV_TYPE_SIZE UINT8_SIZE 20 #define TLV_LENGTH_SIZE UINT16_SIZE 21 #define TLV_HEADER_SIZE (TLV_TYPE_SIZE + TLV_LENGTH_SIZE) 22 23 24 #define TLV_END_SIZE TLV_TYPE_SIZE 25 26 #define TLV_MSG_END_CHECK(msg) \ 27 if (msg->cur_ptr >= msg->buffer_end) { return BCM_E_NOT_FOUND; } 28 29 #define PARAM_NULL_CHECK(arg) \ 30 if ((arg) == NULL) { return BCM_E_PARAM; } 31 32 /* Function pointer types for pack/unpack */ 33 typedef void (*_tlv_msg_value_pack_fp)(void *buffer, const void *value); 34 typedef void (*_tlv_msg_value_unpack_fp)(const void *buffer, void *value); 35 36 37 /* 38 * Function: 39 * _tlv_msg_uint8_pack 40 * _tlv_msg_uint16_pack 41 * _tlv_msg_uint32_pack 42 * _tlv_msg_string_pack 43 * Purpose: 44 * Packs given value into buffer. 45 * Numbers are packed in network byte order. 46 * Strings must be null-terminated. 47 * Parameters: 48 * buffer - (OUT) Buffer where to write to 49 * value - Value to pack 50 * Returns: 51 * None 52 * Notes: 53 * Assumes enough space in buffer. 54 */ 55 STATIC void 56 _tlv_msg_uint8_pack(void *buffer, const void *value) 57 { 58 *((uint8 *)buffer) = *((uint8 *)value); 59 60 return; 61 } 62 63 STATIC void 64 _tlv_msg_uint16_pack(void *buffer, const void *value) 65 { 66 uint16 raw; 67 68 raw = bcm_htons(*((uint16 *)value)); 69 sal_memcpy(buffer, (const void *)&raw, UINT16_SIZE); 70 71 return; 72 } 73 74 STATIC void 75 _tlv_msg_uint32_pack(void *buffer, const void *value) 76 { 77 uint32 raw; 78 79 raw = bcm_htonl(*((uint32 *)value)); 80 sal_memcpy(buffer, (const void *)&raw, UINT32_SIZE); 81 82 return; 83 } 84 85 STATIC void 86 _tlv_msg_string_pack(void *buffer, const void *value) 87 { 88 int len_value = 0; 89 90 len_value = sal_strlen((const char*)value); 91 sal_strncpy((char *)buffer, (const char *)value, len_value); 92 if(len_value) 93 *((char*)buffer+ len_value) = '\0'; 94 95 return; 96 } 97 98 /* 99 * Function: 100 * _tlv_msg_uint8_unpack 101 * _tlv_msg_uint16_unpack 102 * _tlv_msg_uint32_unpack 103 * _tlv_msg_string_unpack 104 * Purpose: 105 * Unpacks value from given buffer. 106 * Parameters: 107 * buffer - Buffer where to read data from 108 * value - (OUT) Returns unpacked value 109 * Returns: 110 * None 111 * Notes: 112 * Assumes available space in value. 113 */ 114 STATIC void 115 _tlv_msg_uint8_unpack(const void *buffer, void *value) 116 { 117 *((uint8 *)value) = *((uint8 *)buffer); 118 119 return; 120 } 121 122 STATIC void 123 _tlv_msg_uint16_unpack(const void *buffer, void *value) 124 { 125 uint16 raw; 126 127 sal_memcpy((void *)&raw, buffer, UINT16_SIZE); 128 *((uint16 *)value) = bcm_ntohs(raw); 129 130 return; 131 } 132 133 STATIC void 134 _tlv_msg_uint32_unpack(const void *buffer, void *value) 135 { 136 uint32 raw; 137 138 sal_memcpy((void *)&raw, buffer, UINT32_SIZE); 139 *((uint32 *)value) = bcm_ntohl(raw); 140 141 return; 142 } 143 144 STATIC void 145 _tlv_msg_string_unpack(const void *buffer, void *value) 146 { 147 int len_buffer = 0; 148 149 len_buffer = sal_strlen((const char*)buffer); 150 sal_strncpy((char *)value, (const char *)buffer, len_buffer); 151 if (len_buffer) 152 *((char*)value + len_buffer) = '\0'; 153 154 return; 155 } 156 157 /* 158 * Function: 159 * _tlv_msg_end 160 * Purpose: 161 * Marks the end of message by setting the End-TLV. 162 * Parameters: 163 * msg - (IN/OUT) TLV message object to set End-TLV 164 * Returns: 165 * BCM_E_NONE 166 * Notes: 167 * Assumes caller has checked for available space in message buffer. 168 */ 169 STATIC int 170 _tlv_msg_end(tlv_msg_t *msg) 171 { 172 uint8 type = TLV_TYPE_END; 173 174 _tlv_msg_uint8_pack((void *)msg->cur_ptr, (const void *)&type); 175 msg->end = msg->cur_ptr + TLV_END_SIZE; 176 177 return BCM_E_NONE; 178 } 179 180 /* 181 * Function: 182 * _tlv_msg_length_check 183 * Purpose: 184 * Checks that there is available space in message for given 185 * value size. 186 * Parameters: 187 * msg - TLV message object to check available space 188 * size - Size in bytes 189 * Returns: 190 * BCM_E_NONE 191 * BCM_E_MEMORY - Not enough space left in buffer 192 */ 193 STATIC int 194 _tlv_msg_length_check(tlv_msg_t *msg, int size) 195 { 196 /* Add End-TLV size (only once) */ 197 if (msg->start == msg->end) { 198 size += TLV_END_SIZE; 199 } 200 201 if ((msg->buffer_end - msg->end) < size) { 202 return BCM_E_MEMORY; 203 } 204 205 return BCM_E_NONE; 206 } 207 208 /* 209 * Function: 210 * _tlv_msg_value_add 211 * Purpose: 212 * Adds value for given message object. 213 * Parameters: 214 * msg - (IN/OUT) Message object where to add value 215 * value - Value to add 216 * value_size - Size of value, in bytes 217 * value_pack - Pointer to packer routine 218 * Returns: 219 * BCM_E_NONE - Success 220 * BCM_E_PARAM - Null pointer 221 * BCM_E_MEMORY - Not enough space left in buffer 222 * BCM_E_XXX - Failure 223 */ 224 STATIC int 225 _tlv_msg_value_add(tlv_msg_t *msg, const void *value, int value_size, 226 _tlv_msg_value_pack_fp value_pack) 227 { 228 PARAM_NULL_CHECK(msg); 229 PARAM_NULL_CHECK(value); 230 231 /* Check available space */ 232 BCM_IF_ERROR_RETURN(_tlv_msg_length_check(msg, value_size)); 233 234 /* Write value */ 235 value_pack((void *)msg->cur_ptr, value); 236 msg->cur_ptr += value_size; 237 238 /* Update TLV length */ 239 if (msg->tlv_length_ptr != NULL) { 240 msg->tlv_length += value_size; 241 _tlv_msg_uint16_pack((void *)msg->tlv_length_ptr, 242 (const void *)&msg->tlv_length); 243 } 244 245 /* End-TLV */ 246 _tlv_msg_end(msg); 247 248 return BCM_E_NONE; 249 } 250 251 /* 252 * Function: 253 * _tlv_msg_value_get 254 * Purpose: 255 * Gets value from given message object. 256 * Parameters: 257 * msg - (IN/OUT) Message object where to read value from 258 * value - (OUT) Value read 259 * value_size - Size of value, in bytes 260 * value_size_max - If >= 0, indicates max size for returning value 261 * (e.g. for strings) 262 * If < 0, ignore 263 * value_unpack - Pointer to unpacker routine 264 * Returns: 265 * BCM_E_NONE - Success 266 * BCM_E_PARAM - Null pointer 267 * BCM_E_NOT_FOUND - No more data to read 268 * BCM_E_FAIL - Size of data left to read is smaller than expected 269 * BCM_E_XXX - Failure 270 */ 271 STATIC int 272 _tlv_msg_value_get(tlv_msg_t *msg, void *value, int value_size, 273 int value_size_max, _tlv_msg_value_unpack_fp value_unpack) 274 { 275 int length_left; 276 277 PARAM_NULL_CHECK(msg); 278 PARAM_NULL_CHECK(value); 279 280 TLV_MSG_END_CHECK(msg); 281 282 /* 283 * Get length of remaining data to read 284 * 285 * If currently reading a TLV, get unread number of bytes in TLV; 286 * else, get unread number of bytes in message. 287 */ 288 if (msg->tlv_length_ptr != NULL) { 289 length_left = msg->tlv_left; 290 } else { 291 length_left = msg->buffer_end - msg->cur_ptr; 292 } 293 if (length_left <= 0) { 294 return BCM_E_NOT_FOUND; /* No more data to read */ 295 } 296 if (length_left < value_size) { 297 return BCM_E_FAIL; /* Bytes left to read smaller than size */ 298 } 299 300 /* If max size is specified, check that value fits */ 301 if (value_size_max >= 0) { 302 if (value_size_max < value_size) { 303 return BCM_E_MEMORY; 304 } 305 } 306 value_unpack((const void *)msg->cur_ptr, value); 307 msg->cur_ptr += value_size; 308 309 if (msg->tlv_length_ptr != NULL) { 310 msg->tlv_left -= value_size; 311 } 312 313 return BCM_E_NONE; 314 } 315 316 /* 317 * Function: 318 * tlv_msg_t_init 319 * Purpose: 320 * Initializes a TLV message structure. 321 * Parameters: 322 * msg - (IN/OUT) TLV message structure to initialize 323 * Returns: 324 * None 325 */ 326 void 327 tlv_msg_t_init(tlv_msg_t *msg) 328 { 329 if (msg != NULL) { 330 sal_memset(msg, 0, sizeof(*msg)); 331 } 332 333 return; 334 } 335 336 /* 337 * Function: 338 * tlv_msg_buffer_set 339 * Purpose: 340 * Sets the buffer for given TLV message object with given buffer. 341 * This routine must be called prior to setting or getting 342 * a TLV message. 343 * Parameters: 344 * msg - (IN/OUT) TLV message object 345 * buffer - (IN/OUT) Buffer where to write or read message 346 * length - Buffer size 347 * Returns: 348 * BCM_E_NONE - Success 349 * BCM_E_PARAM - Null TLV message pointer 350 */ 351 int 352 tlv_msg_buffer_set(tlv_msg_t *msg, uint8 *buffer, int length) 353 { 354 PARAM_NULL_CHECK(msg); 355 356 if (buffer == NULL) { 357 length = 0; 358 } 359 360 /* Set pointers to buffer */ 361 msg->start = msg->end = msg->cur_ptr = buffer; 362 msg->buffer_end = buffer + length; 363 msg->tlv_length_ptr = NULL; 364 msg->tlv_length = 0; 365 msg->tlv_left = 0; 366 367 return BCM_E_NONE; 368 } 369 370 /* 371 * Function: 372 * tlv_msg_add 373 * Purpose: 374 * Adds a new TLV to current message object. 375 * Parameters: 376 * msg - (IN/OUT) Message object where to add TLV to 377 * type - TLV type 378 * Returns: 379 * BCM_E_NONE - Success 380 * BCM_E_PARAM - Null pointer 381 * BCM_E_MEMORY - Not enough space left in buffer 382 * BCM_E_XXX - Failure, other 383 */ 384 int 385 tlv_msg_add(tlv_msg_t *msg, tlv_msg_type_t type) 386 { 387 PARAM_NULL_CHECK(msg); 388 389 /* Check available space */ 390 BCM_IF_ERROR_RETURN(_tlv_msg_length_check(msg, TLV_HEADER_SIZE)); 391 392 /* Set TLV type */ 393 _tlv_msg_uint8_pack((void *)msg->cur_ptr, (const void *)&type); 394 msg->cur_ptr += UINT8_SIZE; 395 396 /* Set TLV length */ 397 msg->tlv_length_ptr = msg->cur_ptr; 398 msg->tlv_length = 0; 399 _tlv_msg_uint16_pack((void *)msg->cur_ptr, (const void *)&msg->tlv_length); 400 msg->cur_ptr += UINT16_SIZE; 401 402 /* End-TLV */ 403 _tlv_msg_end(msg); 404 405 return BCM_E_NONE; 406 } 407 408 /* 409 * Function: 410 * tlv_msg_get 411 * Purpose: 412 * Gets next TLV type and length from given message object. 413 * Parameters: 414 * msg - (IN/OUT) Message object where to get TLV 415 * type - (OUT) Returns TLV field type 416 * length - (OUT) If non-null, returns TLV length 417 * Returns: 418 * BCM_E_NONE - Success 419 * BCM_E_PARAM - Null pointer 420 * BCM_E_NOT_FOUND - End of message, no more TLV elements 421 * BCM_E_XXX - Failure 422 */ 423 int 424 tlv_msg_get(tlv_msg_t *msg, tlv_msg_type_t *type, tlv_msg_length_t *length) 425 { 426 PARAM_NULL_CHECK(msg); 427 PARAM_NULL_CHECK(type); 428 429 TLV_MSG_END_CHECK(msg); 430 431 /* This skips to next TLV if in the middle of reading a TLV */ 432 msg->cur_ptr += msg->tlv_left; 433 434 msg->tlv_length_ptr = NULL; 435 msg->tlv_length = 0; 436 msg->tlv_left = 0; 437 438 /* TLV type */ 439 _tlv_msg_uint8_unpack((const void *)msg->cur_ptr, (void *)type); 440 msg->cur_ptr += UINT8_SIZE; 441 if (*type == TLV_TYPE_END) { 442 if (length != NULL) { 443 *length = 0; 444 } 445 return BCM_E_NOT_FOUND; 446 } 447 448 /* TLV length */ 449 msg->tlv_length_ptr = msg->cur_ptr; 450 _tlv_msg_uint16_unpack((const void *)msg->cur_ptr, 451 (void *)&msg->tlv_length); 452 msg->cur_ptr += UINT16_SIZE; 453 msg->tlv_left = msg->tlv_length; 454 if (length != NULL) { 455 *length = msg->tlv_length; 456 } 457 458 return BCM_E_NONE; 459 } 460 461 /* 462 * Value adders 463 * 464 * Adds values into a TLV message. If there are multiple values associated 465 * with a TLV message header or a TLV type, the routine of the correct 466 * type must be called for each one. 467 */ 468 /* 469 * Function: 470 * tlv_msg_uint8_add 471 * tlv_msg_uint16_add 472 * tlv_msg_uint32_add 473 * Purpose: 474 * Adds a value for given message object. 475 * Parameters: 476 * msg - (IN/OUT) Message object where to add value 477 * value - Value to add 478 * Returns: 479 * BCM_E_NONE - Success 480 * BCM_E_MEMORY - Not enough space left in buffer 481 * BCM_E_XXX - Failure other 482 */ 483 int 484 tlv_msg_uint8_add(tlv_msg_t *msg, uint8 value) 485 { 486 return(_tlv_msg_value_add(msg, (const void *)&value, sizeof(value), 487 _tlv_msg_uint8_pack)); 488 } 489 490 int 491 tlv_msg_uint16_add(tlv_msg_t *msg, uint16 value) 492 { 493 return(_tlv_msg_value_add(msg, (const void *)&value, sizeof(value), 494 _tlv_msg_uint16_pack)); 495 } 496 497 int 498 tlv_msg_uint32_add(tlv_msg_t *msg, uint32 value) 499 { 500 return(_tlv_msg_value_add(msg, (const void *)&value, sizeof(value), 501 _tlv_msg_uint32_pack)); 502 } 503 504 /* 505 * Function: 506 * tlv_msg_string_add 507 * Purpose: 508 * Adds a string value for given message object, 509 * including the null-terminator. 510 * Parameters: 511 * msg - (IN/OUT) Message object where to add string 512 * value - String value to add 513 * Returns: 514 * BCM_E_NONE - Success 515 * BCM_E_PARAM - Null pointer 516 * BCM_E_MEMORY - Not enough space left in buffer 517 * BCM_E_XXX - Failure other 518 */ 519 int 520 tlv_msg_string_add(tlv_msg_t *msg, const char *value) 521 { 522 return(_tlv_msg_value_add(msg, (const void *)value, strlen(value) + 1, 523 _tlv_msg_string_pack)); 524 } 525 526 /* 527 * Value getters 528 * 529 * Gets values from a TLV message. If there are multiple values 530 * associated with a TLV message header or a TLV type, the 531 * getter must be called in the same order and use the same type 532 * as the corresponding adder. 533 */ 534 /* 535 * Function: 536 * tlv_msg_uint8_get 537 * tlv_msg_uint16_get 538 * tlv_msg_uint32_get 539 * Purpose: 540 * Gets a value from given message object. 541 * Parameters: 542 * msg - (IN/OUT) Message object where to get value 543 * value - (OUT) Value 544 * Returns: 545 * BCM_E_NONE - Success 546 * BCM_E_PARAM - Null pointer 547 * BCM_E_NOT_FOUND - No more data to read 548 * BCM_E_FAIL - Size of data left to read is smaller than expected 549 * BCM_E_XXX - Failure 550 */ 551 int 552 tlv_msg_uint8_get(tlv_msg_t *msg, uint8 *value) 553 { 554 return (_tlv_msg_value_get(msg, (void *)value, sizeof(*value), -1, 555 _tlv_msg_uint8_unpack)); 556 } 557 558 int 559 tlv_msg_uint16_get(tlv_msg_t *msg, uint16 *value) 560 { 561 return (_tlv_msg_value_get(msg, (void *)value, sizeof(*value), -1, 562 _tlv_msg_uint16_unpack)); 563 } 564 565 int 566 tlv_msg_uint32_get(tlv_msg_t *msg, uint32 *value) 567 { 568 return (_tlv_msg_value_get(msg, (void *)value, sizeof(*value), -1, 569 _tlv_msg_uint32_unpack)); 570 } 571 572 /* 573 * Function: 574 * tlv_msg_string_get 575 * Purpose: 576 * Gets a string value from given message object. 577 * Parameters: 578 * msg - (IN/OUT) Message object where to get string from 579 * value_max - Size of array 580 * value - (OUT) String value 581 * Returns: 582 * BCM_E_NONE - Success 583 * BCM_E_XXX - Failure 584 */ 585 int 586 tlv_msg_string_get(tlv_msg_t *msg, int value_max, char *value) 587 { 588 return (_tlv_msg_value_get(msg, (void *)value, 589 sal_strlen((const char *) msg->cur_ptr) + 1, 590 value_max, 591 _tlv_msg_string_unpack)); 592 } 593 594 /* 595 * Function: 596 * tlv_msg_length 597 * Purpose: 598 * Gets the TLV message length, including the End-TLV marker. 599 * Only valid when setting TLV message. 600 * Parameters: 601 * msg - Message object 602 * length - (OUT) Message length 603 * Returns: 604 * BCM_E_NONE - Success 605 * BCM_E_PARAM - Null pointer 606 * BCM_E_XXX - Failure 607 */ 608 int 609 tlv_msg_length(tlv_msg_t *msg, int *length) 610 { 611 PARAM_NULL_CHECK(msg); 612 PARAM_NULL_CHECK(length); 613 614 *length = msg->end - msg->start; 615 616 return BCM_E_NONE; 617 } 618 619 /* 620 * Function: 621 * tlv_msg_resize 622 * Purpose: 623 * Copies contents of the old message buffer into the 624 * new buffer and updates message object to use new buffer. 625 * It is an error if the new buffer is smaller than what the message 626 * currently requires. 627 * 628 * The caller is responsible for releasing the previous buffer 629 * back to whatever allocator was used. 630 * Parameters: 631 * msg - (IN/OUT) Message object to resize 632 * buffer - (OUT) New buffer to be used by message 633 * length - Buffer size 634 * Returns: 635 * BCM_E_NONE - Success 636 * BCM_E_PARAM - Null pointer 637 * BCM_E_MEMORY - New buffer size is too small 638 * BCM_E_XXX - Failure 639 */ 640 int 641 tlv_msg_resize(tlv_msg_t *msg, uint8 *buffer, int length) 642 { 643 int msg_size; 644 uint8 *buffer_old; 645 646 PARAM_NULL_CHECK(msg); 647 PARAM_NULL_CHECK(buffer); 648 649 /* Check that new buffer is not smaller than message current length */ 650 BCM_IF_ERROR_RETURN(tlv_msg_length(msg, &msg_size)); 651 if (length < msg_size) { 652 return BCM_E_MEMORY; 653 } 654 655 /* Copy buffer data */ 656 buffer_old = msg->start; 657 sal_memcpy(buffer, buffer_old, msg_size); 658 659 /* Update buffer information */ 660 msg->start = buffer; 661 msg->buffer_end = buffer + length; 662 msg->end = buffer + (msg->end - buffer_old); 663 msg->cur_ptr = buffer + (msg->cur_ptr - buffer_old); 664 if (msg->tlv_length_ptr != NULL) { 665 msg->tlv_length_ptr = buffer + (msg->tlv_length_ptr - buffer_old); 666 } 667 668 return BCM_E_NONE; 669 }