[VOL-5452]: Disable/Enable Onu OLT agent

Change-Id: I99855e5627fd683cd5310b887be65133813ddbe9
Signed-off-by: balaji.nagarajan <balaji.nagarajan@radisys.com>
diff --git a/Makefile b/Makefile
index 43f0f19..09e4fff 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@
 
 ## Variables
 OPENOLTDEVICE     ?= sim
-OPENOLT_PROTO_VER ?= v5.6.5
+OPENOLT_PROTO_VER ?= v5.6.6
 
 DOCKER                     ?= docker
 DOCKER_REGISTRY            ?=
diff --git a/VERSION b/VERSION
index e86ec35..e4fe76e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.10.2
\ No newline at end of file
+3.10.3
\ No newline at end of file
diff --git a/agent/common/core.h b/agent/common/core.h
index 2eb201c..5e5a49b 100644
--- a/agent/common/core.h
+++ b/agent/common/core.h
@@ -215,6 +215,10 @@
     const char *vendor_id, const char *vendor_specific);
 Status EnablePonIf_(uint32_t intf_id);
 Status DisablePonIf_(uint32_t intf_id);
+Status DisableOnuSerialNumber_(const ::openolt::InterfaceOnuSerialNumber* request);
+Status EnableOnuSerialNumber_(const ::openolt::InterfaceOnuSerialNumber* request);
+Status DisableOnu_(const ::openolt::InterfaceOnuSerialNumberOnuId* request);
+Status EnableOnu_(const ::openolt::InterfaceOnuSerialNumberOnuId* request);
 Status SetStateUplinkIf_(uint32_t intf_id, bool set_state);
 uint32_t GetNniSpeed_(uint32_t intf_id);
 unsigned NumNniIf_();
diff --git a/agent/common/server.cc b/agent/common/server.cc
index 507bfc1..5f46a6a 100644
--- a/agent/common/server.cc
+++ b/agent/common/server.cc
@@ -226,6 +226,38 @@
         return DisablePonIf_(request->intf_id());
     }
 
+    Status DisableOnuSerialNumber(
+            ServerContext* context,
+            const openolt::InterfaceOnuSerialNumber* request,
+            openolt::Empty* response) override {
+
+        return DisableOnuSerialNumber_(request);
+    }
+
+    Status EnableOnuSerialNumber(
+            ServerContext* context,
+            const openolt::InterfaceOnuSerialNumber* request,
+            openolt::Empty* response) override {
+
+        return EnableOnuSerialNumber_(request);
+    }
+    
+    Status DisableOnu(
+            ServerContext* context,
+            const openolt::InterfaceOnuSerialNumberOnuId* request,
+            openolt::Empty* response) override {
+
+        return DisableOnu_(request);
+    }
+
+    Status EnableOnu(
+            ServerContext* context,
+            const openolt::InterfaceOnuSerialNumberOnuId* request,
+            openolt::Empty* response) override {
+
+        return EnableOnu_(request);
+    }
+    
     Status CollectStatistics(
             ServerContext* context,
             const openolt::Empty* request,
diff --git a/agent/src/core_api_handler.cc b/agent/src/core_api_handler.cc
index d8f2ae4..bb2e466 100644
--- a/agent/src/core_api_handler.cc
+++ b/agent/src/core_api_handler.cc
@@ -1138,6 +1138,175 @@
     return speed;
 }
 
+Status DisableOnuSerialNumber_(const ::openolt::InterfaceOnuSerialNumber* request) {
+    bcmos_errno err = BCM_ERR_OK;
+    uint32_t intf_id = request->intf_id();
+     
+    // 1. Parse ONU Serial Number ▒~V~R~@~T assuming 4-byte vendor_id + 4-byte vendor_specific
+    bcmolt_serial_number itu_serial_number = {};
+    bcmolt_bin_str_4 itu_serial_number_vendor_id = {};
+    bcmolt_bin_str_4 itu_serial_number_vendor_specific = {};
+ 
+    // Extract vendor_id and vendor_specific from string
+    // Example onu_serial_number = "BBSM0001530A" ▒~V~R~F~R "BBSM" + binary(vendor_specific)
+    memcpy(itu_serial_number_vendor_id.arr, ((request->onu_serial_number()).vendor_id()).c_str(), 4);
+    memcpy(itu_serial_number_vendor_specific.arr, ((request->onu_serial_number()).vendor_specific()).c_str(), 4);
+ 
+    
+     // 2. Set fields in BAL serial number object
+    BCMOLT_FIELD_SET(&itu_serial_number, serial_number, vendor_id, itu_serial_number_vendor_id);
+    BCMOLT_FIELD_SET(&itu_serial_number, serial_number, vendor_specific, itu_serial_number_vendor_specific);
+ 
+    OPENOLT_LOG(INFO, openolt_log_id, "Received disable request for ONU serial number %s with vendor_id: %s, vendor_specific: %s\n",
+        serial_number_to_str(&itu_serial_number).c_str(),
+                ((request->onu_serial_number()).vendor_id()).c_str(), ((request->onu_serial_number()).vendor_specific()).c_str());
+
+    // 3. Prepare disable_serial_number operation on PON interface
+    bcmolt_pon_interface_key intf_key = {.pon_ni = (bcmolt_interface)intf_id};
+    bcmolt_pon_interface_disable_serial_number pon_interface_disable_sn;
+    BCMOLT_OPER_INIT(&pon_interface_disable_sn, pon_interface, disable_serial_number, intf_key);
+ 
+    // Set the control (enable/disable) and the serial number to disable
+    BCMOLT_FIELD_SET(&pon_interface_disable_sn.data, pon_interface_disable_serial_number_data,
+        control, (bcmolt_disable_serial_number_control)BCMOLT_DISABLE_SERIAL_NUMBER_CONTROL_UNICAST_DISABLE);
+    BCMOLT_FIELD_SET(&pon_interface_disable_sn.data, pon_interface_disable_serial_number_data,
+        serial_number, itu_serial_number);
+ 
+       // 4. Submit operation
+    err = bcmolt_oper_submit(dev_id, &pon_interface_disable_sn.hdr);
+    if(err != BCM_ERR_OK)
+    {
+        OPENOLT_LOG(ERROR, openolt_log_id, "Failed to disable onu serial number %s on port: %d, bcm_err: %s, err_text: %s\n",serial_number_to_str(&itu_serial_number).c_str(), intf_id,
+            bcmos_strerror(err), pon_interface_disable_sn.hdr.hdr.err_text);
+        return bcm_to_grpc_err(err, "Failed to disable onu serialnumber");
+    }
+    OPENOLT_LOG(INFO, openolt_log_id, "Successfully disabled Onu Serial number: %s , interface id %d\n",serial_number_to_str(&itu_serial_number).c_str(),intf_id);
+    return Status::OK;
+}
+
+Status EnableOnuSerialNumber_(const ::openolt::InterfaceOnuSerialNumber* request) {
+    bcmos_errno err = BCM_ERR_OK;
+    uint32_t intf_id = request->intf_id();
+     
+    // 1. Parse ONU Serial Number ▒~V~R~@~T assuming 4-byte vendor_id + 4-byte vendor_specific
+    bcmolt_serial_number itu_serial_number = {};
+    bcmolt_bin_str_4 itu_serial_number_vendor_id = {};
+    bcmolt_bin_str_4 itu_serial_number_vendor_specific = {};
+ 
+    // Extract vendor_id and vendor_specific from string
+    // Example onu_serial_number = "BBSM0001530A" ▒~V~R~F~R "BBSM" + binary(vendor_specific)
+    memcpy(itu_serial_number_vendor_id.arr, ((request->onu_serial_number()).vendor_id()).c_str(), 4);
+    memcpy(itu_serial_number_vendor_specific.arr, ((request->onu_serial_number()).vendor_specific()).c_str(), 4);
+ 
+     // 2. Set fields in BAL serial number object
+    BCMOLT_FIELD_SET(&itu_serial_number, serial_number, vendor_id, itu_serial_number_vendor_id);
+    BCMOLT_FIELD_SET(&itu_serial_number, serial_number, vendor_specific, itu_serial_number_vendor_specific);
+ 
+    OPENOLT_LOG(INFO, openolt_log_id, "Received enable request for ONU serial number %s with vendor_id: %s, vendor_specific: %s\n",
+        serial_number_to_str(&itu_serial_number).c_str(),
+                ((request->onu_serial_number()).vendor_id()).c_str(), ((request->onu_serial_number()).vendor_specific()).c_str());
+    // 3. Prepare disable_serial_number operation on PON interface
+    bcmolt_pon_interface_key intf_key = {.pon_ni = (bcmolt_interface)intf_id};
+    bcmolt_pon_interface_disable_serial_number pon_interface_disable_sn;
+    BCMOLT_OPER_INIT(&pon_interface_disable_sn, pon_interface, disable_serial_number, intf_key);
+ 
+    // Set the control (enable/disable) and the serial number to disable
+    BCMOLT_FIELD_SET(&pon_interface_disable_sn.data, pon_interface_disable_serial_number_data,
+        control, (bcmolt_disable_serial_number_control)BCMOLT_DISABLE_SERIAL_NUMBER_CONTROL_UNICAST_ENABLE);
+    BCMOLT_FIELD_SET(&pon_interface_disable_sn.data, pon_interface_disable_serial_number_data,
+        serial_number, itu_serial_number);
+ 
+       // 4. Submit operation
+    err = bcmolt_oper_submit(dev_id, &pon_interface_disable_sn.hdr);
+    if(err != BCM_ERR_OK)
+    {
+        OPENOLT_LOG(ERROR, openolt_log_id, "Failed to enable onu serial number %s on port: %d, bcm_err: %s, err_text: %s\n",serial_number_to_str(&itu_serial_number).c_str(), intf_id,
+            bcmos_strerror(err), pon_interface_disable_sn.hdr.hdr.err_text);
+        return bcm_to_grpc_err(err, "Failed to enable onu serialnumber");
+    }
+    OPENOLT_LOG(INFO, openolt_log_id, "Successfully enabled Onu Serial number: %s , interface id %d\n",serial_number_to_str(&itu_serial_number).c_str(),intf_id);
+    return Status::OK;
+}
+
+Status DisableOnu_(const ::openolt::InterfaceOnuSerialNumberOnuId* request) {
+    bcmos_errno err = BCM_ERR_OK;
+    uint32_t intf_id = (request->intf_id_serial_num()).intf_id();
+    uint32_t onu_id = request->onu_id();
+
+     // 1. Parse ONU Serial Number ▒~V~R~@~T assuming 4-byte vendor_id + 4-byte vendor_specific
+    bcmolt_serial_number itu_serial_number = {};
+    bcmolt_bin_str_4 itu_serial_number_vendor_id = {};
+    bcmolt_bin_str_4 itu_serial_number_vendor_specific = {};
+ 
+    // Extract vendor_id and vendor_specific from string
+    // Example onu_serial_number = "BBSM0001530A" ▒~V~R~F~R "BBSM" + binary(vendor_specific)
+    memcpy(itu_serial_number_vendor_id.arr, (((request->intf_id_serial_num()).onu_serial_number()).vendor_id()).c_str(), 4);
+    memcpy(itu_serial_number_vendor_specific.arr, (((request->intf_id_serial_num()).onu_serial_number()).vendor_specific()).c_str(), 4);
+
+    // 2. Set fields in BAL serial number object
+    BCMOLT_FIELD_SET(&itu_serial_number, serial_number, vendor_id, itu_serial_number_vendor_id);
+    BCMOLT_FIELD_SET(&itu_serial_number, serial_number, vendor_specific, itu_serial_number_vendor_specific);
+
+    bcmolt_onu_set_onu_state    onu_oper;
+    bcmolt_onu_key              onu_key;
+    onu_key.onu_id = onu_id;
+    onu_key.pon_ni = intf_id;
+    BCMOLT_OPER_INIT(&onu_oper, onu, set_onu_state, onu_key);
+    BCMOLT_FIELD_SET(&onu_oper.data, onu_set_onu_state_data,
+                onu_state, BCMOLT_ONU_OPERATION_DISABLE);
+ 
+    err = bcmolt_oper_submit(dev_id, &onu_oper.hdr);
+    if (err != BCM_ERR_OK)
+    {
+        OPENOLT_LOG(ERROR, openolt_log_id,"Failed to set onu state to disabled.onu serial number=%s, intf_id=%d, onu_id=%d, bcm_err=%s\n",
+                serial_number_to_str(&itu_serial_number).c_str(),
+                intf_id, onu_id,  bcmos_strerror(err));
+        return bcm_to_grpc_err(err, "Failed to disable onu");
+    }
+    OPENOLT_LOG(ERROR, openolt_log_id, "Successfully disabled Onu device with serial number %s ,id: %d , interface id %d\n",serial_number_to_str(&itu_serial_number).c_str(),onu_id,intf_id);
+    return Status::OK;
+}
+
+Status EnableOnu_(const ::openolt::InterfaceOnuSerialNumberOnuId* request) {
+    bcmos_errno err = BCM_ERR_OK;
+    uint32_t intf_id = (request->intf_id_serial_num()).intf_id();
+    uint32_t onu_id = request->onu_id();
+
+     // 1. Parse ONU Serial Number ▒~V~R~@~T assuming 4-byte vendor_id + 4-byte vendor_specific
+    bcmolt_serial_number itu_serial_number = {};
+    bcmolt_bin_str_4 itu_serial_number_vendor_id = {};
+    bcmolt_bin_str_4 itu_serial_number_vendor_specific = {};
+ 
+    // Extract vendor_id and vendor_specific from string
+    // Example onu_serial_number = "BBSM0001530A" ▒~V~R~F~R "BBSM" + binary(vendor_specific)
+    memcpy(itu_serial_number_vendor_id.arr, (((request->intf_id_serial_num()).onu_serial_number()).vendor_id()).c_str(), 4);
+    memcpy(itu_serial_number_vendor_specific.arr, (((request->intf_id_serial_num()).onu_serial_number()).vendor_specific()).c_str(), 4);
+
+    // 2. Set fields in BAL serial number object
+    BCMOLT_FIELD_SET(&itu_serial_number, serial_number, vendor_id, itu_serial_number_vendor_id);
+    BCMOLT_FIELD_SET(&itu_serial_number, serial_number, vendor_specific, itu_serial_number_vendor_specific);
+
+    bcmolt_onu_set_onu_state    onu_oper;
+    bcmolt_onu_key              onu_key;
+    onu_key.onu_id = onu_id;
+    onu_key.pon_ni = intf_id;
+
+    BCMOLT_OPER_INIT(&onu_oper, onu, set_onu_state, onu_key);
+    BCMOLT_FIELD_SET(&onu_oper.data, onu_set_onu_state_data,
+                onu_state, BCMOLT_ONU_OPERATION_ENABLE);
+ 
+    err = bcmolt_oper_submit(dev_id, &onu_oper.hdr);
+    if (err != BCM_ERR_OK)
+    {
+        OPENOLT_LOG(ERROR, openolt_log_id,"Failed to set onu state to enabled. Serial number=%s, intf_id=%d, onu_id=%d, bcm_err=%s\n",
+                serial_number_to_str(&itu_serial_number).c_str(),               
+                intf_id, onu_id,  bcmos_strerror(err));
+        return bcm_to_grpc_err(err, "Failed to enable onu");
+    }
+    OPENOLT_LOG(ERROR, openolt_log_id, "Successfully enabled Onu device with serial number %s, id: %d , interface id %d\n",serial_number_to_str(&itu_serial_number).c_str(),onu_id,intf_id);
+    return Status::OK;
+}
+
 Status DisablePonIf_(uint32_t intf_id) {
     bcmos_errno err;
     bcmolt_pon_interface_cfg interface_obj;
diff --git a/agent/src/indications.cc b/agent/src/indications.cc
index f24dca9..681ed99 100644
--- a/agent/src/indications.cc
+++ b/agent/src/indications.cc
@@ -340,6 +340,77 @@
     bcmolt_msg_free(msg);
 }
 
+static void OnuDisableIndication(bcmolt_devid olt, bcmolt_msg *msg) {
+    openolt::Indication ind;
+    openolt::OnuDisabledIndication* onu_disable_ind = new openolt::OnuDisabledIndication;
+    openolt::SerialNumber* serial_number = new openolt::SerialNumber;
+
+    switch (msg->obj_type) {
+        case BCMOLT_OBJ_ID_ONU:
+            switch (msg->subgroup) {
+                case BCMOLT_ONU_AUTO_SUBGROUP_ONU_DISABLE_COMPLETED:
+                {
+                    bcmolt_onu_onu_disable_completed* onu = (bcmolt_onu_onu_disable_completed *)msg;
+                    bcmolt_onu_key *key = &((bcmolt_onu_onu_disable_completed *)msg)->key;
+
+                    int port_no = interface_key_to_port_no(key->pon_ni, BCMOLT_INTERFACE_TYPE_PON);
+
+                    bcmolt_serial_number *in_serial_number = &(onu->data.serial_number);
+
+
+                    OPENOLT_LOG(INFO, openolt_log_id, "onu disable indication, pon_ni %d, onu_id %d, port_no %d, status %s, serial_number %s\n",
+                        key->pon_ni, key->onu_id, port_no, bcmolt_result_to_string(onu->data.status).c_str(),serial_number_to_str(in_serial_number).c_str());
+
+                    onu_disable_ind->set_intf_id(key->pon_ni);
+                    onu_disable_ind->set_onu_id(key->onu_id);
+                    serial_number->set_vendor_id(reinterpret_cast<const char *>(in_serial_number->vendor_id.arr), 4);
+                    serial_number->set_vendor_specific(reinterpret_cast<const char *>(in_serial_number->vendor_specific.arr), 8);
+                    onu_disable_ind->set_allocated_serial_number(serial_number);
+                    ind.set_allocated_onu_disabled_ind(onu_disable_ind);
+                    break;
+                }
+            }
+    }
+
+    oltIndQ.push(ind);
+    bcmolt_msg_free(msg);
+}
+
+static void OnuEnableIndication(bcmolt_devid olt, bcmolt_msg *msg) {
+    openolt::Indication ind;
+    openolt::OnuEnabledIndication* onu_enable_ind = new openolt::OnuEnabledIndication;
+    openolt::SerialNumber* serial_number = new openolt::SerialNumber;
+
+    switch (msg->obj_type) {
+        case BCMOLT_OBJ_ID_ONU:
+            switch (msg->subgroup) {
+                case BCMOLT_ONU_AUTO_SUBGROUP_ONU_ENABLE_COMPLETED:
+                {
+                    bcmolt_onu_onu_enable_completed* onu = (bcmolt_onu_onu_enable_completed *)msg;
+                    bcmolt_onu_key *key = &((bcmolt_onu_onu_enable_completed *)msg)->key;
+
+                    int port_no = interface_key_to_port_no(key->pon_ni, BCMOLT_INTERFACE_TYPE_PON);
+                    bcmolt_serial_number *in_serial_number = &(onu->data.serial_number);
+
+                    OPENOLT_LOG(INFO, openolt_log_id, "onu enable indication, pon_ni %d, onu_id %d, port_no %d, serial_number %s\n",
+                        key->pon_ni, key->onu_id, port_no,serial_number_to_str(in_serial_number).c_str());
+
+                    onu_enable_ind->set_intf_id(key->pon_ni);
+                    onu_enable_ind->set_onu_id(key->onu_id);
+                    serial_number->set_vendor_id(reinterpret_cast<const char *>(in_serial_number->vendor_id.arr), 4);
+                    serial_number->set_vendor_specific(reinterpret_cast<const char *>(in_serial_number->vendor_specific.arr), 8);
+                    onu_enable_ind->set_allocated_serial_number(serial_number);
+
+                    ind.set_allocated_onu_enabled_ind(onu_enable_ind);
+                    break;
+                }
+            }
+    }
+
+    oltIndQ.push(ind);
+    bcmolt_msg_free(msg);
+}
+
 static void OnuAlarmIndication(bcmolt_devid olt, bcmolt_msg *msg) {
     openolt::Indication ind;
     openolt::AlarmIndication* alarm_ind = new openolt::AlarmIndication;
@@ -1340,6 +1411,22 @@
     if(rc != BCM_ERR_OK)
         return Status(grpc::StatusCode::INTERNAL, "onu dying-gasp indication subscribe failed");
 
+    rx_cfg.obj_type = BCMOLT_OBJ_ID_ONU;
+    rx_cfg.rx_cb = OnuDisableIndication;
+    rx_cfg.flags = BCMOLT_AUTO_FLAGS_NONE;
+    rx_cfg.subgroup = bcmolt_onu_auto_subgroup_onu_disable_completed;
+    rc = bcmolt_ind_subscribe(current_device, &rx_cfg);
+    if(rc != BCM_ERR_OK)
+        return Status(grpc::StatusCode::INTERNAL, "onu disable indication subscribe failed");
+
+    rx_cfg.obj_type = BCMOLT_OBJ_ID_ONU;
+    rx_cfg.rx_cb = OnuEnableIndication;
+    rx_cfg.flags = BCMOLT_AUTO_FLAGS_NONE;
+    rx_cfg.subgroup = bcmolt_onu_auto_subgroup_onu_enable_completed;
+    rc = bcmolt_ind_subscribe(current_device, &rx_cfg);
+    if(rc != BCM_ERR_OK)
+        return Status(grpc::StatusCode::INTERNAL, "onu enable indication subscribe failed"); 
+
     rx_cfg.obj_type = BCMOLT_OBJ_ID_PON_INTERFACE;
     rx_cfg.rx_cb = OnuDiscoveryIndication;
     rx_cfg.flags = BCMOLT_AUTO_FLAGS_NONE;
diff --git a/agent/test/Makefile b/agent/test/Makefile
index f152e16..ede65a5 100644
--- a/agent/test/Makefile
+++ b/agent/test/Makefile
@@ -21,7 +21,7 @@
 TOP_DIR=`pwd`
 OPENOLTDEVICE ?= sim
 
-OPENOLT_PROTO_VER ?= v5.6.5
+OPENOLT_PROTO_VER ?= v5.6.6
 
 ########################################################################
 ##
diff --git a/protos/Makefile b/protos/Makefile
index f3686c1..dd42d20 100644
--- a/protos/Makefile
+++ b/protos/Makefile
@@ -19,7 +19,7 @@
 # This specifies the GIT tag in https://github.com/opencord/voltha-protos
 # repo that we need to refer to, to pick the right version of
 # openolt.proto, ext_config.proto and tech_profile.proto
-OPENOLT_PROTO_VER ?= v5.6.5
+OPENOLT_PROTO_VER ?= v5.6.6
 CXX ?= g++
 CPPFLAGS += `pkg-config --cflags protobuf grpc` -I googleapis/gens -I./
 CXXFLAGS += -std=c++11