| /* |
| <: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 <bcmolt_msg.h> |
| #include <bcmcli.h> |
| |
| #include "bcm_api_cli_helpers.h" |
| |
| typedef enum |
| { |
| APICLI_OUTPUT_STYLE_STD, |
| APICLI_OUTPUT_STYLE_C_INIT |
| } apicli_output_style; |
| |
| typedef struct |
| { |
| const bcmcli_type_descr *type; |
| void *data; |
| uint8_t bit; |
| } apicli_presence_mask_info; |
| |
| static bcmos_errno _apicli_dump_array( |
| bcmcli_session *session, |
| const bcmcli_type_descr *td, |
| void *data, |
| uint32_t size, |
| const char *name, |
| apicli_output_style style, |
| const apicli_presence_mask_info *presence_mask, |
| const char *prefix, |
| const char *suffix); |
| |
| static bcmos_errno _apicli_read_snum(bcmcli_session *session, const bcmcli_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 _apicli_read_unum(bcmcli_session *session, const bcmcli_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 _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 *_apicli_get_c_enum_id(const bcmcli_type_descr *td, const char *name) |
| { |
| static char full_name_buf[256]; |
| full_name_buf[0] = '\0'; |
| _apicli_strcat_upper(full_name_buf, sizeof(full_name_buf), td->name, strlen(td->name)); |
| _apicli_strcat_upper(full_name_buf, sizeof(full_name_buf), "_", 1); |
| _apicli_strcat_upper(full_name_buf, sizeof(full_name_buf), name, strlen(name)); |
| return full_name_buf; |
| } |
| |
| static bcmos_errno _apicli_dump_simple_data_type( |
| bcmcli_session *session, |
| const bcmcli_type_descr *td, |
| void *data, |
| const char *name, |
| apicli_output_style style) |
| { |
| bcmos_errno rc = BCM_ERR_OK; |
| |
| switch (td->base_type) |
| { |
| case BCMOLT_BASE_TYPE_ID_SNUM: /* signed number */ |
| { |
| int64_t n = 0; |
| rc = _apicli_read_snum(session, td, data, &n); |
| bcmcli_print(session, "%lld", (long long)n); |
| break; |
| } |
| |
| case BCMOLT_BASE_TYPE_ID_UNUM: /* unsigned number */ |
| { |
| uint64_t n = 0; |
| rc = _apicli_read_unum(session, td, data, &n); |
| bcmcli_print(session, "%llu", (unsigned long long)n); |
| break; |
| } |
| |
| case BCMOLT_BASE_TYPE_ID_UNUM_HEX: /* unsigned number printed in hex */ |
| { |
| uint64_t n = 0; |
| rc = _apicli_read_unum(session, td, data, &n); |
| bcmcli_print(session, "0x%llx", (unsigned long long)n); |
| break; |
| } |
| |
| case BCMOLT_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 BCMOLT_BASE_TYPE_ID_BOOL: |
| { |
| const char *no_str = style == APICLI_OUTPUT_STYLE_C_INIT ? "BCMOS_FALSE" : "no"; |
| const char *yes_str = style == APICLI_OUTPUT_STYLE_C_INIT ? "BCMOS_TRUE" : "yes"; |
| uint64_t n = 0; |
| rc = _apicli_read_unum(session, td, data, &n); |
| bcmcli_print(session, "%s", n == 0 ? no_str : yes_str); |
| break; |
| } |
| |
| case BCMOLT_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 BCMOLT_BASE_TYPE_ID_IPV4: /* IPv4 address */ |
| { |
| uint32_t ip; |
| memcpy(&ip, data, sizeof(ip)); |
| bcmcli_print( |
| session, |
| style == 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 BCMOLT_BASE_TYPE_ID_MAC: /* MAC address */ |
| { |
| bcmos_mac_address mac; |
| memcpy(mac.u8, data, sizeof(mac.u8)); |
| bcmcli_print( |
| session, |
| style == 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 BCMOLT_BASE_TYPE_ID_ENUM: /* enum */ |
| { |
| uint64_t n = 0; |
| const char *s; |
| rc = _apicli_read_unum(session, td, data, &n); |
| BUG_ON(td->x.e == NULL); |
| s = bcmcli_enum_stringval(td->x.e, (long)n); |
| if (style == APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| s = _apicli_get_c_enum_id(td, s); |
| } |
| bcmcli_print(session, "%s", s); |
| break; |
| } |
| |
| case BCMOLT_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 = _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 == APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| s = _apicli_get_c_enum_id(td, s); |
| } |
| bcmcli_print(session, "%s%s", first ? "" : (style == 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 == 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 _api_cli_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 *_apicli_skip_union_prefix(const char *name) |
| { |
| if (name[0] == 'u' && name[1] == '.') |
| { |
| name += 2; |
| } |
| return name; |
| } |
| |
| static bcmos_bool _apicli_is_value_set(bcmcli_session *session, const 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; |
| } |
| _apicli_read_unum(session, presence_mask->type, presence_mask->data, &pm_value_num); |
| return ((pm_value_num >> presence_mask->bit) & 1) != 0; |
| } |
| |
| static bcmos_errno _apicli_arr_dyn_len_get(const bcmcli_type_descr *td, void *data, uint32_t *array_size) |
| { |
| 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: return BCM_ERR_NOT_SUPPORTED; |
| } |
| |
| return BCM_ERR_OK; |
| } |
| |
| static void *_apicli_arr_dyn_data_get(const bcmcli_type_descr *td, void *data) |
| { |
| return *(void**)BCMOS_ROUND_UP((long)data + td->x.arr_dyn.len_size, sizeof(void *)); |
| } |
| |
| /* Dump data type */ |
| static bcmos_errno _apicli_dump_data_type( |
| bcmcli_session *session, |
| const bcmcli_type_descr *td, |
| void *data, |
| const char *name, |
| uint32_t num_entries, |
| uint32_t entry_size, |
| apicli_output_style style, |
| const apicli_presence_mask_info *presence_mask, |
| const char *prefix, |
| const char *suffix) |
| { |
| bcmos_errno rc = BCM_ERR_OK; |
| |
| switch (td->base_type) |
| { |
| case BCMOLT_BASE_TYPE_ID_STRUCT: |
| { |
| uint16_t f; |
| char full_name[APICLI_MAX_PARM_NAME_LENGTH]; |
| if (!td->x.s.num_fields) |
| return 0; |
| BUG_ON(!td->x.s.fields); |
| if (style == APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, "{ "); |
| } |
| for (f = 0; f < td->x.s.num_fields; f++) |
| { |
| const bcmcli_field_descr *fld = &td->x.s.fields[f]; |
| void *fdata = (void *)((long)data + fld->offset); |
| apicli_presence_mask_info field_pm = {}; |
| if (((td->x.s.fields[0].flags & BCMCLI_FIELD_DESCR_FLAGS_PRESENCE_MASK) != 0) && |
| style != 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 == 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 = _apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, &field_pm, prefix, suffix); |
| } |
| if (style == APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, " }"); |
| } |
| break; |
| } |
| |
| case BCMOLT_BASE_TYPE_ID_UNION: |
| { |
| /* Print fields up to selector, then selector, then selected sub-structure */ |
| uint16_t f; |
| char full_name[APICLI_MAX_PARM_NAME_LENGTH]; |
| const bcmcli_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 == 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 = _apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, presence_mask, prefix, suffix); |
| if (f == td->x.u.classifier_idx) |
| { |
| rc = rc ? rc : _apicli_read_snum(session, fld->type, fdata, &selector_val); |
| } |
| if (style == 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 = _api_cli_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 == 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 = _apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, presence_mask, prefix, suffix); |
| } |
| |
| /* Selected field */ |
| fld = &td->x.u.union_fields[selector_val]; |
| if (fld->type) |
| { |
| if (style == APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, "{ .%s = ", _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 = _apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, presence_mask, prefix, suffix); |
| if (style == APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, " }"); |
| } |
| } |
| if (style == APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, " }"); |
| } |
| break; |
| } |
| |
| case BCMOLT_BASE_TYPE_ID_ARR_FIXED: /* fixed array */ |
| { |
| rc = _apicli_dump_array(session, td->x.arr_fixed.elem_type, data, td->x.arr_fixed.size, name, style, presence_mask, prefix, suffix); |
| break; |
| } |
| |
| case BCMOLT_BASE_TYPE_ID_ARR_DYN: /* dynamic array that should be printed as buffer */ |
| { |
| /* Read length */ |
| uint32_t array_size; |
| |
| rc = _apicli_arr_dyn_len_get(td, data, &array_size); |
| if (BCM_ERR_OK != rc) |
| { |
| bcmcli_print(session, "*** %s: dyn array len_size %u is not supported\n", name, td->x.arr_dyn.len_size); |
| return rc; |
| } |
| |
| if (style == APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| const char *field_name = strrchr(name, '.'); |
| if (field_name == NULL) |
| { |
| field_name = name; |
| } |
| else |
| { |
| ++field_name; |
| } |
| bcmcli_print(session, "{ %u, %s }", array_size, field_name); |
| } |
| else |
| { |
| data = _apicli_arr_dyn_data_get(td, data); |
| rc = _apicli_dump_array(session, td->x.arr_dyn.elem_type, data, array_size, name, style, presence_mask, prefix, suffix); |
| } |
| break; |
| } |
| |
| default: |
| { |
| /* Finally! Simple type that maps to a single CLI parameter */ |
| int n; |
| 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 && !_apicli_is_value_set(session, presence_mask)) |
| { |
| break; |
| } |
| |
| if (style != APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| if (name) |
| { |
| bcmcli_print(session, "%s%s=", prefix, name); |
| } |
| if (!num_entries) |
| { |
| bcmcli_print(session, BCMCLI_ARRAY_EMPTY); |
| } |
| } |
| |
| /* Dump simple value or array of simple values */ |
| local_pm = presence_mask ? *presence_mask : (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 (_apicli_is_value_set(session, &local_pm)) |
| { |
| rc = _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); |
| } |
| bcmcli_print(session, "%s", suffix); |
| break; |
| } |
| } |
| return rc; |
| } |
| |
| /* Dump array */ |
| static bcmos_errno _apicli_dump_array( |
| bcmcli_session *session, |
| const bcmcli_type_descr *td, |
| void *data, |
| uint32_t size, |
| const char *name, |
| apicli_output_style style, |
| const apicli_presence_mask_info *presence_mask, |
| const char *prefix, |
| const char *suffix) |
| { |
| bcmos_errno rc = BCM_ERR_OK; |
| |
| /* Print as buffer or element by element ? */ |
| if (style == APICLI_OUTPUT_STYLE_C_INIT) |
| { |
| bcmcli_print(session, "{ "); |
| rc = _apicli_dump_data_type(session, td, data, name, size, td->size, style, presence_mask, prefix, suffix); |
| bcmcli_print(session, " }"); |
| } |
| else if ((td->base_type == BCMOLT_BASE_TYPE_ID_UNUM || td->base_type == BCMOLT_BASE_TYPE_ID_UNUM_HEX) && td->size == 1) |
| { |
| if (_apicli_is_value_set(session, presence_mask)) |
| { |
| uint32_t i; |
| |
| bcmcli_print(session, "%s%s=", prefix, name); |
| for (i = 0; i < size; ++i) |
| { |
| bcmcli_print(session, "%02x", ((uint8_t*)data)[i]); |
| } |
| bcmcli_print(session, "%s", suffix); |
| } |
| } |
| else |
| { |
| rc = _apicli_dump_data_type(session, td, data, name, size, td->size, style, presence_mask, prefix, suffix); |
| } |
| return rc; |
| } |
| |
| /* Dump property */ |
| bcmos_errno apicli_dump_prop(bcmcli_session *session, const bcmcli_prop_descr *pd, void *prop_data) |
| { |
| return _apicli_dump_data_type(session, pd->type, prop_data, pd->name, 1, 0, APICLI_OUTPUT_STYLE_STD, NULL, " ", "\n"); |
| } |
| |
| /* Dump a single property value in C initializer format */ |
| bcmos_errno apicli_dump_prop_initializer(bcmcli_session *session, const bcmcli_prop_descr *pd, void *prop_data) |
| { |
| return _apicli_dump_data_type(session, pd->type, prop_data, pd->name, 1, 0, APICLI_OUTPUT_STYLE_C_INIT, NULL, "", ""); |
| } |
| |
| bcmos_errno apicli_dump_dyn_array( |
| bcmcli_session *session, |
| const bcmcli_type_descr *td, |
| void *data, |
| const char *name) |
| { |
| bcmos_errno rc; |
| uint32_t array_size; |
| |
| rc = _apicli_arr_dyn_len_get(td, data, &array_size); |
| BCMOS_RETURN_IF_ERROR(rc); |
| return _apicli_dump_array( |
| session, |
| td->x.arr_dyn.elem_type, |
| _apicli_arr_dyn_data_get(td, data), |
| array_size, |
| name, |
| APICLI_OUTPUT_STYLE_C_INIT, |
| NULL, |
| "", |
| ""); |
| } |
| |
| /* Dump property as CLI parameters */ |
| bcmos_errno apicli_dump_prop_param(bcmcli_session *session, const bcmcli_prop_descr *pd, void *prop_data, const char *prefix) |
| { |
| return _apicli_dump_data_type(session, pd->type, prop_data, pd->name, 1, 0, APICLI_OUTPUT_STYLE_STD, NULL, prefix, ""); |
| } |
| |
| /* Calculate property pointer given the group data pointer and property description */ |
| static inline void *_apicli_prop_data_ptr(void *group_ptr, const bcmcli_prop_descr *pd) |
| { |
| return (void *)((long)group_ptr + pd->offset); |
| } |
| |
| /* Dump object data */ |
| static bcmos_errno _apicli_dump_data(bcmcli_session *session, bcmolt_msg *msg, void *data, uint32_t data_size) |
| { |
| uint16_t prop; |
| bcmos_errno rc = BCM_ERR_OK; |
| const bcmcli_prop_descr *pd; |
| |
| bcmcli_print(session, "data:\n"); |
| for (prop = 0; |
| api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK; |
| ++prop) |
| { |
| void *prop_data = _apicli_prop_data_ptr(data, pd); |
| if (!(msg->presence_mask & (1LL << prop))) |
| continue; |
| if (!prop_data) |
| { |
| continue; |
| } |
| BUG_ON(pd->offset > data_size); |
| rc = apicli_dump_prop(session, pd, prop_data); |
| if (rc != BCM_ERR_OK) |
| { |
| break; |
| } |
| } |
| return rc; |
| } |
| |
| /* Dump object key */ |
| static bcmos_errno _apicli_dump_key(bcmcli_session *session, bcmolt_msg *msg, void *key, uint32_t key_size) |
| { |
| uint16_t prop; |
| bcmos_errno rc = BCM_ERR_OK; |
| const bcmcli_prop_descr *pd; |
| |
| bcmcli_print(session, "key:\n"); |
| for (prop = 0; |
| api_cli_object_property(msg->obj_type, BCMOLT_MGT_GROUP_KEY, 0, prop, &pd) == BCM_ERR_OK; |
| ++prop) |
| { |
| void *prop_data = _apicli_prop_data_ptr(key, pd); |
| if (!prop_data) |
| { |
| continue; |
| } |
| BUG_ON(pd->offset > key_size); |
| rc = apicli_dump_prop(session, pd, prop_data); |
| if (rc != BCM_ERR_OK) |
| { |
| break; |
| } |
| } |
| return rc; |
| } |
| |
| const char *apicli_mgt_group_to_str(bcmolt_mgt_group group) |
| { |
| static const char *str_table[BCMOLT_MGT_GROUP__NUM_OF] = |
| { |
| [BCMOLT_MGT_GROUP_KEY] = "key", |
| [BCMOLT_MGT_GROUP_CFG] = "cfg", |
| [BCMOLT_MGT_GROUP_STAT] = "stat", |
| [BCMOLT_MGT_GROUP_STAT_CFG] = "stat_cfg", |
| [BCMOLT_MGT_GROUP_AUTO] = "auto", |
| [BCMOLT_MGT_GROUP_AUTO_CFG] = "auto_cfg", |
| [BCMOLT_MGT_GROUP_OPER] = "oper", |
| [BCMOLT_MGT_GROUP_PROXY] = "proxy", |
| [BCMOLT_MGT_GROUP_PROXY_RX] = "proxy_rx" |
| }; |
| return (group >= BCMOLT_MGT_GROUP__NUM_OF) ? "<unknown>" : str_table[group]; |
| } |
| |
| /* Dump message set returned by multi-object GET */ |
| static bcmos_errno _apicli_dump_msgset( |
| bcmcli_session *session, |
| bcmolt_msg *msg, |
| uint32_t key_size, |
| uint32_t data_size, |
| uint32_t data_offset) |
| { |
| uint16_t inst; |
| bcmos_errno rc; |
| void *key = NULL; |
| void *data = NULL; |
| |
| if (msg->msg_set == NULL) |
| { |
| return BCM_ERR_NULL; |
| } |
| |
| bcmcli_print(session, "more: %s\n", msg->msg_set->more ? "yes" : "no"); |
| if (msg->msg_set->more) |
| { |
| bcmcli_print(session, "next "); |
| _apicli_dump_key(session, msg, msg->msg_set->next_key, key_size); |
| } |
| |
| bcmcli_print(session, "number of objects returned: %d\n", msg->msg_set->num_instances); |
| for (inst = 0; inst < msg->msg_set->num_instances; inst++) |
| { |
| bcmcli_print(session, "object %d:\n", inst); |
| |
| key = (void *)((long)msg->msg_set->msg[inst] + sizeof(bcmolt_msg)); |
| rc = _apicli_dump_key(session, msg->msg_set->msg[inst], key, key_size); |
| if (rc != BCM_ERR_OK) |
| { |
| return rc; |
| } |
| |
| data = (void *)((long)msg->msg_set->msg[inst] + data_offset); |
| rc = _apicli_dump_data(session, msg->msg_set->msg[inst], data, data_size); |
| if (rc) |
| { |
| return rc; |
| } |
| } |
| |
| return BCM_ERR_OK; |
| } |
| |
| /* Dump message */ |
| bcmos_errno apicli_msg_dump(bcmcli_session *session, bcmolt_msg *msg) |
| { |
| bcmos_errno rc; |
| const char *name, *descr; |
| uint32_t key_size; |
| uint32_t key_offset; |
| uint32_t data_size; |
| uint32_t data_offset; |
| void *key = NULL; |
| void *data = NULL; |
| |
| rc = api_cli_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 = api_cli_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 & BCMOLT_MSG_TYPE_GET) != 0 ? "get" : "set"); |
| if ((msg->type & BCMOLT_MSG_TYPE_CLEAR) != 0) |
| { |
| bcmcli_print(session, ",clear"); |
| } |
| if ((msg->type & BCMOLT_MSG_TYPE_MULTI) != 0) |
| { |
| bcmcli_print(session, ",multi"); |
| } |
| bcmcli_print(session, " %s ", apicli_mgt_group_to_str(msg->group)); |
| |
| if (msg->group != BCMOLT_MGT_GROUP_CFG && msg->group != BCMOLT_MGT_GROUP_STAT && |
| msg->group != BCMOLT_MGT_GROUP_AUTO_CFG && msg->group != BCMOLT_MGT_GROUP_STAT_CFG) |
| { |
| const char *sub_name, *sub_descr; |
| /* Get name of specific subgroup */ |
| rc = api_cli_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 == BCMOLT_MSG_DIR_REQUEST) |
| { |
| bcmcli_print(session, "request\n"); |
| } |
| else |
| { |
| bcmcli_print(session, "response: %s %s\n", bcmos_strerror(msg->err), msg->err_text); |
| } |
| |
| if (msg->dir == BCMOLT_MSG_DIR_RESPONSE && (msg->type & BCMOLT_MSG_TYPE_MULTI) != 0) |
| { |
| rc = _apicli_dump_msgset(session, msg, key_size, data_size, data_offset); |
| if (rc) |
| { |
| goto dump_error; |
| } |
| } |
| else |
| { |
| if ((msg->group != BCMOLT_MGT_GROUP_AUTO_CFG) && key_size) |
| { |
| key = (void *)((long)msg + key_offset); |
| rc = _apicli_dump_key(session, msg, key, key_size); |
| if (rc) |
| { |
| goto dump_error; |
| } |
| } |
| if (data_size && |
| ( ((msg->dir == BCMOLT_MSG_DIR_REQUEST) && (msg->type & BCMOLT_MSG_TYPE_SET)) || |
| ((msg->dir == BCMOLT_MSG_DIR_RESPONSE) && (msg->type & BCMOLT_MSG_TYPE_GET)) || |
| (msg->group == BCMOLT_MGT_GROUP_AUTO) || |
| (msg->group == BCMOLT_MGT_GROUP_PROXY_RX) |
| ) |
| ) |
| { |
| data = (void *)((long)msg + data_offset); |
| rc = _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; |
| } |
| |