| /* |
| <:copyright-BRCM:2016:DUAL/GPL:standard |
| |
| Broadcom Proprietary and Confidential.(c) 2016 Broadcom |
| All Rights Reserved |
| |
| Unless you and Broadcom execute a separate written software license |
| agreement governing use of this software, this software is licensed |
| to you under the terms of the GNU General Public License version 2 |
| (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, |
| with the following added to such license: |
| |
| As a special exception, the copyright holders of this software give |
| you permission to link this software with independent modules, and |
| to copy and distribute the resulting executable under terms of your |
| choice, provided that you also meet, for each linked independent |
| module, the terms and conditions of the license of that module. |
| An independent module is a module which is not derived from this |
| software. The special exception does not apply to any modifications |
| of the software. |
| |
| Not withstanding the above, under no circumstances may you combine |
| this software in any way with any other Broadcom software provided |
| under a license other than the GPL, without Broadcom's express prior |
| written consent. |
| |
| :> |
| */ |
| |
| #include <bcmos_system.h> |
| #include <bal_obj.h> |
| #include <bcmcli.h> |
| #include "bal_api_cli_helpers.h" |
| |
| typedef enum |
| { |
| BCMBAL_APICLI_OUTPUT_STYLE_STD, |
| BCMBAL_APICLI_OUTPUT_STYLE_C_INIT |
| } bcmbal_apicli_output_style; |
| |
| typedef struct |
| { |
| const bcmbal_apicli_type_descr *type; |
| void *data; |
| uint8_t bit; |
| } bcmbal_apicli_presence_mask_info; |
| |
| static bcmos_errno bcmbal_apicli_dump_array( |
| bcmcli_session *session, |
| const bcmbal_apicli_type_descr *td, |
| void *data, |
| uint32_t size, |
| const char *name, |
| bcmbal_apicli_output_style style, |
| const bcmbal_apicli_presence_mask_info *presence_mask); |
| |
| static bcmos_errno bcmbal_apicli_read_snum( |
| bcmcli_session *session, const bcmbal_apicli_type_descr *td, void *data, int64_t *n) |
| { |
| switch (td->size) |
| { |
| case 1: |
| { |
| int8_t n1 = *(int8_t *)data; |
| *n = n1; |
| break; |
| } |
| case 2: |
| { |
| int16_t n2 = *(int16_t *)data; |
| *n = n2; |
| break; |
| } |
| case 4: |
| { |
| int32_t n4 = *(int32_t *)data; |
| *n = n4; |
| break; |
| } |
| case 8: |
| { |
| memcpy(n, data, sizeof(*n)); |
| break; |
| } |
| default: |
| bcmcli_print(session, "*** number size %u is not supported\n", td->size); |
| return BCM_ERR_NOT_SUPPORTED; |
| } |
| return BCM_ERR_OK; |
| } |
| |
| static bcmos_errno bcmbal_apicli_read_unum( |
| bcmcli_session *session, const bcmbal_apicli_type_descr *td, void *data, uint64_t *n) |
| { |
| switch (td->size) |
| { |
| case 1: |
| { |
| uint8_t n1 = *(uint8_t *)data; |
| *n = n1; |
| break; |
| } |
| case 2: |
| { |
| uint16_t n2 = *(uint16_t *)data; |
| *n = n2; |
| break; |
| } |
| case 4: |
| { |
| uint32_t n4 = *(uint32_t *)data; |
| *n = n4; |
| break; |
| } |
| case 8: |
| { |
| memcpy(n, data, sizeof(*n)); |
| break; |
| } |
| default: |
| bcmcli_print(session, "*** number size %u is not supported\n", td->size); |
| return BCM_ERR_NOT_SUPPORTED; |
| } |
| return BCM_ERR_OK; |
| } |
| |
| static void bcmbal_apicli_strcat_upper(char *dest, uint32_t dest_len, const char *src, uint32_t src_len) |
| { |
| uint32_t src_idx; |
| uint32_t dest_idx; |
| |
| for (dest_idx = 0; dest_idx < dest_len - 1; ++dest_idx) |
| { |
| if (dest[dest_idx] == '\0') |
| { |
| break; |
| } |
| } |
| |
| for (src_idx = 0; src_idx < src_len && dest_idx < dest_len - 1; ++src_idx, ++dest_idx) |
| { |
| dest[dest_idx] = src[src_idx]; |
| if (dest[dest_idx] >= 'a' && dest[dest_idx] <= 'z') |
| { |
| dest[dest_idx] = 'A' + (dest[dest_idx] - 'a'); |
| } |
| } |
| |
| dest[dest_idx] = '\0'; |
| } |
| |
| static const char *bcmbal_apicli_get_c_enum_id(const bcmbal_apicli_type_descr *td, const char *name) |
| { |
| static char full_name_buf[256]; |
| full_name_buf[0] = '\0'; |
| bcmbal_apicli_strcat_upper(full_name_buf, sizeof(full_name_buf), td->name, strlen(td->name)); |
| bcmbal_apicli_strcat_upper(full_name_buf, sizeof(full_name_buf), "_", 1); |
| bcmbal_apicli_strcat_upper(full_name_buf, sizeof(full_name_buf), name, strlen(name)); |
| return full_name_buf; |
| } |
| |
| static bcmos_errno bcmbal_apicli_dump_simple_data_type( |
| bcmcli_session *session, |
| const bcmbal_apicli_type_descr *td, |
| void *data, |
| const char *name, |
| bcmbal_apicli_output_style style) |
| { |
| bcmos_errno rc = BCM_ERR_OK; |
| |
| switch (td->base_type) |
| { |
| case BCMBAL_APICLI_BASE_TYPE_ID_SNUM: /* signed number */ |
| { |
| int64_t n = 0; |
| rc = bcmbal_apicli_read_snum(session, td, data, &n); |
| bcmcli_print(session, "%lld", (long long)n); |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_UNUM: /* unsigned number */ |
| { |
| uint64_t n = 0; |
| rc = bcmbal_apicli_read_unum(session, td, data, &n); |
| bcmcli_print(session, "%llu", (unsigned long long)n); |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_UNUM_HEX: /* unsigned number printed in hex */ |
| { |
| uint64_t n = 0; |
| rc = bcmbal_apicli_read_unum(session, td, data, &n); |
| bcmcli_print(session, "0x%llx", (unsigned long long)n); |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_FLOAT: /* floating-point number */ |
| { |
| if (td->size == sizeof(float)) |
| { |
| bcmcli_print(session, "%f", *(float *)data); |
| } |
| else if (td->size == sizeof(double)) |
| { |
| bcmcli_print(session, "%f", *(double *)data); |
| } |
| else |
| { |
| bcmcli_print(session, "*** floating-point number of width %u is not supported\n", td->size); |
| rc = BCM_ERR_NOT_SUPPORTED; |
| } |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_BOOL: |
| { |
| const char *no_str = style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT ? "BCMOS_FALSE" : "no"; |
| const char *yes_str = style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT ? "BCMOS_TRUE" : "yes"; |
| uint64_t n = 0; |
| rc = bcmbal_apicli_read_unum(session, td, data, &n); |
| bcmcli_print(session, "%s", n == 0 ? no_str : yes_str); |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_STRING: /* string */ |
| { |
| if (td->size == 0) |
| { |
| bcmcli_print(session, "\"%s\"", (char *)data); |
| } |
| else |
| { |
| /* we know the size of the buffer */ |
| bcmcli_print(session, "\"%.*s\"", td->size, (char *)data); |
| } |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_IPV4: /* IPv4 address */ |
| { |
| uint32_t ip; |
| memcpy(&ip, data, sizeof(ip)); |
| bcmcli_print( |
| session, |
| style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT ? "{ %d,%d,%d,%d }" : "%d.%d.%d.%d", |
| (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_MAC: /* MAC address */ |
| { |
| bcmos_mac_address mac; |
| memcpy(mac.u8, data, sizeof(mac.u8)); |
| bcmcli_print( |
| session, |
| style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT ? |
| "{{ 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x }}" : |
| "%02x:%02x:%02x:%02x:%02x:%02x", |
| mac.u8[0], mac.u8[1], mac.u8[2], mac.u8[3], mac.u8[4], mac.u8[5]); |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_ENUM: /* enum */ |
| { |
| uint64_t n = 0; |
| const char *s; |
| rc = bcmbal_apicli_read_unum(session, td, data, &n); |
| BUG_ON(td->x.e == NULL); |
| s = bcmcli_enum_stringval(td->x.e, (long)n); |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| s = bcmbal_apicli_get_c_enum_id(td, s); |
| } |
| bcmcli_print(session, "%s", s); |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_ENUM_MASK: |
| { |
| uint64_t n = 0; |
| const char *s; |
| const char *none = NULL; |
| bcmcli_enum_val *value = td->x.e; |
| bcmos_bool first = BCMOS_TRUE; |
| BUG_ON(value == NULL); |
| rc = bcmbal_apicli_read_unum(session, td, data, &n); |
| while (value->name != NULL) |
| { |
| if (value->val == 0) |
| { |
| none = value->name; |
| } |
| if ((value->val & n) != 0) |
| { |
| s = value->name; |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| s = bcmbal_apicli_get_c_enum_id(td, s); |
| } |
| bcmcli_print(session, "%s%s", first ? "" : (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT ? "|" : BCMCLI_ENUM_MASK_DEL_STR), s); |
| first = BCMOS_FALSE; |
| n -= value->val; |
| } |
| ++value; |
| } |
| if (first) |
| { |
| bcmcli_print(session, "%s", (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) || (NULL == none) ? "0" : none); |
| } |
| break; |
| } |
| |
| default: |
| bcmcli_print(session, "*** type %d is not supported\n", (int)td->base_type); |
| rc = BCM_ERR_NOT_SUPPORTED; |
| break; |
| } |
| return rc; |
| } |
| |
| |
| /* calculate number of enum values */ |
| static int bcmbal_apicli_get_num_enum_vals(const bcmcli_enum_val *vals) |
| { |
| const bcmcli_enum_val *v = vals; |
| while (v && v->name) |
| { |
| ++v; |
| } |
| return (v - vals); |
| } |
| |
| /* helper function to skip the "u." in front of union field names */ |
| static inline const char *bcmbal_apicli_skip_union_prefix(const char *name) |
| { |
| if (name[0] == 'u' && name[1] == '.') |
| { |
| name += 2; |
| } |
| return name; |
| } |
| |
| static bcmos_bool bcmbal_apicli_is_value_set( |
| bcmcli_session *session, |
| const bcmbal_apicli_presence_mask_info *presence_mask) |
| { |
| uint64_t pm_value_num = 0; |
| if (!presence_mask || !presence_mask->type) |
| { |
| /* no presence mask - all values are implicitly set */ |
| return BCMOS_TRUE; |
| } |
| bcmbal_apicli_read_unum(session, presence_mask->type, presence_mask->data, &pm_value_num); |
| return ((pm_value_num >> presence_mask->bit) & 1) != 0; |
| } |
| |
| /* Dump data type */ |
| static bcmos_errno bcmbal_apicli_dump_data_type( |
| bcmcli_session *session, |
| const bcmbal_apicli_type_descr *td, |
| void *data, |
| const char *name, |
| uint32_t num_entries, |
| uint32_t entry_size, |
| bcmbal_apicli_output_style style, |
| const bcmbal_apicli_presence_mask_info *presence_mask) |
| { |
| bcmos_errno rc = BCM_ERR_OK; |
| |
| switch (td->base_type) |
| { |
| case BCMBAL_APICLI_BASE_TYPE_ID_STRUCT: |
| { |
| uint16_t f; |
| char full_name[BCMBAL_APICLI_MAX_PARM_NAME_LENGTH]; |
| if (!td->x.s.num_fields) |
| return 0; |
| BUG_ON(!td->x.s.fields); |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, "{ "); |
| } |
| for (f = 0; f < td->x.s.num_fields; f++) |
| { |
| const bcmbal_apicli_field_descr *fld = &td->x.s.fields[f]; |
| void *fdata = (void *)((long)data + fld->offset); |
| bcmbal_apicli_presence_mask_info field_pm = {}; |
| if (((td->x.s.fields[0].flags & BCMBAL_APICLI_FIELD_DESCR_FLAGS_PRESENCE_MASK) != 0) && |
| style != BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| /* If the struct has a presence mask, skip the presence mask field itself, then record the position |
| * of the presence mask so we can check it later for each entry. */ |
| if (f == 0) |
| { |
| continue; |
| } |
| |
| field_pm.type = td->x.s.fields[0].type; |
| field_pm.data = (uint8_t *)data + td->x.s.fields[0].offset; |
| field_pm.bit = (uint8_t)(f - 1); |
| } |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT && f > 0) |
| { |
| bcmcli_print(session, ", "); |
| } |
| bcmcli_strncpy(full_name, name, sizeof(full_name)); |
| bcmcli_strncat(full_name, ".", sizeof(full_name)); |
| bcmcli_strncat(full_name, fld->name, sizeof(full_name)); |
| rc = bcmbal_apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, &field_pm); |
| } |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, " }"); |
| } |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_UNION: |
| { |
| /* Print fields up to selector, then selector, then selected sub-structure */ |
| uint16_t f; |
| char full_name[BCMBAL_APICLI_MAX_PARM_NAME_LENGTH]; |
| const bcmbal_apicli_field_descr *fld; |
| void *fdata; |
| int64_t selector_val = 0; |
| int num_union_vals; |
| |
| if (!td->x.u.num_common_fields) |
| return 0; |
| BUG_ON(!td->x.u.common_fields); |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, "{ "); |
| } |
| /* Common fields, including selector */ |
| for (f = 0; f <= td->x.u.classifier_idx && !rc; f++) |
| { |
| fld = &td->x.u.common_fields[f]; |
| fdata = (void *)((long)data + fld->offset); |
| |
| bcmcli_strncpy(full_name, name, sizeof(full_name)); |
| if (fld->name && strlen(fld->name)) |
| { |
| bcmcli_strncat(full_name, ".", sizeof(full_name)); |
| bcmcli_strncat(full_name, fld->name, sizeof(full_name)); |
| } |
| rc = bcmbal_apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, presence_mask); |
| if (f == td->x.u.classifier_idx) |
| { |
| rc = rc ? rc : bcmbal_apicli_read_snum(session, fld->type, fdata, &selector_val); |
| } |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, ", "); |
| } |
| } |
| if (rc) |
| { |
| bcmcli_print(session, "***internal error when dumping field %s\n", |
| td->x.u.common_fields[f].name); |
| return rc; |
| } |
| |
| num_union_vals = bcmbal_apicli_get_num_enum_vals(td->x.u.common_fields[td->x.u.classifier_idx].type->x.e); |
| if ((unsigned)selector_val >= num_union_vals) |
| { |
| bcmcli_print(session, "***invalid union selector value %lld\n", (long long)selector_val); |
| return BCM_ERR_INTERNAL; |
| } |
| |
| /* Common fields following selector */ |
| for (; f < td->x.u.num_common_fields; f++) |
| { |
| fld = &td->x.u.common_fields[f]; |
| fdata = (void *)((long)data + fld->offset); |
| |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, ", "); |
| } |
| bcmcli_strncpy(full_name, name, sizeof(full_name)); |
| if (fld->name && strlen(fld->name)) |
| { |
| bcmcli_strncat(full_name, ".", sizeof(full_name)); |
| bcmcli_strncat(full_name, fld->name, sizeof(full_name)); |
| } |
| rc = bcmbal_apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, presence_mask); |
| } |
| |
| /* Selected field */ |
| fld = &td->x.u.union_fields[selector_val]; |
| if (fld->type) |
| { |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, "{ .%s = ", bcmbal_apicli_skip_union_prefix(fld->name)); |
| } |
| fdata = (void *)((long)data + fld->offset); |
| |
| bcmcli_strncpy(full_name, name, sizeof(full_name)); |
| if (fld->name && strlen(fld->name)) |
| { |
| bcmcli_strncat(full_name, ".", sizeof(full_name)); |
| bcmcli_strncat(full_name, fld->name, sizeof(full_name)); |
| } |
| rc = bcmbal_apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, presence_mask); |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, " }"); |
| } |
| } |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, " }"); |
| } |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_ARR_FIXED: /* fixed array */ |
| { |
| rc = bcmbal_apicli_dump_array(session, td->x.arr_fixed.elem_type, data, td->x.arr_fixed.size, name, style, presence_mask); |
| break; |
| } |
| |
| case BCMBAL_APICLI_BASE_TYPE_ID_ARR_DYN: /* dynamic array that should be printed as buffer */ |
| { |
| /* Read length */ |
| uint32_t array_size; |
| long base_ptr; |
| |
| switch (td->x.arr_dyn.len_size ) |
| { |
| case 1: array_size = *(uint8_t *)data; break; |
| case 2: array_size = *(uint16_t *)data; break; |
| case 4: array_size = *(uint32_t *)data; break; |
| default: |
| bcmcli_print(session, |
| "*** %s: dyn array len_size %u is not supported\n", name, td->x.arr_dyn.len_size); |
| return BCM_ERR_NOT_SUPPORTED; |
| } |
| base_ptr = BCMOS_ROUND_UP((long)data + td->x.arr_dyn.len_size, sizeof(void *)); |
| BUG_ON(!base_ptr); |
| data = *(void **)base_ptr; |
| rc = bcmbal_apicli_dump_array(session, td->x.arr_dyn.elem_type, data, array_size, name, style, presence_mask); |
| break; |
| } |
| |
| default: |
| { |
| /* Finally! Simple type that maps to a single CLI parameter */ |
| int n; |
| bcmbal_apicli_presence_mask_info local_pm; |
| |
| /* If we have a single value and that value is not included in the presence mask, just skip it entirely */ |
| if (num_entries == 1 && !bcmbal_apicli_is_value_set(session, presence_mask)) |
| { |
| break; |
| } |
| |
| if (style != BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| if (name) |
| { |
| bcmcli_print(session, " %s=", name); |
| } |
| if (!num_entries) |
| { |
| bcmcli_print(session, BCMCLI_ARRAY_EMPTY); |
| } |
| } |
| |
| /* Dump simple value or array of simple values */ |
| local_pm = presence_mask ? *presence_mask : (bcmbal_apicli_presence_mask_info){}; |
| for (n = 0; n < num_entries; n++) |
| { |
| if (n) |
| { |
| bcmcli_print(session, ","); |
| } |
| |
| /* If we have a presence mask, make sure to print a special token if the value is unset */ |
| if (bcmbal_apicli_is_value_set(session, &local_pm)) |
| { |
| rc = bcmbal_apicli_dump_simple_data_type(session, td, data, name, style); |
| } |
| else |
| { |
| bcmcli_print(session, BCMCLI_PARM_NO_VALUE); |
| } |
| |
| data = (void *)((long)data + entry_size); |
| local_pm.data = (void *)((long)local_pm.data + entry_size); |
| } |
| if (style != BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, "\n"); |
| } |
| break; |
| } |
| } |
| return rc; |
| } |
| |
| /* Dump array */ |
| static bcmos_errno bcmbal_apicli_dump_array( |
| bcmcli_session *session, |
| const bcmbal_apicli_type_descr *td, |
| void *data, |
| uint32_t size, |
| const char *name, |
| bcmbal_apicli_output_style style, |
| const bcmbal_apicli_presence_mask_info *presence_mask) |
| { |
| bcmos_errno rc = BCM_ERR_OK; |
| |
| /* Print as buffer or element by element ? */ |
| if (style == BCMBAL_APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, "{ "); |
| rc = bcmbal_apicli_dump_data_type(session, td, data, name, size, td->size, style, presence_mask); |
| bcmcli_print(session, " }"); |
| } |
| else if ((td->base_type == BCMBAL_APICLI_BASE_TYPE_ID_UNUM || |
| td->base_type == BCMBAL_APICLI_BASE_TYPE_ID_UNUM_HEX) && td->size == 1) |
| { |
| if (bcmbal_apicli_is_value_set(session, presence_mask)) |
| { |
| bcmcli_print(session, " %s=\n", name); |
| bcmcli_session_hexdump(session, data, 0, size, " "); |
| } |
| } |
| else |
| { |
| rc = bcmbal_apicli_dump_data_type(session, td, data, name, size, td->size, style, presence_mask); |
| } |
| return rc; |
| } |
| |
| /* Dump property */ |
| bcmos_errno bcmbal_apicli_dump_prop(bcmcli_session *session, const bcmbal_apicli_prop_descr *pd, void *prop_data) |
| { |
| return bcmbal_apicli_dump_data_type( |
| session, pd->type, prop_data, pd->name, 1, 0, BCMBAL_APICLI_OUTPUT_STYLE_STD, NULL); |
| } |
| |
| /* Dump a single property value in C initializer format */ |
| bcmos_errno bcmbal_apicli_dump_prop_initializer( |
| bcmcli_session *session, const bcmbal_apicli_prop_descr *pd, void *prop_data) |
| { |
| return bcmbal_apicli_dump_data_type( |
| session, pd->type, prop_data, pd->name, 1, 0, BCMBAL_APICLI_OUTPUT_STYLE_C_INIT, NULL); |
| } |
| |
| /* Calculate property pointer given the group data pointer and property description */ |
| static inline void *bcmbal_apicli_prop_data_ptr(void *group_ptr, const bcmbal_apicli_prop_descr *pd) |
| { |
| return (void *)((long)group_ptr + pd->offset); |
| } |
| |
| /* Dump object data */ |
| static bcmos_errno bcmbal_apicli_dump_data(bcmcli_session *session, bcmbal_obj *msg, void *data, uint32_t data_size) |
| { |
| uint16_t prop; |
| bcmos_errno rc = BCM_ERR_OK; |
| const bcmbal_apicli_prop_descr *pd; |
| |
| bcmcli_print(session, "data:\n"); |
| for (prop = 0; |
| bcmbal_apicli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK; |
| ++prop) |
| { |
| void *prop_data = bcmbal_apicli_prop_data_ptr(data, pd); |
| if (!(msg->presence_mask & (1LL << prop))) |
| continue; |
| if (!prop_data) |
| { |
| continue; |
| } |
| BUG_ON(pd->offset > data_size); |
| rc = bcmbal_apicli_dump_prop(session, pd, prop_data); |
| if (rc != BCM_ERR_OK) |
| { |
| break; |
| } |
| } |
| return rc; |
| } |
| |
| /* Dump object key */ |
| static bcmos_errno bcmbal_apicli_dump_key(bcmcli_session *session, bcmbal_obj *msg, void *key, uint32_t key_size) |
| { |
| uint16_t prop; |
| bcmos_errno rc = BCM_ERR_OK; |
| const bcmbal_apicli_prop_descr *pd; |
| |
| bcmcli_print(session, "key:\n"); |
| for (prop = 0; |
| bcmbal_apicli_object_property(msg->obj_type, BCMBAL_MGT_GROUP_KEY, 0, prop, &pd) == BCM_ERR_OK; |
| ++prop) |
| { |
| void *prop_data = bcmbal_apicli_prop_data_ptr(key, pd); |
| if (!prop_data) |
| { |
| continue; |
| } |
| BUG_ON(pd->offset > key_size); |
| rc = bcmbal_apicli_dump_prop(session, pd, prop_data); |
| if (rc != BCM_ERR_OK) |
| { |
| break; |
| } |
| } |
| return rc; |
| } |
| |
| const char *bcmbal_apicli_mgt_group_to_str(bcmbal_mgt_group group) |
| { |
| static const char *str_table[BCMBAL_MGT_GROUP__NUM_OF] = |
| { |
| [BCMBAL_MGT_GROUP_KEY] = "key", |
| [BCMBAL_MGT_GROUP_CFG] = "cfg", |
| [BCMBAL_MGT_GROUP_STAT] = "stat", |
| [BCMBAL_MGT_GROUP_AUTO] = "auto", |
| [BCMBAL_MGT_GROUP_AUTO_CFG] = "auto_cfg", |
| }; |
| return (group >= BCMBAL_MGT_GROUP__NUM_OF) ? "<unknown>" : str_table[group]; |
| } |
| |
| /* Dump message */ |
| bcmos_errno bcmbal_apicli_msg_dump(bcmcli_session *session, bcmbal_obj *msg) |
| { |
| bcmos_errno rc; |
| const char *name, *descr; |
| uint32_t key_size; |
| uint32_t key_offset; |
| uint32_t data_size = 0; |
| uint32_t data_offset; |
| void *key = NULL; |
| void *data = NULL; |
| |
| rc = bcmbal_apicli_object_name(msg->obj_type, &name, &descr); |
| if (rc) |
| { |
| goto dump_error; |
| } |
| |
| bcmcli_print(session, "object: "); |
| if (name) |
| { |
| bcmcli_print(session, "%s", name); |
| } |
| if (descr) |
| { |
| bcmcli_print(session, " - %s", descr); |
| } |
| bcmcli_print(session, "\n"); |
| rc = bcmbal_apicli_object_struct_size(msg->obj_type, BCMBAL_MGT_GROUP_KEY, 0, &key_size, &key_offset, &data_size, &data_offset); |
| rc = rc ? rc : bcmbal_apicli_object_struct_size(msg->obj_type, msg->group, msg->subgroup, &key_size, &key_offset, &data_size, &data_offset); |
| if (rc) |
| { |
| goto dump_error; |
| } |
| |
| bcmcli_print(session, (msg->type & BCMBAL_OBJ_MSG_TYPE_GET) != 0 ? "get" : "set"); |
| if ((msg->type & BCMBAL_OBJ_MSG_TYPE_CLEAR) != 0) |
| { |
| bcmcli_print(session, ",clear"); |
| } |
| bcmcli_print(session, " %s ", bcmbal_apicli_mgt_group_to_str(msg->group)); |
| |
| if (msg->group != BCMBAL_MGT_GROUP_CFG && |
| msg->group != BCMBAL_MGT_GROUP_STAT && |
| msg->group != BCMBAL_MGT_GROUP_AUTO_CFG) |
| { |
| const char *sub_name, *sub_descr; |
| /* Get name of specific subgroup */ |
| rc = bcmbal_apicli_object_subgroup_name(msg->obj_type, msg->group, msg->subgroup, &sub_name, &sub_descr); |
| if (rc) |
| { |
| goto dump_error; |
| } |
| bcmcli_print(session, "subgroup: %s-%s ", sub_name ? sub_name : "?", sub_descr ? sub_descr : ""); |
| } |
| if (msg->dir == BCMBAL_OBJ_MSG_DIR_REQUEST) |
| { |
| bcmcli_print(session, "request\n"); |
| } |
| else |
| { |
| bcmcli_print(session, "response: %s\n", bcmos_strerror(msg->status)); |
| bcmcli_print(session, "is in-progress: %s\n", (msg->is_inprogress == BCMOS_TRUE) ? "yes" : "no"); |
| } |
| |
| if ((msg->group != BCMBAL_MGT_GROUP_AUTO_CFG) && key_size) |
| { |
| key = (void *)((long)msg + sizeof(bcmbal_obj)); |
| rc = bcmbal_apicli_dump_key(session, msg, key, key_size); |
| if (rc) |
| { |
| goto dump_error; |
| } |
| } |
| if (data_size && |
| ( ((msg->dir == BCMBAL_OBJ_MSG_DIR_REQUEST) && (msg->type & BCMBAL_OBJ_MSG_TYPE_SET)) || |
| ((msg->dir == BCMBAL_OBJ_MSG_DIR_RESPONSE) && (msg->type & BCMBAL_OBJ_MSG_TYPE_GET)) || |
| (msg->group == BCMBAL_MGT_GROUP_AUTO) |
| ) |
| ) |
| { |
| data = (void *)((long)msg + data_offset); |
| rc = bcmbal_apicli_dump_data(session, msg, data, data_size); |
| if (rc) |
| { |
| goto dump_error; |
| } |
| } |
| return BCM_ERR_OK; |
| |
| dump_error: |
| bcmcli_print(session, "*** Object dump error %s (%d)\n", bcmos_strerror(rc), rc); |
| return rc; |
| } |
| |