| /* |
| <: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 <bcmolt_host_api.h> |
| #include "bcmolt_user_appl_gpon_utils.h" |
| #include <bcmolt_dev_selector.h> |
| |
| static bcmcli_entry *gpon_utils_cli_dir; |
| static bcmcli_entry *gpon_utils_cli_top_dir; |
| static bcmos_bool gpon_utils_is_registered; |
| |
| static bcmos_errno bcmolt_user_appl_gpon_utils_create(bcmcli_entry *top_dir); |
| |
| #define MAX_GEM_PORTS_FOR_SEND 64 |
| #define MAX_ONUS_FOR_SEND 64 |
| #define MAX_PACKET_SIZE 2048 |
| |
| typedef enum |
| { |
| GENERATED_PACKET_PATTERN_BYTE_CYCLE, |
| GENERATED_PACKET_PATTERN_WORD_CYCLE, |
| GENERATED_PACKET_PATTERN_CONST |
| } generated_packet_pattern; |
| |
| typedef enum |
| { |
| PON_MODE_GPON, |
| PON_MODE_XGPON, |
| PON_MODE_INVALID |
| } pon_mode; |
| |
| static uint8_t saved_packet[MAX_PACKET_SIZE]; |
| static bcmolt_packet_type saved_packet_type; |
| static bcmos_bool saved_packet_calc_crc; |
| static uint16_t saved_packet_len = 0; |
| |
| static void gpon_utils_cli_dir_cli_destroy(void) |
| { |
| if (gpon_utils_cli_dir) |
| { |
| bcmcli_token_destroy(gpon_utils_cli_dir); |
| gpon_utils_cli_dir = NULL; |
| } |
| } |
| |
| /* Current device change indication */ |
| static void bcmolt_user_appl_gpon_utils_device_change_ind(bcmcli_session *session, bcmolt_devid dev) |
| { |
| bcmolt_system_mode system_mode; |
| bcmos_errno err = bcmolt_system_mode_get(dev, &system_mode); |
| |
| if (err != BCM_ERR_OK) |
| { |
| bcmcli_session_print(session, "Error device Id\n"); |
| return; |
| } |
| |
| if (system_mode == BCMOLT_SYSTEM_MODE_GPON__16_X || |
| system_mode == BCMOLT_SYSTEM_MODE_GPON__8_X || |
| system_mode == BCMOLT_SYSTEM_MODE_GPON__4_X || |
| system_mode == BCMOLT_SYSTEM_MODE_XGPON_1__8_X || |
| system_mode == BCMOLT_SYSTEM_MODE_XGPON_1__4_X || |
| system_mode == BCMOLT_SYSTEM_MODE_XGS__2_X_10_G || |
| system_mode == BCMOLT_SYSTEM_MODE_NGPON2__2_X_10_G) |
| { |
| bcmcli_session_print(session, "Building gpon_utils CLI for device %d\n", dev); |
| |
| err = bcmolt_user_appl_gpon_utils_create(gpon_utils_cli_top_dir); |
| if (err) |
| { |
| bcmcli_session_print(session, "Error building gpon_utils CLI\n"); |
| } |
| } |
| else |
| { |
| gpon_utils_cli_dir_cli_destroy(); |
| } |
| } |
| |
| static inline pon_mode pon_mode_get(bcmolt_pon_ni pon_id) |
| { |
| bcmolt_system_mode system_mode; |
| bcmos_errno err = bcmolt_system_mode_get(current_device, &system_mode); |
| if (err != BCM_ERR_OK) |
| { |
| return PON_MODE_INVALID; |
| } |
| |
| if (system_mode == BCMOLT_SYSTEM_MODE_GPON_8_XGPON_4_X_COEXISTENCE) |
| { |
| /* special handling for the 8x GPON / 4x XGPON co-existence mode */ |
| return pon_id < 8 ? PON_MODE_XGPON : PON_MODE_GPON; |
| } |
| else if (bcmolt_obj_tag_valid_for_system_mode(system_mode, BCMOLT_OBJ_TAG_GPON)) |
| { |
| return PON_MODE_GPON; |
| } |
| else if (bcmolt_obj_tag_valid_for_system_mode(system_mode, BCMOLT_OBJ_TAG_XGPON)) |
| { |
| return PON_MODE_XGPON; |
| } |
| else |
| { |
| return PON_MODE_INVALID; |
| } |
| } |
| |
| static bcmos_errno build_packet(bcmcli_session *session, bcmolt_packet_type type) |
| { |
| uint16_t i; |
| bcmos_bool calc_crc = (bcmos_bool)bcmcli_find_named_parm(session, "calc_crc")->value.unumber; |
| uint16_t packet_size = (uint16_t)bcmcli_find_named_parm(session, "packet_size")->value.unumber; |
| generated_packet_pattern pattern = |
| (generated_packet_pattern)bcmcli_find_named_parm(session, "pattern")->value.unumber; |
| uint8_t const_value = (uint8_t)bcmcli_find_named_parm(session, "const_value")->value.unumber; |
| uint16_t data_offset; |
| |
| /* save packet type / size / CRC flag */ |
| saved_packet_type = type; |
| saved_packet_len = packet_size; |
| saved_packet_calc_crc = calc_crc; |
| |
| if (type == BCMOLT_PACKET_TYPE_CPU) |
| { |
| bcmos_mac_address eth_da = bcmcli_find_named_parm(session, "eth_da")->value.mac; |
| bcmos_mac_address eth_sa = bcmcli_find_named_parm(session, "eth_sa")->value.mac; |
| |
| /* copy destination MAC */ |
| memcpy(saved_packet, ð_da, 6); |
| |
| /* copy source MAC */ |
| memcpy(&saved_packet[6], ð_sa, 6); |
| |
| /* write EtherType of 0000 */ |
| memset(&saved_packet[12], 0, 2); |
| |
| /* data starts after EtherType */ |
| data_offset = 14; |
| } |
| else |
| { |
| /* fill the entire packet */ |
| data_offset = 0; |
| } |
| |
| /* fill the rest of the buffer using the specified data pattern */ |
| switch (pattern) |
| { |
| case GENERATED_PACKET_PATTERN_BYTE_CYCLE: |
| const_value = 0; |
| for (i = data_offset; i < packet_size; i++) |
| { |
| saved_packet[i] = const_value++; |
| } |
| break; |
| case GENERATED_PACKET_PATTERN_WORD_CYCLE: |
| /* first 4 bytes = 00000000, next 4 = 11111111, next 4 = 22222222, etc */ |
| const_value = 0; |
| for (i = data_offset; i < packet_size; i += 4) |
| { |
| uint16_t j; |
| for (j = i; j < i + 4 && j < packet_size; j++) |
| { |
| saved_packet[j] = const_value; |
| } |
| const_value = (const_value == 0xFF) ? 0 : const_value + 0x11; |
| } |
| break; |
| case GENERATED_PACKET_PATTERN_CONST: |
| for (i = data_offset; i < packet_size; i++) |
| { |
| saved_packet[i] = const_value; |
| } |
| break; |
| default: |
| bcmcli_session_print(session, "[Error] Invalid pattern: %u\n", pattern); |
| return BCM_ERR_INTERNAL; |
| } |
| |
| return BCM_ERR_OK; |
| } |
| |
| static bcmos_errno build_cpu_packet_cb(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms) |
| { |
| bcmos_errno err = build_packet(session, BCMOLT_PACKET_TYPE_CPU); |
| if (err == BCM_ERR_OK) |
| { |
| bcmcli_session_print(session, "CPU packet buffer saved successfully\n"); |
| } |
| else |
| { |
| bcmcli_session_print(session, "[Error] saving CPU packet buffer: %s\n", bcmos_strerror(err)); |
| } |
| return err; |
| } |
| |
| static bcmos_errno build_omci_packet_cb(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms) |
| { |
| bcmos_errno err = build_packet(session, BCMOLT_PACKET_TYPE_OMCI); |
| if (err == BCM_ERR_OK) |
| { |
| bcmcli_session_print(session, "OMCI packet buffer saved successfully\n"); |
| } |
| else |
| { |
| bcmcli_session_print(session, "[Error] saving OMCI packet buffer: %s\n", bcmos_strerror(err)); |
| } |
| return err; |
| } |
| |
| static bcmos_errno send_packet_to_gpon_gem_list(bcmcli_session *session, uint16_t gem_count, bcmolt_gpon_gem_id *gems) |
| { |
| uint16_t count = 1; |
| uint16_t i; |
| uint16_t gem_idx; |
| bcmos_errno err; |
| bcmcli_cmd_parm *parm; |
| bcmolt_devid device = (bcmolt_devid)bcmcli_find_named_parm(session, "device")->value.unumber; |
| bcmolt_pon_ni pon_ni = (bcmolt_pon_ni)bcmcli_find_named_parm(session, "pon_ni")->value.unumber; |
| bcmolt_gpon_ni_key pon_ni_key = { .pon_ni = pon_ni }; |
| bcmolt_gpon_gem_id_list_u8_max_16 gem_port_list; |
| bcmolt_gpon_ni_cpu_packets proxy; |
| bcmolt_u8_list_u32_max_2048 buffer = { .len = saved_packet_len, .val = saved_packet }; |
| |
| if (saved_packet_len == 0) |
| { |
| bcmcli_session_print(session, "[Error] you must build/save a packet before you can send it\n"); |
| return BCM_ERR_PARM; |
| } |
| |
| parm = bcmcli_find_named_parm(session, "count"); |
| if (parm != NULL) |
| { |
| count = (uint16_t)parm->value.unumber; |
| } |
| |
| bcmcli_session_print( |
| session, |
| "Sending %u proxy packet%s to %u GEM port%s...\n", |
| count, |
| count == 1 ? "" : "s", |
| gem_count, |
| gem_count == 1 ? "" : "s"); |
| |
| /* build the proxy API message, except the GEM port list */ |
| BCMOLT_PROXY_INIT(&proxy, gpon_ni, cpu_packets, pon_ni_key); |
| BCMOLT_PROXY_PROP_SET(&proxy, gpon_ni, cpu_packets, packet_type, saved_packet_type); |
| BCMOLT_PROXY_PROP_SET(&proxy, gpon_ni, cpu_packets, calc_crc, saved_packet_calc_crc); |
| BCMOLT_PROXY_PROP_SET(&proxy, gpon_ni, cpu_packets, buffer, buffer); |
| |
| /* call the proxy API <count> times */ |
| for (i = 0; i < count; i++) |
| { |
| /* we may need to split this up into multiple API calls (only 16 GEM ports are allowed per proxy API) */ |
| for (gem_idx = 0; gem_idx < gem_count; gem_idx += 16) |
| { |
| gem_port_list.len = MIN(16, gem_count - gem_idx); |
| gem_port_list.val = &gems[gem_idx]; |
| BCMOLT_PROXY_PROP_SET(&proxy, gpon_ni, cpu_packets, gem_port_list, gem_port_list); |
| |
| err = bcmolt_proxy_send(device, &proxy.hdr); |
| if (err != BCM_ERR_OK) |
| { |
| bcmcli_session_print( |
| session, |
| "[Error] proxy send: packet index %u GEM index %u: %s\n", |
| i, |
| gem_idx, |
| bcmos_strerror(err)); |
| return err; |
| } |
| } |
| } |
| |
| bcmcli_session_print(session, "%u proxy packet%s sent successfully!\n", count, count == 1 ? "" : "s"); |
| return BCM_ERR_OK; |
| } |
| |
| static bcmos_errno send_packet_to_xgpon_gem_list(bcmcli_session *session, uint16_t gem_count, bcmolt_xgpon_gem_id *gems) |
| { |
| uint16_t count = 1; |
| uint16_t i; |
| uint16_t gem_idx; |
| bcmos_errno err; |
| bcmcli_cmd_parm *parm; |
| bcmolt_devid device = (bcmolt_devid)bcmcli_find_named_parm(session, "device")->value.unumber; |
| bcmolt_pon_ni pon_ni = (bcmolt_pon_ni)bcmcli_find_named_parm(session, "pon_ni")->value.unumber; |
| bcmolt_xgpon_ni_key pon_ni_key = { .pon_ni = pon_ni }; |
| bcmolt_xgpon_gem_id_list_u8_max_16 gem_port_list; |
| bcmolt_xgpon_ni_cpu_packets proxy; |
| bcmolt_u8_list_u32_max_2048 buffer = { .len = saved_packet_len, .val = saved_packet }; |
| |
| if (saved_packet_len == 0) |
| { |
| bcmcli_session_print(session, "[Error] you must build/save a packet before you can send it\n"); |
| return BCM_ERR_PARM; |
| } |
| |
| parm = bcmcli_find_named_parm(session, "count"); |
| if (parm != NULL) |
| { |
| count = (uint16_t)parm->value.unumber; |
| } |
| |
| bcmcli_session_print( |
| session, |
| "Sending %u proxy packet%s to %u GEM port%s...\n", |
| count, |
| count == 1 ? "" : "s", |
| gem_count, |
| gem_count == 1 ? "" : "s"); |
| |
| /* build the proxy API message, except the GEM port list */ |
| BCMOLT_PROXY_INIT(&proxy, xgpon_ni, cpu_packets, pon_ni_key); |
| BCMOLT_PROXY_PROP_SET(&proxy, xgpon_ni, cpu_packets, packet_type, saved_packet_type); |
| BCMOLT_PROXY_PROP_SET(&proxy, xgpon_ni, cpu_packets, calc_crc, saved_packet_calc_crc); |
| BCMOLT_PROXY_PROP_SET(&proxy, xgpon_ni, cpu_packets, buffer, buffer); |
| |
| /* call the proxy API <count> times */ |
| for (i = 0; i < count; i++) |
| { |
| /* we may need to split this up into multiple API calls (only 16 GEM ports are allowed per proxy API) */ |
| for (gem_idx = 0; gem_idx < gem_count; gem_idx += 16) |
| { |
| gem_port_list.len = MIN(16, gem_count - gem_idx); |
| gem_port_list.val = &gems[gem_idx]; |
| BCMOLT_PROXY_PROP_SET(&proxy, xgpon_ni, cpu_packets, gem_port_list, gem_port_list); |
| |
| err = bcmolt_proxy_send(device, &proxy.hdr); |
| if (err != BCM_ERR_OK) |
| { |
| bcmcli_session_print( |
| session, |
| "[Error] proxy send: packet index %u GEM index %u: %s\n", |
| i, |
| gem_idx, |
| bcmos_strerror(err)); |
| return err; |
| } |
| } |
| } |
| |
| bcmcli_session_print(session, "%u proxy packet%s sent successfully!\n", count, count == 1 ? "" : "s"); |
| return BCM_ERR_OK; |
| } |
| |
| static bcmos_errno send_to_gem_cb(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms) |
| { |
| bcmcli_cmd_parm *gem_parm = bcmcli_find_named_parm(session, "gem"); |
| bcmolt_pon_ni pon_id = (bcmolt_pon_ni)bcmcli_find_named_parm(session, "pon_ni")->value.unumber; |
| uint16_t i; |
| pon_mode mode = pon_mode_get(pon_id); |
| |
| if (mode == PON_MODE_GPON) |
| { |
| static bcmolt_gpon_gem_id gem_id_buf[MAX_GEM_PORTS_FOR_SEND]; |
| for (i = 0; i < gem_parm->array_size; i++) |
| { |
| gem_id_buf[i] = (bcmolt_gpon_gem_id)gem_parm->values[i].unumber; |
| } |
| return send_packet_to_gpon_gem_list(session, (uint16_t)gem_parm->array_size, gem_id_buf); |
| } |
| else if (mode == PON_MODE_XGPON) |
| { |
| static bcmolt_xgpon_gem_id gem_id_buf[MAX_GEM_PORTS_FOR_SEND]; |
| for (i = 0; i < gem_parm->array_size; i++) |
| { |
| gem_id_buf[i] = (bcmolt_xgpon_gem_id)gem_parm->values[i].unumber; |
| } |
| return send_packet_to_xgpon_gem_list(session, (uint16_t)gem_parm->array_size, gem_id_buf); |
| } |
| else |
| { |
| bcmcli_session_print(session, "[Error] Invalid system mode\n"); |
| return BCM_ERR_INTERNAL; |
| } |
| } |
| |
| static bcmos_errno send_packet_to_gpon_onu_list(bcmcli_session *session, uint16_t onu_count, bcmolt_gpon_onu_id *onus) |
| { |
| uint16_t count = 1; |
| uint16_t i; |
| uint16_t onu_idx; |
| bcmos_errno err; |
| bcmcli_cmd_parm *parm; |
| bcmolt_devid device = (bcmolt_devid)bcmcli_find_named_parm(session, "device")->value.unumber; |
| bcmolt_pon_ni pon_ni = (bcmolt_pon_ni)bcmcli_find_named_parm(session, "pon_ni")->value.unumber; |
| |
| if (saved_packet_len == 0) |
| { |
| bcmcli_session_print(session, "[Error] you must build/save a packet before you can send it\n"); |
| return BCM_ERR_PARM; |
| } |
| |
| parm = bcmcli_find_named_parm(session, "count"); |
| if (parm != NULL) |
| { |
| count = (uint16_t)parm->value.unumber; |
| } |
| |
| bcmcli_session_print( |
| session, |
| "Sending %u proxy packet%s to %u ONU%s...\n", |
| count, |
| count == 1 ? "" : "s", |
| onu_count, |
| onu_count == 1 ? "" : "s"); |
| |
| /* call the proxy API (potentially several times) for each ONU */ |
| for (onu_idx = 0; onu_idx < onu_count; onu_idx++) |
| { |
| bcmolt_gpon_onu_key onu_key = { .pon_ni = pon_ni, .onu_id = onus[onu_idx] }; |
| bcmolt_u8_list_u32_max_2048 buffer = { .val = saved_packet }; |
| bcmolt_gpon_onu_cpu_packets proxy; |
| uint16_t packets_per_proxy; |
| |
| /* build the proxy API message, except the buffer/number of packets */ |
| BCMOLT_PROXY_INIT(&proxy, gpon_onu, cpu_packets, onu_key); |
| BCMOLT_PROXY_PROP_SET(&proxy, gpon_onu, cpu_packets, packet_type, saved_packet_type); |
| BCMOLT_PROXY_PROP_SET(&proxy, gpon_onu, cpu_packets, calc_crc, saved_packet_calc_crc); |
| BCMOLT_PROXY_PROP_SET(&proxy, gpon_onu, cpu_packets, packet_size, saved_packet_len); |
| |
| /* calculate the number of packets we can fit per invocation of the proxy API */ |
| packets_per_proxy = MIN(count, 2048 / saved_packet_len); |
| BCMOLT_PROXY_PROP_SET(&proxy, gpon_onu, cpu_packets, number_of_packets, packets_per_proxy); |
| |
| /* prepare the buffer data with several copies of the same packet in a row */ |
| for (i = 1; i < packets_per_proxy; i++) |
| { |
| memcpy(&saved_packet[i * saved_packet_len], saved_packet, saved_packet_len); |
| } |
| |
| /* call the proxy API enough times to send the requested number of packets */ |
| for (i = 0; i < count; i += packets_per_proxy) |
| { |
| uint16_t number_of_packets = MIN(packets_per_proxy, count - i); |
| BCMOLT_PROXY_PROP_SET(&proxy, gpon_onu, cpu_packets, number_of_packets, number_of_packets); |
| |
| buffer.len = number_of_packets * saved_packet_len; |
| BCMOLT_PROXY_PROP_SET(&proxy, gpon_onu, cpu_packets, buffer, buffer); |
| |
| err = bcmolt_proxy_send(device, &proxy.hdr); |
| if (err != BCM_ERR_OK) |
| { |
| bcmcli_session_print( |
| session, |
| "[Error] proxy send: ONU %u packet index %u: %s\n", |
| onus[onu_idx], |
| i, |
| bcmos_strerror(err)); |
| return err; |
| } |
| } |
| } |
| |
| bcmcli_session_print(session, "%u proxy packet%s sent successfully!\n", count, count == 1 ? "" : "s"); |
| return BCM_ERR_OK; |
| } |
| |
| static bcmos_errno send_packet_to_xgpon_onu_list(bcmcli_session *session, uint16_t onu_count, bcmolt_xgpon_onu_id *onus) |
| { |
| uint16_t count = 1; |
| uint16_t i; |
| uint16_t onu_idx; |
| bcmos_errno err; |
| bcmcli_cmd_parm *parm; |
| bcmolt_devid device = (bcmolt_devid)bcmcli_find_named_parm(session, "device")->value.unumber; |
| bcmolt_pon_ni pon_ni = (bcmolt_pon_ni)bcmcli_find_named_parm(session, "pon_ni")->value.unumber; |
| |
| if (saved_packet_len == 0) |
| { |
| bcmcli_session_print(session, "[Error] you must build/save a packet before you can send it\n"); |
| return BCM_ERR_PARM; |
| } |
| |
| parm = bcmcli_find_named_parm(session, "count"); |
| if (parm != NULL) |
| { |
| count = (uint16_t)parm->value.unumber; |
| } |
| |
| bcmcli_session_print( |
| session, |
| "Sending %u proxy packet%s to %u ONU%s...\n", |
| count, |
| count == 1 ? "" : "s", |
| onu_count, |
| onu_count == 1 ? "" : "s"); |
| |
| /* call the proxy API (potentially several times) for each ONU */ |
| for (onu_idx = 0; onu_idx < onu_count; onu_idx++) |
| { |
| bcmolt_xgpon_onu_key onu_key = { .pon_ni = pon_ni, .onu_id = onus[onu_idx] }; |
| bcmolt_u8_list_u32_max_2048 buffer = { .val = saved_packet }; |
| bcmolt_xgpon_onu_cpu_packets proxy; |
| uint16_t packets_per_proxy; |
| |
| /* build the proxy API message, except the buffer/number of packets */ |
| BCMOLT_PROXY_INIT(&proxy, xgpon_onu, cpu_packets, onu_key); |
| BCMOLT_PROXY_PROP_SET(&proxy, xgpon_onu, cpu_packets, packet_type, saved_packet_type); |
| BCMOLT_PROXY_PROP_SET(&proxy, xgpon_onu, cpu_packets, calc_crc, saved_packet_calc_crc); |
| BCMOLT_PROXY_PROP_SET(&proxy, xgpon_onu, cpu_packets, packet_size, saved_packet_len); |
| |
| /* calculate the number of packets we can fit per invocation of the proxy API */ |
| packets_per_proxy = MIN(count, 2048 / saved_packet_len); |
| BCMOLT_PROXY_PROP_SET(&proxy, xgpon_onu, cpu_packets, number_of_packets, packets_per_proxy); |
| |
| /* prepare the buffer data with several copies of the same packet in a row */ |
| for (i = 1; i < packets_per_proxy; i++) |
| { |
| memcpy(&saved_packet[i * saved_packet_len], saved_packet, saved_packet_len); |
| } |
| |
| /* call the proxy API enough times to send the requested number of packets */ |
| for (i = 0; i < count; i += packets_per_proxy) |
| { |
| uint16_t number_of_packets = MIN(packets_per_proxy, count - i); |
| BCMOLT_PROXY_PROP_SET(&proxy, xgpon_onu, cpu_packets, number_of_packets, number_of_packets); |
| |
| buffer.len = number_of_packets * saved_packet_len; |
| BCMOLT_PROXY_PROP_SET(&proxy, xgpon_onu, cpu_packets, buffer, buffer); |
| |
| err = bcmolt_proxy_send(device, &proxy.hdr); |
| if (err != BCM_ERR_OK) |
| { |
| bcmcli_session_print( |
| session, |
| "[Error] proxy send: ONU %u packet index %u: %s\n", |
| onus[onu_idx], |
| i, |
| bcmos_strerror(err)); |
| return err; |
| } |
| } |
| } |
| |
| bcmcli_session_print(session, "%u proxy packet%s sent successfully!\n", count, count == 1 ? "" : "s"); |
| return BCM_ERR_OK; |
| } |
| |
| static bcmos_errno send_to_onu_cb(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms) |
| { |
| bcmcli_cmd_parm *onu_parm = bcmcli_find_named_parm(session, "onu"); |
| bcmolt_pon_ni pon_id = (bcmolt_pon_ni)bcmcli_find_named_parm(session, "pon_ni")->value.unumber; |
| uint16_t i; |
| pon_mode mode = pon_mode_get(pon_id); |
| |
| if (mode == PON_MODE_GPON) |
| { |
| static bcmolt_gpon_onu_id onu_id_buf[MAX_ONUS_FOR_SEND]; |
| for (i = 0; i < onu_parm->array_size; i++) |
| { |
| onu_id_buf[i] = (bcmolt_gpon_onu_id)onu_parm->values[i].unumber; |
| } |
| return send_packet_to_gpon_onu_list(session, (uint16_t)onu_parm->array_size, onu_id_buf); |
| } |
| else if (mode == PON_MODE_XGPON) |
| { |
| static bcmolt_xgpon_onu_id onu_id_buf[MAX_ONUS_FOR_SEND]; |
| for (i = 0; i < onu_parm->array_size; i++) |
| { |
| onu_id_buf[i] = (bcmolt_xgpon_onu_id)onu_parm->values[i].unumber; |
| } |
| return send_packet_to_xgpon_onu_list(session, (uint16_t)onu_parm->array_size, onu_id_buf); |
| } |
| else |
| { |
| bcmcli_session_print(session, "[Error] Invalid system mode\n"); |
| return BCM_ERR_STATE; |
| } |
| } |
| |
| static void dump_saved_mac(bcmcli_session *session, uint16_t offset) |
| { |
| uint16_t i; |
| for (i = 0; i < 6; i++) |
| { |
| if (i != 0) |
| { |
| bcmcli_session_print(session, ":"); |
| } |
| bcmcli_session_print(session, "%02X", saved_packet[offset + i]); |
| } |
| } |
| |
| static bcmos_errno dump_packet_cb(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms) |
| { |
| uint16_t i; |
| uint16_t data_offset; |
| |
| if (saved_packet_len == 0) |
| { |
| bcmcli_session_print(session, "No packet has been built yet\n"); |
| return BCM_ERR_OK; |
| } |
| |
| bcmcli_session_print(session, "Saved packet parameters:\n"); |
| bcmcli_session_print(session, " Type: %s\n", saved_packet_type == BCMOLT_PACKET_TYPE_CPU ? "CPU" : "OMCI"); |
| bcmcli_session_print(session, " Length: %u\n", saved_packet_len); |
| bcmcli_session_print(session, " Auto-calculate CRC: %s\n", saved_packet_calc_crc ? "yes" : "no"); |
| |
| if (saved_packet_type == BCMOLT_PACKET_TYPE_CPU) |
| { |
| bcmcli_session_print(session, " Ethernet DA: "); |
| dump_saved_mac(session, 0); |
| bcmcli_session_print(session, "\n"); |
| |
| bcmcli_session_print(session, " Ethernet SA: "); |
| dump_saved_mac(session, 6); |
| bcmcli_session_print(session, "\n"); |
| |
| bcmcli_session_print(session, " EtherType: 0x%02X%02X\n", saved_packet[12], saved_packet[13]); |
| data_offset = 14; |
| } |
| else |
| { |
| data_offset = 0; |
| } |
| |
| bcmcli_session_print(session, "Data bytes (starting at offset %u):", data_offset); |
| for (i = data_offset; i < saved_packet_len; i++) |
| { |
| if ((i - data_offset) % 16 == 0) |
| { |
| bcmcli_session_print(session, "\n "); |
| } |
| else |
| { |
| bcmcli_session_print(session, " "); |
| } |
| bcmcli_session_print(session, "%02X", saved_packet[i]); |
| } |
| bcmcli_session_print(session, "\n"); |
| |
| return BCM_ERR_OK; |
| } |
| |
| bcmos_errno bcmolt_user_appl_gpon_utils_init(bcmcli_entry *top_dir) |
| { |
| bcmos_errno err = BCM_ERR_OK; |
| |
| if (!gpon_utils_is_registered) |
| { |
| gpon_utils_is_registered = BCMOS_TRUE; |
| |
| /* Subscribe for device change indication */ |
| err = bcmolt_dev_sel_ind_register(bcmolt_user_appl_gpon_utils_device_change_ind); |
| } |
| return err ? err : bcmolt_user_appl_gpon_utils_create(top_dir); |
| } |
| |
| static bcmos_errno bcmolt_user_appl_gpon_utils_create(bcmcli_entry *top_dir) |
| { |
| static bcmcli_enum_val generated_packet_pattern_table[] = |
| { |
| { .name = "byte_cycle", .val = GENERATED_PACKET_PATTERN_BYTE_CYCLE }, |
| { .name = "word_cycle", .val = GENERATED_PACKET_PATTERN_WORD_CYCLE }, |
| { .name = "const", .val = GENERATED_PACKET_PATTERN_CONST }, |
| BCMCLI_ENUM_LAST |
| }; |
| |
| static bcmcli_parm_value gem_port_ids[MAX_GEM_PORTS_FOR_SEND]; |
| static bcmcli_parm_value onu_ids[MAX_ONUS_FOR_SEND]; |
| |
| bcmcli_entry *dir; |
| |
| if (bcmcli_dir_find(top_dir, "gpon")) |
| { |
| return BCM_ERR_OK; |
| } |
| |
| gpon_utils_cli_dir_cli_destroy(); |
| |
| dir = bcmcli_dir_add(top_dir, "gpon", "Common GPON/XGPON functions", BCMCLI_ACCESS_ADMIN, NULL); |
| BCMOS_CHECK_RETURN_ERROR(!dir, BCM_ERR_NOMEM); |
| |
| BCMCLI_MAKE_CMD( |
| dir, |
| "build_cpu_packet", |
| "Build and save CPU packet", |
| build_cpu_packet_cb, |
| BCMCLI_MAKE_PARM_ENUM("calc_crc", "Auto-calculate CRC", bcmcli_enum_bool_table, BCMCLI_PARM_FLAG_NONE), |
| BCMCLI_MAKE_PARM_RANGE( |
| "packet_size", "Full packet size", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_NONE, 0, MAX_PACKET_SIZE), |
| BCMCLI_MAKE_PARM_ENUM("pattern", "Background pattern", generated_packet_pattern_table, BCMCLI_PARM_FLAG_NONE), |
| BCMCLI_MAKE_PARM_RANGE("const_value", "Const value", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_NONE, 0, 0xFF), |
| BCMCLI_MAKE_PARM("eth_da", "Ethernet destination address", BCMCLI_PARM_MAC, BCMCLI_PARM_FLAG_NONE), |
| BCMCLI_MAKE_PARM("eth_sa", "Ethernet source address", BCMCLI_PARM_MAC, BCMCLI_PARM_FLAG_NONE)); |
| |
| BCMCLI_MAKE_CMD( |
| dir, |
| "build_omci_packet", |
| "Build and save OMCI packet", |
| build_omci_packet_cb, |
| BCMCLI_MAKE_PARM_ENUM("calc_crc", "Auto-calculate CRC", bcmcli_enum_bool_table, BCMCLI_PARM_FLAG_NONE), |
| BCMCLI_MAKE_PARM_RANGE( |
| "packet_size", "Full packet size", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_NONE, 0, MAX_PACKET_SIZE), |
| BCMCLI_MAKE_PARM_ENUM("pattern", "Background pattern", generated_packet_pattern_table, BCMCLI_PARM_FLAG_NONE), |
| BCMCLI_MAKE_PARM_RANGE("const_value", "Const value", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_NONE, 0, 0xFF)); |
| |
| BCMCLI_MAKE_CMD( |
| dir, |
| "send_to_gem", |
| "Send saved CPU/OMCI packet to GEM port(s)", |
| send_to_gem_cb, |
| BCMCLI_MAKE_PARM("device", "Device ID", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_NONE), |
| BCMCLI_MAKE_PARM("pon_ni", "PON NI", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_NONE), |
| BCMCLI_MAKE_PARM_ARRAY( |
| "gem", |
| "GEM port IDs, comma separated", |
| BCMCLI_PARM_UNUMBER, |
| BCMCLI_PARM_FLAG_NONE, |
| MAX_GEM_PORTS_FOR_SEND, |
| gem_port_ids), |
| BCMCLI_MAKE_PARM("count", "Number of packets (default 1)", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_OPTIONAL)); |
| |
| BCMCLI_MAKE_CMD( |
| dir, |
| "send_to_onu", |
| "Send saved CPU/OMCI packet to ONU(s) (OMCI GEM port)", |
| send_to_onu_cb, |
| BCMCLI_MAKE_PARM("device", "Device ID", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_NONE), |
| BCMCLI_MAKE_PARM("pon_ni", "PON NI", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_NONE), |
| BCMCLI_MAKE_PARM_ARRAY( |
| "onu", |
| "ONU IDs, comma separated", |
| BCMCLI_PARM_UNUMBER, |
| BCMCLI_PARM_FLAG_NONE, |
| MAX_ONUS_FOR_SEND, |
| onu_ids), |
| BCMCLI_MAKE_PARM("count", "Number of packets (default 1)", BCMCLI_PARM_UNUMBER, BCMCLI_PARM_FLAG_OPTIONAL)); |
| |
| BCMCLI_MAKE_CMD_NOPARM( |
| dir, |
| "dump_packet", |
| "Print saved CPU/OMCI packet data", |
| dump_packet_cb); |
| |
| gpon_utils_cli_dir = dir; |
| gpon_utils_cli_top_dir = top_dir; |
| return BCM_ERR_OK; |
| } |