blob: c632a28add856921954b6be9d1f88e9f46895afb [file] [log] [blame]
/******************************************************************************
*
* <:copyright-BRCM:2016:DUAL/GPL:standard
*
* Copyright (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.
*
* :>
*
*****************************************************************************/
/**
* @file sub_term_fsm.c
* @brief Code to support the BAL subscriber-terminal FSM
*
* @addtogroup sub_terminal
*
*/
/*@{*/
#include <bcmos_system.h>
#include <bal_msg.h>
#include <bal_osmsg.h>
#include "bal_worker.h"
#include "bal_mac_util.h"
#include "bal_switch_util.h"
#include "sub_term_fsm.h"
#include "tm_sched_fsm.h"
#include <bal_objs.h>
#include <fsm_common.h>
#ifdef ENABLE_LOG
#include <bcm_dev_log.h>
/*
* @brief Logging device id for the subscriber-terminal
*/
static dev_log_id log_id_sub_term;
#endif
/* local function declarations */
static bcmos_errno sub_term_fsm_admin_up_start(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_admin_up_error(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_admin_dn_start(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_admin_dn_ok(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_admin_dn_error(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_removing_start(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_ignore_util_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_removing_process_util_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_removing_process_util_auto_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_configuring_process_util_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_null_process_util_auto_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_configured_process_util_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_configuring_process_util_auto_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_state_err(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event);
static bcmos_errno sub_term_fsm_exec(sub_term_inst *p_sub_term_inst, sub_term_fsm_event *p_event);
static bcmos_errno sub_term_free_by_entry(sub_term_inst *p_entry);
static bcmos_errno agg_port_id_list_fill(sub_term_inst *p_sub_term_inst,
bcmbal_aggregation_port_id_list_u8 *agg_port_id_list);
static bcmos_errno svc_port_id_list_fill(sub_term_inst *p_sub_term_inst,
bcmbal_service_port_id_list_u8 *svc_port_id_list);
static bcmos_errno bcmbal_sub_term_tm_scheds_set(const bcmbal_subscriber_terminal_cfg *p_sub_term_cfg);
/*
*@brief Global sub_term fsm context data structure
*/
static sub_term_fsm_ctx g_sub_term_fsm_sub_term_list_ctx;
/*
* Macros for sub_term ctx access
*/
#define SUB_TERM_FSM_SUB_TERM_LIST_CTX (g_sub_term_fsm_sub_term_list_ctx)
#define SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR (&g_sub_term_fsm_sub_term_list_ctx)
/*
* @brief The definition of a sub_term state processing function
*/
typedef bcmos_errno (* sub_term_fsm_state_processor)(sub_term_inst *, void *, sub_term_fsm_event *);
/*
* @brief The Subscriber Terminal FSM state processing array
*/
static sub_term_fsm_state_processor sub_term_states[SUB_TERM_FSM_STATE__NUM_OF][SUB_TERM_FSM_EVENT_TYPE__NUM_OF] =
{
[SUB_TERM_FSM_STATE_NULL] =
{
/*
* Next state: CONFIGURING
*/
[SUB_TERM_FSM_EVENT_TYPE_ADMIN_UP] = sub_term_fsm_admin_up_start,
/*
* Next state: NULL
*/
[SUB_TERM_FSM_EVENT_TYPE_ADMIN_DN] = sub_term_fsm_admin_dn_ok,
/*
* Next state: NULL
*/
[SUB_TERM_FSM_EVENT_TYPE_UTIL_MSG] = sub_term_fsm_ignore_util_msg,
/*
* Next state: NULL
*/
[SUB_TERM_FSM_EVENT_TYPE_UTIL_AUTO_MSG] = sub_term_fsm_null_process_util_auto_msg,
},
[SUB_TERM_FSM_STATE_CONFIGURING] =
{
/*
* Next state: CONFIGURING
*/
[SUB_TERM_FSM_EVENT_TYPE_ADMIN_UP] = sub_term_fsm_admin_up_error,
/*
* Next state: CONFIGURING
*/
[SUB_TERM_FSM_EVENT_TYPE_ADMIN_DN] = sub_term_fsm_admin_dn_error,
/*
* Next state: REMOVING
*/
[SUB_TERM_FSM_EVENT_TYPE_REMOVE] = sub_term_fsm_removing_start,
/*
* Next state: CONFIGURING | CONFIGURED
*/
[SUB_TERM_FSM_EVENT_TYPE_UTIL_MSG] = sub_term_fsm_configuring_process_util_msg,
/*
* Next state: CONFIGURING
*/
[SUB_TERM_FSM_EVENT_TYPE_UTIL_AUTO_MSG] = sub_term_fsm_configuring_process_util_auto_msg,
},
[SUB_TERM_FSM_STATE_CONFIGURED] =
{
/*
* Next state: CONFIGURED
*/
[SUB_TERM_FSM_EVENT_TYPE_ADMIN_UP] = sub_term_fsm_admin_up_start,
/*
* Next state: CONFIGURING
*/
[SUB_TERM_FSM_EVENT_TYPE_ADMIN_DN] = sub_term_fsm_admin_dn_start,
/*
* Next state: REMOVING
*/
[SUB_TERM_FSM_EVENT_TYPE_REMOVE] = sub_term_fsm_removing_start,
/*
* Next state: CONFIGURING
*/
[SUB_TERM_FSM_EVENT_TYPE_UTIL_MSG] = sub_term_fsm_configured_process_util_msg,
/*
* Next state: CONFIGURED
*/
[SUB_TERM_FSM_EVENT_TYPE_UTIL_AUTO_MSG] = sub_term_fsm_ignore_util_msg,
},
[SUB_TERM_FSM_STATE_REMOVING] =
{
/*
* Next state: REMOVING
*/
[SUB_TERM_FSM_EVENT_TYPE_ADMIN_UP] = sub_term_fsm_admin_up_error,
/*
* Next state: REMOVING
*/
[SUB_TERM_FSM_EVENT_TYPE_ADMIN_DN] = sub_term_fsm_admin_dn_error,
/*
* Next state: REMOVING | NULL
*/
[SUB_TERM_FSM_EVENT_TYPE_UTIL_MSG] = sub_term_fsm_removing_process_util_msg,
/*
* Next state: REMOVING
*/
[SUB_TERM_FSM_EVENT_TYPE_UTIL_AUTO_MSG] = sub_term_fsm_removing_process_util_auto_msg,
},
};
static char *state_name_str[] =
{
"SUB_TERM_FSM_STATE_NULL",
"SUB_TERM_FSM_STATE_CONFIGURING",
"SUB_TERM_FSM_STATE_CONFIGURED",
"SUB_TERM_FSM_STATE_REMOVING",
};
/* Ensure that the name array size matches the associated enum */
BAL_STATIC_ASSERT (SUB_TERM_FSM_STATE__LAST == (sizeof (state_name_str) / sizeof (char *)), sub_term_fsm_state);
static char *sub_term_state_name_get(sub_term_fsm_state state)
{
if(state < SUB_TERM_FSM_STATE__LAST)
{
return state_name_str[state];
}
else
{
return "SUB_TERM_UNKNOWN";
}
}
static char *event_name_str[] =
{
"SUB_TERM_FSM_ADMIN_UP_EVENT",
"SUB_TERM_FSM_ADMIN_DN_EVENT",
"SUB_TERM_FSM_REMOVE_EVENT",
"SUB_TERM_FSM_UTIL_MSG_EVENT",
"SUB_TERM_FSM_UTIL_AUTO_IND_EVENT",
};
/* Ensure that the name array size matches the associated enum */
BAL_STATIC_ASSERT (SUB_TERM_FSM_EVENT_TYPE__LAST == (sizeof (event_name_str) / sizeof (char *)), sub_term_fsm_event_type);
static char *sub_term_event_name_get(sub_term_fsm_event_type event)
{
if(event < SUB_TERM_FSM_EVENT_TYPE__LAST)
{
return event_name_str[event];
}
else
{
return "SUB_TERM_EVT_UNKNOWN";
}
}
/*****************************************************************************/
/**
* @brief A function to initialize the current sub_term_info object of the
* supplied entry.
*
* @param p_entry A pointer to the entry to be initialized
*
*
* @returns void
*****************************************************************************/
static void sub_term_inst_entry_obj_init(sub_term_inst *p_entry)
{
bcmbal_subscriber_terminal_key key = { .sub_term_id = 0, .intf_id = 0 };
BCMBAL_CFG_INIT(&p_entry->current_sub_term_info,
subscriber_terminal,
key);
BCMBAL_CFG_PROP_SET(&p_entry->current_sub_term_info,
subscriber_terminal, admin_state, BCMBAL_STATE_DOWN);
BCMBAL_CFG_PROP_SET(&p_entry->current_sub_term_info,
subscriber_terminal, oper_status, BCMBAL_STATUS_NOT_PRESENT);
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_entry->current_sub_term_info), BCMOS_FALSE);
}
/*****************************************************************************/
/**
* @brief A function called to initialize the subscriber-terminal FSM
* infrastructure.
*
* NOTE: This is called once on startup and NOT for each FSM instance.
*
* @returns void
*****************************************************************************/
bcmos_errno sub_term_fsm_init(void)
{
int ii;
sub_term_inst *new_entry;
bcmos_errno ret = BCM_ERR_OK;
#ifdef ENABLE_LOG
log_id_sub_term = bcm_dev_log_id_register("SUB_TERM", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
BUG_ON(log_id_sub_term == DEV_LOG_INVALID_ID);
#endif
/* Initialize all of the sub_term queues */
TAILQ_INIT(&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->free_sub_term_list);
TAILQ_INIT(&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->active_sub_term_list);
/* Populate the free list with it's set of sub_term instance entries */
for(ii=0; ii<NUM_SUPPORTED_SUB_TERMS; ii++)
{
new_entry = bcmos_calloc(sizeof(sub_term_inst));
if (NULL == new_entry)
{
BCM_LOG(FATAL, log_id_sub_term,
"Failed to initialize the sub_term free list - FATAL\n");
ret = BCM_ERR_NOMEM;
break;
}
/* And add it to the free list */
sub_term_free_by_entry(new_entry);
}
return ret;
}
/*****************************************************************************/
/**
* @brief A function to un-initialize the subscriber-terminal FSM infrastructure.
*
* NOTE: This is called once on shutdown and NOT for each FSM instance.
*
* @returns bcmos_errno
*****************************************************************************/
bcmos_errno sub_term_fsm_finish(void)
{
sub_term_inst *current_entry, *p_temp_entry;
agg_port_id_entry *agg_port_entry;
svc_port_id_entry *svc_port_entry;
/* Free all the entries on the active list */
TAILQ_FOREACH_SAFE(current_entry,
&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->active_sub_term_list,
sub_term_inst_next,
p_temp_entry)
{
/* free the aggregation port list */
TAILQ_FOREACH(agg_port_entry,
&current_entry->agg_port_id_list,
next)
{
bcmos_free(agg_port_entry);
}
/* free the service port list */
TAILQ_FOREACH(svc_port_entry,
&current_entry->svc_port_id_list,
next)
{
bcmos_free(svc_port_entry);
}
/* Remove it from the active list */
TAILQ_REMOVE(&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->active_sub_term_list,
current_entry, sub_term_inst_next);
bcmos_free(current_entry);
}
/* Free all the entries on the free list */
TAILQ_FOREACH_SAFE(current_entry,
&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->free_sub_term_list,
sub_term_inst_next,
p_temp_entry)
{
/* Remove it from the active list */
TAILQ_REMOVE(&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->free_sub_term_list,
current_entry, sub_term_inst_next);
bcmos_free(current_entry);
}
return BCM_ERR_OK;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing executive function
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_exec(sub_term_inst *p_sub_term_inst, sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
sub_term_fsm_state pre_state;
sub_term_fsm_state fsm_state;
sub_term_fsm_state_processor sub_term_state_processor;
/* Parameter checks */
BUG_ON(NULL == p_event);
/* Record the present state for debug printing
*/
pre_state = (NULL == p_sub_term_inst) ? SUB_TERM_FSM_STATE_NULL : p_sub_term_inst->fsm_state;
/*
* Get the state processing function
*/
sub_term_state_processor = sub_term_states[pre_state][p_event->event_type];
/*
* If there's a state processing function for this event and state, execute it.
* Otherwise, process a generic error.
*/
if (sub_term_state_processor)
{
ret = sub_term_state_processor(p_sub_term_inst, p_event->msg, p_event);
} else
{
sub_term_fsm_state_err(p_sub_term_inst, p_event->msg, p_event);
}
/* And get the new state for debug printing */
fsm_state = (NULL == p_sub_term_inst) ? SUB_TERM_FSM_STATE_NULL : p_sub_term_inst->fsm_state;
BCM_LOG(DEBUG, log_id_sub_term,
"*** Event %s, State: %s --> %s\n",
sub_term_event_name_get(p_event->event_type),
sub_term_state_name_get(pre_state), sub_term_state_name_get(fsm_state));
return ret;
}
/*****************************************************************************/
/**
* @brief A function called by the core worker thread to process an
* subscriber-terminal object message (SET, GET, CLEAR, STATS) received
* from the BAL Public API.
*
* @param msg_payload Pointer to a BAL message received from the
* BAL Public API.
*
* @returns bcmos_errno
*****************************************************************************/
bcmos_errno process_subscriber_terminal_object(void *msg_payload)
{
bcmos_errno ret = BCM_ERR_OK;
bcmbal_subscriber_terminal_cfg *p_sub_term_cfg = (bcmbal_subscriber_terminal_cfg *)msg_payload;
sub_term_inst *p_sub_term_inst;
sub_term_fsm_event fsm_event;
bcmbal_subscriber_terminal_key *sub_term_key;
bcmbal_obj_msg_type oper_type;
/* Parameter checks */
BUG_ON(NULL == msg_payload);
BCM_LOG(DEBUG, log_id_sub_term, "Processing a sub_term object\n");
sub_term_key = &p_sub_term_cfg->key;
oper_type = p_sub_term_cfg->hdr.hdr.type;
/*
* A message pointer may be passed inside the event structure.
*/
fsm_event.msg = msg_payload;
/* SET or GET or CLEAR ? */
switch (oper_type)
{
case (BCMBAL_OBJ_MSG_TYPE_SET):
{
bcmos_bool b_generate_event = BCMOS_FALSE;
BCM_LOG(DEBUG, log_id_sub_term, "Processing a sub_term SET REQ mgmt message\n");
/*
* Find or create the specified sub_term instance
*/
p_sub_term_inst = sub_term_inst_get(sub_term_key, SUB_TERM_FLAG_ANY);
do
{
if(NULL == p_sub_term_inst)
{
/* This is a fatal error condition
*/
BCM_LOG(ERROR, log_id_sub_term,
"Specified sub_term not found. No further processing\n");
ret = BCM_ERR_NOMEM;
break;
}
/* If the state of this sub_term is in flux, then reject the SET request */
if(BCMOS_TRUE == BCMBAL_OBJ_IN_PROGRESS_GET(&(p_sub_term_inst->current_sub_term_info)))
{
BCM_LOG(ERROR, log_id_sub_term,
"The subscriber_terminal is in-progress, SETs are not allowed\n");
ret = BCM_ERR_IN_PROGRESS;
break;
}
if(BCM_ERR_OK != (ret = bcmbal_sub_term_tm_scheds_set(p_sub_term_cfg)))
{
BCM_LOG(ERROR, log_id_sub_term,
"could not set subscriber terminal as owner of specified tm scheds\n");
ret = BCM_ERR_PARM;
}
/*
* Fill in the local sub_term instance API request data structure
*/
p_sub_term_inst->api_req_sub_term_info = *p_sub_term_cfg;
BCM_LOG(DEBUG, log_id_sub_term,
"sub_term admin state is: %s\n",
(BCMBAL_STATE_UP == p_sub_term_inst->api_req_sub_term_info.data.admin_state) ? "UP" : "DOWN");
/* If there's no state change, then we're done */
if(p_sub_term_inst->current_sub_term_info.data.admin_state ==
p_sub_term_inst->api_req_sub_term_info.data.admin_state)
{
break;
}
/* For subscriber terminals that have already been configured and then made dormant, merge the
* requested data with the current data, and this is the new request.
*/
if(BCMBAL_STATUS_DOWN == p_sub_term_inst->current_sub_term_info.data.oper_status)
{
bcmbal_sub_term_object_overlay_w_dst_priority(&p_sub_term_inst->api_req_sub_term_info,
&p_sub_term_inst->current_sub_term_info);
}
/*
* Check if the mandatory subscriber terminal attributes have been set, and range check where
* applicable.
*/
/* The admin state attribute is mandatory */
if(BCMOS_FALSE == BCMBAL_CFG_PROP_IS_SET(&p_sub_term_inst->api_req_sub_term_info,
subscriber_terminal,
admin_state))
{
ret = BCM_ERR_MANDATORY_PARM_IS_MISSING;
break;
}
/*
* Perform the validation check(s) that the utils require
*/
if(BCM_ERR_OK !=
(ret = mac_util_subscriber_terminal_info_validate(&p_sub_term_inst->api_req_sub_term_info)))
{
break;
}
}
while(0);
/* We respond to the BAL public API backend with a result. We always
* send a complete msg_payload back to the API, but the data portion
* of the object is only relevant when a GET or GET-STATS has been requested.
*/
mgmt_msg_send_balapi_rsp(ret, msg_payload, oper_type, log_id_sub_term);
if(BCM_ERR_OK != ret)
{
break;
}
/*
* Initial checks complete. Process the request
*/
if((BCMBAL_STATE_UP == p_sub_term_inst->api_req_sub_term_info.data.admin_state)
&& (BCMBAL_STATE_UP != p_sub_term_inst->current_sub_term_info.data.admin_state))
{
BCMBAL_CFG_PROP_SET(&p_sub_term_inst->api_req_sub_term_info,
subscriber_terminal,
svc_port_id,
sub_term_key->sub_term_id);
p_sub_term_inst->api_req_sub_term_info.data.admin_state = BCMBAL_STATE_UP;
/* Set the expected state of the oper_status upon success */
p_sub_term_inst->api_req_sub_term_info.data.oper_status = BCMBAL_STATUS_UP;
fsm_event.event_type = SUB_TERM_FSM_EVENT_TYPE_ADMIN_UP;
b_generate_event = BCMOS_TRUE;
BCM_LOG(INFO, log_id_sub_term,
"***Using GEM %d for subscriber terminal OMCI channel\n",
p_sub_term_inst->api_req_sub_term_info.data.svc_port_id);
}
else if((BCMBAL_STATE_DOWN == p_sub_term_inst->api_req_sub_term_info.data.admin_state)
&& (BCMBAL_STATE_DOWN != p_sub_term_inst->current_sub_term_info.data.admin_state))
{
p_sub_term_inst->current_sub_term_info.data.admin_state = BCMBAL_STATE_DOWN;
/* Set the expected state of the oper_status upon success */
p_sub_term_inst->api_req_sub_term_info.data.oper_status = BCMBAL_STATUS_DOWN;
fsm_event.event_type = SUB_TERM_FSM_EVENT_TYPE_ADMIN_DN;
b_generate_event = BCMOS_TRUE;
}
else
{
/* @todo implement a MODIFY here */
BCM_LOG(INFO, log_id_sub_term, "no state change...done\n");
break; /* no state change detected - do nothing for now */
}
/* If there was an event generated, call the state machine exec */
if(BCMOS_TRUE == b_generate_event)
{
/*
* Run the sub_term FSM to process this event
*/
ret = sub_term_fsm_exec(p_sub_term_inst, &fsm_event);
}
break;
}
case (BCMBAL_OBJ_MSG_TYPE_GET):
{
bcmbal_aggregation_port_id_list_u8 agg_port_id_list = {};
bcmbal_service_port_id_list_u8 svc_port_id_list = {};
BCM_LOG(DEBUG, log_id_sub_term, "Processing a sub_term GET REQ mgmt message\n");
/*
* Just return the sub_term data info that we have on record for
* this sub_term instance
*/
/*
* Find the specified sub_term instance
*/
p_sub_term_inst = sub_term_inst_get(sub_term_key, SUB_TERM_FLAG_ACTIVE);
if(NULL == p_sub_term_inst)
{
/* This is not a fatal error condition
*/
BCM_LOG(ERROR, log_id_sub_term, "Specified sub_term not found on GET\n");
ret = BCM_ERR_NOENT;
}
else
{
do
{
/* Return the agg_port_id list if requested */
BCMBAL_CFG_PROP_CLEAR(&p_sub_term_inst->current_sub_term_info,
subscriber_terminal,
agg_port_id_list);
/* If the user requested the list of agg_port_ids for this subscriber terminal
* then return the list.
*/
if(BCMBAL_CFG_PROP_IS_SET(p_sub_term_cfg,
subscriber_terminal,
agg_port_id_list))
{
if(BCM_ERR_OK == agg_port_id_list_fill(p_sub_term_inst, &agg_port_id_list))
{
/* NOTE: The returned list may be empty */
BCMBAL_CFG_PROP_SET(&p_sub_term_inst->current_sub_term_info,
subscriber_terminal,
agg_port_id_list,
agg_port_id_list);
}
else
{
BCM_LOG(ERROR, log_id_sub_term, "Error trying to fill agg_port list to return\n");
ret = BCM_ERR_INTERNAL;
break;
}
}
/* Return the svc_port_id list if requested */
BCMBAL_CFG_PROP_CLEAR(&p_sub_term_inst->current_sub_term_info,
subscriber_terminal,
svc_port_id_list);
/* If the user requested the list of sub_term_ids for this subscriber terminal,
* then return the list.
*/
if(BCMBAL_CFG_PROP_IS_SET(p_sub_term_cfg,
subscriber_terminal,
svc_port_id_list))
{
if(BCM_ERR_OK == svc_port_id_list_fill(p_sub_term_inst, &svc_port_id_list))
{
/* NOTE: The returned list may be empty */
BCMBAL_CFG_PROP_SET(&p_sub_term_inst->current_sub_term_info,
subscriber_terminal,
svc_port_id_list,
svc_port_id_list);
}
else
{
BCM_LOG(ERROR, log_id_sub_term, "Error trying to fill svc_port list to return\n");
ret = BCM_ERR_INTERNAL;
break;
}
}
}while (0);
/* We respond to the BAL public API backend with a result. We always
* send a complete msg_payload back to the API, but the data portion
* of the object is only relevant when a GET or GET-STATS has been requested.
*/
p_sub_term_inst->current_sub_term_info.hdr.hdr.comm_hdr = ((bcmbal_obj *)msg_payload)->comm_hdr;
*((bcmbal_subscriber_terminal_cfg *)msg_payload) = p_sub_term_inst->current_sub_term_info;
}
mgmt_msg_send_balapi_rsp(ret, msg_payload, oper_type, log_id_sub_term);
/* Free the temporary lists if they were used */
if(svc_port_id_list.val)
{
bcmos_free(svc_port_id_list.val);
}
if(agg_port_id_list.val)
{
bcmos_free(agg_port_id_list.val);
}
break;
}
case (BCMBAL_OBJ_MSG_TYPE_CLEAR):
{
/*
* Find the specified sub_term instance
*/
p_sub_term_inst = sub_term_inst_get(sub_term_key, SUB_TERM_FLAG_ACTIVE);
if(NULL == p_sub_term_inst)
{
/* This is not a fatal error condition
*/
BCM_LOG(ERROR, log_id_sub_term, "Specified sub_term not found on CLEAR\n");
ret = BCM_ERR_NOENT;
}
else
{
/*
* Fill in the local sub_term instance API request data structure
*/
p_sub_term_inst->api_req_sub_term_info = *p_sub_term_cfg;
}
/* We respond to the BAL public API backend with a result.
*/
mgmt_msg_send_balapi_rsp(ret, msg_payload, oper_type, log_id_sub_term);
if(BCM_ERR_OK == ret)
{
fsm_event.event_type = SUB_TERM_FSM_EVENT_TYPE_REMOVE;
/* Run the sub_term FSM to process this event */
ret = sub_term_fsm_exec(p_sub_term_inst, &fsm_event);
}
break;
}
default:
{
BCM_LOG(ERROR, log_id_sub_term,
"Unsupported operation on sub_term object (%d)\n",
bcmbal_msg_id_oper_get(msg_payload) );
ret = BCM_ERR_NOT_SUPPORTED;
/* We respond to the BAL public API backend with a result. We always
* send a complete msg_payload back to the API, but the data portion
* of the object is only relevant when a GET or GET-STATS has been requested.
*/
mgmt_msg_send_balapi_rsp(ret, msg_payload, oper_type, log_id_sub_term);
break;
}
}
return ret;
}
bcmos_errno process_subscriber_terminal_util_msg(void *msg_payload)
{
bcmos_errno ret = BCM_ERR_OK;
sub_term_inst *p_sub_term_inst = NULL;
bcmbal_msg_type type;
sub_term_fsm_event sub_term_event;
bcmbal_subscriber_terminal_key key;
BUG_ON(NULL == msg_payload);
type = bcmbal_type_minor_get(msg_payload);
BCM_LOG(DEBUG, log_id_sub_term,
"Processing a sub_term %s util message from %s\n",
bcmbal_msg_t_str[type],
subsystem_str[bcmbal_sender_get(msg_payload)]);
/* recover the key from the message */
key = ((bal_util_msg_ind *)msg_payload)->obj_key.sub_term_key;
do
{
BCM_LOG(DEBUG, log_id_sub_term, "Got sub_term key id from util (ID%d, PON %d)\n",
key.sub_term_id, key.intf_id);
/* Don't bother to look up the sub_term instance for DISCOVERY messages from the
* mac util where the sub_term_id is unknown. This is a new ONU, so it will not
* be found in the ACTIVE table.
*/
if((BAL_MSG_TYPE_AUTO_IND != (bcmbal_msg_type)type) ||
(BAL_MSG_TYPE_AUTO_IND == (bcmbal_msg_type)type && BCMBAL_SUB_ID_UNKNOWN != key.sub_term_id))
{
/*
* Get the sub_term instance that's being referenced
*/
p_sub_term_inst = sub_term_inst_get(&key, SUB_TERM_FLAG_ACTIVE);
if(NULL == p_sub_term_inst)
{
BCM_LOG(ERROR, log_id_sub_term,
"invalid sub_term (ID%d, PON%d) found while processing a util message type %s from %s\n",
key.sub_term_id,
key.intf_id,
bcmbal_msg_t_str[type],
subsystem_str[bcmbal_sender_get(msg_payload)]);
ret = BCM_ERR_INTERNAL;
break;
}
}
/*
* Record the msg for further processing access
*/
sub_term_event.msg = msg_payload;
if (BAL_MSG_TYPE_IND == type)
{
sub_term_event.event_type = SUB_TERM_FSM_EVENT_TYPE_UTIL_MSG;
}
else if (BAL_MSG_TYPE_AUTO_IND == type)
{
sub_term_event.event_type = SUB_TERM_FSM_EVENT_TYPE_UTIL_AUTO_MSG;
}
else
{
ret = BCM_ERR_NOT_SUPPORTED;
BCM_LOG(ERROR, log_id_sub_term,
"Unknown message type received from the APP (not one of RSP:ACK:IND:AUTO_IND) (type:%d)\n",
type);
}
if (p_sub_term_inst)
{
BCM_LOG(DEBUG, log_id_sub_term, "p_sub_term_inst->fsm_state=%d , sub_term_event.event_type = %d\n",
p_sub_term_inst->fsm_state, sub_term_event.event_type);
}
else
{
if (BAL_MSG_TYPE_IND == type)
{
BCM_LOG(WARNING, log_id_sub_term, "p_sub_term_inst is NULL\n");
}
}
/*
* Run the Sub_Term FSM to process this event
*/
if(BCM_ERR_OK == ret)
{
ret = sub_term_fsm_exec(p_sub_term_inst, &sub_term_event);
}
}
while(0);
return ret;
}
/************************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing for a subscriber-terminal
* admin-up command received from the BAL Public API when the specified
* subscriber-terminal instance is in the admin-down state (i.e. when
* the subscriber-terminal instance FSM is in the NULL or REMOVED state).
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
***********************************************************************************/
static bcmos_errno sub_term_fsm_admin_up_start(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
BCM_LOG(INFO, log_id_sub_term,
"Received a admin UP request from BAL API - bringing up SUB_TERM\n");
/* change subscriber terminal state to CONFIGURING */
p_sub_term_inst->fsm_state = SUB_TERM_FSM_STATE_CONFIGURING;
/*– Core calls Mac Utils to set the subscriber-terminal parameters using the applicable SDK calls */
ret = mac_util_subscriber_terminal_set(p_sub_term_inst, BAL_UTIL_OPER_SUB_TERM_ADD, BCMOS_FALSE);
do
{
/* check for object in wrong state, this is not an actual error */
if(BCM_ERR_STATE == ret)
{
BCM_LOG(INFO, log_id_sub_term,
"mac_util_subscriber_terminal_set() subscriber_terminal could not be activated at this time\n");
}
/* check for errors */
else if(BCM_ERR_OK != ret)
{
BCM_LOG(ERROR, log_id_sub_term,
"Error detected in mac_util_subscriber_terminal_set(): %s\n",
bcmos_strerror(ret));
break;
}
/* The hardware has properly accepted the object info, so the request object becomes
* the current state, except for the oper_status.
*/
bcmbal_sub_term_object_overlay_w_src_priority(&p_sub_term_inst->current_sub_term_info,
&p_sub_term_inst->api_req_sub_term_info);
/* Add this subscriber_terminal to the list of subscriber_terminals associated with it's interface */
bcmbal_interface_sub_term_list_entry_add(p_sub_term_inst->current_sub_term_info.key);
/* Record that this object is in progress */
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_sub_term_inst->current_sub_term_info), BCMOS_TRUE);
} while(0);
/* If there were errors during processing, then report the error to the API */
if(BCM_ERR_OK != ret)
{
mgmt_msg_send_balapi_ind(ret,
msg,
log_id_sub_term);
}
return ret;
}
/*****************************************************************************/
/**
* @brief The subscriber terminal FSM state processing for a subscriber terminal
* admin-up command received from the BAL Public API when the specified
* subscriber terminal FSM is already in the REMOVING state.
*
* @param p_sub_term_inst Pointer to a subscriber terminal instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_admin_up_error(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_STATE;
BCM_LOG(DEBUG, log_id_sub_term,
"Received a admin UP request from BAL API - returning ERROR to the API"
" - no further function\n");
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing for an subscriber-terminal
* admin-down command received from the BAL Public API when the specified
* subscriber-terminal is admin-up (i.e when the specified subscriber-terminal
* instance FSM is in the CONFIGURED state).
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_admin_dn_start(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
BCM_LOG(INFO, log_id_sub_term,
"Received a admin DOWN request from BAL API - bringing down SUB_TERM\n");
/* change subscriber terminal state to CONFIGURING */
p_sub_term_inst->fsm_state = SUB_TERM_FSM_STATE_CONFIGURING;
/*– Core calls Mac Utils to set the subscriber-terminal parameters using the applicable SDK calls */
ret = mac_util_subscriber_terminal_set(p_sub_term_inst, BAL_UTIL_OPER_SUB_TERM_REMOVE, BCMOS_FALSE);
/* check for errors */
if(BCM_ERR_OK != ret)
{
BCM_LOG(ERROR, log_id_sub_term,
"Error detected in mac_util_subscriber_terminal_set(): %s\n",
bcmos_strerror(ret));
/* report the status to the API */
mgmt_msg_send_balapi_ind(ret,
msg,
log_id_sub_term);
}
else
{
/* NOTE: The hardware has properly accepted the object info but we do
* not overwrite the current subscriber terminal data as there is nothing in the request
* that is relevant besides the admin_state. We merely set the object to in_progress.
*/
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_sub_term_inst->current_sub_term_info), BCMOS_TRUE);
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing for an subscriber-terminal
* clear command received from the BAL Public API
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_removing_start(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
BCM_LOG(INFO, log_id_sub_term,
"Received a REMOVE request from BAL API - removing SUB_TERM\n");
/* change subscriber terminal state to REMOVING */
p_sub_term_inst->fsm_state = SUB_TERM_FSM_STATE_REMOVING;
/*– Core calls Mac Utils to set the subscriber-terminal parameters using the applicable SDK calls */
ret = mac_util_subscriber_terminal_set(p_sub_term_inst, BAL_UTIL_OPER_SUB_TERM_CLEAR, BCMOS_FALSE);
/* check for errors */
if(BCM_ERR_OK != ret)
{
BCM_LOG(ERROR, log_id_sub_term,
"Error detected in mac_util_subscriber_terminal_set(): %s\n",
bcmos_strerror(ret));
/* report the error to the API */
mgmt_msg_send_balapi_ind(ret,
msg,
log_id_sub_term);
}
else
{
/* The hardware has properly accepted the object info, so the request object becomes
* the current state, except for the oper_status.
*/
bcmbal_sub_term_object_overlay_w_src_priority(&p_sub_term_inst->current_sub_term_info,
&p_sub_term_inst->api_req_sub_term_info);
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_sub_term_inst->current_sub_term_info), BCMOS_TRUE);
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing for subscriber-terminal
* admin-down command from the BAL Public API when the specified
* subscriber-terminal is already admin-down.
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_admin_dn_ok(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
BCM_LOG(DEBUG, log_id_sub_term,
"Received a admin DOWN request from BAL API - returning OK to the API"
" - no further function\n");
mgmt_msg_send_balapi_ind(ret,
msg,
log_id_sub_term);
return ret;
}
/*****************************************************************************/
/**
* @brief The subscriber terminal FSM state processing for a subscriber terminal
* admin-down command received from the BAL Public API when the specified
* subscriber terminal FSM is already in the REMOVING state.
*
* @param p_sub_term_inst Pointer to a subscriber terminal instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_admin_dn_error(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_STATE;
BCM_LOG(DEBUG, log_id_sub_term,
"Received a admin DOWN request from BAL API - returning ERROR to the API"
" - no further function\n");
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing function to ignore a
* received message.
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_ignore_util_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
BCM_LOG(DEBUG, log_id_sub_term, "Ignoring message from BAL utils\n");
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing function to process an
* AUTO IND message from one of the BAL apps while in the NULL state.
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from one of
* the BAL apps.
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_null_process_util_auto_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
bcmbal_subscriber_terminal_cfg subscriber_terminal_obj;
bcmbal_serial_number serial = {};
bal_util_msg_ind *ind_msg;
/* Process checks */
BUG_ON(NULL == msg);
BUG_ON(NULL == p_event);
ind_msg = (bal_util_msg_ind *)msg;
BCM_LOG(DEBUG, log_id_sub_term, "Received a AUTO IND in the null state\n");
/*
* Set the key in the subscriber_terminal object
*/
BCMBAL_CFG_INIT(&subscriber_terminal_obj, subscriber_terminal, ind_msg->obj_key.sub_term_key);
/*
* Set the serial number in the subscriber_terminal object
*/
memcpy(&serial, ind_msg->data, sizeof(bcmbal_serial_number));
BCMBAL_CFG_PROP_SET(&subscriber_terminal_obj, subscriber_terminal, serial_number, serial);
/* And mark it's status as DOWN */
BCMBAL_CFG_PROP_SET(&subscriber_terminal_obj, subscriber_terminal, oper_status, BCMBAL_STATUS_DOWN);
/*
* Send the indication back to the BAL public API here
*/
mgmt_msg_send_balapi_ind(ret,
(void *)&subscriber_terminal_obj.hdr,
log_id_sub_term);
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing function to process an
* AUTO IND message from one of the BAL apps while in the CONFIGURING state.
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from one of
* the BAL apps.
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_configuring_process_util_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret;
bal_util_msg_ind *ind_msg;
/* Parameter checks */
BUG_ON(NULL == p_sub_term_inst);
BUG_ON(NULL == msg);
BUG_ON(NULL == p_event);
ind_msg = (bal_util_msg_ind *)msg;
/*
* NOTE: AUTO_IND messages are not processed in this function,
* so there is no need to consider them in this logic.
*/
BCM_LOG(DEBUG, log_id_sub_term,
" Received a IND message from BAL UTIL (%s) during CONFIGURING state\n",
subsystem_str[bcmbal_sender_get(msg)]);
/* Handle response */
ret = ind_msg->status;
if(BCM_ERR_OK == ret)
{
/* If this indication is for a subscriber terminal that has been ADDED and is ADMIN_UP,
* OR for a subscriber terminal that has been REMOVED and is ADMIN_DOWN
* then complete the state transition.
*/
if((BAL_UTIL_OPER_SUB_TERM_ADD == bcmbal_msg_id_oper_get(msg) &&
BCMBAL_STATE_UP == p_sub_term_inst->current_sub_term_info.data.admin_state) ||
(BAL_UTIL_OPER_SUB_TERM_REMOVE == bcmbal_msg_id_oper_get(msg) &&
BCMBAL_STATE_DOWN == p_sub_term_inst->current_sub_term_info.data.admin_state))
{
if (bcm_topo_pon_get_pon_family(p_sub_term_inst->current_sub_term_info.key.intf_id) == BCM_TOPO_PON_FAMILY_EPON)
{
uint16_t tunnel_id;
/* Recover the tunnel_id from the indication message */
memcpy(&tunnel_id, ind_msg->data, sizeof(tunnel_id));
/* And store it in the sub_term instance, to be used by the switch */
p_sub_term_inst->current_sub_term_info.data.svc_port_id = tunnel_id;
}
p_sub_term_inst->current_sub_term_info.data.oper_status =
p_sub_term_inst->api_req_sub_term_info.data.oper_status;
/*
* The subscriber terminal has been successfully configured
*/
p_sub_term_inst->fsm_state = SUB_TERM_FSM_STATE_CONFIGURED;
}
}
else
{
/* Error */
BCM_LOG(ERROR, log_id_sub_term,
"Failed in state %s;%s\n",
sub_term_state_name_get(p_sub_term_inst->fsm_state),
bcmos_strerror(ret));
}
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_sub_term_inst->current_sub_term_info), BCMOS_FALSE);
/*
* Send the indication back to the BAL public API here
*/
mgmt_msg_send_balapi_ind(ret,
(void *)&p_sub_term_inst->current_sub_term_info.hdr,
log_id_sub_term);
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing function to process an
* IND message from one of the BAL apps while in the CONFIGURED state.
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from one of
* the BAL apps.
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_configured_process_util_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
/* Process checks */
BUG_ON(NULL == p_sub_term_inst);
BUG_ON(NULL == msg);
BUG_ON(NULL == p_event);
BCM_LOG(DEBUG, log_id_sub_term,
" Received a IND message from BAL UTIL (%s) during CONFIGURED state\n",
subsystem_str[bcmbal_sender_get(msg)]);
if((BAL_UTIL_OPER_SUB_TERM_REMOVE != bcmbal_msg_id_oper_get(msg)) &&
(BAL_UTIL_OPER_SUB_TERM_CLEAR != bcmbal_msg_id_oper_get(msg)))
{
BCM_LOG(ERROR, log_id_sub_term,
"Received an unrecognized IND (%u) received in the configured state"
"- no further function\n", bcmbal_msg_id_oper_get(msg));
}
else
{
/* change subscriber terminal state to CONFIGURING */
p_sub_term_inst->fsm_state = SUB_TERM_FSM_STATE_CONFIGURING;
/* Set the oper_status upon success */
p_sub_term_inst->current_sub_term_info.data.oper_status = BCMBAL_STATUS_NOT_PRESENT;
/*
* Send the indication back to the BAL public API here
*/
mgmt_msg_send_balapi_ind(ret,
&p_sub_term_inst->current_sub_term_info.hdr,
log_id_sub_term);
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing function to process an
* AUTO IND message from one of the BAL apps while in the CONFIGURED state.
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from one of
* the BAL apps.
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_configuring_process_util_auto_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
/* Process checks */
BUG_ON(NULL == p_sub_term_inst);
BUG_ON(NULL == msg);
BUG_ON(NULL == p_event);
BCM_LOG(DEBUG, log_id_sub_term,
" Received a AUTO IND message from BAL UTIL (%s) during CONFIGURING state\n",
subsystem_str[bcmbal_sender_get(msg)]);
if(BAL_UTIL_OPER_SUB_TERM_DISCOVERY != bcmbal_msg_id_oper_get(msg))
{
BCM_LOG(ERROR, log_id_sub_term,
"Received an unrecognized AUTO IND in the configuring state"
"- no further function\n");
}
else
{
/*– Core calls Mac Utils to set the subscriber-terminal parameters using the applicable SDK calls */
/* send TRUE in last argument to indicate the request is after a ONU Discovery */
ret = mac_util_subscriber_terminal_set(p_sub_term_inst, BAL_UTIL_OPER_SUB_TERM_ADD, BCMOS_TRUE);
}
/* If there were errors during processing, then report the error to the API */
if(BCM_ERR_OK != ret)
{
mgmt_msg_send_balapi_ind(ret,
(void *)&p_sub_term_inst->current_sub_term_info.hdr,
log_id_sub_term);
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing function to process a
* message from one of the BAL apps while in the REMOVING state.
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from one of
* the BAL apps.
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_removing_process_util_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret;
bal_util_msg_ind *ind_msg;
/* Parameter checks */
BUG_ON(NULL == p_sub_term_inst);
BUG_ON(NULL == msg);
BUG_ON(NULL == p_event);
ind_msg = (bal_util_msg_ind *)msg;
/*
* NOTE: AUTO_IND messages are not processed in this function,
* so there is no need to consider them in this logic.
*/
/* Handle indication */
ret = ind_msg->status;
BCM_LOG(INFO, log_id_sub_term,
"Received a %s message from BAL APP (%s) during REMOVING state\n",
(BAL_MSG_TYPE_IND == bcmbal_type_minor_get(msg)) ? "IND" : "RSP",
subsystem_str[bcmbal_sender_get(msg)]);
if(BCM_ERR_OK == ret)
{
/* Set the admin_state and oper_status to be DOWN and NOT_PRESENT respectively,
* since we are clearing this object anyway. These parameters are set in the free function,
* but they need to be set here for the indication below to be correct */
p_sub_term_inst->current_sub_term_info.data.admin_state = BCMBAL_STATE_DOWN;
p_sub_term_inst->current_sub_term_info.data.oper_status = BCMBAL_STATUS_NOT_PRESENT;
}
if(BCM_ERR_OK == ret)
{
/* Remove this subscriber_terminal from the list of subscriber_terminals associated with it's interface */
bcmbal_interface_sub_term_list_entry_remove(p_sub_term_inst->current_sub_term_info.key);
/*
* Send the success indication back to the BAL public API here
*/
mgmt_msg_send_balapi_ind(ret,
&p_sub_term_inst->current_sub_term_info.hdr,
log_id_sub_term);
/* Return the subscriber terminal to the free pool */
sub_term_free_by_entry(p_sub_term_inst);
BCM_LOG(DEBUG, log_id_sub_term, "sub term freed\n");
}
else
{
p_sub_term_inst->fsm_state = SUB_TERM_FSM_STATE_CONFIGURED;
/*
* Send the failure indication back to the BAL public API here
*/
mgmt_msg_send_balapi_ind(ret,
&p_sub_term_inst->current_sub_term_info.hdr,
log_id_sub_term);
BCM_LOG(ERROR, log_id_sub_term,
"Error encountered in REMOVING state (status is %s)\n",
bcmos_strerror(ret));
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM state processing function to process an
* AUTO IND message from one of the BAL apps while in the REMOVING state.
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from one of
* the BAL apps.
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_removing_process_util_auto_msg(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
/* Parameter checks */
BUG_ON(NULL == p_sub_term_inst);
BUG_ON(NULL == msg);
BUG_ON(NULL == p_event);
BCM_LOG(DEBUG, log_id_sub_term,
"Received a AUTO IND in the removing state"
" - no further function\n");
return ret;
}
/*****************************************************************************/
/**
* @brief The Subscriber terminal FSM function which is executed when an error
* is encountered during FSM processing.
*
* @param p_sub_term_inst Pointer to an subscriber terminal instance
* @param msg Pointer to a BAL message received from one of
* the BAL apps
* @param p_event Pointer to an subscriber terminal event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_fsm_state_err(sub_term_inst *p_sub_term_inst,
void *msg,
sub_term_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_INVALID_OP;
BCM_LOG(ERROR, log_id_sub_term,
"Error encountered processing SUB_TERM FSM - BAD EVENT ()\n");
return ret;
}
/*
* Helper functions
*/
/*****************************************************************************/
/**
* @brief A function to retrieve a subscriber-terminal instance of the specified
* class.
*
* @param key A pointer to the key of the subscriber-terminal being
* referenced
* @param search_flag A flag specifying the type of subscriber-terminal
* instance to be retrieved
*
* @returns sub_term_inst_t* A pointer to the found subscriber-terminal instance,
* or NULL if one is not found
*****************************************************************************/
sub_term_inst *sub_term_inst_get(bcmbal_subscriber_terminal_key *key,
sub_term_flag search_flag)
{
sub_term_inst *current_entry = NULL;
sub_term_inst *p_temp_entry;
/*
* First, check the active list
*/
TAILQ_FOREACH(current_entry,
&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->active_sub_term_list,
sub_term_inst_next)
{
if((current_entry->api_req_sub_term_info.key.sub_term_id == key->sub_term_id) &&
(current_entry->api_req_sub_term_info.key.intf_id == key->intf_id))
{
/* The sub_term instance pointer is in current_entry */
break;
}
}
if((SUB_TERM_FLAG_ANY == search_flag) && (NULL == current_entry))
{
/* Now check the free list */
TAILQ_FOREACH_SAFE(current_entry,
&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->free_sub_term_list,
sub_term_inst_next,
p_temp_entry)
{
/* Remove it from the free list */
TAILQ_REMOVE(&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->free_sub_term_list,
current_entry, sub_term_inst_next);
/* And add it to the active list */
TAILQ_INSERT_TAIL(&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->active_sub_term_list,
current_entry, sub_term_inst_next);
/*
* Initialize the sub_term data
*/
current_entry->fsm_state = SUB_TERM_FSM_STATE_NULL;
break;
}
}
if(NULL == current_entry)
{
/*
* A sub_term was not found on either list*/
BCM_LOG(DEBUG, log_id_sub_term, "no sub_term found\n");
}
return current_entry;
}
bcmos_errno sub_term_svc_port_id_get(bcmbal_sub_id sub_term_id,
uint16_t access_int_id,
bcmbal_service_port_id *p_svc_port_id)
{
sub_term_inst *p_sub_term_inst;
bcmbal_subscriber_terminal_key sub_term_key;
bcmos_errno ret = BCM_ERR_OK;
BUG_ON(NULL == p_svc_port_id);
/* Create the key to find the subscriber terminal instance being referenced */
sub_term_key.sub_term_id = sub_term_id;
sub_term_key.intf_id = access_int_id;
if(NULL == (p_sub_term_inst = sub_term_inst_get(&sub_term_key, SUB_TERM_FLAG_ACTIVE)))
{
BCM_LOG(ERROR, log_id_sub_term, "Specified sub_term (sub:%d on int:%d) not found\n",
sub_term_id, access_int_id);
ret = BCM_ERR_NOENT;
}
else
{
*p_svc_port_id = p_sub_term_inst->current_sub_term_info.data.svc_port_id;
}
return ret;
}
/*****************************************************************************/
/**
* @brief A function to free a subscriber terminal instance specified
* by a the supplied entry pointer.
*
* @param p_entry A pointer to the entry to be freed
*
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno sub_term_free_by_entry(sub_term_inst *p_entry)
{
bcmos_errno ret = BCM_ERR_OK;
sub_term_inst *current_entry;
sub_term_inst *p_temp_entry;
BUG_ON(NULL == p_entry);
/*
* First, check the active list (an active sub_term can be in the adding or removing state)
*/
TAILQ_FOREACH_SAFE(current_entry,
&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->active_sub_term_list,
sub_term_inst_next,
p_temp_entry)
{
if(current_entry == p_entry)
{
/* Remove it from the active list */
TAILQ_REMOVE(&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->active_sub_term_list,
current_entry, sub_term_inst_next);
}
}
/* Initialize the svc_port_id and agg_port_id lists */
p_entry->num_svc_port_ids = 0;
TAILQ_INIT(&p_entry->svc_port_id_list);
p_entry->num_agg_port_ids = 0;
TAILQ_INIT(&p_entry->agg_port_id_list);
/* And add the entry to the free list */
p_entry->fsm_state = SUB_TERM_FSM_STATE_NULL;
/* And initialize the current object in the sub_term instance */
sub_term_inst_entry_obj_init(p_entry);
TAILQ_INSERT_TAIL(&SUB_TERM_FSM_SUB_TERM_LIST_CTX_PTR->free_sub_term_list,
p_entry, sub_term_inst_next);
return ret;
}
bcmos_errno bcmbal_sub_term_svc_port_id_list_entry_add(sub_term_inst *p_sub_term_inst,
bcmbal_service_port_id svc_port_id)
{
bcmos_errno ret = BCM_ERR_OK;
svc_port_id_entry *current_entry;
do
{
if(NULL == p_sub_term_inst)
{
BCM_LOG(ERROR, log_id_sub_term,
"attempting to add a svc_port_id (%u) entry "
"to NULL subscriber terminal\n",
svc_port_id);
ret = BCM_ERR_NOENT;
break;
}
/* Check if the id is already on the list before adding it */
TAILQ_FOREACH(current_entry,
&p_sub_term_inst->svc_port_id_list,
next)
{
if(current_entry->svc_port_id == svc_port_id)
{
ret = BCM_ERR_ALREADY;
break;
}
}
if(BCM_ERR_OK == ret)
{
/* Get a new entry and configure it */
current_entry = bcmos_calloc(sizeof(svc_port_id_entry));
if (NULL == current_entry)
{
BCM_LOG(ERROR, log_id_sub_term,
"No memory available\n");
ret = BCM_ERR_NOMEM;
break;
}
current_entry->svc_port_id = svc_port_id;
/* Save the entry on the list of subscriber-terminal ids on this interface */
TAILQ_INSERT_TAIL(&p_sub_term_inst->svc_port_id_list,
current_entry, next);
(p_sub_term_inst->num_svc_port_ids)++;
}
current_entry->ref_count++;
} while (0);
return ret;
}
bcmos_errno bcmbal_sub_term_svc_port_id_list_entry_remove(sub_term_inst *p_sub_term_inst,
bcmbal_service_port_id svc_port_id)
{
bcmos_errno ret = BCM_ERR_NOENT;
svc_port_id_entry *current_entry, *p_temp_entry;
do
{
if(NULL == p_sub_term_inst)
{
BCM_LOG(ERROR, log_id_sub_term,
"attempting to remove a svc_port_id (%u) entry "
"from a NULL subscriber terminal\n",
svc_port_id);
ret = BCM_ERR_NOENT;
break;
}
/* Check if the id is on the list */
TAILQ_FOREACH_SAFE(current_entry,
&p_sub_term_inst->svc_port_id_list,
next,
p_temp_entry)
{
if(current_entry->svc_port_id == svc_port_id)
{
if(0 == --current_entry->ref_count)
{
/* Remove it from the list of agg_port_ids on this subscriber terminal */
TAILQ_REMOVE(&p_sub_term_inst->svc_port_id_list,
current_entry, next);
bcmos_free(current_entry);
(p_sub_term_inst->num_svc_port_ids)--;
}
ret = BCM_ERR_OK;
break;
}
}
} while (0);
return ret;
}
bcmos_errno bcmbal_sub_term_agg_port_id_list_entry_add( sub_term_inst *p_sub_term_inst,
bcmbal_aggregation_port_id agg_port_id)
{
bcmos_errno ret = BCM_ERR_OK;
agg_port_id_entry *current_entry;
do
{
if(NULL == p_sub_term_inst)
{
BCM_LOG(ERROR, log_id_sub_term,
"attempting to add a svc_port_id (%u) entry "
"to a NULL subscriber terminal\n",
agg_port_id);
ret = BCM_ERR_NOENT;
break;
}
/* Check if the id is already on the list before adding it */
TAILQ_FOREACH(current_entry,
&p_sub_term_inst->agg_port_id_list,
next)
{
if(current_entry->agg_port_id == agg_port_id)
{
ret = BCM_ERR_ALREADY;
break;
}
}
if(BCM_ERR_OK == ret)
{
/* Get a new entry and configure it */
current_entry = bcmos_calloc(sizeof(agg_port_id_entry));
if (NULL == current_entry)
{
BCM_LOG(ERROR, log_id_sub_term,
"No memory available\n");
ret = BCM_ERR_NOMEM;
break;
}
current_entry->agg_port_id = agg_port_id;
/* Save the entry on the list of subscriber-terminal ids on this interface */
TAILQ_INSERT_TAIL(&p_sub_term_inst->agg_port_id_list,
current_entry, next);
(p_sub_term_inst->num_agg_port_ids)++;
}
(current_entry->ref_count)++;
} while (0);
return ret;
}
bcmos_errno bcmbal_sub_term_agg_port_id_list_entry_remove(sub_term_inst *p_sub_term_inst,
bcmbal_aggregation_port_id agg_port_id)
{
bcmos_errno ret = BCM_ERR_NOENT;
agg_port_id_entry *current_entry, *p_temp_entry;
do
{
if(NULL == p_sub_term_inst)
{
BCM_LOG(ERROR, log_id_sub_term,
"attempting to remove a agg_port_id (%u) entry "
"from a NULL subscriber terminal\n",
agg_port_id);
ret = BCM_ERR_NOENT;
break;
}
/* Check if the id is on the list */
TAILQ_FOREACH_SAFE(current_entry,
&p_sub_term_inst->agg_port_id_list,
next,
p_temp_entry)
{
if(current_entry->agg_port_id == agg_port_id)
{
if(0 == --current_entry->ref_count)
{
/* Remove it from the list of agg_port_ids on this subscriber terminal */
TAILQ_REMOVE(&p_sub_term_inst->agg_port_id_list,
current_entry, next);
bcmos_free(current_entry);
(p_sub_term_inst->num_agg_port_ids)--;
}
ret = BCM_ERR_OK;
break;
}
}
} while (0);
return ret;
}
static bcmos_errno svc_port_id_list_fill(sub_term_inst *p_sub_term_inst,
bcmbal_service_port_id_list_u8 *svc_port_id_list)
{
bcmos_errno ret = BCM_ERR_OK;
svc_port_id_entry *current_entry = NULL;
int ii = 0;
do
{
/* Traverse the list of svc_port_ids recorded and fill in the list to be returned */
svc_port_id_list->len = p_sub_term_inst->num_svc_port_ids;
svc_port_id_list->val = bcmos_calloc(sizeof(bcmbal_service_port_id) * svc_port_id_list->len);
if (NULL == svc_port_id_list->val)
{
BCM_LOG(ERROR, log_id_sub_term,
"No memory available\n");
ret = BCM_ERR_NOMEM;
break;
}
TAILQ_FOREACH(current_entry,
&p_sub_term_inst->svc_port_id_list,
next)
{
svc_port_id_list->val[ii++] = current_entry->svc_port_id;
}
} while (0);
return ret;
}
static bcmos_errno agg_port_id_list_fill(sub_term_inst *p_sub_term_inst,
bcmbal_aggregation_port_id_list_u8 *agg_port_id_list)
{
bcmos_errno ret = BCM_ERR_OK;
agg_port_id_entry *current_entry = NULL;
int ii = 0;
do
{
/* Traverse the list of svc_port_ids recorded and fill in the list to be returned */
agg_port_id_list->len = p_sub_term_inst->num_agg_port_ids;
agg_port_id_list->val = bcmos_calloc(sizeof(bcmbal_aggregation_port_id) * agg_port_id_list->len);
if (NULL == agg_port_id_list->val)
{
BCM_LOG(ERROR, log_id_sub_term,
"No memory available\n");
ret = BCM_ERR_NOMEM;
break;
}
TAILQ_FOREACH(current_entry,
&p_sub_term_inst->agg_port_id_list,
next)
{
agg_port_id_list->val[ii++] = current_entry->agg_port_id;
}
} while (0);
return ret;
}
bcmos_errno bcmbal_sub_term_check_svc_port_in_use(sub_term_inst *p_sub_term_inst,
bcmbal_service_port_id svc_port_id)
{
bcmos_errno ret = BCM_ERR_NOENT;
svc_port_id_entry *current_entry = NULL;
do
{
if(NULL == p_sub_term_inst)
{
BCM_LOG(ERROR, log_id_sub_term,
"NULL subscriber terminal\n");
break;
}
/* Check if the id is on the list */
TAILQ_FOREACH(current_entry,
&p_sub_term_inst->svc_port_id_list,
next)
{
if(current_entry->svc_port_id == svc_port_id)
{
ret = BCM_ERR_OK;
break;
}
}
} while (0);
return ret;
}
bcmos_errno bcmbal_sub_term_check_agg_port_in_use(sub_term_inst *p_sub_term_inst,
bcmbal_aggregation_port_id agg_port_id)
{
bcmos_errno ret = BCM_ERR_NOENT;
agg_port_id_entry *current_entry = NULL;
do
{
if(NULL == p_sub_term_inst)
{
BCM_LOG(ERROR, log_id_sub_term,
"NULL subscriber terminal\n");
break;
}
/* Check if the id is on the list */
TAILQ_FOREACH(current_entry,
&p_sub_term_inst->agg_port_id_list,
next)
{
if(current_entry->agg_port_id == agg_port_id)
{
ret = BCM_ERR_OK;
break;
}
}
} while (0);
return ret;
}
static bcmos_errno bcmbal_sub_term_tm_scheds_set(const bcmbal_subscriber_terminal_cfg *p_sub_term_cfg)
{
bcmos_errno ret = BCM_ERR_OK;
bcmbal_tm_sched_key tm_sched_key;
do
{
if(BCMBAL_CFG_PROP_IS_SET(p_sub_term_cfg, subscriber_terminal, us_tm))
{
tm_sched_key.dir = BCMBAL_TM_SCHED_DIR_US;
tm_sched_key.id = p_sub_term_cfg->data.us_tm;
if(BCM_ERR_OK!= (ret = bcmbal_tm_sched_set_sub_term_owner(tm_sched_key, p_sub_term_cfg)))
{
BCM_LOG(ERROR, log_id_sub_term,
"failed to set sub term us_tm, ret = %s", bcmos_strerror(ret));
break;
}
}
if(BCMBAL_CFG_PROP_IS_SET(p_sub_term_cfg, subscriber_terminal, ds_tm))
{
tm_sched_key.dir = BCMBAL_TM_SCHED_DIR_DS;
tm_sched_key.id = p_sub_term_cfg->data.ds_tm;
if(BCM_ERR_OK!= (ret = bcmbal_tm_sched_set_sub_term_owner(tm_sched_key, p_sub_term_cfg)))
{
BCM_LOG(ERROR, log_id_sub_term,
"failed to set sub term ds_tm, ret = %s", bcmos_strerror(ret));
break;
}
}
}while(0);
return ret;
}
/*@}*/