blob: a96db2672e72cfac1432904de6818d12180fe63c [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2<:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written consent.
26
27:>
28 */
29
30#include <bcmos_system.h>
31#include <bcmolt_msg.h>
32#include <bcmcli.h>
33
34#include "bcm_api_cli_helpers.h"
35
36typedef enum
37{
38 APICLI_OUTPUT_STYLE_STD,
39 APICLI_OUTPUT_STYLE_C_INIT
40} apicli_output_style;
41
42typedef struct
43{
44 const bcmcli_type_descr *type;
45 void *data;
46 uint8_t bit;
47} apicli_presence_mask_info;
48
49static bcmos_errno _apicli_dump_array(
50 bcmcli_session *session,
51 const bcmcli_type_descr *td,
52 void *data,
53 uint32_t size,
54 const char *name,
55 apicli_output_style style,
56 const apicli_presence_mask_info *presence_mask,
57 const char *prefix,
58 const char *suffix);
59
60static bcmos_errno _apicli_read_snum(bcmcli_session *session, const bcmcli_type_descr *td, void *data, int64_t *n)
61{
62 switch (td->size)
63 {
64 case 1:
65 {
66 int8_t n1 = *(int8_t *)data;
67 *n = n1;
68 break;
69 }
70 case 2:
71 {
72 int16_t n2 = *(int16_t *)data;
73 *n = n2;
74 break;
75 }
76 case 4:
77 {
78 int32_t n4 = *(int32_t *)data;
79 *n = n4;
80 break;
81 }
82 case 8:
83 {
84 memcpy(n, data, sizeof(*n));
85 break;
86 }
87 default:
88 bcmcli_print(session, "*** number size %u is not supported\n", td->size);
89 return BCM_ERR_NOT_SUPPORTED;
90 }
91 return BCM_ERR_OK;
92}
93
94static bcmos_errno _apicli_read_unum(bcmcli_session *session, const bcmcli_type_descr *td, void *data, uint64_t *n)
95{
96 switch (td->size)
97 {
98 case 1:
99 {
100 uint8_t n1 = *(uint8_t *)data;
101 *n = n1;
102 break;
103 }
104 case 2:
105 {
106 uint16_t n2 = *(uint16_t *)data;
107 *n = n2;
108 break;
109 }
110 case 4:
111 {
112 uint32_t n4 = *(uint32_t *)data;
113 *n = n4;
114 break;
115 }
116 case 8:
117 {
118 memcpy(n, data, sizeof(*n));
119 break;
120 }
121 default:
122 bcmcli_print(session, "*** number size %u is not supported\n", td->size);
123 return BCM_ERR_NOT_SUPPORTED;
124 }
125 return BCM_ERR_OK;
126}
127
128static void _apicli_strcat_upper(char *dest, uint32_t dest_len, const char *src, uint32_t src_len)
129{
130 uint32_t src_idx;
131 uint32_t dest_idx;
132
133 for (dest_idx = 0; dest_idx < dest_len - 1; ++dest_idx)
134 {
135 if (dest[dest_idx] == '\0')
136 {
137 break;
138 }
139 }
140
141 for (src_idx = 0; src_idx < src_len && dest_idx < dest_len - 1; ++src_idx, ++dest_idx)
142 {
143 dest[dest_idx] = src[src_idx];
144 if (dest[dest_idx] >= 'a' && dest[dest_idx] <= 'z')
145 {
146 dest[dest_idx] = 'A' + (dest[dest_idx] - 'a');
147 }
148 }
149
150 dest[dest_idx] = '\0';
151}
152
153static const char *_apicli_get_c_enum_id(const bcmcli_type_descr *td, const char *name)
154{
155 static char full_name_buf[256];
156 full_name_buf[0] = '\0';
157 _apicli_strcat_upper(full_name_buf, sizeof(full_name_buf), td->name, strlen(td->name));
158 _apicli_strcat_upper(full_name_buf, sizeof(full_name_buf), "_", 1);
159 _apicli_strcat_upper(full_name_buf, sizeof(full_name_buf), name, strlen(name));
160 return full_name_buf;
161}
162
163static bcmos_errno _apicli_dump_simple_data_type(
164 bcmcli_session *session,
165 const bcmcli_type_descr *td,
166 void *data,
167 const char *name,
168 apicli_output_style style)
169{
170 bcmos_errno rc = BCM_ERR_OK;
171
172 switch (td->base_type)
173 {
174 case BCMOLT_BASE_TYPE_ID_SNUM: /* signed number */
175 {
176 int64_t n = 0;
177 rc = _apicli_read_snum(session, td, data, &n);
178 bcmcli_print(session, "%lld", (long long)n);
179 break;
180 }
181
182 case BCMOLT_BASE_TYPE_ID_UNUM: /* unsigned number */
183 {
184 uint64_t n = 0;
185 rc = _apicli_read_unum(session, td, data, &n);
186 bcmcli_print(session, "%llu", (unsigned long long)n);
187 break;
188 }
189
190 case BCMOLT_BASE_TYPE_ID_UNUM_HEX: /* unsigned number printed in hex */
191 {
192 uint64_t n = 0;
193 rc = _apicli_read_unum(session, td, data, &n);
194 bcmcli_print(session, "0x%llx", (unsigned long long)n);
195 break;
196 }
197
198 case BCMOLT_BASE_TYPE_ID_FLOAT: /* floating-point number */
199 {
200 if (td->size == sizeof(float))
201 {
202 bcmcli_print(session, "%f", *(float *)data);
203 }
204 else if (td->size == sizeof(double))
205 {
206 bcmcli_print(session, "%f", *(double *)data);
207 }
208 else
209 {
210 bcmcli_print(session, "*** floating-point number of width %u is not supported\n", td->size);
211 rc = BCM_ERR_NOT_SUPPORTED;
212 }
213 break;
214 }
215
216 case BCMOLT_BASE_TYPE_ID_BOOL:
217 {
218 const char *no_str = style == APICLI_OUTPUT_STYLE_C_INIT ? "BCMOS_FALSE" : "no";
219 const char *yes_str = style == APICLI_OUTPUT_STYLE_C_INIT ? "BCMOS_TRUE" : "yes";
220 uint64_t n = 0;
221 rc = _apicli_read_unum(session, td, data, &n);
222 bcmcli_print(session, "%s", n == 0 ? no_str : yes_str);
223 break;
224 }
225
226 case BCMOLT_BASE_TYPE_ID_STRING: /* string */
227 {
228 if (td->size == 0)
229 {
230 bcmcli_print(session, "\"%s\"", (char *)data);
231 }
232 else
233 {
234 /* we know the size of the buffer */
235 bcmcli_print(session, "\"%.*s\"", td->size, (char *)data);
236 }
237 break;
238 }
239
240 case BCMOLT_BASE_TYPE_ID_IPV4: /* IPv4 address */
241 {
242 uint32_t ip;
243 memcpy(&ip, data, sizeof(ip));
244 bcmcli_print(
245 session,
246 style == APICLI_OUTPUT_STYLE_C_INIT ? "{ %d,%d,%d,%d }" : "%d.%d.%d.%d",
247 (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
248 break;
249 }
250
251 case BCMOLT_BASE_TYPE_ID_MAC: /* MAC address */
252 {
253 bcmos_mac_address mac;
254 memcpy(mac.u8, data, sizeof(mac.u8));
255 bcmcli_print(
256 session,
257 style == APICLI_OUTPUT_STYLE_C_INIT ?
258 "{{ 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x }}" :
259 "%02x:%02x:%02x:%02x:%02x:%02x",
260 mac.u8[0], mac.u8[1], mac.u8[2], mac.u8[3], mac.u8[4], mac.u8[5]);
261 break;
262 }
263
264 case BCMOLT_BASE_TYPE_ID_ENUM: /* enum */
265 {
266 uint64_t n = 0;
267 const char *s;
268 rc = _apicli_read_unum(session, td, data, &n);
269 BUG_ON(td->x.e == NULL);
270 s = bcmcli_enum_stringval(td->x.e, (long)n);
271 if (style == APICLI_OUTPUT_STYLE_C_INIT)
272 {
273 s = _apicli_get_c_enum_id(td, s);
274 }
275 bcmcli_print(session, "%s", s);
276 break;
277 }
278
279 case BCMOLT_BASE_TYPE_ID_ENUM_MASK:
280 {
281 uint64_t n = 0;
282 const char *s;
283 const char *none = NULL;
284 bcmcli_enum_val *value = td->x.e;
285 bcmos_bool first = BCMOS_TRUE;
286 BUG_ON(value == NULL);
287 rc = _apicli_read_unum(session, td, data, &n);
288 while (value->name != NULL)
289 {
290 if (value->val == 0)
291 {
292 none = value->name;
293 }
294 if ((value->val & n) != 0)
295 {
296 s = value->name;
297 if (style == APICLI_OUTPUT_STYLE_C_INIT)
298 {
299 s = _apicli_get_c_enum_id(td, s);
300 }
301 bcmcli_print(session, "%s%s", first ? "" : (style == APICLI_OUTPUT_STYLE_C_INIT ? "|" : BCMCLI_ENUM_MASK_DEL_STR), s);
302 first = BCMOS_FALSE;
303 n -= value->val;
304 }
305 ++value;
306 }
307 if (first)
308 {
309 bcmcli_print(session, "%s", (style == APICLI_OUTPUT_STYLE_C_INIT) || (NULL == none) ? "0" : none);
310 }
311 break;
312 }
313
314 default:
315 bcmcli_print(session, "*** type %d is not supported\n", (int)td->base_type);
316 rc = BCM_ERR_NOT_SUPPORTED;
317 break;
318 }
319 return rc;
320}
321
322
323/* calculate number of enum values */
324static int _api_cli_get_num_enum_vals(const bcmcli_enum_val *vals)
325{
326 const bcmcli_enum_val *v = vals;
327 while (v && v->name)
328 {
329 ++v;
330 }
331 return (v - vals);
332}
333
334/* helper function to skip the "u." in front of union field names */
335static inline const char *_apicli_skip_union_prefix(const char *name)
336{
337 if (name[0] == 'u' && name[1] == '.')
338 {
339 name += 2;
340 }
341 return name;
342}
343
344static bcmos_bool _apicli_is_value_set(bcmcli_session *session, const apicli_presence_mask_info *presence_mask)
345{
346 uint64_t pm_value_num = 0;
347 if (!presence_mask || !presence_mask->type)
348 {
349 /* no presence mask - all values are implicitly set */
350 return BCMOS_TRUE;
351 }
352 _apicli_read_unum(session, presence_mask->type, presence_mask->data, &pm_value_num);
353 return ((pm_value_num >> presence_mask->bit) & 1) != 0;
354}
355
356static bcmos_errno _apicli_arr_dyn_len_get(const bcmcli_type_descr *td, void *data, uint32_t *array_size)
357{
358 switch (td->x.arr_dyn.len_size)
359 {
360 case 1: *array_size = *(uint8_t *)data; break;
361 case 2: *array_size = *(uint16_t *)data; break;
362 case 4: *array_size = *(uint32_t *)data; break;
363 default: return BCM_ERR_NOT_SUPPORTED;
364 }
365
366 return BCM_ERR_OK;
367}
368
369static void *_apicli_arr_dyn_data_get(const bcmcli_type_descr *td, void *data)
370{
371 return *(void**)BCMOS_ROUND_UP((long)data + td->x.arr_dyn.len_size, sizeof(void *));
372}
373
374/* Dump data type */
375static bcmos_errno _apicli_dump_data_type(
376 bcmcli_session *session,
377 const bcmcli_type_descr *td,
378 void *data,
379 const char *name,
380 uint32_t num_entries,
381 uint32_t entry_size,
382 apicli_output_style style,
383 const apicli_presence_mask_info *presence_mask,
384 const char *prefix,
385 const char *suffix)
386{
387 bcmos_errno rc = BCM_ERR_OK;
388
389 switch (td->base_type)
390 {
391 case BCMOLT_BASE_TYPE_ID_STRUCT:
392 {
393 uint16_t f;
394 char full_name[APICLI_MAX_PARM_NAME_LENGTH];
395 if (!td->x.s.num_fields)
396 return 0;
397 BUG_ON(!td->x.s.fields);
398 if (style == APICLI_OUTPUT_STYLE_C_INIT)
399 {
400 bcmcli_print(session, "{ ");
401 }
402 for (f = 0; f < td->x.s.num_fields; f++)
403 {
404 const bcmcli_field_descr *fld = &td->x.s.fields[f];
405 void *fdata = (void *)((long)data + fld->offset);
406 apicli_presence_mask_info field_pm = {};
407 if (((td->x.s.fields[0].flags & BCMCLI_FIELD_DESCR_FLAGS_PRESENCE_MASK) != 0) &&
408 style != APICLI_OUTPUT_STYLE_C_INIT)
409 {
410 /* If the struct has a presence mask, skip the presence mask field itself, then record the position
411 * of the presence mask so we can check it later for each entry. */
412 if (f == 0)
413 {
414 continue;
415 }
416
417 field_pm.type = td->x.s.fields[0].type;
418 field_pm.data = (uint8_t *)data + td->x.s.fields[0].offset;
419 field_pm.bit = (uint8_t)(f - 1);
420 }
421 if (style == APICLI_OUTPUT_STYLE_C_INIT && f > 0)
422 {
423 bcmcli_print(session, ", ");
424 }
425 bcmcli_strncpy(full_name, name, sizeof(full_name));
426 bcmcli_strncat(full_name, ".", sizeof(full_name));
427 bcmcli_strncat(full_name, fld->name, sizeof(full_name));
428 rc = _apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, &field_pm, prefix, suffix);
429 }
430 if (style == APICLI_OUTPUT_STYLE_C_INIT)
431 {
432 bcmcli_print(session, " }");
433 }
434 break;
435 }
436
437 case BCMOLT_BASE_TYPE_ID_UNION:
438 {
439 /* Print fields up to selector, then selector, then selected sub-structure */
440 uint16_t f;
441 char full_name[APICLI_MAX_PARM_NAME_LENGTH];
442 const bcmcli_field_descr *fld;
443 void *fdata;
444 int64_t selector_val = 0;
445 int num_union_vals;
446
447 if (!td->x.u.num_common_fields)
448 return 0;
449 BUG_ON(!td->x.u.common_fields);
450 if (style == APICLI_OUTPUT_STYLE_C_INIT)
451 {
452 bcmcli_print(session, "{ ");
453 }
454 /* Common fields, including selector */
455 for (f = 0; f <= td->x.u.classifier_idx && !rc; f++)
456 {
457 fld = &td->x.u.common_fields[f];
458 fdata = (void *)((long)data + fld->offset);
459
460 bcmcli_strncpy(full_name, name, sizeof(full_name));
461 if (fld->name && strlen(fld->name))
462 {
463 bcmcli_strncat(full_name, ".", sizeof(full_name));
464 bcmcli_strncat(full_name, fld->name, sizeof(full_name));
465 }
466 rc = _apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, presence_mask, prefix, suffix);
467 if (f == td->x.u.classifier_idx)
468 {
469 rc = rc ? rc : _apicli_read_snum(session, fld->type, fdata, &selector_val);
470 }
471 if (style == APICLI_OUTPUT_STYLE_C_INIT)
472 {
473 bcmcli_print(session, ", ");
474 }
475 }
476 if (rc)
477 {
478 bcmcli_print(session, "***internal error when dumping field %s\n",
479 td->x.u.common_fields[f].name);
480 return rc;
481 }
482
483 num_union_vals = _api_cli_get_num_enum_vals(td->x.u.common_fields[td->x.u.classifier_idx].type->x.e);
484 if ((unsigned)selector_val >= num_union_vals)
485 {
486 bcmcli_print(session, "***invalid union selector value %lld\n", (long long)selector_val);
487 return BCM_ERR_INTERNAL;
488 }
489
490 /* Common fields following selector */
491 for (; f < td->x.u.num_common_fields; f++)
492 {
493 fld = &td->x.u.common_fields[f];
494 fdata = (void *)((long)data + fld->offset);
495
496 if (style == APICLI_OUTPUT_STYLE_C_INIT)
497 {
498 bcmcli_print(session, ", ");
499 }
500 bcmcli_strncpy(full_name, name, sizeof(full_name));
501 if (fld->name && strlen(fld->name))
502 {
503 bcmcli_strncat(full_name, ".", sizeof(full_name));
504 bcmcli_strncat(full_name, fld->name, sizeof(full_name));
505 }
506 rc = _apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, presence_mask, prefix, suffix);
507 }
508
509 /* Selected field */
510 fld = &td->x.u.union_fields[selector_val];
511 if (fld->type)
512 {
513 if (style == APICLI_OUTPUT_STYLE_C_INIT)
514 {
515 bcmcli_print(session, "{ .%s = ", _apicli_skip_union_prefix(fld->name));
516 }
517 fdata = (void *)((long)data + fld->offset);
518
519 bcmcli_strncpy(full_name, name, sizeof(full_name));
520 if (fld->name && strlen(fld->name))
521 {
522 bcmcli_strncat(full_name, ".", sizeof(full_name));
523 bcmcli_strncat(full_name, fld->name, sizeof(full_name));
524 }
525 rc = _apicli_dump_data_type(session, fld->type, fdata, full_name, num_entries, entry_size, style, presence_mask, prefix, suffix);
526 if (style == APICLI_OUTPUT_STYLE_C_INIT)
527 {
528 bcmcli_print(session, " }");
529 }
530 }
531 if (style == APICLI_OUTPUT_STYLE_C_INIT)
532 {
533 bcmcli_print(session, " }");
534 }
535 break;
536 }
537
538 case BCMOLT_BASE_TYPE_ID_ARR_FIXED: /* fixed array */
539 {
540 rc = _apicli_dump_array(session, td->x.arr_fixed.elem_type, data, td->x.arr_fixed.size, name, style, presence_mask, prefix, suffix);
541 break;
542 }
543
544 case BCMOLT_BASE_TYPE_ID_ARR_DYN: /* dynamic array that should be printed as buffer */
545 {
546 /* Read length */
547 uint32_t array_size;
548
549 rc = _apicli_arr_dyn_len_get(td, data, &array_size);
550 if (BCM_ERR_OK != rc)
551 {
552 bcmcli_print(session, "*** %s: dyn array len_size %u is not supported\n", name, td->x.arr_dyn.len_size);
553 return rc;
554 }
555
556 if (style == APICLI_OUTPUT_STYLE_C_INIT)
557 {
558 const char *field_name = strrchr(name, '.');
559 if (field_name == NULL)
560 {
561 field_name = name;
562 }
563 else
564 {
565 ++field_name;
566 }
567 bcmcli_print(session, "{ %u, %s }", array_size, field_name);
568 }
569 else
570 {
571 data = _apicli_arr_dyn_data_get(td, data);
572 rc = _apicli_dump_array(session, td->x.arr_dyn.elem_type, data, array_size, name, style, presence_mask, prefix, suffix);
573 }
574 break;
575 }
576
577 default:
578 {
579 /* Finally! Simple type that maps to a single CLI parameter */
580 int n;
581 apicli_presence_mask_info local_pm;
582
583 /* If we have a single value and that value is not included in the presence mask, just skip it entirely */
584 if (num_entries == 1 && !_apicli_is_value_set(session, presence_mask))
585 {
586 break;
587 }
588
589 if (style != APICLI_OUTPUT_STYLE_C_INIT)
590 {
591 if (name)
592 {
593 bcmcli_print(session, "%s%s=", prefix, name);
594 }
595 if (!num_entries)
596 {
597 bcmcli_print(session, BCMCLI_ARRAY_EMPTY);
598 }
599 }
600
601 /* Dump simple value or array of simple values */
602 local_pm = presence_mask ? *presence_mask : (apicli_presence_mask_info){};
603 for (n = 0; n < num_entries; n++)
604 {
605 if (n)
606 {
607 bcmcli_print(session, ",");
608 }
609
610 /* If we have a presence mask, make sure to print a special token if the value is unset */
611 if (_apicli_is_value_set(session, &local_pm))
612 {
613 rc = _apicli_dump_simple_data_type(session, td, data, name, style);
614 }
615 else
616 {
617 bcmcli_print(session, BCMCLI_PARM_NO_VALUE);
618 }
619
620 data = (void *)((long)data + entry_size);
621 local_pm.data = (void *)((long)local_pm.data + entry_size);
622 }
623 bcmcli_print(session, "%s", suffix);
624 break;
625 }
626 }
627 return rc;
628}
629
630/* Dump array */
631static bcmos_errno _apicli_dump_array(
632 bcmcli_session *session,
633 const bcmcli_type_descr *td,
634 void *data,
635 uint32_t size,
636 const char *name,
637 apicli_output_style style,
638 const apicli_presence_mask_info *presence_mask,
639 const char *prefix,
640 const char *suffix)
641{
642 bcmos_errno rc = BCM_ERR_OK;
643
644 /* Print as buffer or element by element ? */
645 if (style == APICLI_OUTPUT_STYLE_C_INIT)
646 {
647 bcmcli_print(session, "{ ");
648 rc = _apicli_dump_data_type(session, td, data, name, size, td->size, style, presence_mask, prefix, suffix);
649 bcmcli_print(session, " }");
650 }
651 else if ((td->base_type == BCMOLT_BASE_TYPE_ID_UNUM || td->base_type == BCMOLT_BASE_TYPE_ID_UNUM_HEX) && td->size == 1)
652 {
653 if (_apicli_is_value_set(session, presence_mask))
654 {
655 uint32_t i;
656
657 bcmcli_print(session, "%s%s=", prefix, name);
658 for (i = 0; i < size; ++i)
659 {
660 bcmcli_print(session, "%02x", ((uint8_t*)data)[i]);
661 }
662 bcmcli_print(session, "%s", suffix);
663 }
664 }
665 else
666 {
667 rc = _apicli_dump_data_type(session, td, data, name, size, td->size, style, presence_mask, prefix, suffix);
668 }
669 return rc;
670}
671
672/* Dump property */
673bcmos_errno apicli_dump_prop(bcmcli_session *session, const bcmcli_prop_descr *pd, void *prop_data)
674{
675 return _apicli_dump_data_type(session, pd->type, prop_data, pd->name, 1, 0, APICLI_OUTPUT_STYLE_STD, NULL, " ", "\n");
676}
677
678/* Dump a single property value in C initializer format */
679bcmos_errno apicli_dump_prop_initializer(bcmcli_session *session, const bcmcli_prop_descr *pd, void *prop_data)
680{
681 return _apicli_dump_data_type(session, pd->type, prop_data, pd->name, 1, 0, APICLI_OUTPUT_STYLE_C_INIT, NULL, "", "");
682}
683
684bcmos_errno apicli_dump_dyn_array(
685 bcmcli_session *session,
686 const bcmcli_type_descr *td,
687 void *data,
688 const char *name)
689{
690 bcmos_errno rc;
691 uint32_t array_size;
692
693 rc = _apicli_arr_dyn_len_get(td, data, &array_size);
694 BCMOS_RETURN_IF_ERROR(rc);
695 return _apicli_dump_array(
696 session,
697 td->x.arr_dyn.elem_type,
698 _apicli_arr_dyn_data_get(td, data),
699 array_size,
700 name,
701 APICLI_OUTPUT_STYLE_C_INIT,
702 NULL,
703 "",
704 "");
705}
706
707/* Dump property as CLI parameters */
708bcmos_errno apicli_dump_prop_param(bcmcli_session *session, const bcmcli_prop_descr *pd, void *prop_data, const char *prefix)
709{
710 return _apicli_dump_data_type(session, pd->type, prop_data, pd->name, 1, 0, APICLI_OUTPUT_STYLE_STD, NULL, prefix, "");
711}
712
713/* Calculate property pointer given the group data pointer and property description */
714static inline void *_apicli_prop_data_ptr(void *group_ptr, const bcmcli_prop_descr *pd)
715{
716 return (void *)((long)group_ptr + pd->offset);
717}
718
719/* Dump object data */
720static bcmos_errno _apicli_dump_data(bcmcli_session *session, bcmolt_msg *msg, void *data, uint32_t data_size)
721{
722 uint16_t prop;
723 bcmos_errno rc = BCM_ERR_OK;
724 const bcmcli_prop_descr *pd;
725
726 bcmcli_print(session, "data:\n");
727 for (prop = 0;
728 api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
729 ++prop)
730 {
731 void *prop_data = _apicli_prop_data_ptr(data, pd);
732 if (!(msg->presence_mask & (1LL << prop)))
733 continue;
734 if (!prop_data)
735 {
736 continue;
737 }
738 BUG_ON(pd->offset > data_size);
739 rc = apicli_dump_prop(session, pd, prop_data);
740 if (rc != BCM_ERR_OK)
741 {
742 break;
743 }
744 }
745 return rc;
746}
747
748/* Dump object key */
749static bcmos_errno _apicli_dump_key(bcmcli_session *session, bcmolt_msg *msg, void *key, uint32_t key_size)
750{
751 uint16_t prop;
752 bcmos_errno rc = BCM_ERR_OK;
753 const bcmcli_prop_descr *pd;
754
755 bcmcli_print(session, "key:\n");
756 for (prop = 0;
757 api_cli_object_property(msg->obj_type, BCMOLT_MGT_GROUP_KEY, 0, prop, &pd) == BCM_ERR_OK;
758 ++prop)
759 {
760 void *prop_data = _apicli_prop_data_ptr(key, pd);
761 if (!prop_data)
762 {
763 continue;
764 }
765 BUG_ON(pd->offset > key_size);
766 rc = apicli_dump_prop(session, pd, prop_data);
767 if (rc != BCM_ERR_OK)
768 {
769 break;
770 }
771 }
772 return rc;
773}
774
775const char *apicli_mgt_group_to_str(bcmolt_mgt_group group)
776{
777 static const char *str_table[BCMOLT_MGT_GROUP__NUM_OF] =
778 {
779 [BCMOLT_MGT_GROUP_KEY] = "key",
780 [BCMOLT_MGT_GROUP_CFG] = "cfg",
781 [BCMOLT_MGT_GROUP_STAT] = "stat",
782 [BCMOLT_MGT_GROUP_STAT_CFG] = "stat_cfg",
783 [BCMOLT_MGT_GROUP_AUTO] = "auto",
784 [BCMOLT_MGT_GROUP_AUTO_CFG] = "auto_cfg",
785 [BCMOLT_MGT_GROUP_OPER] = "oper",
786 [BCMOLT_MGT_GROUP_PROXY] = "proxy",
787 [BCMOLT_MGT_GROUP_PROXY_RX] = "proxy_rx"
788 };
789 return (group >= BCMOLT_MGT_GROUP__NUM_OF) ? "<unknown>" : str_table[group];
790}
791
792/* Dump message set returned by multi-object GET */
793static bcmos_errno _apicli_dump_msgset(
794 bcmcli_session *session,
795 bcmolt_msg *msg,
796 uint32_t key_size,
797 uint32_t data_size,
798 uint32_t data_offset)
799{
800 uint16_t inst;
801 bcmos_errno rc;
802 void *key = NULL;
803 void *data = NULL;
804
805 if (msg->msg_set == NULL)
806 {
807 return BCM_ERR_NULL;
808 }
809
810 bcmcli_print(session, "more: %s\n", msg->msg_set->more ? "yes" : "no");
811 if (msg->msg_set->more)
812 {
813 bcmcli_print(session, "next ");
814 _apicli_dump_key(session, msg, msg->msg_set->next_key, key_size);
815 }
816
817 bcmcli_print(session, "number of objects returned: %d\n", msg->msg_set->num_instances);
818 for (inst = 0; inst < msg->msg_set->num_instances; inst++)
819 {
820 bcmcli_print(session, "object %d:\n", inst);
821
822 key = (void *)((long)msg->msg_set->msg[inst] + sizeof(bcmolt_msg));
823 rc = _apicli_dump_key(session, msg->msg_set->msg[inst], key, key_size);
824 if (rc != BCM_ERR_OK)
825 {
826 return rc;
827 }
828
829 data = (void *)((long)msg->msg_set->msg[inst] + data_offset);
830 rc = _apicli_dump_data(session, msg->msg_set->msg[inst], data, data_size);
831 if (rc)
832 {
833 return rc;
834 }
835 }
836
837 return BCM_ERR_OK;
838}
839
840/* Dump message */
841bcmos_errno apicli_msg_dump(bcmcli_session *session, bcmolt_msg *msg)
842{
843 bcmos_errno rc;
844 const char *name, *descr;
845 uint32_t key_size;
846 uint32_t key_offset;
847 uint32_t data_size;
848 uint32_t data_offset;
849 void *key = NULL;
850 void *data = NULL;
851
852 rc = api_cli_object_name(msg->obj_type, &name, &descr);
853 if (rc)
854 {
855 goto dump_error;
856 }
857
858 bcmcli_print(session, "object: ");
859 if (name)
860 {
861 bcmcli_print(session, "%s", name);
862 }
863 if (descr)
864 {
865 bcmcli_print(session, " - %s", descr);
866 }
867 bcmcli_print(session, "\n");
868 rc = api_cli_object_struct_size(
869 msg->obj_type,
870 msg->group,
871 msg->subgroup,
872 &key_size,
873 &key_offset,
874 &data_size,
875 &data_offset);
876 if (rc)
877 {
878 goto dump_error;
879 }
880
881 bcmcli_print(session, (msg->type & BCMOLT_MSG_TYPE_GET) != 0 ? "get" : "set");
882 if ((msg->type & BCMOLT_MSG_TYPE_CLEAR) != 0)
883 {
884 bcmcli_print(session, ",clear");
885 }
886 if ((msg->type & BCMOLT_MSG_TYPE_MULTI) != 0)
887 {
888 bcmcli_print(session, ",multi");
889 }
890 bcmcli_print(session, " %s ", apicli_mgt_group_to_str(msg->group));
891
892 if (msg->group != BCMOLT_MGT_GROUP_CFG && msg->group != BCMOLT_MGT_GROUP_STAT &&
893 msg->group != BCMOLT_MGT_GROUP_AUTO_CFG && msg->group != BCMOLT_MGT_GROUP_STAT_CFG)
894 {
895 const char *sub_name, *sub_descr;
896 /* Get name of specific subgroup */
897 rc = api_cli_object_subgroup_name(msg->obj_type, msg->group, msg->subgroup, &sub_name, &sub_descr);
898 if (rc)
899 {
900 goto dump_error;
901 }
902 bcmcli_print(session, "subgroup: %s-%s ", sub_name ? sub_name : "?", sub_descr ? sub_descr : "");
903 }
904 if (msg->dir == BCMOLT_MSG_DIR_REQUEST)
905 {
906 bcmcli_print(session, "request\n");
907 }
908 else
909 {
910 bcmcli_print(session, "response: %s %s\n", bcmos_strerror(msg->err), msg->err_text);
911 }
912
913 if (msg->dir == BCMOLT_MSG_DIR_RESPONSE && (msg->type & BCMOLT_MSG_TYPE_MULTI) != 0)
914 {
915 rc = _apicli_dump_msgset(session, msg, key_size, data_size, data_offset);
916 if (rc)
917 {
918 goto dump_error;
919 }
920 }
921 else
922 {
923 if ((msg->group != BCMOLT_MGT_GROUP_AUTO_CFG) && key_size)
924 {
925 key = (void *)((long)msg + key_offset);
926 rc = _apicli_dump_key(session, msg, key, key_size);
927 if (rc)
928 {
929 goto dump_error;
930 }
931 }
932 if (data_size &&
933 ( ((msg->dir == BCMOLT_MSG_DIR_REQUEST) && (msg->type & BCMOLT_MSG_TYPE_SET)) ||
934 ((msg->dir == BCMOLT_MSG_DIR_RESPONSE) && (msg->type & BCMOLT_MSG_TYPE_GET)) ||
935 (msg->group == BCMOLT_MGT_GROUP_AUTO) ||
936 (msg->group == BCMOLT_MGT_GROUP_PROXY_RX)
937 )
938 )
939 {
940 data = (void *)((long)msg + data_offset);
941 rc = _apicli_dump_data(session, msg, data, data_size);
942 if (rc)
943 {
944 goto dump_error;
945 }
946 }
947 }
948 return BCM_ERR_OK;
949
950dump_error:
951 bcmcli_print(session, "*** Object dump error %s (%d)\n", bcmos_strerror(rc), rc);
952 return rc;
953}
954