BAL and Maple Release 2.2
Signed-off-by: Shad Ansari <developer@Carbon.local>
diff --git a/bal_release/src/lib/libbalapi/Makefile b/bal_release/src/lib/libbalapi/Makefile
new file mode 100644
index 0000000..79fea84
--- /dev/null
+++ b/bal_release/src/lib/libbalapi/Makefile
@@ -0,0 +1,38 @@
+###############################################################################
+#
+# <: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.
+#
+# :>
+#
+###############################################################################
+MOD_NAME = bal_api
+MOD_TYPE = lib
+MOD_DEPS = common_include dev_log maple_sdk balobjmsg
+ifeq ("$(BAL_MONOLITHIC)", "y")
+MOD_DEPS += bal_core
+endif
+
+srcs = bal_api.c bal_api_worker.c
diff --git a/bal_release/src/lib/libbalapi/bal_api.c b/bal_release/src/lib/libbalapi/bal_api.c
new file mode 100644
index 0000000..4374fd2
--- /dev/null
+++ b/bal_release/src/lib/libbalapi/bal_api.c
@@ -0,0 +1,658 @@
+/******************************************************************************
+ *
+ * <: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 bal_api.c
+ * @brief The BAL Public API
+ *
+ * @addtogroup api
+ */
+
+/*@{*/
+
+/* Project includes */
+#include "bal_api.h"
+#include "bal_msg.h"
+#include "bal_api_worker.h"
+#include "bal_obj_msg_pack_unpack.h"
+#ifdef BAL_MONOLITHIC
+#include <bal_worker.h>
+#endif
+
+#ifdef ENABLE_LOG
+#include <bcm_dev_log.h>
+
+/*
+ * @brief The logging device id for the BAL public API
+ */
+dev_log_id log_id_public_api;
+#endif
+
+/*
+ * @brief The global mgmt queues
+ *
+ * These are the queues through which the BAL API communicates with
+ * the core, and vice versa.
+ */
+static bcmos_msg_queue balapi_rsp_queue;
+static bcmos_msg_queue balapi_to_core_queue;
+
+bcmos_msg_queue *p_balapi_rsp_queue;
+bcmos_msg_queue *p_balapi_to_core_queue;
+
+static bcmos_mutex balapi_lock;
+static uint32_t balapi_exchange_id;
+static STAILQ_HEAD(pending_req_list, bcmos_msg) pending_req_list;
+
+static bcmos_task api_rsp_rx_thread;
+static int _bal_ipc_api_rx_handler(long data);
+
+/* Rx polling timeout (us) */
+#define BAL_API_RX_POLL_TIMEOUT 100000
+
+/*****************************************************************************
+ * Initialize the BAL Public API internal data structures
+ *****************************************************************************/
+bcmos_errno bcmbal_api_init(const char *balapi_mgmt_ip_port,
+ const char *core_mgmt_ip_port)
+{
+ bcmos_errno ret = BCM_ERR_OK;
+ bcmos_msg_queue_parm msg_q_p = {};
+ bcmos_task_parm task_p = {};
+
+#ifdef ENABLE_LOG
+ log_id_public_api = bcm_dev_log_id_register("BAL_API", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
+ BUG_ON(log_id_public_api == DEV_LOG_INVALID_ID);
+#endif
+
+ do
+ {
+ STAILQ_INIT(&pending_req_list);
+
+ ret = bcmos_mutex_create(&balapi_lock, 0, "bal_api");
+ if (BCM_ERR_OK != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API protection mutex\n");
+ break;
+ }
+
+ /* Create BAL API RX management queue - the BAL Public API
+ * exchanges management messages with the BAL core using this queue.
+ */
+ msg_q_p.name = "balapi_mgmt_q";
+ if (NULL != balapi_mgmt_ip_port)
+ {
+ msg_q_p.local_ep_address = balapi_mgmt_ip_port;
+ msg_q_p.remote_ep_address = NULL;
+ msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_UDP_SOCKET;
+ }
+ else
+ {
+ msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_LOCAL;
+ }
+ ret = bcmos_msg_queue_create(&balapi_rsp_queue, &msg_q_p);
+ if (BCM_ERR_OK != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API mgmt queue\n");
+ ret = BCM_ERR_INTERNAL;
+ break;
+ }
+ p_balapi_rsp_queue = &balapi_rsp_queue;
+#ifdef BAL_MONOLITHIC
+ if (NULL == balapi_mgmt_ip_port)
+ p_bal_core_to_api_queue = p_balapi_rsp_queue;
+#endif
+
+ /* Create queue for sending API requests to the core. Only do it if API and core interact via UDP
+ */
+ if (NULL != core_mgmt_ip_port)
+ {
+ msg_q_p.name = "balapi_to_core_q";
+ msg_q_p.local_ep_address = NULL;
+ msg_q_p.remote_ep_address = core_mgmt_ip_port;
+ msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_UDP_SOCKET;
+
+ ret = bcmos_msg_queue_create(&balapi_to_core_queue, &msg_q_p);
+ if (BCM_ERR_OK != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API mgmt queue\n");
+ ret = BCM_ERR_INTERNAL;
+ break;
+ }
+ p_balapi_to_core_queue = &balapi_to_core_queue;
+ }
+
+ /* Create BAL API RX thread */
+ task_p.name = "ipc_api_rsp_rx_thread";
+ task_p.priority = TASK_PRIORITY_IPC_RX;
+ task_p.handler = _bal_ipc_api_rx_handler;
+ task_p.data = (long)p_balapi_rsp_queue;
+
+ ret = bcmos_task_create(&api_rsp_rx_thread, &task_p);
+ if (ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API response RX thread\n");
+ break;
+ }
+
+ /*
+ * Initialize the BAL Public API backend worker and rx threads. These
+ * threads are used to receive asynchronous indications from the core.
+ */
+ enable_bal_api_indications(balapi_mgmt_ip_port);
+
+ }
+ while(0);
+
+ return ret;
+}
+
+/*****************************************************************************
+ * Un-initialize the BAL Public API internal data structures
+ *****************************************************************************/
+bcmos_errno bcmbal_api_finish(void)
+{
+ bcmos_task_destroy(&api_rsp_rx_thread);
+ bcmos_msg_queue_destroy(&balapi_rsp_queue);
+ if (p_balapi_to_core_queue == &balapi_to_core_queue)
+ bcmos_msg_queue_destroy(&balapi_to_core_queue);
+
+ bal_api_indications_finish();
+
+ return BCM_ERR_OK;
+}
+
+/* Find pending request matching response */
+static bal_comm_msg_hdr *_bal_api_get_request_by_ex_id(uint32_t ex_id)
+{
+ bcmos_msg *req_msg, *tmp_msg;
+ bal_comm_msg_hdr *comm_hdr = NULL;
+
+ STAILQ_FOREACH_SAFE(req_msg, &pending_req_list, next, tmp_msg)
+ {
+ comm_hdr = bcmbal_bal_hdr_get_by_bcmos_hdr(req_msg);
+ if (comm_hdr->ex_id == ex_id)
+ {
+ STAILQ_REMOVE(&pending_req_list, req_msg, bcmos_msg, next);
+ break;
+ }
+ }
+ return req_msg ? comm_hdr : NULL;
+}
+
+/* Check if any pending request timed out */
+static void _bal_api_check_req_timeout(void)
+{
+ bcmos_msg *req_msg, *tmp_msg;
+ bal_comm_msg_hdr *comm_hdr;
+ bcmbal_obj *req_obj;
+ uint32_t ts = bcmos_timestamp();
+
+ STAILQ_FOREACH_SAFE(req_msg, &pending_req_list, next, tmp_msg)
+ {
+ comm_hdr = bcmbal_bal_hdr_get_by_bcmos_hdr(req_msg);
+ if (ts - comm_hdr->timestamp >= BCMBAL_MSG_TIMEOUT_1_SEC)
+ {
+ STAILQ_REMOVE(&pending_req_list, req_msg, bcmos_msg, next);
+ req_obj = (bcmbal_obj *)bcmbal_payload_ptr_get(comm_hdr);
+ /* Release pending API call */
+ req_obj->status = BCM_ERR_TIMEOUT;
+ BCM_LOG(DEBUG, log_id_public_api, "Timing out request %p\n", comm_hdr);
+ bcmos_sem_post(&comm_hdr->sem);
+ }
+ }
+}
+
+/* API response handler */
+static int _bal_ipc_api_rx_handler(long data)
+{
+ static uint32_t last_timeout_check_ts;
+ bcmos_msg_queue *rxq = (bcmos_msg_queue *)data;
+ bcmos_task *my_task = bcmos_task_current();
+ bcmos_msg *msg;
+ bcmos_errno ret = BCM_ERR_OK;
+ uint32_t ex_id;
+ bal_comm_msg_hdr *req;
+ bcmbal_obj *req_obj;
+
+ last_timeout_check_ts = bcmos_timestamp();
+ while (!my_task->destroy_request)
+ {
+ /* Wait for response */
+ msg = NULL;
+ req = NULL;
+
+ ret = bcmos_msg_recv(rxq, BAL_API_RX_POLL_TIMEOUT, &msg);
+ if(BCM_ERR_OK != ret && BCM_ERR_TIMEOUT != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api,
+ "error during bcmos_msg_recv (error:%s)\n", bcmos_strerror(ret));
+ }
+
+ /* Peek exchange id */
+ if (msg)
+ {
+ ret = bcmbal_bal_msg_peek_ex_id(msg, &ex_id);
+ if(BCM_ERR_OK != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api,
+ "bad message. Can't find exchange id (error:%s)\n", bcmos_strerror(ret));
+ bcmos_msg_free(msg);
+ msg = NULL;
+ }
+ else
+ {
+ BCM_LOG(DEBUG, log_id_public_api, "Received message with ex_id=%u\n", ex_id);
+ }
+ }
+
+ /* Now find pending request and also check if any pending request(s) timed out */
+ bcmos_mutex_lock(&balapi_lock);
+ if (msg)
+ {
+ req = _bal_api_get_request_by_ex_id(ex_id);
+ if (NULL == req)
+ {
+ BCM_LOG(ERROR, log_id_public_api,
+ "Request with ex_id=%u is not found. Probably expired. Response discarded\n", ex_id);
+ }
+ else
+ {
+ BCM_LOG(DEBUG, log_id_public_api, "Found request %p\n", req);
+ }
+ }
+ if (bcmos_timestamp() - last_timeout_check_ts >= BCMBAL_MSG_TIMEOUT_1_SEC)
+ {
+ _bal_api_check_req_timeout();
+ last_timeout_check_ts = bcmos_timestamp();
+ }
+ bcmos_mutex_unlock(&balapi_lock);
+
+ /* Got a message. Now unpack it */
+ if (req)
+ {
+ req_obj = (bcmbal_obj *)bcmbal_payload_ptr_get(req);
+ ret = bcmbal_obj_msg_unpack(msg, &req);
+ if (BCM_ERR_OK != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Error during message unpack: %s\n", bcmos_strerror(ret));
+ req_obj->status = ret;
+ }
+ /* Release pending API */
+ BCM_LOG(DEBUG, log_id_public_api, "Posting request semaphore for %p\n", req);
+ bcmos_sem_post(&req->sem);
+ }
+
+ if (msg)
+ bcmos_msg_free(msg); /* release packed message. It is no longer needed */
+ }
+
+ my_task->destroyed = BCMOS_TRUE;
+
+ return (BCM_ERR_OK == ret) ? 0 : -EINVAL;
+}
+
+static bcmbal_mgmt_oper_id _bcmbal_obj_to_oper_id(const bcmbal_obj *objinfo)
+{
+ if (objinfo->group == BCMBAL_MGT_GROUP_STAT)
+ {
+ return BCMBAL_MGMT_OPER_ID_GET_STATS;
+ }
+ else if ((objinfo->type & BCMBAL_OBJ_MSG_TYPE_GET))
+ {
+ return BCMBAL_MGMT_OPER_ID_GET;
+ }
+ else if ((objinfo->type & BCMBAL_OBJ_MSG_TYPE_CLEAR))
+ {
+ return BCMBAL_MGMT_OPER_ID_CLEAR;
+ }
+ else
+ {
+ return BCMBAL_MGMT_OPER_ID_SET;
+ }
+}
+
+#define BALAPI_OPER_TIMEOUT (30000000) /* 30 seconds */
+
+static bcmos_errno _bcmbal_oper(bcmbal_obj *objinfo)
+{
+ bal_comm_msg_hdr *comm_hdr = bcmbal_bal_hdr_get(objinfo);
+ bcmos_msg *os_msg;
+ bcmos_errno ret = BCM_ERR_OK;
+
+ /*
+ * Send the message to the core for processing
+ */
+
+ /* Parameter checks */
+ BUG_ON(NULL == objinfo);
+
+ /* Check the magic number to be sure that the object has been properly initialized */
+ if(BCMBAL_OBJ_INIT_VAL != objinfo->obj_init_val)
+ {
+ BCM_LOG(ERROR, log_id_public_api,
+ "Object has not been initialized: must use a BCMBAL INIT macro on the object before calling the BAL API\n");
+ return BCM_ERR_PARM;
+ }
+
+ ret = bcmos_sem_create(&comm_hdr->sem, 0, 0, "api_req");
+ if (ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Can't create semaphore: %s\n", bcmos_strerror(ret));
+ /* return here. We don't want to destroy semaphore that wasn't created */
+ return ret;
+ }
+
+ do
+ {
+ bcmbal_msg_hdr_set(objinfo,
+ BCMBAL_MGMT_MSG,
+ BAL_MSG_TYPE_REQ,
+ BAL_SUBSYSTEM_PUBLIC_API,
+ objinfo->obj_type,
+ _bcmbal_obj_to_oper_id(objinfo),
+ 0);
+
+ BCM_LOG(DEBUG, log_id_public_api, "about to send %p\n", objinfo);
+
+ bcmos_mutex_lock(&balapi_lock);
+ bcmbal_ex_id_set(objinfo, ++balapi_exchange_id);
+ os_msg = bcmbal_bcmos_hdr_get(objinfo);
+ STAILQ_INSERT_TAIL(&pending_req_list, os_msg, next);
+ bcmos_mutex_unlock(&balapi_lock);
+
+ if (BCM_ERR_OK != (ret = bcmbal_msg_send(p_balapi_to_core_queue, objinfo, BCMOS_MSG_SEND_NO_FREE_ON_ERROR)))
+ {
+ BCM_LOG(ERROR, log_id_public_api, "message send failed with error: %s\n", bcmos_strerror(ret));
+ break;
+ }
+ BCM_LOG(DEBUG, log_id_public_api, "REQ message sent to core\n");
+
+ /*
+ * We've sent the message to the core, now, wait for the response (or timeout)
+ */
+ ret = bcmos_sem_wait(&comm_hdr->sem, BALAPI_OPER_TIMEOUT);
+ if (BCM_ERR_OK != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "rsp message receive for failed with error: %s\n",
+ bcmos_strerror(ret));
+ break;
+ }
+ BCM_LOG(DEBUG, log_id_public_api, "RSP message received from core\n");
+
+ if (BCM_ERR_OK != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "failed to process rsp msg\n");
+ break;
+ }
+
+ if(BCM_ERR_OK != objinfo->status)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "remote message command status is: %s\n",
+ bcmos_strerror(objinfo->status));
+ }
+
+ /*
+ * Pass the command status received from the core back to the caller
+ */
+ ret = objinfo->status;
+ }
+ while(0);
+
+ bcmos_sem_destroy(&comm_hdr->sem);
+
+ return ret;
+}
+
+/*****************************************************************************
+ * BAL Public API Set (or modify) command.
+ *****************************************************************************/
+bcmos_errno bcmbal_cfg_set(bcmbal_cfg *objinfo)
+{
+ bcmos_errno ret = BCM_ERR_OK;
+
+ BCM_LOG(INFO, log_id_public_api, "BAL PUBLIC API - BCMBAL_SET\n");
+
+ if(BCMBAL_OBJ_ID_PACKET == objinfo->hdr.obj_type)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "unsupported object id detected %d\n", objinfo->hdr.obj_type);
+ ret = BCM_ERR_NOT_SUPPORTED;
+
+ }
+ else
+ {
+ objinfo->hdr.type = BCMBAL_OBJ_MSG_TYPE_SET;
+ ret = _bcmbal_oper(&objinfo->hdr);
+ }
+
+ return ret;
+}
+
+#define BCMBAL_MAX_PROXY_PACKET_SIZE (1600)
+
+/*****************************************************************************
+ * BAL Public API Packet Send function.
+ *****************************************************************************/
+bcmos_errno bcmbal_pkt_send(bcmbal_dest dest,
+ const char *packet_to_send,
+ uint16_t packet_len)
+{
+ /* Convert the user packet into a BAL object */
+ bcmbal_packet_cfg *p_packet_obj;
+ bcmbal_packet_key key;
+ bcmbal_u8_list_u32 pkt;
+ bcmos_errno ret;
+
+ BCM_LOG(INFO, log_id_public_api, "BAL PUBLIC API - BCMBAL_SEND to %s\n",
+ (BCMBAL_DEST_TYPE_NNI == dest.type) ? "NNI" : "SUB-TERM");
+
+ if(BCMBAL_MAX_PROXY_PACKET_SIZE < packet_len)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "user packet length (%d) cannot be greater than %d\n",
+ packet_len,
+ BCMBAL_MAX_PROXY_PACKET_SIZE);
+
+ return BCM_ERR_PARM;
+ }
+
+ BCM_LOG(INFO, log_id_public_api, "user packet first 8 bytes %02X%02X%02X%02X%02X%02X%02X%02X\n",
+ packet_to_send[0], packet_to_send[1], packet_to_send[2], packet_to_send[3],
+ packet_to_send[4], packet_to_send[5], packet_to_send[6], packet_to_send[7]);
+
+ /* Set up the object key */
+ key.packet_send_dest = dest;
+
+ /* Allocate room for the packet object including the user packet */
+ p_packet_obj = bcmos_calloc(sizeof(bcmbal_packet_cfg) + packet_len);
+
+ BCMBAL_CFG_INIT(p_packet_obj, packet, key);
+
+ /* Now fill in user packet data into the object */
+ pkt.len = packet_len;
+ pkt.val = (uint8_t *)&p_packet_obj[1];
+ memcpy(pkt.val, packet_to_send, packet_len);
+
+ BCMBAL_CFG_PROP_SET(p_packet_obj, packet, pkt, pkt);
+
+ p_packet_obj->hdr.hdr.type = BCMBAL_OBJ_MSG_TYPE_SET; /* internally packet SEND is modeled as a config SET */
+ ret = _bcmbal_oper(&(p_packet_obj->hdr.hdr));
+ bcmos_free(p_packet_obj);
+
+ return ret;
+}
+
+/*****************************************************************************
+ * BAL Public API Get command.
+ *****************************************************************************/
+bcmos_errno bcmbal_cfg_get(bcmbal_cfg *objinfo)
+{
+ bcmos_errno ret = BCM_ERR_OK;
+
+ BCM_LOG(DEBUG, log_id_public_api, "BAL PUBLIC API - BCMBAL_GET\n");
+
+ if(BCMBAL_OBJ_ID_PACKET == objinfo->hdr.obj_type)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "unsupported object id detected %d\n", objinfo->hdr.obj_type);
+ ret = BCM_ERR_NOT_SUPPORTED;
+
+ }
+ else
+ {
+ objinfo->hdr.type = BCMBAL_OBJ_MSG_TYPE_GET;
+ ret = _bcmbal_oper(&(objinfo->hdr));
+ }
+
+ return ret;
+}
+
+/*****************************************************************************
+ * BAL Public API Clear command.
+ *****************************************************************************/
+bcmos_errno bcmbal_cfg_clear(bcmbal_cfg *objinfo)
+{
+ bcmos_errno ret = BCM_ERR_OK;
+
+ BCM_LOG(INFO, log_id_public_api, "BAL PUBLIC API - BCMBAL_CLEAR\n");
+
+ if(BCMBAL_OBJ_ID_PACKET == objinfo->hdr.obj_type)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "unsupported object id detected %d\n", objinfo->hdr.obj_type);
+ ret = BCM_ERR_NOT_SUPPORTED;
+
+ }
+ else
+ {
+ objinfo->hdr.type = BCMBAL_OBJ_MSG_TYPE_CLEAR;
+ ret = _bcmbal_oper(&objinfo->hdr);
+ }
+
+ return ret;
+}
+
+/*****************************************************************************
+ * @brief BAL Public API Get Stats command.
+ *****************************************************************************/
+bcmos_errno bcmbal_stat_get(bcmbal_stat *objinfo)
+{
+
+ /* Parameter checks */
+ BUG_ON(NULL == objinfo);
+
+ /*
+ * @todo Finish the stats function
+ */
+
+ BCM_LOG(ERROR, log_id_public_api, "bal get stats API not supported\n");
+
+ return BCM_ERR_NOT_SUPPORTED;
+}
+
+/*****************************************************************************
+ * BAL Public API indication subscription.
+ *****************************************************************************/
+bcmos_errno bcmbal_subscribe_ind(bcmbal_cb_cfg *cb_cfg)
+{
+
+ bcmos_errno ret = BCM_ERR_OK;
+
+ /*
+ * The indication subscription function
+ */
+ BCM_LOG(DEBUG, log_id_public_api, "BAL indication subscription for type: %s (%d)\n",
+ bcmbal_objtype_str(cb_cfg->obj_type), cb_cfg->obj_type);
+
+ ret = _manage_api_ind_listener(IND_CB_SUBSCRIBE, cb_cfg);
+
+ return ret;
+}
+
+/*****************************************************************************
+ * BAL Public API indication un-subscription.
+ *****************************************************************************/
+bcmos_errno bcmbal_unsubscribe_ind(bcmbal_cb_cfg *cb_cfg)
+{
+
+ bcmos_errno ret = BCM_ERR_OK;
+
+ BUG_ON(NULL == cb_cfg);
+
+ /*
+ * The indication subscription function
+ */
+ BCM_LOG(DEBUG, log_id_public_api, "BAL indication un-subscription for type: %s (%d)\n",
+ bcmbal_objtype_str(cb_cfg->obj_type), cb_cfg->obj_type);
+
+ ret = _manage_api_ind_listener(IND_CB_UNSUBSCRIBE, cb_cfg);
+
+ return ret;
+}
+
+/*****************************************************************************/
+/**
+ * @brief A function to get the string representation of the interface type
+ *
+ * @param int_type The interface type to get
+ *
+ * @returns const char * A pointer to a string containing the interface type,
+ * or "INVALID", if not a valid type.
+ *
+ *****************************************************************************/
+const char *bcmbal_get_interface_type_str(bcmbal_intf_type int_type)
+{
+ const char *type_str;
+
+ switch (int_type)
+ {
+ case(BCMBAL_INTF_TYPE_PON):
+ {
+ type_str = "pon";
+ }
+ break;
+
+ case(BCMBAL_INTF_TYPE_NNI):
+ {
+ type_str = "nni";
+ }
+ break;
+
+ default:
+ {
+ type_str = "INVALID";
+ }
+ break;
+
+ }
+
+ return type_str;
+}
+
+
+/*@}*/
diff --git a/bal_release/src/lib/libbalapi/bal_api.dox b/bal_release/src/lib/libbalapi/bal_api.dox
new file mode 100644
index 0000000..f8db011
--- /dev/null
+++ b/bal_release/src/lib/libbalapi/bal_api.dox
@@ -0,0 +1,108 @@
+/*
+ * BAL Programmers Guide - introduction
+ */
+
+/** \mainpage BAL Public Interface Concept
+
+\section intro Introduction
+This document describes the BAL user interface. The user interface is constructed from a
+small set of public APIs and an objects model.
+
+The objects model is designed to manage different entities in the system, and enables a simple and intuitive
+approach for managing line card.
+
+The API layer is designed to enable the management of line card containing muultiple MAC and SWITCH devices
+and support any host application architecture. It includes a set of APIs to access the line card configuration and
+asynchronous indications to send events to the host application.
+
+The API layer is part of the Broadcom® BAL SDK, which is provided as C source code, which is
+independent of the CPU and operating system being used.
+
+\section object_model_table BAL Object Model
+
+The system is modeled as a set of managed objects. The term “object” here doesn’t imply any inheritance, it
+means an entity that can be addressed individually and has a set of properties (attributes) and methods
+(operations), for example, access_terminal, flow, etc.
+
+Each object can have multiple properties (aka attributes), whereas a property is an object parameter that can be set or
+retrieved independently.
+ - A property is a simple type or a structure containing one or more fields, where fields can themselves be
+structures
+ - Each property has a specific permission type, such as Read-Only (RO) and Read-Write (RW).
+
+Object properties are grouped into sections/management groups. The following sections can contain zero or
+more properties:
+ - Key—Field(s) that uniquely identify the object instance (for example, subscriber_terminal key = {subs_id, intf_id}).
+ - Configuration
+ - Read-Write, Read-Only and Write-Only configuration properties
+ - Statistics
+ - Performance monitoring counters
+ - Debug counters
+ - Autonomous Indications
+ - Notifications that are generated asynchronously.
+ Indications can be either autonomous (such as alarms) or asynchronous responses to previously
+ submitted configuration change (for instance, subscriber_terminal admin_state=up request).
+
+\section object_model_prop Object and Properties Implementation
+
+\subsection object_model_structs Object Structures
+
+The main input parameter of all the APIs is an object structure, referred to as the Object Request Message. Each
+object section has a different structure that includes a generic header, object key, and a specific section structure
+according to the section type (for example, configuration, statics, etc).
+ - Generic header: A basic component of all the different section structures is the object generic header
+ \ref bcmbal_obj
+
+ - The configuration structure bcmbal_xx_cfg contains:
+ - The generic header \ref bcmbal_cfg
+ - The object key, if any
+ - The structure bcmbal_xx_cfg_data, containing all object configuration properties
+
+ - This statistics structure bcmbal_xx_stat contains:
+ - The generic header \ref bcmbal_stat
+ - The object key, if any
+ - The structure bcmbal_xx_stat_data, containing all the object statistics
+
+ - The per-autonomous indication structure bcmbal_xx_auto_yy contains:
+ - The generic header \ref bcmbal_auto
+ - The autonomous message ID is stored in the subgroup field.
+ - The object key, if any
+ - The structure bcmbal_xx_auto_yy_data, containing all indication properties, if any
+
+\subsection object_model_init_macros Structure Initialization Macros
+The following macros are used for initializing objects:
+ - \ref BCMBAL_CFG_INIT(cfg_msg, _object, _key)
+ - \ref BCMBAL_STAT_INIT(stat_msg, _object, _key)
+
+The macros perform the following tasks:
+ - Check that the structure matches the object section.
+ - Clear all control fields in the generic header \ref bcmbal_obj.
+
+\subsection object_model_prop_macros Property Presence Mask Manipulation Macros
+The presence mask indicates which of the properties in the object structure need to be accessed (set/get, etc.)
+The mask is a bit field, wherein each bit corresponds to a specific property. The following macros should be used
+for setting the presence mask:
+
+ - Set configuration parameter value:\n
+ \ref BCMBAL_CFG_PROP_SET(_msg, _object, _parm_name, _parm_value)
+ - Indicate that the property should be fetched by a bcmolt_cfg_get() request:\n
+ \ref BCMBAL_CFG_PROP_GET(_msg, _object, _parm_name)
+ - Indicate that the statistic should be fetched by a bcmolt_stat_get() request:\n
+ \ref BCMBAL_STAT_PROP_GET(_msg, _object, _parm_name)
+
+\subsection object_model_enums Enumerations
+In the following descriptions, XX is the object name and YY is the property name from the XML model.
+
+The system model includes the enumerations:
+ - The bcmbal_obj_id enumeration lists all objects. It includes per-object BCMBAL_OBJ_ID_XX constants,
+ where XX is the object name from the XML model.
+ - The bcmbal_xx_cfg_id enumeration lists all XX objects' properties from the “Configuration” section in the
+ XML model. It includes the BCMBAL_XX_CFG_ID_YY constants.
+ - The bcmbal_xx_stat_id enumeration lists all XX object's properties from the “Statistics” section in the XML
+ model. It includes the BCMBAL_XX_STAT_ID_YY constants.
+ - The bcmbal_xx_auto_id enumeration lists all XX object's indications from the “Autonomous Indications”
+ section in the XML model. It includes the BCMBAL_XX_AUTO_ID_YY constants.
+
+\section api_section BAL Public API
+ See \ref api in API Reference chapter
+*/
diff --git a/bal_release/src/lib/libbalapi/bal_api.h b/bal_release/src/lib/libbalapi/bal_api.h
new file mode 100644
index 0000000..60f1e0b
--- /dev/null
+++ b/bal_release/src/lib/libbalapi/bal_api.h
@@ -0,0 +1,286 @@
+/******************************************************************************
+ *
+ * <: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 bal_api.h
+ * @brief Function declarations and all inclusions required for the BAL Public API
+ *
+ * @defgroup api BAL Public API
+ */
+#ifndef BCMBAL_API_H
+#define BCMBAL_API_H
+
+#include <bcmos_system.h>
+#include <bcmolt_model_types.h>
+
+#include <bal_objs.h>
+
+
+/*@{*/
+
+/*
+ * This example only controls the default access terminal
+ */
+#define DEFAULT_ATERM_ID (0)
+
+/* Max number of access-terminals supported by BAL */
+#define MAX_ACC_TERM_ID (255)
+
+/*------------------------------------------------
+ * See the bal_objs.h file for the BAL objects
+ *------------------------------------------------
+ */
+
+/*
+ * An enumeration of the BAL mgmt operations
+ */
+typedef enum
+{
+ BCMBAL_MGMT_OPER_ID_SET = 1 << 0,
+ BCMBAL_MGMT_OPER_ID_GET = 1 << 1,
+ BCMBAL_MGMT_OPER_ID_GET_STATS = 1 << 2,
+ BCMBAL_MGMT_OPER_ID_CLEAR = 1 << 3,
+ BCMBAL_MGMT_OPER_ID__NUM_OF = 1 << 4,
+ BCMBAL_MGMT_OPER_ID_ALL = BCMBAL_MGMT_OPER_ID__NUM_OF - 1,
+} bcmbal_mgmt_oper_id;
+
+
+/* access_terminal:key:acc_term_id max value */
+#define BAL_API_MAX_ACC_TERM_ID (255)
+
+/* flow:key:flow_id max value */
+#define BAL_API_MAX_FLOW_ID (65535)
+
+/* interface:mtu limits */
+#define BAL_API_MIN_INTF_MTU_SIZE (64)
+#define BAL_API_MAX_INTF_MTU_SIZE (9216)
+
+/* Max number of interfaces per interface:type in BAL */
+#define BAL_API_MAX_INTF_ID (15)
+
+/* Max sub_term_id per interface for the various modes */
+#define BAL_API_MAX_SUB_TERM_ID_GPON (127)
+#define BAL_API_MAX_SUB_TERM_ID_EPON (256)
+#define BAL_API_MAX_SUB_TERM_ID_XGPON (511)
+
+/* Max and min values for interface attributes */
+#define BAL_API_MIN_LOW_DATA_AGG_PORT_ID (256)
+#define BAL_API_MAX_LOW_DATA_AGG_PORT_ID (14591)
+
+#define BAL_API_MIN_LOW_DATA_SVC_PORT_ID (1024)
+#define BAL_API_MAX_LOW_DATA_SVC_PORT_ID (57598)
+
+
+/* Max and Min values for agg_port_id and svc_port_id */
+#define BAL_API_MIN_DATA_SVC_PORT_ID (256)
+#define BAL_API_MAX_DATA_SVC_PORT_ID (16383)
+
+/* Max and Min values for agg_port_id and svc_port_id */
+#define BAL_API_MIN_DATA_AGG_PORT_ID (256)
+#define BAL_API_MAX_DATA_AGG_PORT_ID (16383)
+
+/* Max value for pbits */
+#define MAX_PBITS_VALUE (7)
+
+/*
+ * BAL CLI max values
+ */
+/** Max number of supported OLTs */
+#define MAX_SUPPORTED_OLTS (BAL_API_MAX_ACC_TERM_ID+1)
+
+/** Max number of supported subscriber terminals (ONUs) */
+#define MAX_SUPPORTED_SUBS (BAL_API_MAX_SUB_TERM_ID_XGPON+1)
+
+/** Max number of supported flows */
+#define MAX_SUPPORTED_FLOWS (BAL_API_MAX_FLOW_ID+1)
+
+/** Max number of supported PON and NNI interfaces */
+#define MAX_SUPPORTED_INTF (BAL_API_MAX_INTF_ID+1)
+
+/** BAL Indication callback handler function prototype */
+typedef void (*f_bcmbal_ind_handler)(bcmbal_obj *obj);
+
+/** BAL Indication callback registration parameters */
+typedef struct bcmbal_cb_cfg
+{
+ bcmbal_obj_id obj_type; /**< Object type */
+ f_bcmbal_ind_handler ind_cb_hdlr; /**< Indication callback function. NULL=unregister */
+ bcmos_module_id module; /**< Target module id.
+ If it is BCMOS_MODULE_ID_NONE (0), the callback will be called
+ in BAL's context. Otherwise, it will be called in application
+ module's context */
+} bcmbal_cb_cfg; /* This structure is used for passing the mgmt queue
+
+ * IP:port information between the core main thread and
+ * core worker thread and bal API.
+ */
+typedef struct mgmt_queue_addr_ports
+{
+ const char *core_mgmt_ip_port;
+ const char *balapi_mgmt_ip_port;
+} mgmt_queue_addr_ports;
+
+extern dev_log_id log_id_public_api;
+
+const char *bcmbal_get_interface_type_str(bcmbal_intf_type int_type);
+
+/*
+ *------------------------------------------------------------------------------------------
+ *
+ * @brief The BAL Public API
+ *
+ *------------------------------------------------------------------------------------------
+ */
+
+/**
+ * @brief Initialize the BAL Public API internal data structures
+ *
+ * @param balapi_mgmt_ip_port The IP:port of the BAL API management queue
+ *
+ * @param core_mgmt_ip_port The IP:port of the core management queue
+ *
+ * @returns bcmos_errno
+ *
+ **/
+bcmos_errno bcmbal_api_init(const char *balapi_mgmt_ip_port, const char *core_mgmt_ip_port);
+
+/**
+ * @brief Un-initialize the BAL Public API internal data structures
+ *
+ * @returns bcmos_errno == BCM_ERR_OK
+ *
+ **/
+bcmos_errno bcmbal_api_finish(void);
+
+/**
+ * @brief BAL Public API Set (or modify) command.
+ *
+ * Set (or modify) the specified object instance (with implicit creation
+ * of dynamic objects) associated with the specified access-terminal device.
+ *
+ * @param objinfo A pointer to a BAL object
+ *
+ * @returns bcmos_errno
+ *
+ **/
+bcmos_errno bcmbal_cfg_set(bcmbal_cfg *objinfo);
+
+/**
+ * @brief BAL Public API Get command.
+ *
+ * Get the specified object instance
+ *
+ * @param objinfo A pointer to a BAL object
+ *
+ * @returns bcmos_errno
+ *
+ */
+bcmos_errno bcmbal_cfg_get(bcmbal_cfg *objinfo);
+
+/**
+ * @brief BAL Public API Packet Send function.
+ *
+ * Send a packet to the specified destination
+ *
+ * @param dest The destination of the user packet
+ *
+ * @param packet_to_send A pointer to the user packet to send to the specified destination
+ *
+ * @param packet_len The length of the user packet (must be <=1600 bytes)
+ *
+ * @returns bcmos_errno
+ *
+ */
+bcmos_errno bcmbal_pkt_send(bcmbal_dest dest,
+ const char *packet_to_send,
+ uint16_t packet_len);
+
+/**
+ * @brief BAL Public API Clear command.
+ *
+ * Set all attributes to default (or remove the object instance for
+ * dynamic objects) for the specified object instance
+ *
+ * @param objinfo A pointer to a BAL object
+ *
+ * @returns bcmos_errno
+ *
+ */
+bcmos_errno bcmbal_cfg_clear(bcmbal_cfg * objinfo);
+
+/**
+ * @brief BAL Public API Get Stats command.
+ *
+ * Get (and clear) the stats associated with specified object instance
+ *
+ * @param objinfo A pointer to a BAL object
+ *
+ * @returns bcmos_errno
+ *
+ */
+bcmos_errno bcmbal_stat_get(bcmbal_stat *objinfo);
+
+/**
+ * @brief BAL Public API indication subscription.
+ *
+ * Subscription function for the specified indications
+ *
+ * @param cb_cfg A pointer to the callback configuration parameters for the
+ * object indications being subscribed to.
+ *
+ * @returns bcmos_errno
+ *
+ */
+bcmos_errno bcmbal_subscribe_ind(bcmbal_cb_cfg *cb_cfg);
+
+/**
+ * @brief BAL Public API indication un-subscription.
+ *
+ * Un-subscription function for the specified (or all) indications
+ *
+ * @param cb_cfg A pointer to the callback configuration parameters for the
+ * object indications being un-subscribed from.
+ *
+ * @returns bcmos_errno
+ *
+ */
+bcmos_errno bcmbal_unsubscribe_ind(bcmbal_cb_cfg *cb_cfg);
+
+/**
+ * @brief Get the number of NNI ports supported by the running system
+ *
+ * @returns Number of NNI ports
+ */
+uint16_t bcmbal_num_nni_ports_get(void);
+
+/*@}*/
+
+#endif /* BCMBAL_API_H */
diff --git a/bal_release/src/lib/libbalapi/bal_api_worker.c b/bal_release/src/lib/libbalapi/bal_api_worker.c
new file mode 100644
index 0000000..178060c
--- /dev/null
+++ b/bal_release/src/lib/libbalapi/bal_api_worker.c
@@ -0,0 +1,513 @@
+/******************************************************************************
+ *
+ * <: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 bal_api_worker.c
+ * @brief Main processing loop for the worker thread that handles INDications
+ * sent from the core to the BAL public API
+ *
+ */
+
+/*
+ * We need access to the BAL subsystem names
+ */
+#define BAL_SUBSYSTEM_STR_REQ
+
+#include <bcmos_system.h>
+#include <bal_msg.h>
+#include <bal_obj_msg_pack_unpack.h>
+#include <bal_osmsg.h>
+#include <bal_api.h>
+#include "bal_api_worker.h"
+#ifdef BAL_MONOLITHIC
+#include <bal_worker.h>
+#endif
+#ifdef ENABLE_LOG
+#include <bcm_dev_log.h>
+#endif
+
+/* This rx thread and worker thread are used to process indications from the core
+ */
+static bcmos_task api_ind_rx_thread;
+static bcmos_task api_ind_worker_thread;
+
+/* Local function declarations */
+static int _bal_ipc_api_ind_rx_handler(long data);
+static void bal_ipc_api_indication_handler(bcmos_module_id module_id, bcmos_msg *msg);
+
+
+typedef struct indication_subscription_inst indication_subscription_inst;
+struct indication_subscription_inst
+{
+ bcmbal_cb_cfg cb_cfg;
+ /**< TAILQ link for list management */
+ TAILQ_ENTRY(indication_subscription_inst) indication_subscription_inst_next;
+};
+
+TAILQ_HEAD(indication_subscription_list_head, indication_subscription_inst) indication_subscription_list;
+
+/*
+ * The queue through which the core converses with
+ * the backend of the Public API for indications.
+ */
+static bcmos_msg_queue bal_api_ind_backend_queue;
+bcmos_msg_queue *p_bal_api_ind_queue;
+
+/* Create API backend message queue */
+bcmos_errno bal_api_ind_msg_queue_create(mgmt_queue_addr_ports *mgmt_queue_info)
+{
+ bcmos_msg_queue_parm msg_q_p = {};
+ bcmos_errno ret = BCM_ERR_OK;
+
+ do
+ {
+ /* Create BAL API indication receive queue - the core sends IND messages
+ * to the BAL public API using this queue.
+ */
+ msg_q_p.name = "api_ind_rx_q";
+
+ if (NULL != mgmt_queue_info->balapi_mgmt_ip_port)
+ {
+ uint16_t portnum;
+ char *p_ind_portnum_str;
+ char balapi_ind_port_str[256];
+
+ /*
+ * make a copy of the user chosen bal api mgmt port
+ */
+ strcpy(balapi_ind_port_str, mgmt_queue_info->balapi_mgmt_ip_port);
+
+ /* Find the port number */
+ p_ind_portnum_str = strchr(balapi_ind_port_str, ':') + 1;
+
+ /* convert to an integer and increment it by one */
+ portnum = atoi(p_ind_portnum_str) + 1;
+
+ /* create the new string defining the BAL API indication port */
+ sprintf(p_ind_portnum_str,"%d", portnum);
+
+ /* Set up the BAL API indication IP:port access parameter
+ */
+ msg_q_p.local_ep_address = balapi_ind_port_str;
+ msg_q_p.remote_ep_address = NULL;
+ msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_UDP_SOCKET;
+ }
+ else
+ {
+ msg_q_p.ep_type = BCMOS_MSG_QUEUE_EP_LOCAL;
+ }
+
+ ret = bcmos_msg_queue_create(&bal_api_ind_backend_queue, &msg_q_p);
+ if (BCM_ERR_OK != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Couldn't BAL API rx indication queue\n");
+ break;
+ }
+
+ p_bal_api_ind_queue = &bal_api_ind_backend_queue;
+#ifdef BAL_MONOLITHIC
+ if (NULL == mgmt_queue_info->balapi_mgmt_ip_port)
+ p_bal_core_to_api_ind_queue = p_bal_api_ind_queue;
+#endif
+ } while (0);
+
+ return ret;
+}
+
+/* Worker module init function.
+ * Register for messages this module is expected to receive
+ */
+static bcmos_errno _bal_worker_module_bal_api_init(long data)
+{
+ bcmos_task_parm task_p = {};
+ bcmos_errno ret = BCM_ERR_OK;
+
+ BUG_ON(0 == data);
+
+ do
+ {
+ /* Create BAL API indication RX thread */
+ task_p.name = "ipc_api_ind_rx_thread";
+ task_p.priority = TASK_PRIORITY_IPC_RX;
+ task_p.handler = _bal_ipc_api_ind_rx_handler;
+ task_p.data = (long)&bal_api_ind_backend_queue;
+
+ ret = bcmos_task_create(&api_ind_rx_thread, &task_p);
+ if (ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API indication RX thread\n");
+ break;
+ }
+
+ /* Register the message types to be handled by the mgmt module
+ */
+ bcmos_msg_register(BCMBAL_MGMT_API_IND_MSG,
+ 0,
+ BCMOS_MODULE_ID_WORKER_API_IND, bal_ipc_api_indication_handler);
+
+ }
+ while(0);
+
+ return ret;
+}
+
+static int _bal_ipc_api_ind_rx_handler(long data)
+{
+ bcmos_msg_queue *rxq = (bcmos_msg_queue *)data;
+ bcmos_task *my_task = bcmos_task_current();
+ bcmos_msg *msg;
+ bcmos_errno ret = BCM_ERR_OK;
+ void *payload;
+
+ while (!my_task->destroy_request)
+ {
+ payload = NULL;
+ ret = bcmbal_msg_recv(rxq, BCMOS_WAIT_FOREVER, &payload);
+ if (ret)
+ {
+ /* Unexpected failure */
+ BCM_LOG(ERROR, log_id_public_api, "bcmbal_msg_recv() -> %s\n", bcmos_strerror(ret));
+ continue;
+ }
+
+ /* Message received */
+ BCM_LOG(DEBUG, log_id_public_api, "bcmbal_msg_recv(%p) -> %s\n", payload, bcmos_strerror(ret));
+
+ /*
+ * Got a message, so now dispatch it. This will result in one
+ * of the modules (registered for the message being processed)
+ * executing its message callback handler.
+ */
+ msg = bcmbal_bcmos_hdr_get(payload);
+ ret = bcmos_msg_dispatch(msg, BCMOS_MSG_SEND_AUTO_FREE);
+ if (ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api,
+ "Couldn't dispatch message %d:%d\n",
+ (int)msg->type, (int)msg->instance);
+ }
+ }
+
+ my_task->destroyed = BCMOS_TRUE;
+
+ return (BCM_ERR_OK == ret) ? 0 : -EINVAL;
+}
+
+
+/* Message wrapper that is called when indication is delivered in application module's context */
+static void _int_deliver_wrapper_cb(bcmos_module_id module_id, bcmos_msg *msg)
+{
+ void *msg_payload = bcmbal_payload_ptr_get(bcmbal_bal_hdr_get_by_bcmos_hdr(msg));
+ f_bcmbal_ind_handler handler = (f_bcmbal_ind_handler)bcmbal_scratchpad_get(msg_payload);
+
+ handler((bcmbal_obj *)msg_payload);
+ bcmbal_msg_free((bcmbal_obj *)msg_payload);
+}
+
+static void process_listener_callbacks(bcmbal_obj *obj)
+{
+
+ indication_subscription_inst *current_entry, *p_temp_entry;
+
+ BCM_LOG(DEBUG, log_id_public_api, "inspecting registered callback for object %d\n",
+ obj->obj_type);
+
+ TAILQ_FOREACH_SAFE(current_entry,
+ &indication_subscription_list,
+ indication_subscription_inst_next,
+ p_temp_entry)
+ {
+ BCM_LOG(DEBUG, log_id_public_api, "entry objtype %d\n", current_entry->cb_cfg.obj_type);
+
+ if((BCMBAL_OBJ_ID_ANY == current_entry->cb_cfg.obj_type) ||
+ (current_entry->cb_cfg.obj_type == obj->obj_type))
+ {
+ BCM_LOG(DEBUG, log_id_public_api,
+ "Calling registered callback for object %d\n",
+ obj->obj_type);
+
+ /* call the registered function directly or in the target module's context */
+ if (BCMOS_MODULE_ID_NONE == current_entry->cb_cfg.module)
+ {
+ current_entry->cb_cfg.ind_cb_hdlr(obj);
+ }
+ else
+ {
+ bcmbal_obj *clone = bcmbal_msg_clone(obj);
+ bcmos_errno err;
+ if (NULL == clone)
+ {
+ BCM_LOG(ERROR, log_id_public_api,
+ "Couldn't clone message for object %d\n",
+ obj->obj_type);
+ continue;
+ }
+ bcmbal_scratchpad_set(clone, current_entry->cb_cfg.ind_cb_hdlr);
+ err = bcmbal_msg_call(clone,
+ current_entry->cb_cfg.module,
+ _int_deliver_wrapper_cb,
+ BCMOS_MSG_SEND_AUTO_FREE);
+ if (BCM_ERR_OK != err)
+ {
+ BCM_LOG(ERROR, log_id_public_api,
+ "Couldn't deliver message for object %d to module %d. Error %s\n",
+ obj->obj_type, current_entry->cb_cfg.module, bcmos_strerror(err));
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+/*
+ * This is the handler for indication messages received by the BAL Public API
+ * backend from the core. We need to see who has subscribed for these messages,
+ * and call those registered functions.
+ */
+static void bal_ipc_api_indication_handler(bcmos_module_id module_id, bcmos_msg *msg)
+{
+
+ void *msg_payload;
+
+ msg_payload = bcmbal_payload_ptr_get(bcmbal_bal_hdr_get_by_bcmos_hdr(msg));
+
+ /*
+ * TO-DO
+ * validate the message major and minor version is correct
+ */
+
+ do
+ {
+ if(BAL_SUBSYSTEM_CORE != bcmbal_sender_get(msg_payload))
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Mgmt IND message received from wrong subsystem (%s)\n",
+ subsystem_str[bcmbal_sender_get(msg_payload)]);
+ break;
+ }
+
+ if(BCMBAL_MGMT_API_IND_MSG != bcmbal_type_major_get(msg_payload))
+ {
+ BCM_LOG(ERROR, log_id_public_api,"Mgmt IND message received with wrong major type (%d)\n",
+ bcmbal_type_major_get(msg_payload));
+ break;
+ }
+
+ /* Look through the list of registered subscribers for this indication
+ * and call them.
+ */
+ BCM_LOG(DEBUG, log_id_public_api,
+ "Processing indication listeners\n");
+
+ process_listener_callbacks((bcmbal_obj *)msg_payload);
+
+ }
+ while(0);
+
+ bcmbal_msg_free(msg_payload);
+
+ return;
+}
+
+void enable_bal_api_indications(const char *balapi_mgmt_ip_port)
+{
+
+ bcmos_task_parm task_p = {};
+ bcmos_module_parm module_p = {};
+ bcmos_errno ret = BCM_ERR_OK;
+ mgmt_queue_addr_ports mgmt_queue_info;
+
+ TAILQ_INIT(&indication_subscription_list);
+
+ do
+ {
+ /* Create quues for communication between BAL API and the core */
+ mgmt_queue_info.balapi_mgmt_ip_port = balapi_mgmt_ip_port;
+ ret = bal_api_ind_msg_queue_create(&mgmt_queue_info);
+ if (BCM_ERR_OK != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API indication queue\n");
+ break;
+ }
+
+ module_p.qparm.name = "bal_api_ind_worker_module";
+ module_p.init = _bal_worker_module_bal_api_init;
+ module_p.data = (long)&mgmt_queue_info; /* IP address and port information */
+
+ /* Create worker thread & modules for BAL indication messages from the core */
+ task_p.name = "bal_api_ind_worker";
+ task_p.priority = TASK_PRIORITY_WORKER;
+
+ ret = bcmos_task_create(&api_ind_worker_thread, &task_p);
+ if (BCM_ERR_OK != ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API indication worker thread\n");
+ break;
+ }
+
+ ret = bcmos_module_create(BCMOS_MODULE_ID_WORKER_API_IND, &api_ind_worker_thread, &module_p);
+ if (ret)
+ {
+ BCM_LOG(ERROR, log_id_public_api, "Couldn't create BAL API indication worker module\n");
+ break;
+ }
+
+ BCM_LOG(DEBUG, log_id_public_api, "BAL API indication handler registered\n");
+
+ }
+ while(0);
+
+ return;
+}
+
+
+/** NOTE: when cb_cfg->obj_type is BCMBAL_OBJ_ID_ANY AND type is UN-SUBSCRIBE, then this is unsubscribe all */
+bcmos_errno _manage_api_ind_listener(bcmbal_ind_cb_management_type type, bcmbal_cb_cfg *cb_cfg)
+{
+
+ bcmos_errno ret = BCM_ERR_OK;
+ indication_subscription_inst *new_ind_entry;
+ indication_subscription_inst *current_entry, *p_temp_entry;
+ bcmos_bool is_unsubscribe;
+
+ BUG_ON(NULL == cb_cfg);
+ BUG_ON(NULL == cb_cfg->ind_cb_hdlr);
+
+ is_unsubscribe = (IND_CB_UNSUBSCRIBE == type);
+
+ BCM_LOG(DEBUG,log_id_public_api,
+ "%s: %s for BAL API indications\n",
+ __FUNCTION__,
+ is_unsubscribe ? "Unsubscribing" : "Subscribing");
+
+ do
+ {
+ bcmos_bool b_found_existing_entry = BCMOS_FALSE;
+
+ TAILQ_FOREACH_SAFE(current_entry,
+ &indication_subscription_list,
+ indication_subscription_inst_next,
+ p_temp_entry)
+ {
+ if(
+ ((is_unsubscribe && (BCMBAL_OBJ_ID_ANY == cb_cfg->obj_type)) ? BCMOS_TRUE :
+ (current_entry->cb_cfg.obj_type == cb_cfg->obj_type)) &&
+ (current_entry->cb_cfg.ind_cb_hdlr == cb_cfg->ind_cb_hdlr) &&
+ (current_entry->cb_cfg.module == cb_cfg->module))
+ {
+ BCM_LOG(DEBUG,log_id_public_api,
+ "Found existing registration\n");
+
+ if(is_unsubscribe)
+ {
+ BCM_LOG(DEBUG,log_id_public_api,
+ "Removing registration\n");
+ TAILQ_REMOVE(&indication_subscription_list, current_entry, indication_subscription_inst_next);
+ bcmos_free(current_entry);
+ }
+
+ b_found_existing_entry = BCMOS_TRUE;
+
+ /* Don't stop looking for matches if we are unsubscribing from ANY indications, there could be many
+ * assigned to a single callback function */
+ if(!(is_unsubscribe && (BCMBAL_OBJ_ID_ANY == cb_cfg->obj_type))) break;
+ }
+
+ }
+
+ /* If we are subscribing to indication and we have already recorded
+ * this subscription, OR we are un-subscribing (whether or not we
+ * found a subscription to remove), then return right away with OK
+ */
+ if((BCMOS_TRUE == b_found_existing_entry) || is_unsubscribe)
+ {
+ break;
+ }
+
+ BCM_LOG(DEBUG,log_id_public_api,
+ "Registering NEW subscriber for BAL API indications\n");
+
+ /* This is a new subscription */
+ new_ind_entry = bcmos_calloc(sizeof(indication_subscription_inst));
+
+ if (NULL == new_ind_entry)
+ {
+ BCM_LOG(FATAL, log_id_public_api,
+ "Failed to register api indication subscription\n");
+ ret = BCM_ERR_NOMEM;
+ break;
+ }
+
+ new_ind_entry->cb_cfg = *cb_cfg;
+
+ TAILQ_INSERT_TAIL(&indication_subscription_list, new_ind_entry, indication_subscription_inst_next);
+
+ } while(0);
+
+ return ret;
+
+}
+
+static void free_all_indication_subscriptions(void)
+{
+ indication_subscription_inst *current_entry, *p_temp_entry;
+
+ TAILQ_FOREACH_SAFE(current_entry,
+ &indication_subscription_list,
+ indication_subscription_inst_next,
+ p_temp_entry)
+ {
+ TAILQ_REMOVE(&indication_subscription_list, current_entry, indication_subscription_inst_next);
+ bcmos_free(current_entry);
+ }
+
+ return;
+}
+
+
+void bal_api_indications_finish(void)
+{
+ free_all_indication_subscriptions();
+
+ bcmos_msg_unregister(BCMBAL_MGMT_API_IND_MSG,
+ 0,
+ BCMOS_MODULE_ID_WORKER_API_IND);
+
+ bcmos_msg_queue_destroy(&bal_api_ind_backend_queue);
+
+ bcmos_module_destroy(BCMOS_MODULE_ID_WORKER_API_IND);
+
+ bcmos_task_destroy(&api_ind_rx_thread);
+
+ bcmos_task_destroy(&api_ind_worker_thread);
+
+ return;
+}
diff --git a/bal_release/src/lib/libbalapi/bal_api_worker.h b/bal_release/src/lib/libbalapi/bal_api_worker.h
new file mode 100644
index 0000000..7e258ca
--- /dev/null
+++ b/bal_release/src/lib/libbalapi/bal_api_worker.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ * <: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 bal_worker.h
+ *
+ * @brief Bal worker thread included
+ *
+ * Module contains the data structures and functions used to support the
+ * BAL core worker thread.
+ */
+
+#ifndef BAL_API_WORKER_H
+#define BAL_API_WORKER_H
+
+#include <bcmos_errno.h>
+
+extern bcmos_msg_queue *p_balapi_to_core_queue;
+
+typedef enum {
+ IND_CB_SUBSCRIBE,
+ IND_CB_UNSUBSCRIBE
+}bcmbal_ind_cb_management_type;
+
+/*
+ * Function declarations
+ */
+extern bcmos_errno bal_api_ind_msg_queue_create(mgmt_queue_addr_ports *mgmt_queue_info);
+extern void enable_bal_api_indications(const char *balapi_mgmt_ip_port);
+extern bcmos_errno _manage_api_ind_listener(bcmbal_ind_cb_management_type type, bcmbal_cb_cfg *cb_cfg);
+extern void bal_api_indications_finish(void);
+
+
+#endif /* BAL_API_WORKER_H */