openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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 }