BAL and Maple Release 2.2

Signed-off-by: Shad Ansari <developer@Carbon.local>
diff --git a/bcm68620_release/release/host_reference/api_proxy/Makefile b/bcm68620_release/release/host_reference/api_proxy/Makefile
new file mode 100644
index 0000000..940b839
--- /dev/null
+++ b/bcm68620_release/release/host_reference/api_proxy/Makefile
@@ -0,0 +1,12 @@
+ifeq ("$(OS)", "posix")
+    MOD_NAME = bcm_api_proxy
+    MOD_TYPE = lib
+    MOD_DEPS = transport cli
+ifeq ("$(RELEASE_BUILD)", "y")
+    MOD_DEPS += common_api
+else
+    MOD_DEPS += api
+endif
+
+    srcs = bcmolt_api_proxy.c
+endif
diff --git a/bcm68620_release/release/host_reference/api_proxy/bcmolt_api_proxy.c b/bcm68620_release/release/host_reference/api_proxy/bcmolt_api_proxy.c
new file mode 100644
index 0000000..9f71630
--- /dev/null
+++ b/bcm68620_release/release/host_reference/api_proxy/bcmolt_api_proxy.c
@@ -0,0 +1,501 @@
+/*
+<:copyright-BRCM:2016:DUAL/GPL:standard
+
+   Broadcom Proprietary and Confidential.(c) 2016 Broadcom
+   All Rights Reserved
+
+Unless you and Broadcom execute a separate written software license
+agreement governing use of this software, this software is licensed
+to you under the terms of the GNU General Public License version 2
+(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
+with the following added to such license:
+
+   As a special exception, the copyright holders of this software give
+   you permission to link this software with independent modules, and
+   to copy and distribute the resulting executable under terms of your
+   choice, provided that you also meet, for each linked independent
+   module, the terms and conditions of the license of that module.
+   An independent module is a module which is not derived from this
+   software.  The special exception does not apply to any modifications
+   of the software.
+
+Not withstanding the above, under no circumstances may you combine
+this software in any way with any other Broadcom software provided
+under a license other than the GPL, without Broadcom's express prior
+written consent.
+
+:>
+ */
+
+#include <bcmos_system.h>
+#include <bcmtr_interface.h>
+#include <bcmtr_header.h>
+#include <bcmtr_transport_cli.h>
+#include <bcmolt_api.h>
+#include <bcmtr_debug.h>
+#ifdef ENABLE_CLI
+#include <bcmcli.h>
+#endif
+#include "bcmolt_api_proxy.h"
+#ifdef ENABLE_LOG
+#include "bcm_dev_log.h"
+#endif
+
+/* Statistics */
+typedef struct proxy_stats
+{
+    unsigned long rx_packets;
+    unsigned long rx_bytes;
+    unsigned long tx_packets;
+    unsigned long tx_bytes;
+    unsigned long rx_errors;
+    unsigned long tx_errors;
+    unsigned long unpack_errors;
+    unsigned long pack_errors;
+    unsigned long msg_errors;
+} proxy_stats;
+
+typedef struct proxy_control_block
+{
+    bcmos_task proxy_rx_task;
+    struct sockaddr_in client;
+    uint32_t proxy_port;
+    int device_id;
+    int client_socket;
+    bcmos_bool is_running;
+    char *on_ready_cmd;
+
+    /* the maximum amount of memory that could possibly by used by all variable-sized lists within a GET request */
+#define DYNAMIC_LIST_BUFFER_SIZE (32 * 1024)
+    uint8_t dynamic_list_buffer[DYNAMIC_LIST_BUFFER_SIZE];
+
+    dev_log_id proxy_log;
+
+    proxy_stats stats;
+} proxy_control_block;
+
+/* Per device proxy control block */
+static proxy_control_block proxy_data[BCMTR_MAX_OLTS];
+static bcmos_bool is_first_proxy = BCMOS_TRUE;
+
+#ifdef ENABLE_CLI
+/*/proxy/stats command handler
+*/
+static bcmos_errno _proxy_stats_cmd(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
+{
+    int device = (int)parm[0].value.number;
+
+    if (device >= BCMTR_MAX_OLTS)
+        return BCM_ERR_RANGE;
+
+    bcmcli_print(session, "%-16s: %lu\n", "rx_packets", proxy_data[device].stats.rx_packets);
+    bcmcli_print(session, "%-16s: %lu\n", "rx_bytes", proxy_data[device].stats.rx_bytes);
+    bcmcli_print(session, "%-16s: %lu\n", "tx_packets", proxy_data[device].stats.tx_packets);
+    bcmcli_print(session, "%-16s: %lu\n", "tx_bytes", proxy_data[device].stats.tx_bytes);
+    bcmcli_print(session, "%-16s: %lu\n", "rx_errors", proxy_data[device].stats.rx_errors);
+    bcmcli_print(session, "%-16s: %lu\n", "tx_errors", proxy_data[device].stats.tx_errors);
+    bcmcli_print(session, "%-16s: %lu\n", "unpack_errors", proxy_data[device].stats.unpack_errors);
+    bcmcli_print(session, "%-16s: %lu\n", "pack_errors", proxy_data[device].stats.pack_errors);
+    bcmcli_print(session, "%-16s: %lu\n", "msg_errors", proxy_data[device].stats.msg_errors);
+    memset(&proxy_data[device].stats, 0, sizeof(proxy_stats));
+
+    return BCM_ERR_OK;
+}
+#endif /* #ifdef ENABLE_CLI */
+
+static bcmos_errno _proxy_msg_error(bcmolt_devid device, bcmolt_msg *proxy_msg)
+{
+    proxy_control_block *proxy = &proxy_data[device];
+    ++proxy->stats.msg_errors;
+    bcmolt_msg_err(proxy_msg, proxy->proxy_log, BCM_ERR_PARM, BCMOLT_ERR_FIELD_NONE, "Message is insane");
+    proxy_msg->dir = BCMOLT_MSG_DIR_RESPONSE;
+    return BCM_ERR_PARM;
+}
+
+static void _proxy_invoke(bcmolt_devid device, bcmolt_msg *proxy_msg)
+{
+    proxy_control_block *proxy = &proxy_data[device];
+    bcmos_errno rc;
+    bcmolt_system_mode system_mode;
+
+    /* Check that the message targets an object that is compatible with our system mode */
+    bcmolt_system_mode_get(device, &system_mode);
+    if (system_mode != BCMOLT_SYSTEM_MODE__NUM_OF && !bcmolt_object_is_supported(system_mode, proxy_msg->obj_type))
+    {
+        ++proxy->stats.msg_errors;
+        proxy_msg->dir = BCMOLT_MSG_DIR_RESPONSE;
+        bcmolt_msg_err(
+            proxy_msg,
+            proxy->proxy_log,
+            BCM_ERR_NOT_SUPPORTED,
+            BCMOLT_ERR_FIELD_NONE,
+            "Object type is not supported in this system mode");
+        return;
+    }
+
+    /* Invoke API */
+    switch (proxy_msg->group)
+    {
+        case BCMOLT_MGT_GROUP_CFG:
+            if ((proxy_msg->type & BCMOLT_MSG_TYPE_CLEAR) != 0)
+            {
+                rc = bcmolt_cfg_clear(device, (bcmolt_cfg *)proxy_msg);
+            }
+            else if ((proxy_msg->type & BCMOLT_MSG_TYPE_GET) != 0)
+            {
+                if ((proxy_msg->type & BCMOLT_MSG_TYPE_MULTI) != 0)
+                {
+                    if (proxy_msg->msg_set == NULL)
+                    {
+                        rc = _proxy_msg_error(device, proxy_msg);
+                    }
+                    else
+                    {
+                        rc = bcmolt_cfg_get_multi(device,
+                                                 (bcmolt_cfg *)proxy_msg,
+                                                 proxy_msg->msg_set->filter_flags,
+                                                 proxy_msg->msg_set);
+                    }
+                }
+                else
+                {
+                    rc = bcmolt_cfg_get(device, (bcmolt_cfg *)proxy_msg);
+                }
+            }
+            else if ((proxy_msg->type & BCMOLT_MSG_TYPE_SET) != 0)
+            {
+                rc = bcmolt_cfg_set(device, (bcmolt_cfg *)proxy_msg);
+            }
+            else
+            {
+                rc = _proxy_msg_error(device, proxy_msg);
+            }
+            break;
+
+        case BCMOLT_MGT_GROUP_STAT:
+            {
+                bcmolt_stat_flags flags;
+
+                flags = ((proxy_msg->type & BCMOLT_MSG_TYPE_CLEAR) != 0) ?
+                        BCMOLT_STAT_FLAGS_CLEAR_ON_READ : 0;
+
+                rc = bcmolt_stat_get(device, (bcmolt_stat *)proxy_msg, flags);
+            }
+            break;
+
+        case BCMOLT_MGT_GROUP_OPER:
+            rc = bcmolt_oper_submit(device, (bcmolt_oper *)proxy_msg);
+            break;
+
+        case BCMOLT_MGT_GROUP_PROXY:
+            rc = bcmolt_proxy_send(device, (bcmolt_proxy *)proxy_msg);
+            break;
+
+        case BCMOLT_MGT_GROUP_STAT_CFG:
+            if ((proxy_msg->type & BCMOLT_MSG_TYPE_GET) != 0)
+            {
+                rc = bcmolt_stat_cfg_get(device, (bcmolt_stat_cfg *)proxy_msg);
+            }
+            else if ((proxy_msg->type & BCMOLT_MSG_TYPE_SET) != 0)
+            {
+                rc = bcmolt_stat_cfg_set(device, (bcmolt_stat_cfg *)proxy_msg);
+            }
+            else
+            {
+                rc = _proxy_msg_error(device, proxy_msg);
+            }
+            break;
+
+        case BCMOLT_MGT_GROUP_AUTO_CFG:
+            if ((proxy_msg->type & BCMOLT_MSG_TYPE_GET) != 0)
+            {
+                rc = bcmolt_auto_cfg_get(device, (bcmolt_auto_cfg *)proxy_msg);
+            }
+            else if ((proxy_msg->type & BCMOLT_MSG_TYPE_SET) != 0)
+            {
+                rc = bcmolt_auto_cfg_set(device, (bcmolt_auto_cfg *)proxy_msg);
+            }
+            else
+            {
+                rc = _proxy_msg_error(device, proxy_msg);
+            }
+            break;
+
+        default:
+            rc = _proxy_msg_error(device, proxy_msg);
+    }
+
+    proxy_msg->err = rc;
+}
+
+/* Pack and send message */
+static void _proxy_send(bcmolt_devid device, bcmolt_msg *msg)
+{
+    bcmtr_hdr hdr = {};
+    int32_t packed_length;
+    bcmolt_buf txb = {};
+    int len;
+
+    /* Allocate buffer and pack */
+    packed_length = bcmolt_msg_get_packed_length(msg);
+    if (packed_length <= 0)
+    {
+        ++proxy_data[device].stats.pack_errors;
+        goto done;
+    }
+    packed_length += BCMTR_HDR_SIZE;
+    if (bcmolt_buf_alloc(&txb, packed_length, BCMOLT_BUF_ENDIAN_FIXED) != BCM_ERR_OK)
+    {
+        ++proxy_data[device].stats.pack_errors;
+        goto done;
+    }
+    bcmtr_header_fill(msg, &hdr);
+    bcmtr_header_pack(&hdr, txb.start);
+    bcmolt_buf_skip(&txb, BCMTR_HDR_SIZE);
+    if (bcmolt_msg_pack(msg, &txb) != BCM_ERR_OK)
+    {
+        ++proxy_data[device].stats.pack_errors;
+        goto done;
+    }
+
+    /* Send to client */
+    len = sendto(proxy_data[device].client_socket, txb.start, bcmolt_buf_get_used(&txb), 0,
+                 (struct sockaddr *)&proxy_data[device].client, sizeof(proxy_data[device].client));
+    if (len <= 0)
+    {
+        ++proxy_data[device].stats.tx_errors;
+    }
+    else
+    {
+        ++proxy_data[device].stats.tx_packets;
+        proxy_data[device].stats.tx_bytes += len;
+    }
+
+done:
+    bcmolt_buf_free(&txb);
+    return;
+}
+
+/* Task that waits for messages from Maple.
+ * Once message is received, it is forwarded to remote application
+ * via UDP socket.
+ */
+static int _proxy_rx_handler(long data)
+{
+    bcmolt_devid device = (bcmolt_devid)data;
+    bcmos_task *self = bcmos_task_current();
+    proxy_control_block *proxy = &proxy_data[device];
+    struct sockaddr_in sender;
+    socklen_t sendsize = sizeof(sender);
+    uint8_t client_buffer[BCMTR_MAX_MTU_SIZE + 128];
+    bcmolt_msg *proxy_msg;
+    bcmtr_hdr tr_hdr;
+    bcmolt_buf rxb;
+    int len;
+    uint16_t corr_tag;
+    bcmos_errno rc;
+
+    while (!self->destroyed)
+    {
+        memset(&sender, 0, sizeof(sender));
+        len = recvfrom(proxy->client_socket, client_buffer, sizeof(client_buffer), 0,
+                       (struct sockaddr *)&sender, &sendsize);
+        if (len < BCMTR_HDR_SIZE)
+        {
+            ++proxy->stats.rx_errors;
+            bcmos_usleep(1000000);
+            continue;
+        }
+        ++proxy->stats.rx_packets;
+        proxy->stats.rx_bytes += len;
+
+        if (proxy->client.sin_addr.s_addr != sender.sin_addr.s_addr ||
+            proxy->client.sin_port != sender.sin_port)
+        {
+#ifdef ENABLE_LOG
+            int client_ip = ntohl(sender.sin_addr.s_addr);
+            int client_port = ntohs(sender.sin_port);
+            BCM_LOG(INFO, proxy->proxy_log, "bcm_api_proxy: device %i connected to %d.%d.%d.%d:%d\n",
+                    (int)device,
+                    (client_ip >> 24) & 0xff, (client_ip >> 16) & 0xff,
+                    (client_ip >> 8) & 0xff, client_ip & 0xff, client_port);
+#endif
+            proxy->client = sender;
+        }
+
+        /* Unpack received message */
+        bcmolt_buf_init(&rxb, len, client_buffer, BCMOLT_BUF_ENDIAN_FIXED);
+        bcmtr_header_unpack(client_buffer, &tr_hdr);
+
+        /* Skip registration messages for now. The proxy has already registered for everything */
+        if (tr_hdr.auto_proxy_reg || tr_hdr.auto_proxy_unreg)
+            continue;
+
+        bcmolt_buf_skip(&rxb, BCMTR_HDR_SIZE);
+        proxy_msg = NULL;
+        rc = bcmolt_msg_unpack(&rxb, &proxy_msg);
+        if (rc)
+        {
+            /* Unpack error. Nothing much we can do */
+            ++proxy->stats.unpack_errors;
+            continue;
+        }
+
+        /* Store correlation tag for later */
+        proxy_msg->corr_tag = tr_hdr.corr_tag;
+        corr_tag = proxy_msg->corr_tag;
+
+        /* Point the message unpacker to local storage for dynamically-sized lists */
+        proxy_msg->list_buf = proxy->dynamic_list_buffer;
+        proxy_msg->list_buf_size = DYNAMIC_LIST_BUFFER_SIZE;
+
+        /* Invoke API */
+        _proxy_invoke(device, proxy_msg);
+
+        /* Pack and send back to the client */
+        proxy_msg->corr_tag = corr_tag;
+        _proxy_send(device, proxy_msg);
+        bcmolt_msg_free(proxy_msg);
+    }
+
+    self->destroyed = BCMOS_TRUE;
+    return 0;
+}
+
+/* Auto / proxy message handler */
+void bcmolt_api_proxy_auto_rx_cb(bcmolt_devid device, bcmolt_msg *msg)
+{
+    if (device >= BCMTR_MAX_OLTS)
+        return;
+
+    if (proxy_data[device].is_running)
+    {
+        if (proxy_data[device].on_ready_cmd &&
+            msg->obj_type == BCMOLT_OBJ_ID_DEVICE &&
+            msg->group == BCMOLT_MGT_GROUP_AUTO &&
+            msg->subgroup == BCMOLT_DEVICE_AUTO_ID_CONNECTION_COMPLETE)
+        {
+            char on_ready_cmd[512];
+            int rc;
+            snprintf(on_ready_cmd, sizeof(on_ready_cmd) - 1, "%s %d", proxy_data[device].on_ready_cmd, (int)device);
+            rc = system(on_ready_cmd);
+#ifdef ENABLE_LOG
+            BCM_LOG(INFO, proxy_data[device].proxy_log, "Executed command %s. rc=%d\n", on_ready_cmd, rc);
+#else
+            (void)rc;
+#endif
+        }
+        _proxy_send(device, msg);
+    }
+}
+
+static bcmos_errno _proxy_start(bcmolt_devid device, uint32_t udp_port, char *on_ready)
+{
+    bcmos_errno rc;
+    bcmos_task_parm proxy_rx_parm =
+    {
+        .name = "proxy_rx",
+        .handler = _proxy_rx_handler,
+        .priority = TASK_PRIORITY_TRANSPORT_PROXY,
+        .data = device
+    };
+    struct sockaddr_in sa = {};
+
+    proxy_data[device].proxy_port = udp_port;
+    proxy_data[device].device_id = device;
+    proxy_data[device].on_ready_cmd = on_ready;
+
+    /* Start listening on proxy port */
+    proxy_data[device].client_socket = socket(AF_INET, SOCK_DGRAM, 0);
+    if (proxy_data[device].client_socket < 0)
+    {
+#ifdef ENABLE_LOG
+        BCM_LOG(ERROR, proxy_data[device].proxy_log, "Can't create UDP socket\n");
+#endif
+        return BCM_ERR_INTERNAL;
+    }
+
+    /* Bind local */
+    sa.sin_family = AF_INET;
+    sa.sin_port = htons(proxy_data[device].proxy_port);
+    sa.sin_addr.s_addr = INADDR_ANY;
+    if (bind(proxy_data[device].client_socket, (struct sockaddr*)&sa, sizeof(sa) ) == -1)
+    {
+        perror("bind");
+#ifdef ENABLE_LOG
+        BCM_LOG(ERROR, proxy_data[device].proxy_log, "Can't bind UDP socket to port %u\n", proxy_data[device].proxy_port);
+#endif
+        close(proxy_data[device].client_socket);
+        return BCM_ERR_INTERNAL;
+    }
+
+    /* Create thread listening for incoming APIs */
+    rc = bcmos_task_create(&proxy_data[device].proxy_rx_task, &proxy_rx_parm);
+    BUG_ON(BCM_ERR_OK != rc);
+
+    proxy_data[device].is_running = BCMOS_TRUE;
+
+#ifdef ENABLE_LOG
+    BCM_LOG(INFO, proxy_data[device].proxy_log, "BCM68620 API proxy for device %d is listening for requests on UDP port %u\n",
+        (int)device, proxy_data[device].proxy_port);
+#endif
+
+    return BCM_ERR_OK;
+}
+
+bcmos_errno bcmolt_api_proxy_init(bcmcli_entry *root, bcmolt_devid device, uint32_t udp_port, char *on_ready)
+{
+#ifdef ENABLE_CLI
+    bcmcli_entry *dir;
+#endif
+
+    if (device >= BCMTR_MAX_OLTS)
+        return BCM_ERR_PARM;
+
+    if (proxy_data[device].is_running)
+        return BCM_ERR_ALREADY;
+
+#ifdef ENABLE_LOG
+    {
+        char log_id[32];
+        snprintf(log_id, sizeof(log_id) - 1, "proxy_%d", (int)device);
+        proxy_data[device].proxy_log = bcm_dev_log_id_register(log_id, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
+    }
+#else
+    proxy_data[device].proxy_log = DEV_LOG_INVALID_ID;
+#endif
+
+    if (is_first_proxy)
+    {
+#ifdef ENABLE_CLI
+        dir = bcmcli_dir_add(root, "proxy", "API proxy", BCMCLI_ACCESS_GUEST, NULL);
+        if (!dir)
+        {
+            BCM_LOG(ERROR, proxy_data[device].proxy_log, "Can't create proxy directory\n");
+            BUG();
+        }
+
+        BCMCLI_MAKE_CMD(dir, "stat", "Proxy statistics", _proxy_stats_cmd,
+            BCMCLI_MAKE_PARM_RANGE("device", "Device index", BCMCLI_PARM_NUMBER, BCMCLI_PARM_FLAG_OPTIONAL,
+                0, BCMTR_MAX_OLTS-1));
+
+#endif
+        is_first_proxy = BCMOS_FALSE;
+    }
+    return _proxy_start(device, udp_port, on_ready);
+}
+
+void bcmolt_api_proxy_stop(void)
+{
+    int i;
+
+    for (i = 0; i < BCMTR_MAX_OLTS; i++)
+    {
+        if (proxy_data[i].is_running)
+        {
+            bcmos_task_destroy(&proxy_data[i].proxy_rx_task);
+            close(proxy_data[i].client_socket);
+        }
+    }
+}
+
diff --git a/bcm68620_release/release/host_reference/api_proxy/bcmolt_api_proxy.h b/bcm68620_release/release/host_reference/api_proxy/bcmolt_api_proxy.h
new file mode 100644
index 0000000..a76c25e
--- /dev/null
+++ b/bcm68620_release/release/host_reference/api_proxy/bcmolt_api_proxy.h
@@ -0,0 +1,44 @@
+/*
+<:copyright-BRCM:2016:DUAL/GPL:standard
+
+   Broadcom Proprietary and Confidential.(c) 2016 Broadcom
+   All Rights Reserved
+
+Unless you and Broadcom execute a separate written software license
+agreement governing use of this software, this software is licensed
+to you under the terms of the GNU General Public License version 2
+(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
+with the following added to such license:
+
+   As a special exception, the copyright holders of this software give
+   you permission to link this software with independent modules, and
+   to copy and distribute the resulting executable under terms of your
+   choice, provided that you also meet, for each linked independent
+   module, the terms and conditions of the license of that module.
+   An independent module is a module which is not derived from this
+   software.  The special exception does not apply to any modifications
+   of the software.
+
+Not withstanding the above, under no circumstances may you combine
+this software in any way with any other Broadcom software provided
+under a license other than the GPL, without Broadcom's express prior
+written consent.
+
+:>
+ */
+
+#ifndef _BCMOLT_API_PROXY_H_
+#define _BCMOLT_API_PROXY_H_
+
+#include <bcmos_system.h>
+#include <bcmolt_msg.h>
+
+void bcmolt_api_proxy_auto_rx_cb(bcmolt_devid olt, bcmolt_msg *msg);
+
+bcmos_errno bcmolt_api_proxy_init(bcmcli_entry *root, bcmolt_devid device, uint32_t udp_port, char *on_ready_cmd);
+
+void bcmolt_api_proxy_stop(void);
+
+#endif
+
+