blob: 558594c27b5bc314b039a64db9ed78f0b53a6e66 [file] [log] [blame]
/*
<:copyright-BRCM:2016:DUAL/GPL:standard
Broadcom Proprietary and Confidential.(c) 2016 Broadcom
All Rights Reserved
Unless you and Broadcom execute a separate written software license
agreement governing use of this software, this software is licensed
to you under the terms of the GNU General Public License version 2
(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
with the following added to such license:
As a special exception, the copyright holders of this software give
you permission to link this software with independent modules, and
to copy and distribute the resulting executable under terms of your
choice, provided that you also meet, for each linked independent
module, the terms and conditions of the license of that module.
An independent module is a module which is not derived from this
software. The special exception does not apply to any modifications
of the software.
Not withstanding the above, under no circumstances may you combine
this software in any way with any other Broadcom software provided
under a license other than the GPL, without Broadcom's express prior
written consent.
:>
*/
#include "bcmos_system.h"
#include "bcmolt_math.h"
#include "bcmolt_utils.h"
#include "bcm_dev_log.h"
#include "bcmolt_msg.h"
#include "bcmolt_msg_pack.h"
#include "bcmolt_api.h"
#include "bcmolt_model_types.h"
#include "bcmolt_user_appl_epon_oam.h"
#include "bcmos_hash_table.h"
#define MAX_CONCURRENT_LINKS 2048
typedef struct
{
bcmolt_devid device_id;
bcmolt_epon_link_key key;
FILE *file;
void *buf;
uint16_t block_size;
uint16_t last_block;
uint16_t last_block_size;
uint8_t retries;
bcmos_bool done;
bcmos_timer timer;
uint32_t timeout_us;
uint32_t last_time;
} epon_oam_dpoe_fw_upgrade_state;
typedef struct
{
bcmolt_devid device_id;
bcmolt_proxy_rx *rx;
bcmolt_user_appl_epon_oam_handle_rx_cb cb;
} epon_oam_proxy_rx_data;
typedef struct
{
epon_oam_dpoe_fw_upgrade_state *state;
} epon_oam_timeout_data;
typedef union
{
epon_oam_proxy_rx_data proxy_rx;
epon_oam_timeout_data timeout;
} epon_oam_msg_data;
typedef struct
{
bcmos_msg os_msg;
epon_oam_msg_data data;
} epon_oam_msg;
static bcmos_bool is_running = BCMOS_FALSE;
static dev_log_id epon_oam_log[BCMTR_MAX_OLTS];
static char mac_buf[MAC_STR_LEN];
static bcmos_task epon_oam_task;
static hash_table *dpoe_fw_upgrade_state;
static void epon_oam_handle_os_msg(bcmos_module_id module_id, bcmos_msg *os_msg);
#define EPON_OAM_LOG(level, device, link, fmt, args...) \
BCM_LOG_CALLER_FMT(level, epon_oam_log[device], "%u-%s: "fmt, (link)->epon_ni, bcmos_mac_2_str(&(link)->mac_address, mac_buf), ##args)
static bcmos_errno epon_oam_get_mac_da(bcmolt_devid device_id, bcmolt_epon_ni epon, bcmos_mac_address *mac)
{
bcmos_errno err;
bcmolt_epon_ni_cfg pon_cfg;
bcmolt_epon_ni_key pon_key = { .epon_ni = epon };
/* retrieve the EPON NI MAC address */
BCMOLT_CFG_INIT(&pon_cfg, epon_ni, pon_key);
BCMOLT_CFG_PROP_GET(&pon_cfg, epon_ni, mac_address);
err = bcmolt_cfg_get(device_id, &pon_cfg.hdr);
if (BCM_ERR_OK != err)
{
BCM_LOG(ERROR, epon_oam_log[device_id], "Failed to retrieve EPON NI MAC address!\n");
}
else
{
*mac = pon_cfg.data.mac_address;
}
return err;
}
bcmos_errno epon_oam_pack_frame(bcmolt_epon_oam_ethernet_frame *oam_frame, uint8_t **buffer, uint16_t *length)
{
bcmolt_buf buf;
*length = MAX(bcmolt_epon_oam_ethernet_frame_get_packed_length(oam_frame), 60);
*buffer = bcmos_calloc(*length);
if (NULL == *buffer)
{
return BCM_ERR_NOMEM;
}
bcmolt_buf_init(&buf, *length, *buffer, BCMOLT_BUF_ENDIAN_FIXED);
if (!bcmolt_epon_oam_ethernet_frame_pack(oam_frame, &buf))
{
bcmos_free(*buffer);
return BCM_ERR_INTERNAL;
}
return BCM_ERR_OK;
}
bcmos_errno epon_oam_pack_and_send(bcmolt_devid device_id,
bcmolt_epon_ni epon,
const bcmos_mac_address *mac,
bcmolt_epon_oam_ethernet_frame *oam_frame)
{
bcmos_errno err;
bcmolt_epon_link_inject_frame inject_frame;
bcmolt_epon_link_key link_key = { .epon_ni = epon, .mac_address = *mac };
bcmolt_ethernet_frame_unmasked frame;
err = epon_oam_pack_frame(oam_frame, &frame.frame_octets.val, &frame.frame_octets.len);
if (BCM_ERR_OK != err)
{
EPON_OAM_LOG(ERROR, device_id, &link_key, "Failed to pack OAM frame: %s!\n", bcmos_strerror(err));
return err;
}
BCMOLT_PROXY_INIT(&inject_frame, epon_link, inject_frame, link_key);
BCMOLT_PROXY_PROP_SET(&inject_frame, epon_link, inject_frame, frame, frame);
err = bcmolt_proxy_send(device_id, &inject_frame.hdr);
bcmos_free(frame.frame_octets.val);
return err;
}
bcmolt_epon_oam_ethernet_frame *epon_oam_unpack(bcmolt_devid device_id, uint32_t len, uint8_t *bytes)
{
bcmolt_buf buf;
uint32_t unpack_bytes = sizeof(bcmolt_epon_oam_ethernet_frame);
void *unpack_mem;
bcmolt_epon_oam_ethernet_frame *frame;
void *extra_mem;
/* We don't know how much space we'll need to unpack the OAM frame. Starting with the known fixed size, we scan the
frame to determine the exact space needed */
bcmolt_buf_init(&buf, len, bytes, BCMOLT_BUF_ENDIAN_FIXED);
if (!bcmolt_epon_oam_ethernet_frame_scan(&buf, &unpack_bytes))
{
BCM_LOG(ERROR, epon_oam_log[device_id], "Failed to scan OAM frame\n");
return NULL;
}
unpack_mem = bcmos_calloc(unpack_bytes);
if (NULL == unpack_mem)
{
BCM_LOG(ERROR, epon_oam_log[device_id], "Failed to allocate %u bytes required to unpack\n", unpack_bytes);
return NULL;
}
else
{
BCM_LOG(DEBUG, epon_oam_log[device_id], "Successfully allocated %u bytes required to unpack\n", unpack_bytes);
}
/* Now that we have an appropriately sized buffer to unpack into, point the fixed structure to the start of the
buffer and direct the unpacker to store any additional data immediately after that */
frame = (bcmolt_epon_oam_ethernet_frame*)unpack_mem;
extra_mem = (void*)(frame + 1);
bcmolt_buf_init(&buf, len, bytes, BCMOLT_BUF_ENDIAN_FIXED);
if (!bcmolt_epon_oam_ethernet_frame_unpack(frame, &buf, &extra_mem))
{
BCM_LOG(ERROR, epon_oam_log[device_id], "Failed to unpack OAM frame\n");
bcmos_free(unpack_mem);
return NULL;
}
return frame;
}
static bcmos_errno epon_oam_make_dpoe_frame(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmolt_epon_oam_ethernet_frame *oam_frame,
bcmolt_epon_oam_ethernet_protocol *protocol)
{
bcmos_errno err;
oam_frame->da = slow_protocol_multicast_mac;
err = epon_oam_get_mac_da(device_id, epon, &oam_frame->sa);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
oam_frame->protocols_count = 1;
oam_frame->protocols = protocol;
protocol->ethertype = BCMOLT_EPON_OAM_PROTOCOL_TYPE_SLOW_PROTOCOL;
protocol->u.slow_protocol.value.subtype = BCMOLT_EPON_OAM_SLOW_PROTOCOL_SUBTYPE_OAM;
protocol->u.slow_protocol.value.u.oam.flags =
BCMOLT_EPON_OAM_OAM_FLAGS_LOCAL_STABLE | BCMOLT_EPON_OAM_OAM_FLAGS_REMOTE_STABLE;
protocol->u.slow_protocol.value.u.oam.content.code = BCMOLT_EPON_OAM_OAM_OPCODE_ORGANIZATION_SPECIFIC;
protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.oui =
BCMOLT_EPON_OAM_WELL_KNOWN_OUI_DPOE;
return err;
}
static bcmos_errno epon_oam_send_os_msg(bcmos_msg_id type, epon_oam_msg_data *msg_data)
{
bcmos_errno rc;
epon_oam_msg *msg = bcmos_calloc(sizeof(*msg));
if (msg == NULL)
{
BCM_LOG(ERROR, epon_oam_log[msg_data->proxy_rx.device_id], "OS msg calloc failed\n");
return BCM_ERR_NOMEM;
}
msg->os_msg.type = type;
msg->os_msg.handler = epon_oam_handle_os_msg;
msg->data = *msg_data;
rc = bcmos_msg_send_to_module(BCMOS_MODULE_ID_USER_APPL_EPON_OAM, &msg->os_msg, 0);
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, epon_oam_log[msg_data->proxy_rx.device_id], "OS msg send failed\n");
}
return rc;
}
bcmos_errno epon_oam_dpoe_get_critical_info(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac)
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_descriptor vars[3] = {};
err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_GET_REQUEST;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.get_request.vars_count =
3;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.get_request.vars = vars;
vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[0].u.extended_attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_ONU_ID;
vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[1].u.extended_attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_MAX_LOGICAL_LINKS;
vars[2].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
vars[2].u.end.unknown_count = 0;
vars[2].u.end.unknown = NULL;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
bcmos_errno epon_oam_dpoe_set_oam_rate(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
uint8_t min,
uint8_t max)
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_container_base vars[2] = {};
err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
2;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[0].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_OAM_RATE;
vars[0].u.extended_attribute.attribute.u.oam_rate.minimum_oam_rate = min;
vars[0].u.extended_attribute.attribute.u.oam_rate.maximum_oam_rate = max;
vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
vars[1].u.end.unknown_count = 0;
vars[1].u.end.unknown = NULL;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
bcmos_errno epon_oam_dpoe_set_report_thresholds(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
uint8_t report_values_per_queue_set,
bcmolt_epon_oam_queue_sets queue_sets,
uint8_t num_queue_sets)
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_container_base vars[2] = {};
err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
2;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[0].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_REPORT_THRESHOLDS;
vars[0].u.extended_attribute.attribute.u.report_thresholds.number_of_queue_sets = num_queue_sets;
vars[0].u.extended_attribute.attribute.u.report_thresholds.report_values_per_queue_set =
report_values_per_queue_set;
vars[0].u.extended_attribute.attribute.u.report_thresholds.queue_set0 = queue_sets[0];
vars[0].u.extended_attribute.attribute.u.report_thresholds.queue_set1 = queue_sets[1];
vars[0].u.extended_attribute.attribute.u.report_thresholds.queue_set2 = queue_sets[2];
vars[0].u.extended_attribute.attribute.u.report_thresholds.queue_set3 = queue_sets[3];
vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
vars[1].u.end.unknown_count = 0;
vars[1].u.end.unknown = NULL;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
bcmos_errno epon_oam_dpoe_set_encryption(
bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
bcmolt_epon_oam_dpoe_encryption_mode enc_mode,
uint16_t period)
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_container_base vars[3] = {};
err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
3;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[0].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_ENCRYPT_MODE;
vars[0].u.extended_attribute.attribute.u.encrypt_mode.encryption_method = enc_mode;
vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[1].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_KEY_EXPIRY_TIME;
vars[1].u.extended_attribute.attribute.u.key_expiry_time.time = period;
vars[2].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
vars[2].u.end.unknown_count = 0;
vars[2].u.end.unknown = NULL;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
bcmos_bool epon_oam_is_dpoe(bcmolt_epon_oam_ethernet_frame *oam)
{
return ((oam->protocols_count > 0) &&
(BCMOLT_EPON_OAM_PROTOCOL_TYPE_SLOW_PROTOCOL == oam->protocols[0].ethertype) &&
(BCMOLT_EPON_OAM_SLOW_PROTOCOL_SUBTYPE_OAM == oam->protocols[0].u.slow_protocol.value.subtype) &&
(BCMOLT_EPON_OAM_OAM_OPCODE_ORGANIZATION_SPECIFIC ==
oam->protocols[0].u.slow_protocol.value.u.oam.content.code) &&
(BCMOLT_EPON_OAM_WELL_KNOWN_OUI_DPOE ==
oam->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.oui));
}
bcmos_bool epon_oam_is_dpoe_encrypt_response(bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe)
{
return (BCMOLT_EPON_OAM_DPOE_OPCODE_SET_RESPONSE == dpoe->op) &&
(dpoe->u.set_response.vars_count > 2) &&
(BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE == dpoe->u.set_response.vars[0].branch) &&
(BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_ENCRYPT_MODE ==
dpoe->u.set_response.vars[0].u.extended_attribute.attribute.leaf) &&
(BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE == dpoe->u.set_response.vars[1].branch) &&
(BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_KEY_EXPIRY_TIME ==
dpoe->u.set_response.vars[1].u.extended_attribute.attribute.leaf);
}
static bcmos_errno epon_oam_dpoe_clear_ingress_rules_make_frame(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
bcmolt_epon_oam_ethernet_frame *oam_frame,
bcmolt_epon_oam_ethernet_protocol *protocol,
bcmolt_epon_oam_dpoe_var_container_base *vars)
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
err = epon_oam_make_dpoe_frame(device_id, epon, oam_frame, protocol);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
3;
protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_OBJECT;
vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ACTION;
vars[1].u.extended_action.action.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ACTION_CLEAR_INGRESS_RULES;
vars[2].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
vars[2].u.end.unknown_count = 0;
vars[2].u.end.unknown = NULL;
return BCM_ERR_OK;
}
bcmos_errno epon_oam_dpoe_clear_ingress_rules_network_pon(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac)
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_container_base vars[3] = {};
uint8_t port = 0;
epon_oam_dpoe_clear_ingress_rules_make_frame(device_id, epon, mac, &oam_frame, &protocol, vars);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
vars[0].u.object.object_context.object_type = BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_NETWORK_PON;
vars[0].u.object.object_context.u.network_pon.pon_count = 1;
vars[0].u.object.object_context.u.network_pon.pon = &port;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
bcmos_errno epon_oam_dpoe_clear_ingress_rules_user_port(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac)
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_container_base vars[3] = {};
uint8_t port = 0;
epon_oam_dpoe_clear_ingress_rules_make_frame(device_id, epon, mac, &oam_frame, &protocol, vars);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
vars[0].u.object.object_context.object_type = BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_USER_PORT;
vars[0].u.object.object_context.u.user_port.port_count = 1;
vars[0].u.object.object_context.u.user_port.port = &port;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
bcmos_errno epon_oam_dpoe_clear_ingress_rules(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac)
{
bcmos_errno err = BCM_ERR_OK;
err = epon_oam_dpoe_clear_ingress_rules_network_pon(device_id, epon, mac);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
return epon_oam_dpoe_clear_ingress_rules_user_port(device_id, epon, mac);
}
bcmos_errno epon_oam_dpoe_set_basic_queue_config(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
uint8_t up_queue_size,
uint8_t dn_queue_size)
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_container_base vars[2] = {};
bcmolt_epon_oam_dpoe_queue_set up_queue_set;
bcmolt_epon_oam_dpoe_queue_set dn_queue_set;
err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
2;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[0].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_QUEUE_CONFIG;
vars[0].u.extended_attribute.attribute.u.queue_config.number_of_links = 1;
vars[0].u.extended_attribute.attribute.u.queue_config.link_configuration = &up_queue_set;
up_queue_set.queue_count = 1;
up_queue_set.queue_sizes = &up_queue_size;
vars[0].u.extended_attribute.attribute.u.queue_config.number_of_ports = 1;
vars[0].u.extended_attribute.attribute.u.queue_config.port_configuration = &dn_queue_set;
dn_queue_set.queue_count = 1;
dn_queue_set.queue_sizes = &dn_queue_size;
vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
vars[1].u.end.unknown_count = 0;
vars[1].u.end.unknown = NULL;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
static bcmos_errno epon_oam_dpoe_add_ingress_rules_make_frame(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
bcmolt_epon_oam_ethernet_frame *oam_frame,
bcmolt_epon_oam_ethernet_protocol *protocol,
bcmolt_epon_oam_dpoe_var_container_base *vars,
dpoe_rule_vlan_mode vlan_mode,
uint8_t vlan_tag[4])
{
static const uint32_t var_count[DPOE_RULE_VLAN_MODE_COUNT] =
{
[DPOE_RULE_VLAN_MODE_NONE] = 8,
[DPOE_RULE_VLAN_MODE_ADD] = 10,
[DPOE_RULE_VLAN_MODE_REMOVE] = 9
};
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
err = epon_oam_make_dpoe_frame(device_id, epon, oam_frame, protocol);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
var_count[vlan_mode];
protocol->u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_OBJECT;
vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[1].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
vars[1].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_HEADER;
vars[1].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.header.precedence = 10;
vars[2].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[2].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_CLAUSE;
vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.field_code.code =
BCMOLT_EPON_OAM_DPOE_FIELD_CODE_L2DA;
vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.field_code.instance = 0;
vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.msb_mask = 0;
vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.lsb_mask = 0;
vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.operator =
BCMOLT_EPON_OAM_RULE_OPERATOR_ALWAYS_MATCH;
vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.match_value_length = 0;
vars[2].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.clause.match_value = NULL;
vars[3].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[3].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_RESULT;
vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.result =
BCMOLT_EPON_OAM_DPOE_RESULT_QUEUE;
vars[4].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[4].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
vars[4].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_RESULT;
vars[4].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.result =
BCMOLT_EPON_OAM_DPOE_RESULT_FORWARD;
switch (vlan_mode)
{
case DPOE_RULE_VLAN_MODE_NONE:
break; /* nothing to do */
case DPOE_RULE_VLAN_MODE_ADD:
vars[5].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[5].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_RESULT;
vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.result =
BCMOLT_EPON_OAM_DPOE_RESULT_INSERT;
vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.insert.field.field.code =
BCMOLT_EPON_OAM_DPOE_FIELD_CODE_CVLAN;
vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.insert.field.field.instance = 0;
vars[6].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[6].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_RESULT;
vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.result =
BCMOLT_EPON_OAM_DPOE_RESULT_SET;
vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.set.field.field.code =
BCMOLT_EPON_OAM_DPOE_FIELD_CODE_CVLAN;
vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.set.field.field.instance = 0;
vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.set.value_count = 4;
vars[6].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.set.value = vlan_tag;
break;
case DPOE_RULE_VLAN_MODE_REMOVE:
vars[5].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[5].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_RESULT;
vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.result =
BCMOLT_EPON_OAM_DPOE_RESULT_DELETE;
vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.delete.field.field.code =
BCMOLT_EPON_OAM_DPOE_FIELD_CODE_CVLAN;
vars[5].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.delete.field.field.instance = 0;
break;
default:
return BCM_ERR_PARM;
}
vars[var_count[vlan_mode]-3].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE;
vars[var_count[vlan_mode]-3].u.extended_attribute.attribute.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_PORT_INGRESS_RULE;
vars[var_count[vlan_mode]-3].u.extended_attribute.attribute.u.port_ingress_rule.rule.subtype = BCMOLT_EPON_OAM_RULE_TYPE_TERMINATOR;
vars[var_count[vlan_mode]-2].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ACTION;
vars[var_count[vlan_mode]-2].u.extended_action.action.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ACTION_ADD_INGRESS_RULES;
vars[var_count[vlan_mode]-1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
vars[var_count[vlan_mode]-1].u.end.unknown_count = 0;
vars[var_count[vlan_mode]-1].u.end.unknown = NULL;
return BCM_ERR_OK;
}
bcmos_errno epon_oam_dpoe_add_ingress_rules_network_pon(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
dpoe_rule_vlan_mode vlan_mode,
uint8_t vlan_tag[4])
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_container_base vars[10] = {};
uint8_t port = 0;
err = epon_oam_dpoe_add_ingress_rules_make_frame(device_id,
epon,
mac,
&oam_frame,
&protocol,
vars,
vlan_mode,
vlan_tag);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
vars[0].u.object.object_context.object_type = BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_NETWORK_PON;
vars[0].u.object.object_context.u.network_pon.pon_count = 1;
vars[0].u.object.object_context.u.network_pon.pon = &port;
vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.type =
BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_USER_PORT;
vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.instance = 0;
vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.queue = 0;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
bcmos_errno epon_oam_dpoe_add_ingress_rules_user_port(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
dpoe_rule_vlan_mode vlan_mode,
uint8_t vlan_tag[4])
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_container_base vars[10] = {};
uint8_t port = 0;
err = epon_oam_dpoe_add_ingress_rules_make_frame(device_id,
epon,
mac,
&oam_frame,
&protocol,
vars,
vlan_mode,
vlan_tag);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
vars[0].u.object.object_context.object_type = BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_USER_PORT;
vars[0].u.object.object_context.u.user_port.port_count = 1;
vars[0].u.object.object_context.u.user_port.port = &port;
vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.type =
BCMOLT_EPON_OAM_DPOE_OBJECT_TYPE_LINK;
vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.instance = 0;
vars[3].u.extended_attribute.attribute.u.port_ingress_rule.rule.u.result.result.u.queue.queue.queue = 0;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
bcmos_errno epon_oam_dpoe_add_ingress_rules(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac)
{
bcmos_errno err = BCM_ERR_OK;
err = epon_oam_dpoe_add_ingress_rules_network_pon(device_id, epon, mac, DPOE_RULE_VLAN_MODE_NONE, NULL);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
return epon_oam_dpoe_add_ingress_rules_user_port(device_id, epon, mac, DPOE_RULE_VLAN_MODE_NONE, NULL);
}
bcmos_errno epon_oam_dpoe_add_ingress_rules_with_vlan(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
uint8_t vlan_tag[4])
{
static uint8_t example_vlan[4] = { 0x81, 0x00, 0x12, 0x34 };
bcmos_errno err = BCM_ERR_OK;
err = epon_oam_dpoe_add_ingress_rules_network_pon(device_id, epon, mac, DPOE_RULE_VLAN_MODE_REMOVE, NULL);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
if (NULL == vlan_tag)
{
vlan_tag = example_vlan;
}
return epon_oam_dpoe_add_ingress_rules_user_port(device_id, epon, mac, DPOE_RULE_VLAN_MODE_ADD, vlan_tag);
}
static bcmos_errno _epon_oam_dpoe_user_traffic_set_action(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
bcmolt_epon_oam_dpoe_leaf_action action)
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_container_base vars[2] = {};
err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
2;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ACTION;
vars[0].u.extended_action.action.leaf = action;
vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
vars[1].u.end.unknown_count = 0;
vars[1].u.end.unknown = NULL;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
bcmos_errno epon_oam_dpoe_disable_user_traffic(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac)
{
return _epon_oam_dpoe_user_traffic_set_action(device_id,
epon,
mac,
BCMOLT_EPON_OAM_DPOE_LEAF_ACTION_DISABLE_USER_TRAFFIC);
}
bcmos_errno epon_oam_dpoe_enable_user_traffic(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac)
{
return _epon_oam_dpoe_user_traffic_set_action(device_id,
epon,
mac,
BCMOLT_EPON_OAM_DPOE_LEAF_ACTION_ENABLE_USER_TRAFFIC);
}
static epon_oam_dpoe_fw_upgrade_state *epon_oam_dpoe_fw_upgrade_state_add(const bcmolt_epon_link_key *key)
{
epon_oam_dpoe_fw_upgrade_state state = {};
return hash_table_put(dpoe_fw_upgrade_state, (const uint8_t*)key, &state);
}
static epon_oam_dpoe_fw_upgrade_state* epon_oam_dpoe_fw_upgrade_state_get(const bcmolt_epon_link_key *key)
{
return hash_table_get(dpoe_fw_upgrade_state, (const uint8_t*)key);
}
static void epon_oam_dpoe_fw_upgrade_state_release(epon_oam_dpoe_fw_upgrade_state *state)
{
if (NULL == state)
{
BCM_LOG(ERROR, epon_oam_log[0], "Tried to release NULL state\n");
return;
}
if (NULL != state->file)
{
fclose(state->file);
}
bcmos_free(state->buf);
bcmos_timer_destroy(&state->timer);
if (!hash_table_remove(dpoe_fw_upgrade_state, (const uint8_t*)&state->key))
{
BCM_LOG(ERROR, epon_oam_log[state->device_id], "Unable to remove from hash table\n");
}
}
static void epon_oam_dpoe_send_block(bcmolt_devid device_id,
const bcmolt_epon_link_key *key,
uint16_t block,
uint8_t *data,
uint16_t length)
{
bcmos_errno err;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
err = epon_oam_make_dpoe_frame(device_id, key->epon_ni, &oam_frame, &protocol);
BCMOS_RETURN_ON_ERROR(err);
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_FILE_TRANSFER;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.opcode = BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_DATA;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_data.block = block;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_data.length = length;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_data.data = data;
if (BCM_ERR_OK != epon_oam_pack_and_send(device_id, key->epon_ni, &key->mac_address, &oam_frame))
{
EPON_OAM_LOG(ERROR, device_id, key, "Failed to send fw upgrade block %u\n", block);
}
else
{
EPON_OAM_LOG(DEBUG, device_id, key, "Sent block %u\n", block);
}
}
static void epon_oam_dpoe_send_ack(bcmolt_devid device_id,
const bcmolt_epon_link_key *key,
bcmolt_epon_oam_dpoe_file_transfer_error error)
{
bcmos_errno err;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
err = epon_oam_make_dpoe_frame(device_id, key->epon_ni, &oam_frame, &protocol);
BCMOS_RETURN_ON_ERROR(err);
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_FILE_TRANSFER;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.opcode = BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_ACK;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_ack.block = 0;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_ack.error = error;
if (BCM_ERR_OK != epon_oam_pack_and_send(device_id, key->epon_ni, &key->mac_address, &oam_frame))
{
EPON_OAM_LOG(ERROR, device_id, key, "Failed to send fw upgrade ack\n");
}
else
{
EPON_OAM_LOG(DEBUG, device_id, key, "Sent ack: error %u\n", error);
}
}
static void epon_oam_dpoe_reset_timeout(epon_oam_dpoe_fw_upgrade_state *state)
{
EPON_OAM_LOG(DEBUG, state->device_id, &state->key, "ONU took %u us to respond\n", bcmos_timestamp() - state->last_time);
state->last_time = bcmos_timestamp();
bcmos_timer_start(&state->timer, state->timeout_us);
}
static void epon_oam_dpoe_handle_ack(bcmolt_devid device_id,
const bcmolt_epon_link_key *key,
const bcmolt_epon_oam_dpoe_file_transfer_base *ft,
bcmolt_user_appl_epon_oam_handle_rx_cb cb)
{
epon_oam_dpoe_fw_upgrade_state *state;
int block_size;
state = epon_oam_dpoe_fw_upgrade_state_get(key);
if (NULL == state)
{
EPON_OAM_LOG(DEBUG, device_id, key, "Rx unexpected ack\n");
return;
}
if (state->done)
{
if (ft->u.file_ack.block != 0)
{
EPON_OAM_LOG(ERROR, device_id, key, "Final ack contained non-zero block: %u\n", ft->u.file_ack.block);
}
switch (ft->u.file_ack.error)
{
case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_OK:
EPON_OAM_LOG(INFO, device_id, key, "Upgrade successful\n");
break;
default:
EPON_OAM_LOG(ERROR, device_id, key, "Upgrade failed with error %u\n", ft->u.file_ack.error);
break;
}
epon_oam_dpoe_fw_upgrade_state_release(state);
return;
}
state->last_block++;
if ((state->last_block - 1) == ft->u.file_ack.block)
{ /* retry last block */
state->last_block--;
state->retries++;
if (state->retries > 3)
{
EPON_OAM_LOG(ERROR, device_id, key, "Exceeded retry limit on block %u\n", ft->u.file_ack.block);
epon_oam_dpoe_send_ack(device_id, key, BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_TIMEOUT);
epon_oam_dpoe_fw_upgrade_state_release(state);
}
else
{
epon_oam_dpoe_send_block(device_id, key, ft->u.file_ack.block, state->buf, state->last_block_size);
epon_oam_dpoe_reset_timeout(state);
}
}
else if (state->last_block == ft->u.file_ack.block)
{ /* send next block */
state->retries = 0;
block_size = fread(state->buf, 1, state->block_size, state->file);
if (block_size > 0)
{
epon_oam_dpoe_send_block(device_id, key, ft->u.file_ack.block, state->buf, block_size);
}
else
{
state->done = BCMOS_TRUE;
epon_oam_dpoe_send_ack(device_id, key, BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_OK);
}
state->last_block_size = block_size;
epon_oam_dpoe_reset_timeout(state);
}
else
{ /* unexpected block */
EPON_OAM_LOG(ERROR, device_id, key, "Unexpected block requested: %u (expecting %u)\n",
ft->u.file_ack.block, state->last_block + 1);
epon_oam_dpoe_send_ack(device_id, key, BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_BAD_BLOCK);
epon_oam_dpoe_fw_upgrade_state_release(state);
}
}
static bcmos_timer_rc epon_oam_dpoe_fw_upgrade_timeout(bcmos_timer *timer, long data)
{
epon_oam_msg_data msg_data;
msg_data.timeout.state = (epon_oam_dpoe_fw_upgrade_state*)data;
epon_oam_send_os_msg(BCMOS_MSG_ID_EPON_OAM_TIMEOUT, &msg_data);
return BCMOS_TIMER_OK;
}
bcmos_errno epon_oam_dpoe_start_upgrade(bcmolt_devid device_id,
bcmolt_epon_ni epon,
bcmos_mac_address *mac,
const char *fw_file,
uint16_t block_size,
uint8_t timeout_sec)
{
bcmos_errno err = BCM_ERR_OK;
bcmolt_epon_link_key link_key = { .epon_ni = epon, .mac_address = *mac };
bcmos_timer_parm tp =
{
.name = "fw_upgrade_timer",
.owner = BCMOS_MODULE_ID_USER_APPL_EPON_OAM,
.periodic = BCMOS_FALSE,
.handler = epon_oam_dpoe_fw_upgrade_timeout
};
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
epon_oam_dpoe_fw_upgrade_state *state;
if (NULL != epon_oam_dpoe_fw_upgrade_state_get(&link_key))
{
return BCM_ERR_ALREADY;
}
state = epon_oam_dpoe_fw_upgrade_state_add(&link_key);
if (NULL == state)
{
return BCM_ERR_NOMEM;
}
state->device_id = device_id;
state->key = link_key;
state->file = fopen(fw_file, "rb");
if (NULL == state->file)
{
epon_oam_dpoe_fw_upgrade_state_release(state);
return BCM_ERR_IO;
}
state->block_size = block_size;
state->buf = bcmos_calloc(block_size);
if (NULL == state->buf)
{
epon_oam_dpoe_fw_upgrade_state_release(state);
return BCM_ERR_NOMEM;
}
state->last_block = 0xffff;/*-1*/
state->retries = 0;
state->done = BCMOS_FALSE;
tp.data = (long)state;
err = bcmos_timer_create(&state->timer, &tp);
if (BCM_ERR_OK != err)
{
epon_oam_dpoe_fw_upgrade_state_release(state);
return err;
}
state->timeout_us = timeout_sec * 1000 * 1000;
state->last_time = bcmos_timestamp();
bcmos_timer_start(&state->timer, state->timeout_us);
err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
if (BCM_ERR_OK != err)
{
epon_oam_dpoe_fw_upgrade_state_release(state);
return err;
}
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_FILE_TRANSFER;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.opcode = BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_WRITE;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_write.filename_count = 0;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.file_transfer.file_transfer.u.file_write.filename = NULL;
err = epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
if (BCM_ERR_OK != err)
{
epon_oam_dpoe_fw_upgrade_state_release(state);
}
return err;
}
bcmos_errno epon_oam_dpoe_reset_onu(bcmolt_devid device_id, bcmolt_epon_ni epon, bcmos_mac_address *mac)
{
bcmos_errno err = BCM_ERR_OK;
/* OAM stuff */
bcmolt_epon_oam_ethernet_frame oam_frame;
bcmolt_epon_oam_ethernet_protocol protocol;
bcmolt_epon_oam_dpoe_var_container_base vars[2] = {};
err = epon_oam_make_dpoe_frame(device_id, epon, &oam_frame, &protocol);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err);
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.op =
BCMOLT_EPON_OAM_DPOE_OPCODE_SET_REQUEST;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars_count =
2;
protocol.u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value.u.set_request.vars = vars;
vars[0].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ACTION;
vars[0].u.extended_action.action.leaf = BCMOLT_EPON_OAM_DPOE_LEAF_ACTION_RESET_ONU;
vars[1].branch = BCMOLT_EPON_OAM_DPOE_BRANCH_END;
vars[1].u.end.unknown_count = 0;
vars[1].u.end.unknown = NULL;
return epon_oam_pack_and_send(device_id, epon, mac, &oam_frame);
}
static void epon_oam_handle_event(bcmolt_devid device_id,
bcmolt_epon_oam_oam_pdu_content *content,
const bcmolt_epon_link_key *key,
bcmolt_user_appl_epon_oam_handle_rx_cb cb)
{
for (uint32_t i = 0; i < content->u.event_notification.tlvs_count; i++)
{
if (BCMOLT_EPON_OAM_LINK_EVENT_TYPE_ORGANIZATION_SPECIFIC == content->u.event_notification.tlvs[i].type)
{
switch (content->u.event_notification.tlvs[i].u.organization_specific.value.oui)
{
case BCMOLT_EPON_OAM_WELL_KNOWN_OUI_DPOE:
if (NULL != cb)
{
cb(device_id, key->epon_ni, &key->mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_DPOE_EVENT, BCM_ERR_OK);
}
EPON_OAM_LOG(INFO, device_id, key, "Received DPoE event %u\n",
content->u.event_notification.tlvs[i].u.organization_specific.value.u.dpoe.value.event_code);
break;
default:
break;
}
}
}
}
static void epon_oam_handle_dpoe_get_response(bcmolt_devid device_id,
bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe,
const bcmolt_epon_link_key *key,
bcmolt_user_appl_epon_oam_handle_rx_cb cb)
{
bcmos_errno rc = BCM_ERR_OK;
EPON_OAM_LOG(DEBUG, device_id, key, "Rx %u vars\n", dpoe->u.get_response.vars_count);
for (uint32_t i = 0; i < dpoe->u.get_response.vars_count; i++)
{
EPON_OAM_LOG(DEBUG, device_id, key, " %u: branch %u\n", i, dpoe->u.get_response.vars[i].branch);
if (BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE == dpoe->u.get_response.vars[i].branch)
{
if (dpoe->u.get_response.vars[i].u.extended_attribute.attribute.width >
BCMOLT_EPON_OAM_DPOE_ERROR_CODE_NO_ERROR)
{
EPON_OAM_LOG(ERROR, device_id, key, "Error 0x%x getting DPoE extended attribute 0x%04x\n",
dpoe->u.get_response.vars[i].u.extended_attribute.attribute.width,
dpoe->u.get_response.vars[i].u.extended_attribute.attribute.leaf);
rc = BCM_ERR_ONU_ERR_RESP;
}
switch (dpoe->u.get_response.vars[i].u.extended_attribute.attribute.leaf)
{
case BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_ONU_ID:
EPON_OAM_LOG(INFO, device_id, key, "Got DPoE ONUID %02x%02x%02x%02x%02x%02x\n",
dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[0],
dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[1],
dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[2],
dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[3],
dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[4],
dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.onu_id.id.u8[5]);
break;
case BCMOLT_EPON_OAM_DPOE_LEAF_ATTRIBUTE_MAX_LOGICAL_LINKS:
EPON_OAM_LOG(INFO, device_id, key, "Got DPoE Max Logical Links BiDir %u, DownOnly %u\n",
dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.max_logical_links.bidirectional,
dpoe->u.get_response.vars[i].u.extended_attribute.attribute.u.max_logical_links.downstream_only);
break;
default:
break;
}
}
}
if (NULL != cb)
{
cb(device_id, key->epon_ni, &key->mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_DPOE_GET_RESPONSE, rc);
}
}
static void epon_oam_handle_dpoe_set_response(bcmolt_devid device_id,
bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe,
const bcmolt_epon_link_key *key,
bcmolt_user_appl_epon_oam_handle_rx_cb cb)
{
bcmos_errno rc = BCM_ERR_OK;
EPON_OAM_LOG(DEBUG, device_id, key, "Rx %u vars\n", dpoe->u.set_response.vars_count);
for (uint32_t i = 0; i < dpoe->u.set_response.vars_count; i++)
{
EPON_OAM_LOG(DEBUG, device_id, key, " %u: branch %u\n", i, dpoe->u.set_response.vars[i].branch);
switch (dpoe->u.set_response.vars[i].branch)
{
case BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ATTRIBUTE:
if (dpoe->u.set_response.vars[i].u.extended_attribute.attribute.width >
BCMOLT_EPON_OAM_DPOE_ERROR_CODE_NO_ERROR)
{
EPON_OAM_LOG(ERROR, device_id, key, "Error 0x%x setting DPoE extended attribute 0x%04x\n",
dpoe->u.set_response.vars[i].u.extended_attribute.attribute.width,
dpoe->u.set_response.vars[i].u.extended_attribute.attribute.leaf);
rc = BCM_ERR_ONU_ERR_RESP;
}
else
{
EPON_OAM_LOG(INFO, device_id, key, "Successfully set DPoE extended attribute 0x%04x\n",
dpoe->u.set_response.vars[i].u.extended_attribute.attribute.leaf);
}
break;
case BCMOLT_EPON_OAM_DPOE_BRANCH_EXTENDED_ACTION:
if (dpoe->u.set_response.vars[i].u.extended_action.action.width >
BCMOLT_EPON_OAM_DPOE_ERROR_CODE_NO_ERROR)
{
EPON_OAM_LOG(ERROR, device_id, key, "Error 0x%x performing DPoE extended action 0x%04x\n",
dpoe->u.set_response.vars[i].u.extended_action.action.width,
dpoe->u.set_response.vars[i].u.extended_action.action.leaf);
rc = BCM_ERR_ONU_ERR_RESP;
}
else
{
EPON_OAM_LOG(INFO, device_id, key, "Successfully performed DPoE extended action 0x%04x\n",
dpoe->u.set_response.vars[i].u.extended_action.action.leaf);
}
break;
default:
break;
}
}
if (NULL != cb)
{
cb(device_id, key->epon_ni, &key->mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_DPOE_SET_RESPONSE, rc);
}
}
static void epon_oam_handle_dpoe_file_transfer(bcmolt_devid device_id,
bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe,
const bcmolt_epon_link_key *key,
bcmolt_user_appl_epon_oam_handle_rx_cb cb)
{
EPON_OAM_LOG(DEBUG, device_id, key, "Got DPoE File Transfer: %u\n", dpoe->u.file_transfer.file_transfer.opcode);
switch (dpoe->u.file_transfer.file_transfer.opcode)
{
case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_ACK:
EPON_OAM_LOG(DEBUG, device_id, key, "Rx ack block %u error %u\n",
dpoe->u.file_transfer.file_transfer.u.file_ack.block,
dpoe->u.file_transfer.file_transfer.u.file_ack.error);
switch (dpoe->u.file_transfer.file_transfer.u.file_ack.error)
{
case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_OK:
epon_oam_dpoe_handle_ack(device_id, key, &dpoe->u.file_transfer.file_transfer, cb);
break;
default:
EPON_OAM_LOG(ERROR, device_id, key, "File transfer failed on block %u with error %u\n",
dpoe->u.file_transfer.file_transfer.u.file_ack.block,
dpoe->u.file_transfer.file_transfer.u.file_ack.error);
break;
}
break;
case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_DATA:
EPON_OAM_LOG(DEBUG, device_id, key, "Rx data\n");
break;
case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_READ:
EPON_OAM_LOG(ERROR, device_id, key, "Rx read request\n");
break;
case BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_OPCODE_FILE_WRITE:
EPON_OAM_LOG(ERROR, device_id, key, "Rx write request\n");
break;
default:
EPON_OAM_LOG(ERROR, device_id, key, "Unknown DPoE File Transfer opcode: %u\n",
dpoe->u.file_transfer.file_transfer.opcode);
break;
}
}
static void epon_oam_handle_dpoe(bcmolt_devid device_id,
bcmolt_epon_oam_dpoe_vendor_extended_base *dpoe,
const bcmolt_epon_link_key *key,
bcmolt_user_appl_epon_oam_handle_rx_cb cb)
{
EPON_OAM_LOG(DEBUG, device_id, key, "Rx DPoE opcode %u\n", dpoe->op);
switch (dpoe->op)
{
case BCMOLT_EPON_OAM_DPOE_OPCODE_GET_RESPONSE:
epon_oam_handle_dpoe_get_response(device_id, dpoe, key, cb);
break;
case BCMOLT_EPON_OAM_DPOE_OPCODE_SET_RESPONSE:
epon_oam_handle_dpoe_set_response(device_id, dpoe, key, cb);
break;
case BCMOLT_EPON_OAM_DPOE_OPCODE_FILE_TRANSFER:
epon_oam_handle_dpoe_file_transfer(device_id, dpoe, key, cb);
break;
default:
break;
}
}
static void bcmolt_user_appl_epon_oam_handle_proxy_rx(epon_oam_proxy_rx_data *data)
{
const bcmolt_epon_link_frame_captured *cap = (bcmolt_epon_link_frame_captured*)data->rx;
bcmolt_epon_oam_ethernet_frame *oam_frame;
oam_frame = epon_oam_unpack(data->device_id, cap->data.frame.len, cap->data.frame.val);
if (NULL == oam_frame)
{
return;
}
if (oam_frame->protocols_count == 0)
{
EPON_OAM_LOG(ERROR, data->device_id, &cap->key, "No protocols in OAM frame\n");
bcmos_free(oam_frame);
return;
}
EPON_OAM_LOG(DEBUG, data->device_id, &cap->key, "Rx ethertype %04x subtype %02x\n",
oam_frame->protocols[0].ethertype, oam_frame->protocols[0].u.slow_protocol.value.subtype);
if ((BCMOLT_EPON_OAM_PROTOCOL_TYPE_SLOW_PROTOCOL == oam_frame->protocols[0].ethertype) &&
(BCMOLT_EPON_OAM_SLOW_PROTOCOL_SUBTYPE_OAM == oam_frame->protocols[0].u.slow_protocol.value.subtype))
{
if (oam_frame->protocols[0].u.slow_protocol.value.u.oam.flags & BCMOLT_EPON_OAM_OAM_FLAGS_LINK_FAULT)
{
if (NULL != data->cb)
{
data->cb(data->device_id, cap->key.epon_ni, &cap->key.mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_LINK_FAULT, BCM_ERR_OK);
}
EPON_OAM_LOG(ERROR, data->device_id, &cap->key, "Received OAM link fault\n");
}
if (oam_frame->protocols[0].u.slow_protocol.value.u.oam.flags & BCMOLT_EPON_OAM_OAM_FLAGS_DYING_GASP)
{
if (NULL != data->cb)
{
data->cb(data->device_id, cap->key.epon_ni, &cap->key.mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_DYING_GASP, BCM_ERR_OK);
}
EPON_OAM_LOG(ERROR, data->device_id, &cap->key, "Received OAM dying gasp\n");
}
if (oam_frame->protocols[0].u.slow_protocol.value.u.oam.flags & BCMOLT_EPON_OAM_OAM_FLAGS_CRITICAL_EVENT)
{
if (NULL != data->cb)
{
data->cb(data->device_id, cap->key.epon_ni, &cap->key.mac_address, BCMOLT_USER_APPL_EPON_OAM_RX_ID_CRITICAL_EVENT, BCM_ERR_OK);
}
EPON_OAM_LOG(ERROR, data->device_id, &cap->key, "Received OAM critical event\n");
}
EPON_OAM_LOG(DEBUG, data->device_id, &cap->key, "Rx opcode %u\n",
oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.code);
switch (oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.code)
{
case BCMOLT_EPON_OAM_OAM_OPCODE_INFO:
break; /* ignore info - this should be handled by eon */
case BCMOLT_EPON_OAM_OAM_OPCODE_EVENT_NOTIFICATION:
epon_oam_handle_event(data->device_id, &oam_frame->protocols[0].u.slow_protocol.value.u.oam.content, &cap->key, data->cb);
break;
case BCMOLT_EPON_OAM_OAM_OPCODE_ORGANIZATION_SPECIFIC:
EPON_OAM_LOG(DEBUG, data->device_id, &cap->key, "Rx OUI %u\n",
oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.oui);
switch (oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.oui)
{
case BCMOLT_EPON_OAM_WELL_KNOWN_OUI_DPOE:
epon_oam_handle_dpoe(data->device_id, &oam_frame->protocols[0].u.slow_protocol.value.u.oam.content.u.organization_specific.value.u.dpoe.value, &cap->key, data->cb);
break;
default:
break;
}
break;
default:
break;
}
}
bcmos_free(oam_frame);
bcmolt_msg_free(&data->rx->hdr);
}
static void epon_oam_dpoe_handle_fw_upgrade_timeout(epon_oam_dpoe_fw_upgrade_state *state)
{
EPON_OAM_LOG(ERROR, state->device_id, &state->key, "Firmware upgrade timed out\n");
epon_oam_dpoe_send_ack(state->device_id, &state->key, BCMOLT_EPON_OAM_DPOE_FILE_TRANSFER_ERROR_TIMEOUT);
epon_oam_dpoe_fw_upgrade_state_release(state);
}
static void epon_oam_handle_os_msg(bcmos_module_id module_id, bcmos_msg *os_msg)
{
epon_oam_msg *msg = (epon_oam_msg*)os_msg;
switch (msg->os_msg.type)
{
case BCMOS_MSG_ID_EPON_OAM_PROXY_RX:
bcmolt_user_appl_epon_oam_handle_proxy_rx(&msg->data.proxy_rx);
break;
case BCMOS_MSG_ID_EPON_OAM_TIMEOUT:
epon_oam_dpoe_handle_fw_upgrade_timeout(msg->data.timeout.state);
break;
default:
BCM_LOG(ERROR, epon_oam_log[0], "Unknown OS message %u\n", msg->os_msg.type);
break;
}
bcmos_free(os_msg);
}
void bcmolt_user_appl_epon_oam_handle_rx(bcmolt_devid device_id,
bcmolt_proxy_rx *rx,
bcmolt_user_appl_epon_oam_handle_rx_cb cb)
{
bcmos_errno rc;
const bcmolt_epon_link_frame_captured *cap = (bcmolt_epon_link_frame_captured*)rx;
epon_oam_msg_data msg_data = {};
if (!is_running)
{
return;
}
if ((BCMOLT_OBJ_ID_EPON_LINK != rx->hdr.obj_type) ||
(BCMOLT_EPON_LINK_PROXY_RX_ID_FRAME_CAPTURED != rx->hdr.subgroup) ||
(cap->data.frame.val[12] != 0x88) ||
(cap->data.frame.val[13] != 0x09) ||
(cap->data.frame.val[14] != 0x03))
{
return; /* not OAM frame captured on a link - ignore */
}
msg_data.proxy_rx.device_id = device_id;
msg_data.proxy_rx.cb = cb;
rc = bcmolt_msg_clone((bcmolt_msg**)&msg_data.proxy_rx.rx, &rx->hdr);
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, epon_oam_log[device_id], "Proxy Rx clone failed: %s\n", bcmos_strerror(rc));
return;
}
if (BCM_ERR_OK != epon_oam_send_os_msg(BCMOS_MSG_ID_EPON_OAM_PROXY_RX, &msg_data))
{
bcmolt_msg_free(&msg_data.proxy_rx.rx->hdr);
}
}
void bcmolt_user_appl_epon_oam_init(void)
{
bcmos_module_parm module_params =
{
.qparm =
{
.name = "user_appl_epon_oam_module",
.size = MAX_CONCURRENT_LINKS
}
};
bcmos_task_parm task_params =
{
.name = "user_appl_epon_oam_task",
.priority = BCMOS_TASK_PRIORITY_12,
.core = BCMOS_CPU_CORE_ANY, /* No CPU affinity */
.init_handler = NULL
};
if (is_running)
{
return;
}
#ifdef ENABLE_LOG
int i;
char log_name[MAX_DEV_LOG_ID_NAME] = {};
for (i=0; i<BCMTR_MAX_OLTS; i++)
{
snprintf(log_name, sizeof(log_name)-1, "epon_oam%d", i);
epon_oam_log[i] = bcm_dev_log_id_register(log_name, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
}
#endif
dpoe_fw_upgrade_state = hash_table_create(MAX_CONCURRENT_LINKS,
sizeof(epon_oam_dpoe_fw_upgrade_state),
sizeof(bcmolt_epon_link_key),
"dpoe_fw_upgrade_state");
if (BCM_ERR_OK != bcmos_task_create(&epon_oam_task, &task_params))
{
BCM_LOG(FATAL, epon_oam_log[0], "Failed to create EPON OAM task!\n");
}
if (BCM_ERR_OK != bcmos_module_create(BCMOS_MODULE_ID_USER_APPL_EPON_OAM, &epon_oam_task, &module_params))
{
BCM_LOG(FATAL, epon_oam_log[0], "Failed to create EPON OAM module!\n");
}
is_running = BCMOS_TRUE;
}