blob: a3b463bbd70bceb91a5779539c0dd91906b33388 [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
7 Unless you and Broadcom execute a separate written software license
8 agreement governing use of this software, this software is licensed
9 to you under the terms of the GNU General Public License version 2
10 (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11 with 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
22 Not withstanding the above, under no circumstances may you combine
23 this software in any way with any other Broadcom software provided
24 under a license other than the GPL, without Broadcom's express prior
25 written consent.
26
27 :>
28*/
29
30#include "bcmos_system.h"
31#include "bcm_dev_log.h"
32#include "bcmolt_api.h"
33#include "bcm_api_cli_helpers.h"
34#include "bcmolt_model_types.h"
35#include "bcmtr_debug.h"
36#include "bcmtr_interface.h"
37#include "bcmolt_user_appl_playback.h"
38#include "bcmolt_bit_utils.h"
39
40/* 'MPBx' in ASCII (M)aple (P)lay(b)ack version x */
41#define VERSION0 0x4d504230
42#define VERSION1 0x4d504231
43
44static const uint32_t CHUNK_SIZE = 2000;
45
46static const char *cap_loc_str[BCMOLT_API_CAPTURE_LOCATION__NUM_OF] =
47{
48 "device",
49 "host"
50};
51
52typedef struct
53{
54 dev_log_id log_id;
55} playback_context;
56
57static playback_context pb_ctxt[BCMTR_MAX_OLTS];
58
59typedef enum
60{
61 PB_FORMAT_API_CLI,
62 PB_FORMAT_C_API,
63
64 PB_FORMAT__COUNT
65} pb_format;
66
67typedef enum
68{
69 PB_CLI_EXTRA_NONE,
70 PB_CLI_EXTRA_MULTI,
71 PB_CLI_EXTRA_STAT,
72 PB_CLI_EXTRA_SUBGROUP
73} pb_cli_extra;
74
75typedef enum
76{
77 PB_FIELDS_NONE,
78 PB_FIELDS_GET,
79 PB_FIELDS_MULTI,
80 PB_FIELDS_SET
81} pb_fields;
82
83typedef struct
84{
85 uint32_t version;
86 bcmolt_api_capture_location location;
87 bcmolt_firmware_sw_version fw_ver;
88 bcmolt_host_sw_version host_ver;
89 uint32_t buf_size;
90 void *capture_buffer;
91} bcmolt_playback;
92
93typedef struct
94{
95 bcmolt_buf buf;
96 bcmtr_capture_entry hdr;
97 uint8_t *msg_start;
98} playback_iterator_raw;
99
100typedef struct
101{
102 playback_iterator_raw raw;
103 bcmolt_buf msg_buf;
104 bcmolt_msg *msg;
105 bcmos_errno err;
106} playback_iterator;
107
108#define FOR_EACH_CAPTURE_ENTRY(it, buffer, size) \
109 bcmolt_buf_init(&(it).buf, size, buffer, BCMOLT_BUF_ENDIAN_FIXED); \
110 while (bcmtr_capture_entry_get_next(&(it).buf, &(it).hdr, &(it).msg_start))
111
112#define FOR_EACH_PLAYBACK_MSG(it, buffer, size) \
113 bcmolt_buf_init(&(it).raw.buf, size, buffer, BCMOLT_BUF_ENDIAN_FIXED); \
114 (it).msg = NULL; \
115 while (playback_next_entry_unpacked(&(it)))
116
117#define DEVICE_REF "device_id"
118#define RC_REF "rc"
119#define VAL_REF "val"
120#define MSG_REF "msg"
121#define KEY_REF "key"
122#define LIST_MEM_REF "list_mem"
123#define MSG_SET_REF "msg_set"
124#define MAX_MSGS_REF "max_msgs"
125#define INVERT_FILTER_REF "invert_filter"
126#define STAT_FLAGS_REF "stat_flags"
127#define DYN_LIST_SIZE "APICLI_DYNAMIC_LIST_BUFFER_SIZE"
128
129static void playback_iterator_cleanup(playback_iterator *it)
130{
131 if ((it->err == BCM_ERR_OK) && (it->msg != NULL))
132 {
133 bcmolt_msg_free(it->msg);
134 it->msg = NULL;
135 }
136}
137
138static bcmos_bool playback_next_entry_unpacked(playback_iterator *it)
139{
140 playback_iterator_cleanup(it);
141 bcmos_bool ret = bcmtr_capture_entry_get_next(&it->raw.buf, &it->raw.hdr, &it->raw.msg_start);
142 if (ret)
143 {
144 bcmolt_buf_init(&it->msg_buf, it->raw.hdr.msg_size, it->raw.msg_start, BCMOLT_BUF_ENDIAN_FIXED);
145 it->err = bcmolt_msg_unpack(&it->msg_buf, &it->msg);
146 }
147 return ret;
148}
149
150static bcmos_errno playback_read_block(uint32_t offset, uint32_t size, uint8_t *buf)
151{
152 bcmos_errno err;
153 bcmolt_debug_cfg debug_cfg;
154 bcmolt_debug_key debug_key = { };
155 bcmolt_api_capture_buffer_reader reader = { .offset = offset, .size = size };
156
157 BCMOLT_CFG_INIT(&debug_cfg, debug, debug_key);
158 BCMOLT_CFG_PROP_SET(&debug_cfg, debug, api_capture_buffer_read, reader);
159 err = bcmolt_cfg_set(current_device, &debug_cfg.hdr);
160 if (BCM_ERR_OK != err)
161 {
162 BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Failed to update reader (%u, %u)!\n", offset, size);
163 }
164 else
165 {
166 BCMOLT_CFG_INIT(&debug_cfg, debug, debug_key);
167 BCMOLT_CFG_PROP_GET(&debug_cfg, debug, api_capture_buffer);
168 debug_cfg.data.api_capture_buffer.val = buf;
169 err = bcmolt_cfg_get(current_device, &debug_cfg.hdr);
170 if (BCM_ERR_OK != err)
171 {
172 BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Failed to retrieve capture buffer chunk (%u, %u)!\n",
173 offset, size);
174 }
175 }
176
177 return err;
178}
179
180static bcmos_errno playback_read(void **buffer, uint32_t *length, bcmolt_api_capture_location *capture_location)
181{
182 bcmos_errno err;
183 bcmolt_debug_cfg debug_cfg;
184 bcmolt_debug_key debug_key = { };
185
186 if ((buffer == NULL) || (length == NULL))
187 {
188 BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "buffer (%p) and length (%p) cannot be NULL\n", buffer, length);
189 }
190
191 BCMOLT_CFG_INIT(&debug_cfg, debug, debug_key);
192 BCMOLT_CFG_PROP_GET(&debug_cfg, debug, api_capture_stats);
193 BCMOLT_CFG_PROP_GET(&debug_cfg, debug, api_capture_cfg);
194 err = bcmolt_cfg_get(current_device, &debug_cfg.hdr);
195 if (BCM_ERR_OK != err)
196 {
197 BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Failed to retrieve capture stats!\n");
198 }
199 else
200 {
201 void *capture_buffer;
202 uint32_t buf_size = debug_cfg.data.api_capture_stats.readable_bytes;
203 uint32_t offset = 0;
204
205 *capture_location = debug_cfg.data.api_capture_cfg.location;
206
207 BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Retrieving %u byte buffer\n", buf_size);
208 capture_buffer = bcmos_alloc(buf_size);
209 if (NULL != capture_buffer)
210 {
211 while ((offset + CHUNK_SIZE) < buf_size)
212 {
213 BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Reading bytes %u - %u\n", offset, offset + CHUNK_SIZE);
214 err = playback_read_block(offset, CHUNK_SIZE, (uint8_t*)capture_buffer + offset);
215 if (BCM_ERR_OK != err)
216 {
217 break;
218 }
219 offset += CHUNK_SIZE;
220 }
221
222 if (BCM_ERR_OK == err)
223 {
224 BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Reading bytes %u - %u\n", offset, buf_size);
225 err = playback_read_block(offset, buf_size - offset, (uint8_t*)capture_buffer + offset);
226 }
227 }
228
229 *buffer = capture_buffer;
230 *length = buf_size;
231 }
232
233 return err;
234}
235
236static bcmos_errno playback_dump(bcmcli_session *session, void *capture_buf, uint32_t buf_size)
237{
238 playback_iterator it;
239 bcmos_errno err = BCM_ERR_OK;
240
241 FOR_EACH_PLAYBACK_MSG(it, capture_buf, buf_size)
242 {
243 BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Dumping message at %u of %u (%u)\n",
244 bcmolt_buf_get_used(&it.raw.buf), buf_size, it.raw.hdr.msg_size);
245 bcmcli_session_print(session, "\n%08x %u:\n", it.raw.hdr.timestamp, it.raw.hdr.event);
246 if (BCM_ERR_OK == it.err)
247 {
248 err = apicli_msg_dump(session, it.msg);
249 BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Dump status: %s\n", bcmos_strerror(err));
250 }
251 else
252 {
253 BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Unpacking failed: %s\n", bcmos_strerror(err));
254 if ((it.raw.msg_start + it.raw.hdr.msg_size) > (it.raw.buf.start + it.raw.buf.len))
255 {
256 bcmcli_session_print(session, "Message length is insane!\n");
257 }
258 else
259 {
260 bcmcli_session_hexdump(session, it.raw.msg_start, 0, it.raw.hdr.msg_size, NULL);
261 }
262 }
263 }
264
265 return err;
266}
267
268static bcmos_bool playback_should_send(bcmolt_api_capture_location capture_location, bcmtr_cld_event_type event_type)
269{
270 switch (capture_location)
271 {
272 case BCMOLT_API_CAPTURE_LOCATION_DEVICE:
273 switch (event_type)
274 {
275 case BCMTR_CLD_EV_RECV:
276 case BCMTR_CLD_EV_RECV_DISCARD:
277 return BCMOS_TRUE;
278 default:
279 return BCMOS_FALSE;
280 }
281 case BCMOLT_API_CAPTURE_LOCATION_HOST:
282 switch (event_type)
283 {
284 case BCMTR_CLD_EV_SEND:
285 case BCMTR_CLD_EV_RESEND:
286 return BCMOS_TRUE;
287 default:
288 return BCMOS_FALSE;
289 }
290 default:
291 return BCMOS_FALSE;
292 }
293}
294
295/*lint -e{429} */
296static bcmos_errno playback_replay(
297 bcmolt_devid device,
298 void *capture_buf,
299 uint32_t buf_size,
300 bcmolt_api_capture_location location,
301 bcmos_bool keep_time)
302{
303 bcmos_errno err = BCM_ERR_OK;
304 playback_iterator_raw it;
305 uint32_t last_time_us = 0;
306 bcmos_bool first = BCMOS_TRUE;
307
308 FOR_EACH_CAPTURE_ENTRY(it, capture_buf, buf_size)
309 {
310 bcmolt_buf msg_buf;
311 bcmolt_msg *msg = NULL;
312
313 BCM_LOG(DEBUG, pb_ctxt[device].log_id, "Processing message (%u,%u,%u)\n",
314 it.hdr.event, it.hdr.timestamp, it.hdr.msg_size);
315 if (playback_should_send(location, (bcmtr_cld_event_type)it.hdr.event))
316 {
317 if (keep_time)
318 {
319 if (!first)
320 {
321 /* approximate original timing; doesn't account for processing time in this code - this could be
322 improved */
323 BCM_LOG(DEBUG, pb_ctxt[device].log_id, "Sleeping for %u us\n", it.hdr.timestamp - last_time_us);
324 bcmos_usleep(it.hdr.timestamp - last_time_us);
325 }
326 else
327 {
328 first = BCMOS_FALSE;
329 }
330 last_time_us = it.hdr.timestamp;
331 }
332 BCM_LOG(DEBUG, pb_ctxt[device].log_id, "Unpacking message\n");
333 bcmolt_buf_init(&msg_buf, it.hdr.msg_size, it.msg_start, BCMOLT_BUF_ENDIAN_FIXED);
334 err = bcmolt_msg_unpack(&msg_buf, &msg);
335 if (BCM_ERR_OK == err)
336 {
337 BCM_LOG(DEBUG, pb_ctxt[device].log_id, "Sending message\n");
338 err = bcmtr_send(device, msg, BCMTR_SEND_FLAGS_NONE);
339 bcmolt_msg_free(msg);
340 if (BCM_ERR_OK != err)
341 {
342 BCM_LOG(INFO, pb_ctxt[device].log_id, "Sending failed: %s\n", bcmos_strerror(err));
343 return err;
344 }
345 }
346 else
347 {
348 BCM_LOG(INFO, pb_ctxt[device].log_id, "Unpacking failed: %s\n", bcmos_strerror(err));
349 return err;
350 }
351 }
352 }
353
354 return err;
355}
356
357static bcmos_errno playback_cli_dump(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
358{
359 bcmos_errno err;
360 void *capture_buffer;
361 uint32_t buf_size;
362 bcmolt_api_capture_location location;
363
364 err = playback_read(&capture_buffer, &buf_size, &location);
365
366 if (BCM_ERR_OK == err)
367 {
368 bcmcli_print(session, "Capture from %s:\n", cap_loc_str[location]);
369 playback_dump(session, capture_buffer, buf_size);
370 }
371
372 bcmos_free(capture_buffer);
373
374 return err;
375}
376
377static void playback_fw_version_get(bcmolt_devid device, bcmolt_firmware_sw_version *fw)
378{
379 bcmos_errno err;
380 bcmolt_device_cfg dev_cfg;
381 bcmolt_device_key dev_key = { };
382
383 BCMOLT_CFG_INIT(&dev_cfg, device, dev_key);
384 BCMOLT_CFG_PROP_GET(&dev_cfg, device, firmware_sw_version);
385 err = bcmolt_cfg_get(device, &dev_cfg.hdr);
386 if (BCM_ERR_OK != err)
387 {
388 BCM_LOG(WARNING, pb_ctxt[device].log_id, "Failed to retrieve fw version!\n");
389 }
390 else
391 {
392 *fw = dev_cfg.data.firmware_sw_version;
393 }
394}
395
396static void playback_host_version_get(bcmolt_devid device, bcmolt_host_sw_version *host)
397{
398 bcmos_errno err;
399 bcmolt_device_cfg dev_cfg;
400 bcmolt_device_key dev_key = { };
401
402 BCMOLT_CFG_INIT(&dev_cfg, device, dev_key);
403 BCMOLT_CFG_PROP_GET(&dev_cfg, device, host_sw_version);
404 err = bcmolt_cfg_get(device, &dev_cfg.hdr);
405 if (BCM_ERR_OK != err)
406 {
407 BCM_LOG(WARNING, pb_ctxt[device].log_id, "Failed to retrieve host version!\n");
408 }
409 else
410 {
411 *host = dev_cfg.data.host_sw_version;
412 }
413}
414
415static bcmos_errno playback_cli_save(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
416{
417 const char *filename = bcmcli_find_named_parm(session, "file")->value.string;
418 bcmolt_playback mpb = {};
419 bcmos_errno err;
420 FILE *file;
421 uint32_t temp;
422
423 err = playback_read(&mpb.capture_buffer, &mpb.buf_size, &mpb.location);
424
425 if (BCM_ERR_OK == err)
426 {
427 playback_fw_version_get(current_device, &mpb.fw_ver);
428 playback_host_version_get(current_device, &mpb.host_ver);
429
430 file = fopen(filename, "wb");
431 /* write file version */
432 temp = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, VERSION1);
433 fwrite(&temp, sizeof(uint32_t), 1, file);
434 /* write capture location */
435 temp = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, (uint32_t)mpb.location);
436 fwrite(&temp, sizeof(uint32_t), 1, file);
437 /* write firmware version */
438 fwrite(&mpb.fw_ver.major, sizeof(uint8_t), 1, file);
439 fwrite(&mpb.fw_ver.minor, sizeof(uint8_t), 1, file);
440 fwrite(&mpb.fw_ver.revision, sizeof(uint8_t), 1, file);
441 temp = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, mpb.fw_ver.model);
442 fwrite(&temp, sizeof(uint32_t), 1, file);
443 fwrite(mpb.fw_ver.build_time, sizeof(mpb.fw_ver.build_time), 1, file);
444 /* write host version */
445 fwrite(&mpb.host_ver.major, sizeof(uint8_t), 1, file);
446 fwrite(&mpb.host_ver.minor, sizeof(uint8_t), 1, file);
447 fwrite(&mpb.host_ver.revision, sizeof(uint8_t), 1, file);
448 temp = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, mpb.host_ver.model);
449 fwrite(&temp, sizeof(uint32_t), 1, file);
450 fwrite(mpb.host_ver.build_time, sizeof(mpb.host_ver.build_time), 1, file);
451 /* write capture buffer */
452 temp = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, mpb.buf_size);
453 fwrite(&temp, sizeof(uint32_t), 1, file);
454 fwrite(mpb.capture_buffer, mpb.buf_size, 1, file);
455 fclose(file);
456 }
457
458 bcmos_free(mpb.capture_buffer);
459
460 return err;
461}
462
463static bcmos_bool playback_version_match(const bcmolt_playback *mpb)
464{
465 bcmolt_firmware_sw_version fw_curr = {};
466 bcmolt_host_sw_version host_curr = {};
467
468 playback_fw_version_get(current_device, &fw_curr);
469 playback_host_version_get(current_device, &host_curr);
470
471 if ((mpb->fw_ver.model != fw_curr.model) || (mpb->host_ver.model != host_curr.model) ||
472 (fw_curr.model == 0) || (host_curr.model == 0))
473 {
474 BCM_LOG(WARNING, pb_ctxt[current_device].log_id,
475 "Possible version mismatch: Capture FW %u, HOST %u; Current FW %u, HOST %u\n",
476 mpb->fw_ver.model, mpb->host_ver.model, fw_curr.model, host_curr.model);
477 return BCMOS_FALSE;
478 }
479
480 return BCMOS_TRUE;
481}
482
483static bcmos_errno playback_file_open(const char *filename, bcmolt_playback *mpb)
484{
485 FILE *file;
486 uint32_t temp;
487 bcmos_errno err = BCM_ERR_OK;
488 uint32_t items_read;
489
490 file = fopen(filename, "rb");
491 items_read = fread(&temp, sizeof(uint32_t), 1, file);
492 if (items_read != 1)
493 return BCM_ERR_PARSE;
494
495 mpb->version = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
496 switch (mpb->version)
497 {
498 case VERSION0:
499 items_read = fread(&temp, sizeof(uint32_t), 1, file);
500 if (items_read != 1)
501 break;
502 temp = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
503 mpb->location = (bcmolt_api_capture_location)temp;
504 items_read = fread(&temp, sizeof(uint32_t), 1, file);
505 if (items_read != 1)
506 break;
507 mpb->buf_size = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
508 mpb->capture_buffer = bcmos_alloc(mpb->buf_size);
509 items_read = fread(mpb->capture_buffer, mpb->buf_size, 1, file);
510 if (items_read != 1)
511 break;
512 break;
513 case VERSION1:
514 /* read capture location */
515 items_read = fread(&temp, sizeof(uint32_t), 1, file);
516 if (items_read != 1)
517 break;
518 temp = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
519 mpb->location = (bcmolt_api_capture_location)temp;
520 /* read firmware version */
521 items_read = fread(&mpb->fw_ver.major, sizeof(uint8_t), 1, file);
522 if (items_read != 1)
523 break;
524 items_read = fread(&mpb->fw_ver.minor, sizeof(uint8_t), 1, file);
525 if (items_read != 1)
526 break;
527 items_read = fread(&mpb->fw_ver.revision, sizeof(uint8_t), 1, file);
528 if (items_read != 1)
529 break;
530 items_read = fread(&temp, sizeof(uint32_t), 1, file);
531 if (items_read != 1)
532 break;
533 mpb->fw_ver.model = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
534 items_read = fread(mpb->fw_ver.build_time, sizeof(mpb->fw_ver.build_time), 1, file);
535 if (items_read != 1)
536 break;
537 /* read host version */
538 items_read = fread(&mpb->host_ver.major, sizeof(uint8_t), 1, file);
539 if (items_read != 1)
540 break;
541 items_read = fread(&mpb->host_ver.minor, sizeof(uint8_t), 1, file);
542 if (items_read != 1)
543 break;
544 items_read = fread(&mpb->host_ver.revision, sizeof(uint8_t), 1, file);
545 if (items_read != 1)
546 break;
547 items_read = fread(&temp, sizeof(uint32_t), 1, file);
548 if (items_read != 1)
549 break;
550 mpb->host_ver.model = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
551 items_read = fread(mpb->host_ver.build_time, sizeof(mpb->host_ver.build_time), 1, file);
552 if (items_read != 1)
553 break;
554 /* read capture buffer */
555 items_read = fread(&temp, sizeof(uint32_t), 1, file);
556 if (items_read != 1)
557 break;
558 mpb->buf_size = BCMOLT_BUF_ENDIAN_BUF_TO_CPU(U32, temp);
559 mpb->capture_buffer = bcmos_alloc(mpb->buf_size);
560 items_read = fread(mpb->capture_buffer, mpb->buf_size, 1, file);
561 if (items_read != 1)
562 break;
563 break;
564 default:
565 BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Unknown version: %u\n", mpb->version);
566 err = BCM_ERR_PARSE;
567 break;
568 }
569
570 fclose(file);
571
572 return err;
573}
574
575static bcmos_errno playback_cli_replay(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
576{
577 const char *filename = bcmcli_find_named_parm(session, "file")->value.string;
578 bcmos_bool ignore_ver = BCMOS_FALSE;
579 bcmos_errno err;
580 bcmolt_playback mpb = {};
581
582 bcmcli_cmd_parm *iv_parm = bcmcli_find_named_parm(session, "ignore_version");
583 if (iv_parm != NULL)
584 {
585 ignore_ver = iv_parm->value.enum_val == (long)BCMOS_TRUE;
586 }
587
588 err = playback_file_open(filename, &mpb);
589
590 if (BCM_ERR_OK == err)
591 {
592 if (playback_version_match(&mpb) || ignore_ver)
593 {
594 err = playback_replay(current_device, mpb.capture_buffer, mpb.buf_size, mpb.location, BCMOS_TRUE);
595 }
596 else
597 {
598 bcmcli_print(session, "Possible version mismatch; use ignore_version=yes to force playback\n");
599 err = BCM_ERR_IMAGE_TYPE;
600 }
601 bcmos_free(mpb.capture_buffer);
602 }
603
604 return err;
605}
606
607static bcmos_errno playback_api_cli_append_prop(
608 bcmolt_string *api_cli,
609 uint32_t size,
610 void *data,
611 const bcmcli_prop_descr *pd,
612 const char *prefix)
613{
614 bcmos_errno err;
615 bcmcli_session *str;
616 void *prop_data = (void *)((long)data + pd->offset);
617
618 BCMOS_CHECK_RETURN_ERROR(pd->offset >= size, BCM_ERR_INTERNAL);
619 err = bcmcli_session_open_string(&str, api_cli);
620 BCMOS_RETURN_IF_ERROR(err);
621 err = apicli_dump_prop_param(str, pd, prop_data, prefix);
622 bcmcli_session_close(str);
623 BCMOS_RETURN_IF_ERROR(err);
624
625 return BCM_ERR_OK;
626}
627
628static bcmos_errno playback_api_cli_key_write(
629 bcmolt_string* api_cli,
630 const bcmolt_msg* msg,
631 uint32_t key_size,
632 uint32_t key_offset)
633{
634 bcmos_errno err;
635 const bcmcli_prop_descr *pd;
636 void *data = (void *)((long)msg + key_offset);
637
638 for (uint16_t prop = 0;
639 api_cli_object_property(msg->obj_type, BCMOLT_MGT_GROUP_KEY, 0, prop, &pd) == BCM_ERR_OK;
640 ++prop)
641 {
642 err = playback_api_cli_append_prop(api_cli, key_size, data, pd, " ");
643 BCMOS_RETURN_IF_ERROR(err);
644 }
645
646 return BCM_ERR_OK;
647}
648
649static bcmos_errno playback_api_cli_pm_write(bcmolt_string *api_cli, const bcmolt_msg* msg, bcmolt_presence_mask pm)
650{
651 int n;
652 const bcmcli_prop_descr *pd;
653
654 for (uint16_t prop = 0;
655 api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
656 ++prop)
657 {
658 if (!(pm & (1ULL << prop)))
659 {
660 continue;
661 }
662 n = bcmolt_string_append(api_cli, " %s=yes", pd->name);
663 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
664 }
665
666 return BCM_ERR_OK;
667}
668
669static bcmos_errno playback_api_cli_props_write(
670 bcmolt_string *api_cli,
671 const bcmolt_msg* msg,
672 const char *prefix,
673 uint32_t size,
674 uint32_t offset)
675{
676 bcmos_errno err;
677 const bcmcli_prop_descr *pd;
678 void *data = (void *)((long)msg + offset);
679
680 for (uint16_t prop = 0;
681 api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
682 ++prop)
683 {
684 if (!(msg->presence_mask & (1ULL << prop)))
685 {
686 continue;
687 }
688 err = playback_api_cli_append_prop(api_cli, size, data, pd, prefix);
689 BCMOS_RETURN_IF_ERROR(err);
690 }
691
692 return BCM_ERR_OK;
693}
694
695static bcmos_errno playback_api_cli_cmd_get(
696 bcmolt_string *api_cli,
697 const bcmolt_msg* msg,
698 const char *cmd,
699 pb_cli_extra extra_parms,
700 pb_fields field_parms)
701{
702 int n;
703 bcmos_errno err;
704 const char *name;
705 const char *desc;
706 uint32_t key_size;
707 uint32_t key_offset;
708 uint32_t data_size;
709 uint32_t data_offset;
710
711 BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "Start %s\n", cmd);
712
713 err = api_cli_object_name(msg->obj_type, &name, &desc);
714 BCMOS_RETURN_IF_ERROR(err);
715
716 n = bcmolt_string_append(api_cli, "/api/%s object=%s", cmd, name);
717 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
718
719 switch (extra_parms)
720 {
721 case PB_CLI_EXTRA_MULTI:
722 n = bcmolt_string_append(
723 api_cli,
724 " max_msgs=%u filter_invert=%s",
725 msg->msg_set->max_instances,
726 BITS_SET(msg->msg_set->filter_flags, BCMOLT_FILTER_FLAGS_INVERT_SELECTION) ? "yes" : "no");
727 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
728 break;
729 case PB_CLI_EXTRA_STAT:
730 n = bcmolt_string_append(api_cli, " clear=%s", BITS_SET(msg->type, BCMOLT_MSG_TYPE_CLEAR) ? "yes" : "no");
731 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
732 break;
733 case PB_CLI_EXTRA_SUBGROUP:
734 err = api_cli_object_subgroup_name(msg->obj_type, msg->group, msg->subgroup, &name, &desc);
735 BCMOS_RETURN_IF_ERROR(err);
736 n = bcmolt_string_append(api_cli, " sub=%s", name);
737 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
738 break;
739 default:
740 break;
741 }
742
743 /* get message info */
744 err = api_cli_object_struct_size(
745 msg->obj_type,
746 msg->group,
747 msg->subgroup,
748 &key_size,
749 &key_offset,
750 &data_size,
751 &data_offset);
752 BCMOS_RETURN_IF_ERROR(err);
753
754 if (BCMOLT_MGT_GROUP_AUTO_CFG != msg->group)
755 {
756 /* write key */
757 err = playback_api_cli_key_write(api_cli, msg, key_size, key_offset);
758 BCMOS_RETURN_IF_ERROR(err);
759 }
760
761 switch (field_parms)
762 {
763 case PB_FIELDS_GET:
764 /* write presence mask */
765 err = playback_api_cli_pm_write(api_cli, msg, msg->presence_mask);
766 BCMOS_RETURN_IF_ERROR(err);
767 break;
768 case PB_FIELDS_MULTI:
769 /* write filter */
770 err = playback_api_cli_props_write(api_cli, msg, " filter.", data_size, data_offset);
771 BCMOS_RETURN_IF_ERROR(err);
772 /* write presence mask */
773 err = playback_api_cli_pm_write(api_cli, msg, msg->msg_set->presence_mask);
774 BCMOS_RETURN_IF_ERROR(err);
775 break;
776 case PB_FIELDS_SET:
777 /* write properties */
778 err = playback_api_cli_props_write(api_cli, msg, " ", data_size, data_offset);
779 BCMOS_RETURN_IF_ERROR(err);
780 break;
781 default:
782 break;
783 }
784
785 n = bcmolt_string_append(api_cli, "\n");
786 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
787
788 BCM_LOG(DEBUG, pb_ctxt[current_device].log_id, "End %s\n", cmd);
789
790 return err;
791}
792
793static bcmos_errno playback_api_cli_get(bcmolt_string* api_cli, const bcmolt_msg* msg)
794{
795 switch (msg->group)
796 {
797 case BCMOLT_MGT_GROUP_CFG:
798 switch (msg->type)
799 {
800 case BCMOLT_MSG_TYPE_GET:
801 return playback_api_cli_cmd_get(api_cli, msg, "get", PB_CLI_EXTRA_NONE, PB_FIELDS_GET);
802 case BCMOLT_MSG_TYPE_GET_MULTI:
803 return playback_api_cli_cmd_get(api_cli, msg, "multiget", PB_CLI_EXTRA_MULTI, PB_FIELDS_MULTI);
804 case BCMOLT_MSG_TYPE_SET:
805 return playback_api_cli_cmd_get(api_cli, msg, "set", PB_CLI_EXTRA_NONE, PB_FIELDS_SET);
806 case BCMOLT_MSG_TYPE_CLEAR:
807 return playback_api_cli_cmd_get(api_cli, msg, "clear", PB_CLI_EXTRA_NONE, PB_FIELDS_NONE);
808 default:
809 return BCM_ERR_INTERNAL;
810 }
811 break;
812 case BCMOLT_MGT_GROUP_STAT:
813 return playback_api_cli_cmd_get(api_cli, msg, "stat", PB_CLI_EXTRA_STAT, PB_FIELDS_GET);
814 case BCMOLT_MGT_GROUP_STAT_CFG:
815 switch (msg->type)
816 {
817 case BCMOLT_MSG_TYPE_GET:
818 return playback_api_cli_cmd_get(api_cli, msg, "saget", PB_CLI_EXTRA_SUBGROUP, PB_FIELDS_NONE);
819 case BCMOLT_MSG_TYPE_SET:
820 return playback_api_cli_cmd_get(api_cli, msg, "saset", PB_CLI_EXTRA_SUBGROUP, PB_FIELDS_SET);
821 default:
822 return BCM_ERR_INTERNAL;
823 }
824 break;
825 case BCMOLT_MGT_GROUP_AUTO_CFG:
826 switch (msg->type)
827 {
828 case BCMOLT_MSG_TYPE_GET:
829 return playback_api_cli_cmd_get(api_cli, msg, "acget", PB_CLI_EXTRA_NONE, PB_FIELDS_GET);
830 case BCMOLT_MSG_TYPE_SET:
831 return playback_api_cli_cmd_get(api_cli, msg, "acset", PB_CLI_EXTRA_NONE, PB_FIELDS_SET);
832 default:
833 return BCM_ERR_INTERNAL;
834 }
835 break;
836 case BCMOLT_MGT_GROUP_OPER:
837 return playback_api_cli_cmd_get(api_cli, msg, "oper", PB_CLI_EXTRA_SUBGROUP, PB_FIELDS_SET);
838 case BCMOLT_MGT_GROUP_PROXY:
839 return playback_api_cli_cmd_get(api_cli, msg, "send", PB_CLI_EXTRA_SUBGROUP, PB_FIELDS_SET);
840 default:
841 return BCM_ERR_INTERNAL;
842 }
843}
844
845static bcmos_errno playback_convert_api_cli(bcmolt_playback *mpb, FILE *out_file)
846{
847 playback_iterator it;
848 bcmos_errno err;
849 bcmolt_string *str;
850
851 err = bcmolt_string_create(&str, 2048);
852 BCMOS_RETURN_IF_ERROR(err);
853 FOR_EACH_PLAYBACK_MSG(it, mpb->capture_buffer, mpb->buf_size)
854 {
855 if (playback_should_send(mpb->location, (bcmtr_cld_event_type)it.raw.hdr.event))
856 {
857 if (BCM_ERR_OK == it.err)
858 {
859 bcmolt_string_reset(str);
860 err = playback_api_cli_get(str, it.msg);
861 fwrite(bcmolt_string_get(str), sizeof(char), strlen(bcmolt_string_get(str)), out_file);
862 }
863 else
864 {
865 err = it.err;
866 BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Unpacking failed: %s\n", bcmos_strerror(err));
867 }
868 }
869 }
870 bcmolt_string_destroy(str);
871
872 return err;
873}
874
875static bcmos_bool playback_field_contains_var_list(const bcmcli_type_descr *type)
876{
877 if (type == NULL)
878 {
879 return BCMOS_FALSE;
880 }
881
882 if (type->base_type == BCMOLT_BASE_TYPE_ID_ARR_DYN)
883 {
884 return BCMOS_TRUE;
885 }
886 else if (type->base_type == BCMOLT_BASE_TYPE_ID_ARR_FIXED)
887 {
888 return playback_field_contains_var_list(type->x.arr_fixed.elem_type);
889 }
890 else if (type->base_type == BCMOLT_BASE_TYPE_ID_STRUCT)
891 {
892 for (uint16_t i = 0; i < type->x.s.num_fields; ++i)
893 {
894 if (playback_field_contains_var_list(type->x.s.fields[i].type))
895 {
896 return BCMOS_TRUE;
897 }
898 }
899 }
900 else if (type->base_type == BCMOLT_BASE_TYPE_ID_UNION)
901 {
902 for (uint16_t i = 0; i < type->x.u.num_common_fields; ++i)
903 {
904 if (playback_field_contains_var_list(type->x.u.common_fields[i].type))
905 {
906 return BCMOS_TRUE;
907 }
908 }
909 for (uint16_t i = 0; type->x.u.common_fields[type->x.u.classifier_idx].type->x.e[i].name != NULL; ++i)
910 {
911 if (playback_field_contains_var_list(type->x.u.union_fields[i].type))
912 {
913 return BCMOS_TRUE;
914 }
915 }
916 }
917 else
918 {
919 /* not a variable sized list */
920 }
921
922 return BCMOS_FALSE;
923}
924
925static bcmos_bool playback_msg_contains_var_list(const bcmolt_msg* msg)
926{
927 const bcmcli_prop_descr *pd;
928
929 for (uint16_t prop = 0;
930 api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
931 ++prop)
932 {
933 if (playback_field_contains_var_list(pd->type))
934 {
935 return BCMOS_TRUE;
936 }
937 }
938
939 return BCMOS_FALSE;
940}
941
942static bcmos_errno playback_string_write_upper(bcmolt_string *dest, const char* src)
943{
944 int n;
945
946 while (*src != '\0')
947 {
948 n = bcmolt_string_append(dest, "%c", (char)toupper((int)*src));
949 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
950 ++src;
951 }
952
953 return BCM_ERR_OK;
954}
955
956static bcmos_errno playback_c_api_pm_write(
957 bcmolt_string *c_api,
958 const bcmolt_msg* msg,
959 bcmolt_presence_mask pm,
960 const char *extra,
961 const char *field,
962 const char *obj)
963{
964 int n;
965 bcmos_errno err;
966 const bcmcli_prop_descr *pd;
967
968 for (uint16_t prop = 0;
969 api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
970 ++prop)
971 {
972 if (!(pm & (1ULL << prop)))
973 {
974 continue;
975 }
976 n = bcmolt_string_append(c_api, "\tBCMOLT_%s", extra);
977 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
978 err = playback_string_write_upper(c_api, apicli_mgt_group_to_str(msg->group));
979 BCMOS_RETURN_IF_ERROR(err);
980 n = bcmolt_string_append(c_api, "_PROP_GET(%s, %s, %s);\n", field, obj, pd->name);
981 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
982 }
983
984 return BCM_ERR_OK;
985}
986
987static bcmos_errno playback_c_api_append_init(
988 bcmolt_string *c_api,
989 void *data,
990 const bcmcli_type_descr *td,
991 const char* name)
992{
993 bcmos_errno rc;
994 bcmcli_session *str;
995
996 rc = bcmcli_session_open_string(&str, c_api);
997 BCMOS_RETURN_IF_ERROR(rc);
998 rc = apicli_dump_dyn_array(str, td, data, name);
999 bcmcli_session_close(str);
1000 BCMOS_RETURN_IF_ERROR(rc);
1001
1002 return BCM_ERR_OK;
1003}
1004
1005
1006static bcmos_errno playback_c_api_append_prop(
1007 bcmolt_string *c_api,
1008 uint32_t size,
1009 void *data,
1010 const bcmcli_prop_descr *pd)
1011{
1012 bcmos_errno err;
1013 bcmcli_session *str;
1014 void *prop_data = (void *)((long)data + pd->offset);
1015
1016 BCMOS_CHECK_RETURN_ERROR(pd->offset >= size, BCM_ERR_INTERNAL);
1017 err = bcmcli_session_open_string(&str, c_api);
1018 BCMOS_RETURN_IF_ERROR(err);
1019 err = apicli_dump_prop_initializer(str, pd, prop_data);
1020 bcmcli_session_close(str);
1021 BCMOS_RETURN_IF_ERROR(err);
1022
1023 return BCM_ERR_OK;
1024}
1025
1026static bcmos_errno playback_c_api_make_var_lists(
1027 bcmolt_string *c_api,
1028 const bcmcli_type_descr *type,
1029 void *data,
1030 const char *name)
1031{
1032 int n;
1033 bcmos_errno rc;
1034
1035 if (type == NULL)
1036 {
1037 return BCM_ERR_OK;
1038 }
1039
1040 if (type->base_type == BCMOLT_BASE_TYPE_ID_ARR_DYN)
1041 {
1042 n = bcmolt_string_append(c_api, "\t%s %s[] = ", type->x.arr_dyn.elem_type->name, name);
1043 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1044 rc = playback_c_api_append_init(c_api, data, type, name);
1045 BCMOS_RETURN_IF_ERROR(rc);
1046 n = bcmolt_string_append(c_api, ";\n");
1047 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1048 }
1049 else if (type->base_type == BCMOLT_BASE_TYPE_ID_ARR_FIXED)
1050 {
1051 for (uint16_t i = 0; i < type->x.arr_fixed.size; ++i)
1052 {
1053 char index_name[64];
1054
1055 sprintf(index_name, "%s%u", name, i);
1056 rc = playback_c_api_make_var_lists(c_api, type->x.arr_fixed.elem_type, data, index_name);
1057 BCMOS_RETURN_IF_ERROR(rc);
1058 data = (void*)((long)data + type->x.arr_fixed.elem_type->size);
1059 }
1060 }
1061 else if (type->base_type == BCMOLT_BASE_TYPE_ID_STRUCT)
1062 {
1063 for (uint16_t i = 0; i < type->x.s.num_fields; ++i)
1064 {
1065 const bcmcli_field_descr *field = &type->x.s.fields[i];
1066 rc = playback_c_api_make_var_lists(c_api, field->type, (void*)((long)data + field->offset), field->name);
1067 BCMOS_RETURN_IF_ERROR(rc);
1068 }
1069 }
1070 else if (type->base_type == BCMOLT_BASE_TYPE_ID_UNION)
1071 {
1072 for (uint16_t i = 0; i < type->x.u.num_common_fields; ++i)
1073 {
1074 const bcmcli_field_descr *field = &type->x.u.common_fields[i];
1075 rc = playback_c_api_make_var_lists(c_api, field->type, (void*)((long)data + field->offset), field->name);
1076 BCMOS_RETURN_IF_ERROR(rc);
1077 }
1078 for (uint16_t i = 0; type->x.u.common_fields[type->x.u.classifier_idx].type->x.e[i].name != NULL; ++i)
1079 {
1080 const bcmcli_field_descr *field = &type->x.u.union_fields[i];
1081 rc = playback_c_api_make_var_lists(c_api, field->type, (void*)((long)data + field->offset), field->name);
1082 BCMOS_RETURN_IF_ERROR(rc);
1083 }
1084 }
1085 else
1086 {
1087 /* not a variable sized list */
1088 }
1089
1090 return BCM_ERR_OK;
1091}
1092
1093static bcmos_errno playback_c_api_props_write(
1094 bcmolt_string *c_api,
1095 const bcmolt_msg* msg,
1096 const char* object,
1097 uint32_t size,
1098 uint32_t offset)
1099{
1100 int n;
1101 bcmos_errno err;
1102 const char *subgroup;
1103 const char *desc;
1104 const bcmcli_prop_descr *pd;
1105 void *data = (void *)((long)msg + offset);
1106
1107 for (uint16_t prop = 0;
1108 api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
1109 ++prop)
1110 {
1111 if (!(msg->presence_mask & (1ULL << prop)))
1112 {
1113 continue;
1114 }
1115 playback_c_api_make_var_lists(c_api, pd->type, (void*)((long)data + pd->offset), pd->name);
1116 }
1117
1118 for (uint16_t prop = 0;
1119 api_cli_object_property(msg->obj_type, msg->group, msg->subgroup, prop, &pd) == BCM_ERR_OK;
1120 ++prop)
1121 {
1122 if (!(msg->presence_mask & (1ULL << prop)))
1123 {
1124 continue;
1125 }
1126 if ((pd->type->base_type == BCMOLT_BASE_TYPE_ID_STRUCT) ||
1127 (pd->type->base_type == BCMOLT_BASE_TYPE_ID_UNION) ||
1128 (pd->type->base_type == BCMOLT_BASE_TYPE_ID_ARR_DYN) ||
1129 (pd->type->base_type == BCMOLT_BASE_TYPE_ID_ARR_FIXED))
1130 {
1131 n = bcmolt_string_append(c_api, "\t%s "VAL_REF" = ", pd->type->name);
1132 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1133 err = playback_c_api_append_prop(c_api, size, data, pd);
1134 BCMOS_RETURN_IF_ERROR(err);
1135 n = bcmolt_string_append(c_api, ";\n");
1136 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1137 n = bcmolt_string_append(c_api, "\tBCMOLT_");
1138 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1139 err = playback_string_write_upper(c_api, apicli_mgt_group_to_str(msg->group));
1140 BCMOS_RETURN_IF_ERROR(err);
1141 n = bcmolt_string_append(c_api, "_PROP_SET(&msg, %s", object);
1142 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1143 if ((msg->group == BCMOLT_MGT_GROUP_OPER) || (msg->group == BCMOLT_MGT_GROUP_PROXY))
1144 {
1145 err = api_cli_object_subgroup_name(msg->obj_type, msg->group, msg->subgroup, &subgroup, &desc);
1146 BCMOS_RETURN_IF_ERROR(err);
1147 n = bcmolt_string_append(c_api, ", %s", subgroup);
1148 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1149 }
1150 n = bcmolt_string_append(c_api, ", %s, "VAL_REF");\n", pd->name);
1151 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1152 }
1153 else
1154 {
1155 n = bcmolt_string_append(c_api, "\tBCMOLT_");
1156 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1157 err = playback_string_write_upper(c_api, apicli_mgt_group_to_str(msg->group));
1158 BCMOS_RETURN_IF_ERROR(err);
1159 n = bcmolt_string_append(c_api, "_PROP_SET(&msg, %s", object);
1160 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1161 if ((msg->group == BCMOLT_MGT_GROUP_OPER) || (msg->group == BCMOLT_MGT_GROUP_PROXY))
1162 {
1163 err = api_cli_object_subgroup_name(msg->obj_type, msg->group, msg->subgroup, &subgroup, &desc);
1164 BCMOS_RETURN_IF_ERROR(err);
1165 n = bcmolt_string_append(c_api, ", %s", subgroup);
1166 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1167 }
1168 n = bcmolt_string_append(c_api, ", %s, ", pd->name);
1169 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1170 err = playback_c_api_append_prop(c_api, size, data, pd);
1171 BCMOS_RETURN_IF_ERROR(err);
1172 n = bcmolt_string_append(c_api, ");\n");
1173 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1174 }
1175 }
1176
1177 return BCM_ERR_OK;
1178}
1179
1180static bcmos_errno playback_c_api_code_get(
1181 bcmolt_string* c_api,
1182 const bcmolt_msg* msg,
1183 const char *call,
1184 pb_fields field_parms)
1185{
1186 int n;
1187 bcmos_errno err;
1188 const char *object;
1189 const char *group;
1190 const char *subgroup;
1191 const char *desc;
1192 uint32_t key_size;
1193 uint32_t key_offset;
1194 uint32_t data_size;
1195 uint32_t data_offset;
1196 void *data;
1197 const bcmcli_prop_descr *pd;
1198 bcmos_bool var_list = (BCMOLT_MSG_TYPE_GET == msg->type) && playback_msg_contains_var_list(msg);
1199
1200 err = api_cli_object_name(msg->obj_type, &object, &desc);
1201 BCMOS_RETURN_IF_ERROR(err);
1202 err = api_cli_object_subgroup_name(msg->obj_type, msg->group, msg->subgroup, &subgroup, &desc);
1203 BCMOS_RETURN_IF_ERROR(err);
1204
1205 group = apicli_mgt_group_to_str(msg->group);
1206
1207 /* get message info */
1208 err = api_cli_object_struct_size(
1209 msg->obj_type,
1210 msg->group,
1211 msg->subgroup,
1212 &key_size,
1213 &key_offset,
1214 &data_size,
1215 &data_offset);
1216 BCMOS_RETURN_IF_ERROR(err);
1217
1218 /* init variables */
1219 n = bcmolt_string_append(c_api, "\t{\n");
1220 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1221 if ((msg->group == BCMOLT_MGT_GROUP_OPER) || (msg->group == BCMOLT_MGT_GROUP_PROXY))
1222 {
1223 n = bcmolt_string_append(c_api, "\tbcmolt_%s_%s "MSG_REF";\n", object, subgroup);
1224 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1225 }
1226 else
1227 {
1228 n = bcmolt_string_append(c_api, "\tbcmolt_%s_%s "MSG_REF";\n", object, group);
1229 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1230 }
1231 n = bcmolt_string_append(c_api, "\tbcmolt_%s_key "KEY_REF" = { };\n", object);
1232 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1233
1234 if (var_list)
1235 {
1236 n = bcmolt_string_append(c_api, "\tuint8_t* "LIST_MEM_REF";\n");
1237 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1238 }
1239
1240 if (msg->type == BCMOLT_MSG_TYPE_GET_MULTI)
1241 {
1242 n = bcmolt_string_append(c_api, "\tbcmolt_msg_set* "MSG_SET_REF" = NULL;\n");
1243 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1244 n = bcmolt_string_append(c_api, "\tuint32_t "MAX_MSGS_REF";\n");
1245 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1246 n = bcmolt_string_append(c_api, "\tbcmos_bool "INVERT_FILTER_REF";\n\n");
1247 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1248 n = bcmolt_string_append(c_api, "\t"MAX_MSGS_REF" = %d;\n", msg->msg_set->max_instances);
1249 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1250 n = bcmolt_string_append(c_api, "\t"INVERT_FILTER_REF" = %s;\n", BITS_SET(msg->msg_set->filter_flags, BCMOLT_FILTER_FLAGS_INVERT_SELECTION) ? "BCMOS_TRUE" : "BCMOS_FALSE");
1251 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1252 n = bcmolt_string_append(c_api, "\tbcmolt_msg_set_alloc(BCMOLT_OBJ_ID_");
1253 err = playback_string_write_upper(c_api, object);
1254 BCMOS_RETURN_IF_ERROR(err);
1255 n = bcmolt_string_append(c_api, ", BCMOLT_MGT_GROUP_");
1256 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1257 err = playback_string_write_upper(c_api, group);
1258 BCMOS_RETURN_IF_ERROR(err);
1259 n = bcmolt_string_append(c_api, ", "MAX_MSGS_REF", &"MSG_SET_REF");\n");
1260 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1261 }
1262 else if (msg->group == BCMOLT_MGT_GROUP_STAT)
1263 {
1264 n = bcmolt_string_append(c_api, "\tbcmolt_stat_flags "STAT_FLAGS_REF";\n\n");
1265 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1266 n = bcmolt_string_append(c_api, "\t"STAT_FLAGS_REF" = %s;\n", BITS_SET(msg->type, BCMOLT_MSG_TYPE_CLEAR) ? "BCMOLT_STAT_FLAGS_CLEAR_ON_READ" : "BCMOLT_STAT_FLAGS_NONE");
1267 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1268 }
1269 else
1270 {
1271 n = bcmolt_string_append(c_api, "\n");
1272 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1273 }
1274
1275 /* set key */
1276 if (BCMOLT_MGT_GROUP_AUTO_CFG != msg->group)
1277 {
1278 /* write key */
1279 data = (void *)((long)msg + key_offset);
1280 for (uint16_t prop = 0;
1281 api_cli_object_property(msg->obj_type, BCMOLT_MGT_GROUP_KEY, 0, prop, &pd) == BCM_ERR_OK;
1282 ++prop)
1283 {
1284 n = bcmolt_string_append(c_api, "\t"KEY_REF".%s = ", pd->name);
1285 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1286 if ((BCMOLT_BASE_TYPE_ID_MAC == pd->type->base_type) ||
1287 (BCMOLT_BASE_TYPE_ID_IPV4 == pd->type->base_type) ||
1288 (BCMOLT_BASE_TYPE_ID_STRUCT == pd->type->base_type) ||
1289 (BCMOLT_BASE_TYPE_ID_UNION == pd->type->base_type))
1290 {
1291 n = bcmolt_string_append(c_api, "(%s)", pd->type->name);
1292 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1293 }
1294 err = playback_c_api_append_prop(c_api, key_size, data, pd);
1295 BCMOS_RETURN_IF_ERROR(err);
1296 n = bcmolt_string_append(c_api, ";\n");
1297 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1298 }
1299 }
1300
1301 /* set properties */
1302 n = bcmolt_string_append(c_api, "\tBCMOLT_");
1303 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1304 err = playback_string_write_upper(c_api, group);
1305 BCMOS_RETURN_IF_ERROR(err);
1306 n = bcmolt_string_append(c_api, "_INIT(&"MSG_REF", %s", object);
1307 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1308 if ((msg->group == BCMOLT_MGT_GROUP_STAT_CFG) ||
1309 (msg->group == BCMOLT_MGT_GROUP_OPER) ||
1310 (msg->group == BCMOLT_MGT_GROUP_PROXY))
1311 {
1312 n = bcmolt_string_append(c_api, ", %s", subgroup);
1313 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1314 }
1315 n = bcmolt_string_append(c_api, ", "KEY_REF");\n");
1316 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1317
1318 switch (field_parms)
1319 {
1320 case PB_FIELDS_GET:
1321 /* write presence mask */
1322 err = playback_c_api_pm_write(c_api, msg, msg->presence_mask, "", "&"MSG_REF, object);
1323 BCMOS_RETURN_IF_ERROR(err);
1324 if (var_list)
1325 {
1326 n = bcmolt_string_append(c_api, "\t"LIST_MEM_REF" = bcmos_calloc("DYN_LIST_SIZE");\n");
1327 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1328 n = bcmolt_string_append(
1329 c_api,
1330 "\tBCMOLT_CFG_LIST_BUF_SET(&"MSG_REF", %s, "LIST_MEM_REF", "DYN_LIST_SIZE");\n", object);
1331 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1332 }
1333 break;
1334 case PB_FIELDS_MULTI:
1335 /* write filter */
1336 err = playback_c_api_props_write(c_api, msg, object, data_size, data_offset);
1337 BCMOS_RETURN_IF_ERROR(err);
1338 /* write presence mask */
1339 err = playback_c_api_pm_write(c_api, msg, msg->presence_mask, "MSGSET_", MSG_SET_REF, object);
1340 BCMOS_RETURN_IF_ERROR(err);
1341 break;
1342 case PB_FIELDS_SET:
1343 /* write properties */
1344 err = playback_c_api_props_write(c_api, msg, object, data_size, data_offset);
1345 BCMOS_RETURN_IF_ERROR(err);
1346 break;
1347 default:
1348 break;
1349 }
1350
1351 /* call API */
1352 n = bcmolt_string_append(c_api, "\t"RC_REF" = bcmolt_%s_%s("DEVICE_REF", &"MSG_REF".hdr", group, call);
1353 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1354 if (msg->type == BCMOLT_MSG_TYPE_GET_MULTI)
1355 {
1356 n = bcmolt_string_append(
1357 c_api,
1358 ", ("INVERT_FILTER_REF") ? BCMOLT_FILTER_FLAGS_INVERT_SELECTION : BCMOLT_FILTER_FLAGS_NONE, "MSG_SET_REF);
1359 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1360 }
1361 else if (msg->group == BCMOLT_MGT_GROUP_STAT)
1362 {
1363 n = bcmolt_string_append(c_api, ", "STAT_FLAGS_REF);
1364 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1365 }
1366 else
1367 {
1368 /* do nothing */
1369 }
1370 n = bcmolt_string_append(c_api, ");\n");
1371 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1372 n = bcmolt_string_append(c_api, "\tbcmos_printf(\"bcmolt_%s_%s returned %%s (%%d)\\n\", bcmos_strerror("RC_REF"), "RC_REF");\n", group, call);
1373 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1374 n = bcmolt_string_append(c_api, "\t}\n\n");
1375 BCMOS_CHECK_RETURN_ERROR(n <= 0, BCM_ERR_INTERNAL);
1376
1377 return BCM_ERR_OK;
1378}
1379
1380static bcmos_errno playback_c_api_get(bcmolt_string* c_api, const bcmolt_msg* msg)
1381{
1382 switch (msg->group)
1383 {
1384 case BCMOLT_MGT_GROUP_CFG:
1385 switch (msg->type)
1386 {
1387 case BCMOLT_MSG_TYPE_GET:
1388 return playback_c_api_code_get(c_api, msg, "get", PB_FIELDS_GET);
1389 case BCMOLT_MSG_TYPE_GET_MULTI:
1390 return playback_c_api_code_get(c_api, msg, "get_multi", PB_FIELDS_MULTI);
1391 case BCMOLT_MSG_TYPE_SET:
1392 return playback_c_api_code_get(c_api, msg, "set", PB_FIELDS_SET);
1393 case BCMOLT_MSG_TYPE_CLEAR:
1394 return playback_c_api_code_get(c_api, msg, "clear", PB_FIELDS_NONE);
1395 default:
1396 return BCM_ERR_INTERNAL;
1397 }
1398 break;
1399 case BCMOLT_MGT_GROUP_STAT:
1400 return playback_c_api_code_get(c_api, msg, "get", PB_FIELDS_GET);
1401 case BCMOLT_MGT_GROUP_STAT_CFG:
1402 switch (msg->type)
1403 {
1404 case BCMOLT_MSG_TYPE_GET:
1405 return playback_c_api_code_get(c_api, msg, "get", PB_FIELDS_NONE);
1406 case BCMOLT_MSG_TYPE_SET:
1407 return playback_c_api_code_get(c_api, msg, "set", PB_FIELDS_SET);
1408 default:
1409 return BCM_ERR_INTERNAL;
1410 }
1411 break;
1412 case BCMOLT_MGT_GROUP_AUTO_CFG:
1413 switch (msg->type)
1414 {
1415 case BCMOLT_MSG_TYPE_GET:
1416 return playback_c_api_code_get(c_api, msg, "get", PB_FIELDS_GET);
1417 case BCMOLT_MSG_TYPE_SET:
1418 return playback_c_api_code_get(c_api, msg, "set", PB_FIELDS_SET);
1419 default:
1420 return BCM_ERR_INTERNAL;
1421 }
1422 break;
1423 case BCMOLT_MGT_GROUP_OPER:
1424 return playback_c_api_code_get(c_api, msg, "submit", PB_FIELDS_SET);
1425 case BCMOLT_MGT_GROUP_PROXY:
1426 return playback_c_api_code_get(c_api, msg, "send", PB_FIELDS_SET);
1427 default:
1428 return BCM_ERR_INTERNAL;
1429 }
1430}
1431
1432static bcmos_errno playback_convert_c_api(bcmolt_playback *mpb, FILE *out_file)
1433{
1434 playback_iterator it;
1435 bcmos_errno err;
1436 bcmolt_string *str;
1437 uint32_t last_time_us = 0;
1438 bcmos_bool first = BCMOS_TRUE;
1439
1440 err = bcmolt_string_create(&str, 16384);
1441 BCMOS_RETURN_IF_ERROR(err);
1442 fprintf(out_file, "void run_playback(void)\n{\n");
1443 fprintf(out_file, "\tbcmolt_devid "DEVICE_REF" = %d;\n", current_device);
1444 fprintf(out_file, "\tbcmos_errno "RC_REF" = BCM_ERR_OK;\n\n");
1445 FOR_EACH_PLAYBACK_MSG(it, mpb->capture_buffer, mpb->buf_size)
1446 {
1447 if (playback_should_send(mpb->location, (bcmtr_cld_event_type)it.raw.hdr.event))
1448 {
1449 if (BCM_ERR_OK == it.err)
1450 {
1451 if (!first)
1452 {
1453 /* approximate original timing; doesn't account for processing time in this code - this could be
1454 improved */
1455 fprintf(out_file, "\n\tbcmos_usleep(%u);\n\n", it.raw.hdr.timestamp - last_time_us);
1456 }
1457 else
1458 {
1459 first = BCMOS_FALSE;
1460 }
1461 last_time_us = it.raw.hdr.timestamp;
1462 bcmolt_string_reset(str);
1463 err = playback_c_api_get(str, it.msg);
1464 fwrite(bcmolt_string_get(str), sizeof(char), strlen(bcmolt_string_get(str)), out_file);
1465 }
1466 else
1467 {
1468 err = it.err;
1469 BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Unpacking failed: %s\n", bcmos_strerror(err));
1470 }
1471 }
1472 }
1473 fprintf(out_file, "}\n");
1474 bcmolt_string_destroy(str);
1475
1476 return err;
1477}
1478
1479static bcmos_errno playback_convert(bcmolt_playback *mpb, pb_format format, FILE *out_file)
1480{
1481 bcmos_errno err;
1482
1483 switch (format)
1484 {
1485 case PB_FORMAT_API_CLI:
1486 err = playback_convert_api_cli(mpb, out_file);
1487 break;
1488 case PB_FORMAT_C_API:
1489 err = playback_convert_c_api(mpb, out_file);
1490 break;
1491 default:
1492 err = BCM_ERR_PARM;
1493 BCM_LOG(ERROR, pb_ctxt[current_device].log_id, "Unknown format: %d\n", format);
1494 break;
1495 }
1496
1497 return err;
1498}
1499
1500static bcmos_errno playback_cli_conv(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
1501{
1502 const char *infilename = bcmcli_find_named_parm(session, "infile")->value.string;
1503 const char *outfilename = bcmcli_find_named_parm(session, "outfile")->value.string;
1504 pb_format format = (pb_format)bcmcli_find_named_parm(session, "format")->value.enum_val;
1505 bcmos_bool ignore_ver = BCMOS_FALSE;
1506 bcmos_errno err;
1507 bcmolt_playback mpb = {};
1508 FILE *out_file;
1509
1510 bcmcli_cmd_parm *iv_parm = bcmcli_find_named_parm(session, "ignore_version");
1511 if (iv_parm != NULL)
1512 {
1513 ignore_ver = iv_parm->value.enum_val == (long)BCMOS_TRUE;
1514 }
1515
1516 err = playback_file_open(infilename, &mpb);
1517
1518 if (BCM_ERR_OK == err)
1519 {
1520 if (playback_version_match(&mpb) || ignore_ver)
1521 {
1522 out_file = fopen(outfilename, "wb");
1523 playback_convert(&mpb, format, out_file);
1524 fclose(out_file);
1525 }
1526 else
1527 {
1528 bcmcli_print(session, "Possible version mismatch; use ignore_version=yes to force conversion\n");
1529 err = BCM_ERR_IMAGE_TYPE;
1530 }
1531 bcmos_free(mpb.capture_buffer);
1532 }
1533
1534 return err;
1535}
1536
1537void bcmolt_user_appl_playback_cli_init(bcmcli_entry *top_dir)
1538{
1539#ifdef ENABLE_CLI
1540 bcmcli_entry *plb_dir = bcmcli_dir_add(top_dir, "playback", "playback", BCMCLI_ACCESS_ADMIN, NULL);
1541 BUG_ON(NULL == plb_dir);
1542
1543 static bcmcli_enum_val format_enum_table[PB_FORMAT__COUNT+1] =
1544 {
1545 {.name = "api_cli", .val = (long)PB_FORMAT_API_CLI},
1546 {.name = "c_api", .val = (long)PB_FORMAT_C_API},
1547 BCMCLI_ENUM_LAST
1548 };
1549
1550 BCMCLI_MAKE_CMD_NOPARM(plb_dir, "dump", "dump capture", playback_cli_dump);
1551 BCMCLI_MAKE_CMD(plb_dir, "save", "save capture", playback_cli_save,
1552 BCMCLI_MAKE_PARM("file", "filename", BCMCLI_PARM_STRING, BCMCLI_PARM_FLAG_NONE));
1553 BCMCLI_MAKE_CMD(plb_dir, "replay", "replay capture", playback_cli_replay,
1554 BCMCLI_MAKE_PARM("file", "filename", BCMCLI_PARM_STRING, BCMCLI_PARM_FLAG_NONE),
1555 BCMCLI_MAKE_PARM_ENUM("ignore_version", "Ignore version mismatch", bcmcli_enum_bool_table, BCMCLI_PARM_FLAG_OPTIONAL));
1556 BCMCLI_MAKE_CMD(plb_dir, "conv", "Convert capture", playback_cli_conv,
1557 BCMCLI_MAKE_PARM("infile", "Input filename", BCMCLI_PARM_STRING, BCMCLI_PARM_FLAG_NONE),
1558 BCMCLI_MAKE_PARM("outfile", "Output filename", BCMCLI_PARM_STRING, BCMCLI_PARM_FLAG_NONE),
1559 BCMCLI_MAKE_PARM_ENUM("format", "Output format", format_enum_table, BCMCLI_PARM_FLAG_NONE),
1560 BCMCLI_MAKE_PARM_ENUM("ignore_version", "Ignore version mismatch", bcmcli_enum_bool_table, BCMCLI_PARM_FLAG_OPTIONAL));
1561#endif
1562}
1563
1564void bcmolt_user_appl_playback_init(void)
1565{
1566 for (uint32_t i = 0; i < BCMTR_MAX_OLTS; i++)
1567 {
1568 char log_name[MAX_DEV_LOG_ID_NAME];
1569 snprintf(log_name, sizeof(log_name)-1, "user_appl_playback_%u", i);
1570 pb_ctxt[i].log_id = bcm_dev_log_id_register(log_name, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
1571 }
1572}
1573