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 */